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.answerproximitysensor; 18 19 import android.content.Context; 20 import android.hardware.display.DisplayManager; 21 import android.os.PowerManager; 22 import android.os.Trace; 23 import android.view.Display; 24 import com.android.dialer.common.LogUtil; 25 import com.android.dialer.configprovider.ConfigProviderComponent; 26 import com.android.incallui.call.DialerCall; 27 import com.android.incallui.call.DialerCallListener; 28 import com.android.incallui.call.state.DialerCallState; 29 30 /** 31 * This class prevents users from accidentally answering calls by keeping the screen off until the 32 * proximity sensor is unblocked. If the screen is already on or if this is a call waiting call then 33 * nothing is done. 34 */ 35 public class AnswerProximitySensor 36 implements DialerCallListener, AnswerProximityWakeLock.ScreenOnListener { 37 38 private static final String CONFIG_ANSWER_PROXIMITY_SENSOR_ENABLED = 39 "answer_proximity_sensor_enabled"; 40 private static final String CONFIG_ANSWER_PSEUDO_PROXIMITY_WAKE_LOCK_ENABLED = 41 "answer_pseudo_proximity_wake_lock_enabled"; 42 43 private final DialerCall call; 44 private final AnswerProximityWakeLock answerProximityWakeLock; 45 shouldUse(Context context, DialerCall call)46 public static boolean shouldUse(Context context, DialerCall call) { 47 Trace.beginSection("AnswerProximitySensor.shouldUse"); 48 // Don't use the AnswerProximitySensor for call waiting and other states. Those states are 49 // handled by the general ProximitySensor code. 50 if (call.getState() != DialerCallState.INCOMING) { 51 LogUtil.i("AnswerProximitySensor.shouldUse", "call state is not incoming"); 52 Trace.endSection(); 53 return false; 54 } 55 56 if (!ConfigProviderComponent.get(context) 57 .getConfigProvider() 58 .getBoolean(CONFIG_ANSWER_PROXIMITY_SENSOR_ENABLED, true)) { 59 LogUtil.i("AnswerProximitySensor.shouldUse", "disabled by config"); 60 Trace.endSection(); 61 return false; 62 } 63 64 if (!context 65 .getSystemService(PowerManager.class) 66 .isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { 67 LogUtil.i("AnswerProximitySensor.shouldUse", "wake lock level not supported"); 68 Trace.endSection(); 69 return false; 70 } 71 72 if (isDefaultDisplayOn(context)) { 73 LogUtil.i("AnswerProximitySensor.shouldUse", "display is already on"); 74 Trace.endSection(); 75 return false; 76 } 77 78 Trace.endSection(); 79 return true; 80 } 81 AnswerProximitySensor( Context context, DialerCall call, PseudoScreenState pseudoScreenState)82 public AnswerProximitySensor( 83 Context context, DialerCall call, PseudoScreenState pseudoScreenState) { 84 Trace.beginSection("AnswerProximitySensor Constructor"); 85 this.call = call; 86 87 LogUtil.i("AnswerProximitySensor.constructor", "acquiring lock"); 88 if (ConfigProviderComponent.get(context) 89 .getConfigProvider() 90 .getBoolean(CONFIG_ANSWER_PSEUDO_PROXIMITY_WAKE_LOCK_ENABLED, true)) { 91 answerProximityWakeLock = new PseudoProximityWakeLock(context, pseudoScreenState); 92 } else { 93 // TODO(twyen): choose a wake lock implementation base on framework/device. 94 // These bugs requires the PseudoProximityWakeLock workaround: 95 // a bug Proximity sensor not working on M 96 // a bug fautly touch input when screen is off on marlin/sailfish 97 answerProximityWakeLock = new SystemProximityWakeLock(context); 98 } 99 answerProximityWakeLock.setScreenOnListener(this); 100 answerProximityWakeLock.acquire(); 101 102 call.addListener(this); 103 Trace.endSection(); 104 } 105 cleanup()106 private void cleanup() { 107 Trace.beginSection("AnswerProximitySensor.Cleanup"); 108 call.removeListener(this); 109 releaseProximityWakeLock(); 110 Trace.endSection(); 111 } 112 releaseProximityWakeLock()113 private void releaseProximityWakeLock() { 114 if (answerProximityWakeLock.isHeld()) { 115 LogUtil.i("AnswerProximitySensor.releaseProximityWakeLock", "releasing lock"); 116 answerProximityWakeLock.release(); 117 } 118 } 119 isDefaultDisplayOn(Context context)120 private static boolean isDefaultDisplayOn(Context context) { 121 Display display = 122 context.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY); 123 return display.getState() == Display.STATE_ON; 124 } 125 126 @Override onDialerCallDisconnect()127 public void onDialerCallDisconnect() { 128 LogUtil.i("AnswerProximitySensor.onDialerCallDisconnect", null); 129 cleanup(); 130 } 131 132 @Override onDialerCallUpdate()133 public void onDialerCallUpdate() { 134 if (call.getState() != DialerCallState.INCOMING) { 135 LogUtil.i("AnswerProximitySensor.onDialerCallUpdate", "no longer incoming, cleaning up"); 136 cleanup(); 137 } 138 } 139 140 @Override onDialerCallChildNumberChange()141 public void onDialerCallChildNumberChange() {} 142 143 @Override onDialerCallLastForwardedNumberChange()144 public void onDialerCallLastForwardedNumberChange() {} 145 146 @Override onDialerCallUpgradeToVideo()147 public void onDialerCallUpgradeToVideo() {} 148 149 @Override onWiFiToLteHandover()150 public void onWiFiToLteHandover() {} 151 152 @Override onHandoverToWifiFailure()153 public void onHandoverToWifiFailure() {} 154 155 @Override onInternationalCallOnWifi()156 public void onInternationalCallOnWifi() {} 157 158 @Override onEnrichedCallSessionUpdate()159 public void onEnrichedCallSessionUpdate() {} 160 161 @Override onDialerCallSessionModificationStateChange()162 public void onDialerCallSessionModificationStateChange() {} 163 164 @Override onScreenOn()165 public void onScreenOn() { 166 cleanup(); 167 } 168 } 169