• 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.incallui.answer.impl.classifier;
18 
19 import android.content.Context;
20 import android.hardware.Sensor;
21 import android.hardware.SensorEvent;
22 import android.hardware.SensorEventListener;
23 import android.hardware.SensorManager;
24 import android.os.PowerManager;
25 import android.view.MotionEvent;
26 import android.view.accessibility.AccessibilityManager;
27 
28 /**
29  * When the phone is locked, listens to touch, sensor and phone events and sends them to
30  * HumanInteractionClassifier to determine if touches are coming from a human.
31  */
32 public class FalsingManager implements SensorEventListener {
33   private static final int[] CLASSIFIER_SENSORS =
34       new int[] {
35         Sensor.TYPE_PROXIMITY,
36       };
37 
38   private final SensorManager mSensorManager;
39   private final HumanInteractionClassifier mHumanInteractionClassifier;
40   private final AccessibilityManager mAccessibilityManager;
41 
42   private boolean mSessionActive = false;
43   private boolean mScreenOn;
44 
FalsingManager(Context context)45   public FalsingManager(Context context) {
46     mSensorManager = context.getSystemService(SensorManager.class);
47     mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
48     mHumanInteractionClassifier = new HumanInteractionClassifier(context);
49     mScreenOn = context.getSystemService(PowerManager.class).isInteractive();
50   }
51 
52   /** Returns {@code true} iff the FalsingManager is enabled and able to classify touches */
isEnabled()53   public boolean isEnabled() {
54     return mHumanInteractionClassifier.isEnabled();
55   }
56 
57   /**
58    * Returns {@code true} iff the classifier determined that this is not a human interacting with
59    * the phone.
60    */
isFalseTouch()61   public boolean isFalseTouch() {
62     // Touch exploration triggers false positives in the classifier and
63     // already sufficiently prevents false unlocks.
64     return !mAccessibilityManager.isTouchExplorationEnabled()
65         && mHumanInteractionClassifier.isFalseTouch();
66   }
67 
68   /**
69    * Should be called when the screen turns on and the related Views become visible. This will start
70    * tracking changes if the manager is enabled.
71    */
onScreenOn()72   public void onScreenOn() {
73     mScreenOn = true;
74     sessionEntrypoint();
75   }
76 
77   /**
78    * Should be called when the screen turns off or the related Views are no longer visible. This
79    * will cause the manager to stop tracking changes.
80    */
onScreenOff()81   public void onScreenOff() {
82     mScreenOn = false;
83     sessionExitpoint();
84   }
85 
86   /**
87    * Should be called when a new touch event has been received and should be classified.
88    *
89    * @param event MotionEvent to be classified as human or false.
90    */
onTouchEvent(MotionEvent event)91   public void onTouchEvent(MotionEvent event) {
92     if (mSessionActive) {
93       mHumanInteractionClassifier.onTouchEvent(event);
94     }
95   }
96 
97   @Override
onSensorChanged(SensorEvent event)98   public synchronized void onSensorChanged(SensorEvent event) {
99     mHumanInteractionClassifier.onSensorChanged(event);
100   }
101 
102   @Override
onAccuracyChanged(Sensor sensor, int accuracy)103   public void onAccuracyChanged(Sensor sensor, int accuracy) {}
104 
shouldSessionBeActive()105   private boolean shouldSessionBeActive() {
106     return isEnabled() && mScreenOn;
107   }
108 
sessionEntrypoint()109   private boolean sessionEntrypoint() {
110     if (!mSessionActive && shouldSessionBeActive()) {
111       onSessionStart();
112       return true;
113     }
114     return false;
115   }
116 
sessionExitpoint()117   private void sessionExitpoint() {
118     if (mSessionActive && !shouldSessionBeActive()) {
119       mSessionActive = false;
120       mSensorManager.unregisterListener(this);
121     }
122   }
123 
onSessionStart()124   private void onSessionStart() {
125     mSessionActive = true;
126 
127     if (mHumanInteractionClassifier.isEnabled()) {
128       registerSensors(CLASSIFIER_SENSORS);
129     }
130   }
131 
registerSensors(int[] sensors)132   private void registerSensors(int[] sensors) {
133     for (int sensorType : sensors) {
134       Sensor s = mSensorManager.getDefaultSensor(sensorType);
135       if (s != null) {
136         mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
137       }
138     }
139   }
140 }
141