Location CTS tests without fine permission
First CTS tests for the cases where we don't have fine permission.
More to follow.
Bug: 7377632
Change-Id: Ia95864614ddc83641f30c37808e9df7268064579
diff --git a/tests/tests/location2/Android.mk b/tests/tests/location2/Android.mk
new file mode 100644
index 0000000..e89204d
--- /dev/null
+++ b/tests/tests/location2/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsLocation2TestCases
+
+LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
+
+# uncomment when dalvik.annotation.Test* are removed or part of SDK
+#LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/location2/AndroidManifest.xml b/tests/tests/location2/AndroidManifest.xml
new file mode 100644
index 0000000..118278b
--- /dev/null
+++ b/tests/tests/location2/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.location2">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="com.android.cts.location2"
+ android:label="CTS tests of android.location"/>
+</manifest>
+
diff --git a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
new file mode 100755
index 0000000..e68fea0
--- /dev/null
+++ b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2012 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 android.location2.cts;
+
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.Criteria;
+import android.location.GpsStatus;
+import android.location.GpsStatus.Listener;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.LocationRequest;
+import android.os.Bundle;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.InstrumentationTestCase;
+
+import java.util.List;
+import java.lang.Thread;
+
+/**
+ * Requires the permissions
+ * android.permission.ACCESS_MOCK_LOCATION to mock provider
+ * android.permission.ACCESS_COARSE_LOCATION to access network provider
+ * android.permission.ACCESS_LOCATION_EXTRA_COMMANDS to send extra commands to provider
+ */
+public class LocationManagerTest extends InstrumentationTestCase {
+
+ private static final String FUSED_PROVIDER_NAME = "fused";
+
+ private static final long TEST_TIME_OUT_MS = 10 * 1000;
+
+ private static final double LAT = 10.0;
+ private static final double LNG = 40.0;
+ private static final double FUDGER_DELTA = 0.2;
+
+ private LocationManager mManager;
+
+ private Context mContext;
+
+ private PendingIntent mPendingIntent;
+
+ private TestIntentReceiver mIntentReceiver;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getInstrumentation().getTargetContext();
+
+ mManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+
+ // test that mock locations are allowed so a more descriptive error message can be logged
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
+ fail("Mock locations are currently disabled in Settings - this test requires "
+ + "mock locations");
+ }
+ }
+
+ public void testGetGpsProvider_notAllowed() {
+ doTestGetFineProvider_notAllowed(LocationManager.GPS_PROVIDER);
+ }
+
+ public void testGetFineProvider_notAllowed() {
+ doTestGetFineProvider_notAllowed("my fine provider name");
+ }
+
+ private void doTestGetFineProvider_notAllowed(String providerName) {
+ addTestProvider(providerName, Criteria.ACCURACY_FINE, false, true, false);
+
+ try {
+ mManager.getProvider(providerName);
+ fail("LocationManager.getProvider() did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ mManager.removeTestProvider(providerName);
+ }
+
+ public void testGetNetworkProvider_allowed() {
+ doTestGetCoarseProvider_allowed(LocationManager.NETWORK_PROVIDER);
+ }
+
+ public void testGetCoarseProvider_allowed() {
+ doTestGetCoarseProvider_allowed("my coarse provider name");
+ }
+
+ public void doTestGetCoarseProvider_allowed(String providerName) {
+ addTestProvider(providerName, Criteria.ACCURACY_COARSE, true, false, true);
+ assertNotNull(mManager.getProvider(providerName));
+ mManager.removeTestProvider(providerName);
+ }
+
+ public void testGetNetworkProviderLocationUpdates_withIntent() {
+ doTestGetLocationUpdates_withIntent(LocationManager.NETWORK_PROVIDER);
+ }
+
+ public void testGetNetworkProviderLocationUpdates_withListener() {
+ doTestGetLocationUpdates_withListener(LocationManager.NETWORK_PROVIDER);
+ }
+
+ public void testGetCoarseLocationUpdates_withIntent() {
+ doTestGetLocationUpdates_withIntent("my coarse provider name");
+ }
+
+ public void testGetCoarseLocationUpdates_withListener() {
+ doTestGetLocationUpdates_withListener("my coarse provider name");
+ }
+
+
+ private void doTestGetLocationUpdates_withIntent(String providerName) {
+ addTestProvider(providerName, Criteria.ACCURACY_COARSE, true, false, true);
+ registerIntentReceiver();
+
+ mManager.requestLocationUpdates(providerName, 0, 0, mPendingIntent);
+ updateLocation(providerName, LAT, LNG);
+ waitForReceiveBroadcast();
+
+ assertNotNull(mIntentReceiver.getLastReceivedIntent());
+ final Location location = mManager.getLastKnownLocation(providerName);
+ assertEquals(providerName, location.getProvider());
+
+ assertEquals(3000.0f, location.getAccuracy());
+ assertEquals(LAT, location.getLatitude(), FUDGER_DELTA);
+ assertEquals(LNG, location.getLongitude(), FUDGER_DELTA);
+
+ mManager.removeUpdates(mPendingIntent);
+ mManager.removeTestProvider(providerName);
+ }
+
+ private void doTestGetLocationUpdates_withListener(String providerName) {
+ addTestProvider(providerName, Criteria.ACCURACY_COARSE, true, false, true);
+
+ MockLocationListener listener = new MockLocationListener();
+ HandlerThread handlerThread = new HandlerThread("testLocationUpdates for " + providerName);
+ handlerThread.start();
+
+ mManager.requestLocationUpdates(providerName, 0, 0, listener, handlerThread.getLooper());
+ updateLocation(providerName, LAT, LNG);
+
+ assertTrue(listener.hasCalledOnLocationChanged(TEST_TIME_OUT_MS));
+ Location location = listener.getLocation();
+ assertEquals(providerName, location.getProvider());
+
+ assertEquals(3000.0f, location.getAccuracy());
+ assertEquals(LAT, location.getLatitude(), FUDGER_DELTA);
+ assertEquals(LNG, location.getLongitude(), FUDGER_DELTA);
+
+ mManager.removeUpdates(listener);
+ mManager.removeTestProvider(providerName);
+ }
+
+ public void testGetFusedLocationUpdates_withIntent() {
+ addTestProvider(FUSED_PROVIDER_NAME, Criteria.ACCURACY_COARSE, true, false, true);
+ registerIntentReceiver();
+
+ mManager.requestLocationUpdates(LocationRequest.create(), mPendingIntent);
+ updateLocation(FUSED_PROVIDER_NAME, LAT, LNG);
+ waitForReceiveBroadcast();
+
+ assertNotNull(mIntentReceiver.getLastReceivedIntent());
+ final Location location = mManager.getLastKnownLocation(FUSED_PROVIDER_NAME);
+ assertEquals(FUSED_PROVIDER_NAME, location.getProvider());
+
+ assertEquals(3000.0f, location.getAccuracy());
+ assertEquals(LAT, location.getLatitude(), FUDGER_DELTA);
+ assertEquals(LNG, location.getLongitude(), FUDGER_DELTA);
+
+ mManager.removeUpdates(mPendingIntent);
+ mManager.removeTestProvider(FUSED_PROVIDER_NAME);
+ }
+
+ public void testGetFusedLocationUpdates_withListener() {
+ addTestProvider(FUSED_PROVIDER_NAME, Criteria.ACCURACY_COARSE, true, false, true);
+
+ MockLocationListener listener = new MockLocationListener();
+ HandlerThread handlerThread = new HandlerThread(
+ "testLocationUpdates for " + FUSED_PROVIDER_NAME);
+ handlerThread.start();
+
+ mManager.requestLocationUpdates(LocationRequest.create(),
+ listener, handlerThread.getLooper());
+ updateLocation(FUSED_PROVIDER_NAME, LAT, LNG);
+
+ assertTrue(listener.hasCalledOnLocationChanged(TEST_TIME_OUT_MS));
+ Location location = listener.getLocation();
+ assertEquals(FUSED_PROVIDER_NAME, location.getProvider());
+
+ assertEquals(3000.0f, location.getAccuracy());
+ assertEquals(LAT, location.getLatitude(), FUDGER_DELTA);
+ assertEquals(LNG, location.getLongitude(), FUDGER_DELTA);
+
+ mManager.removeUpdates(listener);
+ mManager.removeTestProvider(FUSED_PROVIDER_NAME);
+ }
+
+ /**
+ * Helper method to add a test provider with given name.
+ */
+ private void addTestProvider(final String providerName, int accuracy, boolean requiresNetwork,
+ boolean requiresSatellite, boolean requiresCell) {
+ mManager.addTestProvider(providerName,
+ requiresNetwork,
+ requiresSatellite,
+ requiresCell,
+ false, // hasMonetaryCost,
+ false, // supportsAltitude,
+ false, // supportsSpeed,
+ false, // supportsBearing,
+ Criteria.POWER_MEDIUM, // powerRequirement
+ accuracy); // accuracy
+ mManager.setTestProviderEnabled(providerName, true);
+ }
+
+ public void testGetProviders() {
+ List<String> providers = mManager.getProviders(false);
+
+ assertFalse(hasProvider(providers, LocationManager.PASSIVE_PROVIDER));
+ assertFalse(hasProvider(providers, LocationManager.GPS_PROVIDER));
+ }
+
+ private boolean hasProvider(List<String> providers, String providerName) {
+ for (String provider : providers) {
+ if (provider != null && provider.equals(providerName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void testGpsStatusListener() {
+ try {
+ mManager.addGpsStatusListener(new MockGpsStatusListener());
+ fail("Should have failed to add a gps status listener");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ try {
+ mManager.addGpsStatusListener(null);
+ fail("Should have failed to add a gps status listener");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ public void testSendExtraCommand() {
+ addTestProvider(LocationManager.NETWORK_PROVIDER, Criteria.ACCURACY_COARSE, true, false, true);
+ addTestProvider(LocationManager.GPS_PROVIDER, Criteria.ACCURACY_FINE, false, true, false);
+
+ // Unknown command
+ assertFalse(mManager.sendExtraCommand(LocationManager.NETWORK_PROVIDER, "unknown", new Bundle()));
+
+ try {
+ mManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "unknown", new Bundle());
+ fail("Should have failed to send a command to the gps provider");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ mManager.removeTestProvider(LocationManager.GPS_PROVIDER);
+ mManager.removeTestProvider(LocationManager.NETWORK_PROVIDER);
+ }
+
+ private void registerIntentReceiver() {
+ String intentKey = "LocationManagerTest";
+ Intent proximityIntent = new Intent(intentKey);
+ mPendingIntent = PendingIntent.getBroadcast(mContext, 0, proximityIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ mIntentReceiver = new TestIntentReceiver(intentKey);
+ mContext.registerReceiver(mIntentReceiver, mIntentReceiver.getFilter());
+ }
+
+ /**
+ * Blocks until receive intent notification or time out.
+ */
+ private void waitForReceiveBroadcast() {
+ synchronized (mIntentReceiver) {
+ try {
+ mIntentReceiver.wait(TEST_TIME_OUT_MS);
+ } catch (InterruptedException e) {
+ fail("Interrupted while waiting for intent: " + e);
+ }
+ }
+ }
+
+ private void updateLocation(final String providerName, final double latitude,
+ final double longitude) {
+ Location nlocation = new Location(providerName);
+ nlocation.setLatitude(latitude);
+ nlocation.setLongitude(longitude);
+ nlocation.setAccuracy(3000.0f);
+ nlocation.setTime(java.lang.System.currentTimeMillis());
+ nlocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+
+ Location location = new Location(providerName);
+ location.setLatitude(latitude);
+ location.setLongitude(longitude);
+ location.setAccuracy(1.0f);
+ location.setTime(java.lang.System.currentTimeMillis());
+ location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+
+ location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, nlocation);
+
+ mManager.setTestProviderLocation(providerName, location);
+ }
+
+ /**
+ * Helper class that receives a proximity intent and notifies the main class
+ * when received
+ */
+ private static class TestIntentReceiver extends BroadcastReceiver {
+ private String mExpectedAction;
+
+ private Intent mLastReceivedIntent;
+
+ public TestIntentReceiver(String expectedAction) {
+ mExpectedAction = expectedAction;
+ mLastReceivedIntent = null;
+ }
+
+ public IntentFilter getFilter() {
+ IntentFilter filter = new IntentFilter(mExpectedAction);
+ return filter;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && mExpectedAction.equals(intent.getAction())) {
+ synchronized (this) {
+ mLastReceivedIntent = intent;
+ notify();
+ }
+ }
+ }
+
+ public Intent getLastReceivedIntent() {
+ return mLastReceivedIntent;
+ }
+
+ public void clearReceivedIntents() {
+ mLastReceivedIntent = null;
+ }
+ }
+
+ private static class MockLocationListener implements LocationListener {
+ private String mProvider;
+ private int mStatus;
+ private Location mLocation;
+ private Object mStatusLock = new Object();
+ private Object mLocationLock = new Object();
+ private Object mLocationRequestLock = new Object();
+
+ private boolean mHasCalledOnLocationChanged;
+
+ private boolean mHasCalledOnProviderDisabled;
+
+ private boolean mHasCalledOnProviderEnabled;
+
+ private boolean mHasCalledOnStatusChanged;
+
+ private boolean mHasCalledRequestLocation;
+
+ public void reset(){
+ mHasCalledOnLocationChanged = false;
+ mHasCalledOnProviderDisabled = false;
+ mHasCalledOnProviderEnabled = false;
+ mHasCalledOnStatusChanged = false;
+ mHasCalledRequestLocation = false;
+ mProvider = null;
+ mStatus = 0;
+ }
+
+ /**
+ * Call to inform listener that location has been updates have been requested
+ */
+ public void setLocationRequested() {
+ synchronized (mLocationRequestLock) {
+ mHasCalledRequestLocation = true;
+ mLocationRequestLock.notify();
+ }
+ }
+
+ public boolean hasCalledLocationRequested(long timeout) throws InterruptedException {
+ synchronized (mLocationRequestLock) {
+ if (timeout > 0 && !mHasCalledRequestLocation) {
+ mLocationRequestLock.wait(timeout);
+ }
+ }
+ return mHasCalledRequestLocation;
+ }
+
+ /**
+ * Check whether onLocationChanged() has been called. Wait up to timeout milliseconds
+ * for the callback.
+ * @param timeout Maximum time to wait for the callback, 0 to return immediately.
+ */
+ public boolean hasCalledOnLocationChanged(long timeout) {
+ synchronized (mLocationLock) {
+ if (timeout > 0 && !mHasCalledOnLocationChanged) {
+ try {
+ mLocationLock.wait(timeout);
+ } catch (InterruptedException e) {
+ fail("Interrupted while waiting for location change: " + e);
+ }
+ }
+ }
+ return mHasCalledOnLocationChanged;
+ }
+
+ public boolean hasCalledOnProviderDisabled() {
+ return mHasCalledOnProviderDisabled;
+ }
+
+ public boolean hasCalledOnProviderEnabled() {
+ return mHasCalledOnProviderEnabled;
+ }
+
+ public boolean hasCalledOnStatusChanged(long timeout) throws InterruptedException {
+ synchronized(mStatusLock) {
+ // wait(0) would wait forever
+ if (timeout > 0 && !mHasCalledOnStatusChanged) {
+ mStatusLock.wait(timeout);
+ }
+ }
+ return mHasCalledOnStatusChanged;
+ }
+
+ public void onLocationChanged(Location location) {
+ mLocation = location;
+ synchronized (mLocationLock) {
+ mHasCalledOnLocationChanged = true;
+ mLocationLock.notify();
+ }
+ }
+
+ public void onProviderDisabled(String provider) {
+ mHasCalledOnProviderDisabled = true;
+ }
+
+ public void onProviderEnabled(String provider) {
+ mHasCalledOnProviderEnabled = true;
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ mProvider = provider;
+ mStatus = status;
+ synchronized (mStatusLock) {
+ mHasCalledOnStatusChanged = true;
+ mStatusLock.notify();
+ }
+ }
+
+ public String getProvider() {
+ return mProvider;
+ }
+
+ public int getStatus() {
+ return mStatus;
+ }
+
+ public Location getLocation() {
+ return mLocation;
+ }
+ }
+
+ private static class MockGpsStatusListener implements Listener {
+ private boolean mHasCallOnGpsStatusChanged;
+
+ public boolean hasCallOnGpsStatusChanged() {
+ return mHasCallOnGpsStatusChanged;
+ }
+
+ public void reset(){
+ mHasCallOnGpsStatusChanged = false;
+ }
+
+ public void onGpsStatusChanged(int event) {
+ mHasCallOnGpsStatusChanged = true;
+ }
+ }
+}