Add new proximity sensors in Telecomm (2/3)

Add the following two APIs in Telecomm and use them in InCallUI
setProximitySensorOn
setProximitySensorOff(boolean turnScreenOnImmediately)

Bug: 16573954
Change-Id: I8219e9c659f4ea4493f5cd5c8bcaa95a98d180e2
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 8d6d772..fc5a71a 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -79,6 +79,7 @@
     private final HeadsetMediaButton mHeadsetMediaButton;
     private final WiredHeadsetManager mWiredHeadsetManager;
     private final TtyManager mTtyManager;
+    private final ProximitySensorManager mProximitySensorManager;
 
     /**
      * The call the user is currently interacting with. This is the call that should have audio
@@ -104,6 +105,7 @@
         mRinger = new Ringer(mCallAudioManager, this, playerFactory, app);
         mHeadsetMediaButton = new HeadsetMediaButton(app, this);
         mTtyManager = new TtyManager(app, mWiredHeadsetManager);
+        mProximitySensorManager = new ProximitySensorManager(app);
 
         mListeners.add(statusBarNotifier);
         mListeners.add(new CallLogManager(app));
@@ -117,6 +119,7 @@
         mListeners.add(mDtmfLocalTonePlayer);
         mListeners.add(mHeadsetMediaButton);
         mListeners.add(RespondViaSmsManager.getInstance());
+        mListeners.add(mProximitySensorManager);
     }
 
     @Override
@@ -510,6 +513,20 @@
         mCallAudioManager.setAudioRoute(route);
     }
 
+    /** Called by the in-call UI to turn the proximity sensor on. */
+    void turnOnProximitySensor() {
+        mProximitySensorManager.turnOn();
+    }
+
+    /**
+     * Called by the in-call UI to turn the proximity sensor off.
+     * @param screenOnImmediately If true, the screen will be turned on immediately. Otherwise,
+     *        the screen will be kept off until the proximity sensor goes negative.
+     */
+    void turnOffProximitySensor(boolean screenOnImmediately) {
+        mProximitySensorManager.turnOff(screenOnImmediately);
+    }
+
     void phoneAccountClicked(Call call) {
         if (!mCalls.contains(call)) {
             Log.i(this, "phoneAccountClicked in a non-existent call %s", call);
diff --git a/src/com/android/telecomm/InCallAdapter.java b/src/com/android/telecomm/InCallAdapter.java
index 31a009e..0acb3f5 100644
--- a/src/com/android/telecomm/InCallAdapter.java
+++ b/src/com/android/telecomm/InCallAdapter.java
@@ -44,6 +44,8 @@
     private static final int MSG_SPLIT_FROM_CONFERENCE = 12;
     private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 13;
     private static final int MSG_PHONE_ACCOUNT_SELECTED = 14;
+    private static final int MSG_TURN_ON_PROXIMITY_SENSOR = 15;
+    private static final int MSG_TURN_OFF_PROXIMITY_SENSOR = 16;
 
     private final class InCallAdapterHandler extends Handler {
         @Override
@@ -183,6 +185,12 @@
                         Log.w(this, "swapWithBackgroundCall, unknown call id: %s", msg.obj);
                     }
                     break;
+                case MSG_TURN_ON_PROXIMITY_SENSOR:
+                    mCallsManager.turnOnProximitySensor();
+                    break;
+                case MSG_TURN_OFF_PROXIMITY_SENSOR:
+                    mCallsManager.turnOffProximitySensor((boolean) msg.obj);
+                    break;
             }
         }
     }
@@ -298,4 +306,14 @@
     public void swapWithBackgroundCall(String callId) {
         mHandler.obtainMessage(MSG_SWAP_WITH_BACKGROUND_CALL, callId).sendToTarget();
     }
+
+    @Override
+    public void turnOnProximitySensor() {
+        mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget();
+    }
+
+    @Override
+    public void turnOffProximitySensor(boolean screenOnImmediately) {
+        mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget();
+    }
 }
diff --git a/src/com/android/telecomm/ProximitySensorManager.java b/src/com/android/telecomm/ProximitySensorManager.java
new file mode 100644
index 0000000..c6b018a
--- /dev/null
+++ b/src/com/android/telecomm/ProximitySensorManager.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.telecomm;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+/**
+ * This class manages the proximity sensor and allows callers to turn it on and off.
+ */
+public class ProximitySensorManager extends CallsManagerListenerBase {
+    private static final String TAG = ProximitySensorManager.class.getSimpleName();
+
+    private final PowerManager.WakeLock mProximityWakeLock;
+
+    public ProximitySensorManager(Context context) {
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+
+        if (pm.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
+            mProximityWakeLock = pm.newWakeLock(
+                    PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
+        } else {
+            mProximityWakeLock = null;
+        }
+        Log.d(this, "onCreate: mProximityWakeLock: ", mProximityWakeLock);
+    }
+
+    @Override
+    public void onCallRemoved(Call call) {
+        if (CallsManager.getInstance().getCalls().isEmpty()) {
+            Log.v(this, "all calls removed, resetting proximity sensor to default state");
+            turnOff(true);
+        }
+        super.onCallRemoved(call);
+    }
+
+    /**
+     * Turn the proximity sensor on.
+     */
+    void turnOn() {
+        if (mProximityWakeLock == null) {
+            return;
+        }
+        if (!mProximityWakeLock.isHeld()) {
+            Log.i(this, "Acquiring proximity wake lock");
+            mProximityWakeLock.acquire();
+        } else {
+            Log.i(this, "Proximity wake lock already acquired");
+        }
+    }
+
+    /**
+     * Turn the proximity sensor off.
+     * @param screenOnImmediately
+     */
+    void turnOff(boolean screenOnImmediately) {
+        if (mProximityWakeLock == null) {
+            return;
+        }
+        if (mProximityWakeLock.isHeld()) {
+            Log.i(this, "Releasing proximity wake lock");
+            int flags =
+                (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
+            mProximityWakeLock.release(flags);
+        } else {
+            Log.i(this, "Proximity wake lock already released");
+        }
+    }
+}