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.ConfigProviderBindings; 26 import com.android.incallui.call.DialerCall; 27 import com.android.incallui.call.DialerCall.State; 28 import com.android.incallui.call.DialerCallListener; 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() != State.INCOMING) { 51 LogUtil.i("AnswerProximitySensor.shouldUse", "call state is not incoming"); 52 Trace.endSection(); 53 return false; 54 } 55 56 if (!ConfigProviderBindings.get(context) 57 .getBoolean(CONFIG_ANSWER_PROXIMITY_SENSOR_ENABLED, true)) { 58 LogUtil.i("AnswerProximitySensor.shouldUse", "disabled by config"); 59 Trace.endSection(); 60 return false; 61 } 62 63 if (!context 64 .getSystemService(PowerManager.class) 65 .isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { 66 LogUtil.i("AnswerProximitySensor.shouldUse", "wake lock level not supported"); 67 Trace.endSection(); 68 return false; 69 } 70 71 if (isDefaultDisplayOn(context)) { 72 LogUtil.i("AnswerProximitySensor.shouldUse", "display is already on"); 73 Trace.endSection(); 74 return false; 75 } 76 77 Trace.endSection(); 78 return true; 79 } 80 AnswerProximitySensor( Context context, DialerCall call, PseudoScreenState pseudoScreenState)81 public AnswerProximitySensor( 82 Context context, DialerCall call, PseudoScreenState pseudoScreenState) { 83 Trace.beginSection("AnswerProximitySensor Constructor"); 84 this.call = call; 85 86 LogUtil.i("AnswerProximitySensor.constructor", "acquiring lock"); 87 if (ConfigProviderBindings.get(context) 88 .getBoolean(CONFIG_ANSWER_PSEUDO_PROXIMITY_WAKE_LOCK_ENABLED, true)) { 89 answerProximityWakeLock = new PseudoProximityWakeLock(context, pseudoScreenState); 90 } else { 91 // TODO(twyen): choose a wake lock implementation base on framework/device. 92 // These bugs requires the PseudoProximityWakeLock workaround: 93 // a bug Proximity sensor not working on M 94 // a bug fautly touch input when screen is off on marlin/sailfish 95 answerProximityWakeLock = new SystemProximityWakeLock(context); 96 } 97 answerProximityWakeLock.setScreenOnListener(this); 98 answerProximityWakeLock.acquire(); 99 100 call.addListener(this); 101 Trace.endSection(); 102 } 103 cleanup()104 private void cleanup() { 105 Trace.beginSection("AnswerProximitySensor.Cleanup"); 106 call.removeListener(this); 107 releaseProximityWakeLock(); 108 Trace.endSection(); 109 } 110 releaseProximityWakeLock()111 private void releaseProximityWakeLock() { 112 if (answerProximityWakeLock.isHeld()) { 113 LogUtil.i("AnswerProximitySensor.releaseProximityWakeLock", "releasing lock"); 114 answerProximityWakeLock.release(); 115 } 116 } 117 isDefaultDisplayOn(Context context)118 private static boolean isDefaultDisplayOn(Context context) { 119 Display display = 120 context.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY); 121 return display.getState() == Display.STATE_ON; 122 } 123 124 @Override onDialerCallDisconnect()125 public void onDialerCallDisconnect() { 126 LogUtil.i("AnswerProximitySensor.onDialerCallDisconnect", null); 127 cleanup(); 128 } 129 130 @Override onDialerCallUpdate()131 public void onDialerCallUpdate() { 132 if (call.getState() != State.INCOMING) { 133 LogUtil.i("AnswerProximitySensor.onDialerCallUpdate", "no longer incoming, cleaning up"); 134 cleanup(); 135 } 136 } 137 138 @Override onDialerCallChildNumberChange()139 public void onDialerCallChildNumberChange() {} 140 141 @Override onDialerCallLastForwardedNumberChange()142 public void onDialerCallLastForwardedNumberChange() {} 143 144 @Override onDialerCallUpgradeToVideo()145 public void onDialerCallUpgradeToVideo() {} 146 147 @Override onWiFiToLteHandover()148 public void onWiFiToLteHandover() {} 149 150 @Override onHandoverToWifiFailure()151 public void onHandoverToWifiFailure() {} 152 153 @Override onInternationalCallOnWifi()154 public void onInternationalCallOnWifi() {} 155 156 @Override onEnrichedCallSessionUpdate()157 public void onEnrichedCallSessionUpdate() {} 158 159 @Override onDialerCallSessionModificationStateChange()160 public void onDialerCallSessionModificationStateChange() {} 161 162 @Override onScreenOn()163 public void onScreenOn() { 164 cleanup(); 165 } 166 } 167