TwilightService: Ignore (0,0) coordinate location updates

Location providers may erroneously return (0.0, 0.0) when they
fail to determine the device's location. These location updates
can be safely ignored since the chance of a user actually being
at these coordinates is quite low.

Bug: 31009261
Test: added TwilightServiceTest; both tests pass

Change-Id: Ie9d7d10f81ade9b0be10f98ed74978539efaa658
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index db7df25..bb4d67e 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -59,17 +59,17 @@
 
     private final Handler mHandler;
 
-    private AlarmManager mAlarmManager;
+    protected AlarmManager mAlarmManager;
     private LocationManager mLocationManager;
 
     private boolean mBootCompleted;
     private boolean mHasListeners;
 
     private BroadcastReceiver mTimeChangedReceiver;
-    private Location mLastLocation;
+    protected Location mLastLocation;
 
     @GuardedBy("mListeners")
-    private TwilightState mLastTwilightState;
+    protected TwilightState mLastTwilightState;
 
     public TwilightService(Context context) {
         super(context);
@@ -247,7 +247,11 @@
 
     @Override
     public void onLocationChanged(Location location) {
-        if (location != null) {
+        // Location providers may erroneously return (0.0, 0.0) when they fail to determine the
+        // device's location. These location updates can be safely ignored since the chance of a
+        // user actually being at these coordinates is quite low.
+        if (location != null
+                && !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
             Slog.d(TAG, "onLocationChanged:"
                     + " provider=" + location.getProvider()
                     + " accuracy=" + location.getAccuracy()
diff --git a/services/tests/servicestests/src/com/android/server/twilight/TwilightServiceTest.java b/services/tests/servicestests/src/com/android/server/twilight/TwilightServiceTest.java
new file mode 100644
index 0000000..751e4b5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/twilight/TwilightServiceTest.java
@@ -0,0 +1,71 @@
+package com.android.server.twilight;
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.location.Location;
+import android.test.AndroidTestCase;
+
+public class TwilightServiceTest extends AndroidTestCase {
+
+    private TwilightService mTwilightService;
+    private Location mInitialLocation;
+
+    @Override
+    protected void setUp() throws Exception {
+        final Context context = getContext();
+        mTwilightService = new TwilightService(context);
+        mTwilightService.mAlarmManager =
+                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+        mInitialLocation = createMockLocation(10.0, 10.0);
+        mTwilightService.onLocationChanged(mInitialLocation);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mTwilightService = null;
+        mInitialLocation = null;
+    }
+
+    public void testValidLocation_updatedLocation() {
+        final TwilightState priorState = mTwilightService.mLastTwilightState;
+        final Location validLocation = createMockLocation(35.0, 35.0);
+        mTwilightService.onLocationChanged(validLocation);
+        assertEquals(mTwilightService.mLastLocation, validLocation);
+        assertNotSame(priorState, mTwilightService.mLastTwilightState);
+    }
+
+    public void testInvalidLocation_ignoreLocationUpdate() {
+        final TwilightState priorState = mTwilightService.mLastTwilightState;
+        final Location invalidLocation = createMockLocation(0.0, 0.0);
+        mTwilightService.onLocationChanged(invalidLocation);
+        assertEquals(mTwilightService.mLastLocation, mInitialLocation);
+        assertEquals(priorState, mTwilightService.mLastTwilightState);
+    }
+
+    private Location createMockLocation(double latitude, double longitude) {
+        // There's no empty constructor, so we initialize with a string and quickly reset it.
+        final Location location = new Location("");
+        location.reset();
+        location.setLatitude(latitude);
+        location.setLongitude(longitude);
+        return location;
+    }
+
+}