1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/*
2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2013 The Android Open Source Project
3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License.
6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at
7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian *
10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and
14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License
15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.incallui;
18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context;
20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.hardware.display.DisplayManager;
21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.hardware.display.DisplayManager.DisplayListener;
22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.PowerManager;
23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.NonNull;
24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.CallAudioState;
25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.view.Display;
26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.LogUtil;
27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.InCallPresenter.InCallState;
28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.InCallPresenter.InCallStateListener;
298369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanianimport com.android.incallui.audiomode.AudioModeProvider;
308369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanianimport com.android.incallui.audiomode.AudioModeProvider.AudioModeListener;
31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.CallList;
32d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.incallui.call.DialerCall;
33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/**
35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Class manages the proximity sensor for the in-call UI. We enable the proximity sensor while the
36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * user in a phone call. The Proximity sensor turns off the touchscreen and display when the user is
37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * close to the screen to prevent user's cheek from causing touch events. The class requires special
38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * knowledge of the activity and device state to know when the proximity sensor should be enabled
39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * and disabled. Most of that state is fed into this class through public methods.
40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */
41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class ProximitySensor
42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    implements AccelerometerListener.OrientationListener, InCallStateListener, AudioModeListener {
43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private static final String TAG = ProximitySensor.class.getSimpleName();
45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final PowerManager mPowerManager;
47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final PowerManager.WakeLock mProximityWakeLock;
48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final AudioModeProvider mAudioModeProvider;
49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final AccelerometerListener mAccelerometerListener;
50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private final ProximityDisplayListener mDisplayListener;
51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private int mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mUiShowing = false;
53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mIsPhoneOffhook = false;
54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mDialpadVisible;
55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mIsAttemptingVideoCall;
56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private boolean mIsVideoCall;
57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public ProximitySensor(
59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      @NonNull Context context,
60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      @NonNull AudioModeProvider audioModeProvider,
61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      @NonNull AccelerometerListener accelerometerListener) {
62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mPowerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mProximityWakeLock =
65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          mPowerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.i("ProximitySensor.constructor", "Device does not support proximity wake lock.");
68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mProximityWakeLock = null;
69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAccelerometerListener = accelerometerListener;
71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAccelerometerListener.setListener(this);
72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
73ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mDisplayListener =
74ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        new ProximityDisplayListener(
75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE));
76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mDisplayListener.register();
77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAudioModeProvider = audioModeProvider;
79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAudioModeProvider.addListener(this);
80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void tearDown() {
83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAudioModeProvider.removeListener(this);
84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAccelerometerListener.enable(false);
86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mDisplayListener.unregister();
87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    turnOffProximitySensor(true);
89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Called to identify when the device is laid down flat. */
92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void orientationChanged(int orientation) {
94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mOrientation = orientation;
95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    updateProximitySensorMode();
96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Called to keep track of the overall UI state. */
99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // We ignore incoming state because we do not want to enable proximity
102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // sensor during incoming call screen. We check hasLiveCall() because a disconnected call
103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // can also put the in-call screen in the INCALL state.
104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean hasOngoingCall = InCallState.INCALL == newState && callList.hasLiveCall();
10510ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian    boolean isOffhook = (InCallState.OUTGOING == newState) || hasOngoingCall;
106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
107d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    DialerCall activeCall = callList.getActiveCall();
108d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    boolean isVideoCall = activeCall != null && activeCall.isVideoCall();
109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (isOffhook != mIsPhoneOffhook || mIsVideoCall != isVideoCall) {
111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mIsPhoneOffhook = isOffhook;
112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mIsVideoCall = isVideoCall;
113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mAccelerometerListener.enable(mIsPhoneOffhook);
116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      updateProximitySensorMode();
118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  @Override
122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void onAudioStateChanged(CallAudioState audioState) {
123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    updateProximitySensorMode();
124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void onDialpadVisible(boolean visible) {
127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mDialpadVisible = visible;
128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    updateProximitySensorMode();
129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void setIsAttemptingVideoCall(boolean isAttemptingVideoCall) {
132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    LogUtil.i(
133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        "ProximitySensor.setIsAttemptingVideoCall",
134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        "isAttemptingVideoCall: %b",
135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        isAttemptingVideoCall);
136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mIsAttemptingVideoCall = isAttemptingVideoCall;
137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    updateProximitySensorMode();
138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /** Used to save when the UI goes in and out of the foreground. */
140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public void onInCallShowing(boolean showing) {
141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (showing) {
142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mUiShowing = true;
143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // We only consider the UI not showing for instances where another app took the foreground.
145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // If we stopped showing because the screen is off, we still consider that showing.
146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else if (mPowerManager.isScreenOn()) {
147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mUiShowing = false;
148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    updateProximitySensorMode();
150ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
152ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  void onDisplayStateChanged(boolean isDisplayOn) {
153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    LogUtil.i("ProximitySensor.onDisplayStateChanged", "isDisplayOn: %b", isDisplayOn);
154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    mAccelerometerListener.enable(isDisplayOn);
155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * TODO: There is no way to determine if a screen is off due to proximity or if it is legitimately
159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * off, but if ever we can do that in the future, it would be useful here. Until then, this
160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * function will simply return true of the screen is off. TODO: Investigate whether this can be
161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * replaced with the ProximityDisplayListener.
162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public boolean isScreenReallyOff() {
164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    return !mPowerManager.isScreenOn();
165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void turnOnProximitySensor() {
168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mProximityWakeLock != null) {
169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (!mProximityWakeLock.isHeld()) {
170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        LogUtil.i("ProximitySensor.turnOnProximitySensor", "acquiring wake lock");
171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mProximityWakeLock.acquire();
172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        LogUtil.i("ProximitySensor.turnOnProximitySensor", "wake lock already acquired");
174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private void turnOffProximitySensor(boolean screenOnImmediately) {
179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mProximityWakeLock != null) {
180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (mProximityWakeLock.isHeld()) {
181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        LogUtil.i("ProximitySensor.turnOffProximitySensor", "releasing wake lock");
182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        int flags = (screenOnImmediately ? 0 : PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY);
183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mProximityWakeLock.release(flags);
184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      } else {
185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        LogUtil.i("ProximitySensor.turnOffProximitySensor", "wake lock already released");
186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Updates the wake lock used to control proximity sensor behavior, based on the current state of
192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * the phone.
193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * <p>On devices that have a proximity sensor, to avoid false touches during a call, we hold a
195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock whenever the phone is off hook. (When held, that wake
196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * lock causes the screen to turn off automatically when the sensor detects an object close to the
197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * screen.)
198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * <p>This method is a no-op for devices that don't have a proximity sensor.
200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   *
201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * <p>Proximity wake lock will be released if any of the following conditions are true: the audio
202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * is routed through bluetooth, a wired headset, or the speaker; the user requested, received a
203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * request for, or is in a video call; or the phone is horizontal while in a call.
204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  private synchronized void updateProximitySensorMode() {
206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final int audioRoute = mAudioModeProvider.getAudioState().getRoute();
207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    boolean screenOnImmediately =
209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        (CallAudioState.ROUTE_WIRED_HEADSET == audioRoute
210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            || CallAudioState.ROUTE_SPEAKER == audioRoute
211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            || CallAudioState.ROUTE_BLUETOOTH == audioRoute
212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            || mIsAttemptingVideoCall
213ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            || mIsVideoCall);
214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // We do not keep the screen off when the user is outside in-call screen and we are
216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // horizontal, but we do not force it on when we become horizontal until the
217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // proximity sensor goes negative.
218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    final boolean horizontal = (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    screenOnImmediately |= !mUiShowing && horizontal;
220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // We do not keep the screen off when dialpad is visible, we are horizontal, and
222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // the in-call screen is being shown.
223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // At that moment we're pretty sure users want to use it, instead of letting the
224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    // proximity sensor turn off the screen by their hands.
225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    screenOnImmediately |= mDialpadVisible && horizontal;
226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    LogUtil.i(
228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        "ProximitySensor.updateProximitySensorMode",
229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        "screenOnImmediately: %b, dialPadVisible: %b, "
230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian            + "offHook: %b, horizontal: %b, uiShowing: %b, audioRoute: %s",
231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        screenOnImmediately,
232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mDialpadVisible,
233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mIsPhoneOffhook,
234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL,
235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        mUiShowing,
236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        CallAudioState.audioRouteToString(audioRoute));
237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    if (mIsPhoneOffhook && !screenOnImmediately) {
239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.v("ProximitySensor.updateProximitySensorMode", "turning on proximity sensor");
240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Phone is in use!  Arrange for the screen to turn off
241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // automatically when the sensor detects a close object.
242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      turnOnProximitySensor();
243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    } else {
244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      LogUtil.v("ProximitySensor.updateProximitySensorMode", "turning off proximity sensor");
245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // Phone is either idle, or ringing.  We don't want any special proximity sensor
246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      // behavior in either case.
247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      turnOffProximitySensor(screenOnImmediately);
248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  /**
252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * Implementation of a {@link DisplayListener} that maintains a binary state: Screen on vs screen
253ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * off. Used by the proximity sensor manager to decide whether or not it needs to listen to
254ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   * accelerometer events.
255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian   */
256ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  public class ProximityDisplayListener implements DisplayListener {
257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private DisplayManager mDisplayManager;
259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    private boolean mIsDisplayOn = true;
260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
261ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    ProximityDisplayListener(DisplayManager displayManager) {
262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mDisplayManager = displayManager;
263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
265ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void register() {
266ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mDisplayManager.registerDisplayListener(this, null);
267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    void unregister() {
270ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      mDisplayManager.unregisterDisplayListener(this);
271ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
272ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
273ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    @Override
274ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public void onDisplayRemoved(int displayId) {}
275ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
276ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    @Override
277ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public void onDisplayChanged(int displayId) {
278ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      if (displayId == Display.DEFAULT_DISPLAY) {
279ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final Display display = mDisplayManager.getDisplay(displayId);
280ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
281ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        final boolean isDisplayOn = display.getState() != Display.STATE_OFF;
282ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // For call purposes, we assume that as long as the screen is not truly off, it is
283ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        // considered on, even if it is in an unknown or low power idle state.
284ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        if (isDisplayOn != mIsDisplayOn) {
285ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          mIsDisplayOn = isDisplayOn;
286ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian          onDisplayStateChanged(mIsDisplayOn);
287ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian        }
288ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian      }
289ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    }
290ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian
291ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    @Override
292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian    public void onDisplayAdded(int displayId) {}
293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian  }
294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian}
295