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