Device Idle: Android wear support

- Provide config param: autoPowerModeThresholdAngle allowing us to
  adjust the tilt threshold on a per-device basis.
- Provide config param: autoPowerModePrefetchLocation allowing us to
  skip location prefectching on a per-device basis.
- Provide config param: autoPowerModeAnyMotionSensor allowing us to
  use a device-specific sensor on to detect additional types of movement
  that would trigger exiting device idle.
- PRovide config param: autoPowerModePreferWristTilt allows us to use
  the wrist tilt detector in lieu of the SMD if an anymotion sensor
isn't specified.
- Allow DeviceIdleController to use wrist tilt sensors if the device provides
  one.
- Use wrist tilt or SMD when an "any motion" sensor isn't available.
- Fix bugs where DeviceIdleController would crash on devices that did
  not have a location and/or gps provider (some android wear devices).

BUG: 22661021

Change-Id: Ib9f7cdf8f16483ba8f466b7b5c97bdf0494ba228
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 80fd441..46fd28a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -128,7 +128,8 @@
     private boolean mNotMoving;
     private boolean mLocating;
     private boolean mLocated;
-    private boolean mHaveGps;
+    private boolean mHasGps;
+    private boolean mHasNetworkLocation;
     private Location mLastGenericLocation;
     private Location mLastGpsLocation;
 
@@ -882,17 +883,37 @@
                 mDisplayManager = (DisplayManager) getContext().getSystemService(
                         Context.DISPLAY_SERVICE);
                 mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
-                mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
-                mLocationManager = (LocationManager) getContext().getSystemService(
-                        Context.LOCATION_SERVICE);
-                mLocationRequest = new LocationRequest()
-                    .setQuality(LocationRequest.ACCURACY_FINE)
-                    .setInterval(0)
-                    .setFastestInterval(0)
-                    .setNumUpdates(1);
+                int sigMotionSensorId = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
+                if (sigMotionSensorId > 0) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+                }
+                if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_WRIST_TILT_GESTURE);
+                }
+                if (mSigMotionSensor == null) {
+                    // As a last ditch, fall back to SMD.
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_SIGNIFICANT_MOTION);
+                }
+                if (getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
+                    mLocationManager = (LocationManager) getContext().getSystemService(
+                            Context.LOCATION_SERVICE);
+                    mLocationRequest = new LocationRequest()
+                        .setQuality(LocationRequest.ACCURACY_FINE)
+                        .setInterval(0)
+                        .setFastestInterval(0)
+                        .setNumUpdates(1);
+                }
+
+                float angleThreshold = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
                 mAnyMotionDetector = new AnyMotionDetector(
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
-                        mHandler, mSensorManager, this);
+                        mHandler, mSensorManager, this, angleThreshold);
 
                 Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
                         .setPackage("android")
@@ -1279,17 +1300,30 @@
                 EventLogTags.writeDeviceIdle(mState, "step");
                 cancelSensingAlarmLocked();
                 scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);
-                mLocating = true;
-                mLocationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener,
-                        mHandler.getLooper());
-                if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
-                    mHaveGps = true;
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+                    mLocationManager.requestLocationUpdates(mLocationRequest,
+                            mGenericLocationListener, mHandler.getLooper());
+                    mLocating = true;
+                } else {
+                    mHasNetworkLocation = false;
+                }
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+                    mHasGps = true;
                     mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
                             mGpsLocationListener, mHandler.getLooper());
+                    mLocating = true;
                 } else {
-                    mHaveGps = false;
+                    mHasGps = false;
                 }
-                break;
+                // If we have a location provider, we're all set, the listeners will move state
+                // forward.
+                if (mLocating) {
+                    break;
+                }
+
+                // Otherwise, we have to move from locating into idle maintenance.
             case STATE_LOCATING:
                 cancelSensingAlarmLocked();
                 cancelLocatingLocked();
@@ -1346,7 +1380,7 @@
         }
         if (DEBUG) Slog.d(TAG, "Generic location: " + location);
         mLastGenericLocation = new Location(location);
-        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHaveGps) {
+        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHasGps) {
             return;
         }
         mLocated = true;
@@ -1413,9 +1447,9 @@
     void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
         if (mSigMotionSensor == null) {
-            // If there is no significant motion sensor on this device, then we won't schedule
+            // If there is no motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
-            // turns off normal exeuction of device idling, although it is still possible to
+            // turns off normal execution of device idling, although it is still possible to
             // manually poke it by pretending like the alarm is going off.
             return;
         }
@@ -1902,8 +1936,9 @@
             pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
             pw.print("  mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
                     pw.println(mNotMoving);
-            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHaveGps=");
-                    pw.print(mHaveGps); pw.print(" mLocated="); pw.println(mLocated);
+            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
+                    pw.print(mHasGps); pw.print(" mHasNetwork=");
+                    pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated);
             if (mLastGenericLocation != null) {
                 pw.print("  mLastGenericLocation="); pw.println(mLastGenericLocation);
             }