• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.doze;
18 
19 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
20 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
21 
22 import android.annotation.AnyThread;
23 import android.app.ActivityManager;
24 import android.app.AlarmManager;
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.database.ContentObserver;
28 import android.hardware.Sensor;
29 import android.hardware.SensorManager;
30 import android.hardware.TriggerEvent;
31 import android.hardware.TriggerEventListener;
32 import android.hardware.display.AmbientDisplayConfiguration;
33 import android.net.Uri;
34 import android.os.Handler;
35 import android.os.SystemClock;
36 import android.os.UserHandle;
37 import android.provider.Settings;
38 import android.text.TextUtils;
39 import android.util.Log;
40 import android.view.Display;
41 
42 import androidx.annotation.VisibleForTesting;
43 
44 import com.android.internal.logging.MetricsLogger;
45 import com.android.internal.logging.UiEvent;
46 import com.android.internal.logging.UiEventLogger;
47 import com.android.internal.logging.UiEventLoggerImpl;
48 import com.android.internal.logging.nano.MetricsProto;
49 import com.android.internal.util.IndentingPrintWriter;
50 import com.android.systemui.plugins.SensorManagerPlugin;
51 import com.android.systemui.statusbar.phone.DozeParameters;
52 import com.android.systemui.util.sensors.AsyncSensorManager;
53 import com.android.systemui.util.sensors.ProximitySensor;
54 import com.android.systemui.util.wakelock.WakeLock;
55 
56 import java.io.PrintWriter;
57 import java.util.Collection;
58 import java.util.List;
59 import java.util.function.Consumer;
60 
61 public class DozeSensors {
62 
63     private static final boolean DEBUG = DozeService.DEBUG;
64     private static final String TAG = "DozeSensors";
65     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
66 
67     private final Context mContext;
68     private final AlarmManager mAlarmManager;
69     private final AsyncSensorManager mSensorManager;
70     private final ContentResolver mResolver;
71     private final DozeParameters mDozeParameters;
72     private final AmbientDisplayConfiguration mConfig;
73     private final WakeLock mWakeLock;
74     private final Consumer<Boolean> mProxCallback;
75     private final Callback mCallback;
76     @VisibleForTesting
77     protected TriggerSensor[] mSensors;
78 
79     private final Handler mHandler = new Handler();
80     private final ProximitySensor mProximitySensor;
81     private long mDebounceFrom;
82     private boolean mSettingRegistered;
83     private boolean mListening;
84     private boolean mListeningTouchScreenSensors;
85 
86     @VisibleForTesting
87     public enum DozeSensorsUiEvent implements UiEventLogger.UiEventEnum {
88         @UiEvent(doc = "User performs pickup gesture that activates the ambient display")
89         ACTION_AMBIENT_GESTURE_PICKUP(459);
90 
91         private final int mId;
92 
DozeSensorsUiEvent(int id)93         DozeSensorsUiEvent(int id) {
94             mId = id;
95         }
96 
97         @Override
getId()98         public int getId() {
99             return mId;
100         }
101     }
102 
DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog, ProximitySensor proximitySensor)103     public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
104             DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
105             Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
106             ProximitySensor proximitySensor) {
107         mContext = context;
108         mAlarmManager = alarmManager;
109         mSensorManager = sensorManager;
110         mDozeParameters = dozeParameters;
111         mConfig = config;
112         mWakeLock = wakeLock;
113         mProxCallback = proxCallback;
114         mResolver = mContext.getContentResolver();
115         mCallback = callback;
116         mProximitySensor = proximitySensor;
117 
118         boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
119         mSensors = new TriggerSensor[] {
120                 new TriggerSensor(
121                         mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
122                         null /* setting */,
123                         dozeParameters.getPulseOnSigMotion(),
124                         DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */,
125                         false /* touchscreen */, dozeLog),
126                 new TriggerSensor(
127                         mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
128                         Settings.Secure.DOZE_PICK_UP_GESTURE,
129                         true /* settingDef */,
130                         config.dozePickupSensorAvailable(),
131                         DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
132                         false /* touchscreen */,
133                         false /* ignoresSetting */,
134                         dozeLog),
135                 new TriggerSensor(
136                         findSensorWithType(config.doubleTapSensorType()),
137                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
138                         true /* configured */,
139                         DozeLog.REASON_SENSOR_DOUBLE_TAP,
140                         dozeParameters.doubleTapReportsTouchCoordinates(),
141                         true /* touchscreen */,
142                         dozeLog),
143                 new TriggerSensor(
144                         findSensorWithType(config.tapSensorType()),
145                         Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
146                         true /* configured */,
147                         DozeLog.REASON_SENSOR_TAP,
148                         false /* reports touch coordinates */,
149                         true /* touchscreen */,
150                         dozeLog),
151                 new TriggerSensor(
152                         findSensorWithType(config.longPressSensorType()),
153                         Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
154                         false /* settingDef */,
155                         true /* configured */,
156                         DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
157                         true /* reports touch coordinates */,
158                         true /* touchscreen */,
159                         dozeLog),
160                 new PluginSensor(
161                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
162                         Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
163                         mConfig.wakeScreenGestureAvailable() && alwaysOn,
164                         DozeLog.REASON_SENSOR_WAKE_UP,
165                         false /* reports touch coordinates */,
166                         false /* touchscreen */,
167                         dozeLog),
168                 new PluginSensor(
169                         new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
170                         Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
171                         mConfig.wakeScreenGestureAvailable(),
172                         DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
173                         false /* reports touch coordinates */,
174                         false /* touchscreen */,
175                         mConfig.getWakeLockScreenDebounce(),
176                         dozeLog),
177         };
178 
179         setProxListening(false);  // Don't immediately start listening when we register.
180         mProximitySensor.register(
181                 proximityEvent -> {
182                     if (proximityEvent != null) {
183                         mProxCallback.accept(!proximityEvent.getBelow());
184                     }
185                 });
186     }
187 
188     /**
189      *  Unregister any sensors.
190      */
destroy()191     public void destroy() {
192         // Unregisters everything, which is enough to allow gc.
193         for (TriggerSensor triggerSensor : mSensors) {
194             triggerSensor.setListening(false);
195         }
196         mProximitySensor.pause();
197     }
198 
199     /**
200      * Temporarily disable some sensors to avoid turning on the device while the user is
201      * turning it off.
202      */
requestTemporaryDisable()203     public void requestTemporaryDisable() {
204         mDebounceFrom = SystemClock.uptimeMillis();
205     }
206 
findSensorWithType(String type)207     private Sensor findSensorWithType(String type) {
208         return findSensorWithType(mSensorManager, type);
209     }
210 
findSensorWithType(SensorManager sensorManager, String type)211     static Sensor findSensorWithType(SensorManager sensorManager, String type) {
212         if (TextUtils.isEmpty(type)) {
213             return null;
214         }
215         List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
216         for (Sensor s : sensorList) {
217             if (type.equals(s.getStringType())) {
218                 return s;
219             }
220         }
221         return null;
222     }
223 
224     /**
225      * If sensors should be registered and sending signals.
226      */
setListening(boolean listen, boolean includeTouchScreenSensors)227     public void setListening(boolean listen, boolean includeTouchScreenSensors) {
228         if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors) {
229             return;
230         }
231         mListening = listen;
232         mListeningTouchScreenSensors = includeTouchScreenSensors;
233         updateListening();
234     }
235 
236     /**
237      * Registers/unregisters sensors based on internal state.
238      */
updateListening()239     private void updateListening() {
240         boolean anyListening = false;
241         for (TriggerSensor s : mSensors) {
242             boolean listen = mListening
243                     && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors);
244             s.setListening(listen);
245             if (listen) {
246                 anyListening = true;
247             }
248         }
249 
250         if (!anyListening) {
251             mResolver.unregisterContentObserver(mSettingsObserver);
252         } else if (!mSettingRegistered) {
253             for (TriggerSensor s : mSensors) {
254                 s.registerSettingsObserver(mSettingsObserver);
255             }
256         }
257         mSettingRegistered = anyListening;
258     }
259 
260     /** Set the listening state of only the sensors that require the touchscreen. */
setTouchscreenSensorsListening(boolean listening)261     public void setTouchscreenSensorsListening(boolean listening) {
262         for (TriggerSensor sensor : mSensors) {
263             if (sensor.mRequiresTouchscreen) {
264                 sensor.setListening(listening);
265             }
266         }
267     }
268 
onUserSwitched()269     public void onUserSwitched() {
270         for (TriggerSensor s : mSensors) {
271             s.updateListening();
272         }
273     }
274 
onScreenState(int state)275     void onScreenState(int state) {
276         mProximitySensor.setSecondarySafe(
277                 state == Display.STATE_DOZE
278                 || state == Display.STATE_DOZE_SUSPEND
279                 || state == Display.STATE_OFF);
280     }
281 
setProxListening(boolean listen)282     public void setProxListening(boolean listen) {
283         if (mProximitySensor.isRegistered() && listen) {
284             mProximitySensor.alertListeners();
285         } else {
286             if (listen) {
287                 mProximitySensor.resume();
288             } else {
289                 mProximitySensor.pause();
290             }
291         }
292     }
293 
294     private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
295         @Override
296         public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
297             if (userId != ActivityManager.getCurrentUser()) {
298                 return;
299             }
300             for (TriggerSensor s : mSensors) {
301                 s.updateListening();
302             }
303         }
304     };
305 
306     /** Ignore the setting value of only the sensors that require the touchscreen. */
ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore)307     public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) {
308         for (TriggerSensor sensor : mSensors) {
309             if (sensor.mRequiresTouchscreen) {
310                 sensor.ignoreSetting(ignore);
311             }
312         }
313     }
314 
315     /** Dump current state */
dump(PrintWriter pw)316     public void dump(PrintWriter pw) {
317         pw.println("mListening=" + mListening);
318         pw.println("mListeningTouchScreenSensors=" + mListeningTouchScreenSensors);
319         IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
320         idpw.increaseIndent();
321         for (TriggerSensor s : mSensors) {
322             idpw.println("Sensor: " + s.toString());
323         }
324         idpw.println("ProxSensor: " + mProximitySensor.toString());
325     }
326 
327     /**
328      * @return true if prox is currently near, false if far or null if unknown.
329      */
isProximityCurrentlyNear()330     public Boolean isProximityCurrentlyNear() {
331         return mProximitySensor.isNear();
332     }
333 
334     @VisibleForTesting
335     class TriggerSensor extends TriggerEventListener {
336         final Sensor mSensor;
337         final boolean mConfigured;
338         final int mPulseReason;
339         private final String mSetting;
340         private final boolean mReportsTouchCoordinates;
341         private final boolean mSettingDefault;
342         private final boolean mRequiresTouchscreen;
343 
344         protected boolean mRequested;
345         protected boolean mRegistered;
346         protected boolean mDisabled;
347         protected boolean mIgnoresSetting;
348         protected final DozeLog mDozeLog;
349 
TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog)350         public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
351                 boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog) {
352             this(sensor, setting, true /* settingDef */, configured, pulseReason,
353                     reportsTouchCoordinates, requiresTouchscreen, dozeLog);
354         }
355 
TriggerSensor(Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog)356         public TriggerSensor(Sensor sensor, String setting, boolean settingDef,
357                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
358                 boolean requiresTouchscreen, DozeLog dozeLog) {
359             this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
360                     requiresTouchscreen, false /* ignoresSetting */, dozeLog);
361         }
362 
TriggerSensor(Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, boolean ignoresSetting, DozeLog dozeLog)363         private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
364                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
365                 boolean requiresTouchscreen, boolean ignoresSetting, DozeLog dozeLog) {
366             mSensor = sensor;
367             mSetting = setting;
368             mSettingDefault = settingDef;
369             mConfigured = configured;
370             mPulseReason = pulseReason;
371             mReportsTouchCoordinates = reportsTouchCoordinates;
372             mRequiresTouchscreen = requiresTouchscreen;
373             mIgnoresSetting = ignoresSetting;
374             mDozeLog = dozeLog;
375         }
376 
setListening(boolean listen)377         public void setListening(boolean listen) {
378             if (mRequested == listen) return;
379             mRequested = listen;
380             updateListening();
381         }
382 
setDisabled(boolean disabled)383         public void setDisabled(boolean disabled) {
384             if (mDisabled == disabled) return;
385             mDisabled = disabled;
386             updateListening();
387         }
388 
ignoreSetting(boolean ignored)389         public void ignoreSetting(boolean ignored) {
390             if (mIgnoresSetting == ignored) return;
391             mIgnoresSetting = ignored;
392             updateListening();
393         }
394 
updateListening()395         public void updateListening() {
396             if (!mConfigured || mSensor == null) return;
397             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
398                     && !mRegistered) {
399                 mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
400                 if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
401             } else if (mRegistered) {
402                 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
403                 if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt);
404                 mRegistered = false;
405             }
406         }
407 
enabledBySetting()408         protected boolean enabledBySetting() {
409             if (!mConfig.enabled(UserHandle.USER_CURRENT)) {
410                 return false;
411             } else if (TextUtils.isEmpty(mSetting)) {
412                 return true;
413             }
414             return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0,
415                     UserHandle.USER_CURRENT) != 0;
416         }
417 
418         @Override
toString()419         public String toString() {
420             return new StringBuilder("{mRegistered=").append(mRegistered)
421                     .append(", mRequested=").append(mRequested)
422                     .append(", mDisabled=").append(mDisabled)
423                     .append(", mConfigured=").append(mConfigured)
424                     .append(", mIgnoresSetting=").append(mIgnoresSetting)
425                     .append(", mSensor=").append(mSensor).append("}").toString();
426         }
427 
428         @Override
429         @AnyThread
onTrigger(TriggerEvent event)430         public void onTrigger(TriggerEvent event) {
431             mDozeLog.traceSensor(mPulseReason);
432             mHandler.post(mWakeLock.wrap(() -> {
433                 if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
434                 if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
435                     int subType = (int) event.values[0];
436                     MetricsLogger.action(
437                             mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
438                             subType);
439                     UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP);
440                 }
441 
442                 mRegistered = false;
443                 float screenX = -1;
444                 float screenY = -1;
445                 if (mReportsTouchCoordinates && event.values.length >= 2) {
446                     screenX = event.values[0];
447                     screenY = event.values[1];
448                 }
449                 mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
450                 if (!mRegistered) {
451                     updateListening();  // reregister, this sensor only fires once
452                 }
453             }));
454         }
455 
registerSettingsObserver(ContentObserver settingsObserver)456         public void registerSettingsObserver(ContentObserver settingsObserver) {
457             if (mConfigured && !TextUtils.isEmpty(mSetting)) {
458                 mResolver.registerContentObserver(
459                         Settings.Secure.getUriFor(mSetting), false /* descendants */,
460                         mSettingsObserver, UserHandle.USER_ALL);
461             }
462         }
463 
triggerEventToString(TriggerEvent event)464         protected String triggerEventToString(TriggerEvent event) {
465             if (event == null) return null;
466             final StringBuilder sb = new StringBuilder("SensorEvent[")
467                     .append(event.timestamp).append(',')
468                     .append(event.sensor.getName());
469             if (event.values != null) {
470                 for (int i = 0; i < event.values.length; i++) {
471                     sb.append(',').append(event.values[i]);
472                 }
473             }
474             return sb.append(']').toString();
475         }
476     }
477 
478     /**
479      * A Sensor that is injected via plugin.
480      */
481     @VisibleForTesting
482     class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener {
483 
484         final SensorManagerPlugin.Sensor mPluginSensor;
485         private long mDebounce;
486 
PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog)487         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
488                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
489                 DozeLog dozeLog) {
490             this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
491                     requiresTouchscreen, 0L /* debounce */, dozeLog);
492         }
493 
PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, long debounce, DozeLog dozeLog)494         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
495                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
496                 long debounce, DozeLog dozeLog) {
497             super(null, setting, configured, pulseReason, reportsTouchCoordinates,
498                     requiresTouchscreen, dozeLog);
499             mPluginSensor = sensor;
500             mDebounce = debounce;
501         }
502 
503         @Override
updateListening()504         public void updateListening() {
505             if (!mConfigured) return;
506             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
507             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
508                     && !mRegistered) {
509                 asyncSensorManager.registerPluginListener(mPluginSensor, this);
510                 mRegistered = true;
511                 if (DEBUG) Log.d(TAG, "registerPluginListener");
512             } else if (mRegistered) {
513                 asyncSensorManager.unregisterPluginListener(mPluginSensor, this);
514                 mRegistered = false;
515                 if (DEBUG) Log.d(TAG, "unregisterPluginListener");
516             }
517         }
518 
519         @Override
toString()520         public String toString() {
521             return new StringBuilder("{mRegistered=").append(mRegistered)
522                     .append(", mRequested=").append(mRequested)
523                     .append(", mDisabled=").append(mDisabled)
524                     .append(", mConfigured=").append(mConfigured)
525                     .append(", mIgnoresSetting=").append(mIgnoresSetting)
526                     .append(", mSensor=").append(mPluginSensor).append("}").toString();
527         }
528 
triggerEventToString(SensorManagerPlugin.SensorEvent event)529         private String triggerEventToString(SensorManagerPlugin.SensorEvent event) {
530             if (event == null) return null;
531             final StringBuilder sb = new StringBuilder("PluginTriggerEvent[")
532                     .append(event.getSensor()).append(',')
533                     .append(event.getVendorType());
534             if (event.getValues() != null) {
535                 for (int i = 0; i < event.getValues().length; i++) {
536                     sb.append(',').append(event.getValues()[i]);
537                 }
538             }
539             return sb.append(']').toString();
540         }
541 
542         @Override
onSensorChanged(SensorManagerPlugin.SensorEvent event)543         public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
544             mDozeLog.traceSensor(mPulseReason);
545             mHandler.post(mWakeLock.wrap(() -> {
546                 final long now = SystemClock.uptimeMillis();
547                 if (now < mDebounceFrom + mDebounce) {
548                     Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
549                     return;
550                 }
551                 if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
552                 mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
553             }));
554         }
555     }
556 
557     public interface Callback {
558 
559         /**
560          * Called when a sensor requests a pulse
561          * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
562          * @param screenX the location on the screen where the sensor fired or -1
563          *                if the sensor doesn't support reporting screen locations.
564          * @param screenY the location on the screen where the sensor fired or -1
565          * @param rawValues raw values array from the event.
566          */
onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues)567         void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
568     }
569 }
570