1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.location.fused.tests; 18 19 import static android.location.LocationManager.GPS_PROVIDER; 20 import static android.location.LocationManager.NETWORK_PROVIDER; 21 22 import static androidx.test.ext.truth.location.LocationSubject.assertThat; 23 24 import android.content.Context; 25 import android.location.Criteria; 26 import android.location.Location; 27 import android.location.LocationManager; 28 import android.location.LocationRequest; 29 import android.location.provider.ILocationProvider; 30 import android.location.provider.ILocationProviderManager; 31 import android.location.provider.ProviderProperties; 32 import android.location.provider.ProviderRequest; 33 import android.os.ParcelFileDescriptor; 34 import android.os.SystemClock; 35 import android.util.Log; 36 37 import androidx.test.InstrumentationRegistry; 38 import androidx.test.core.app.ApplicationProvider; 39 import androidx.test.runner.AndroidJUnit4; 40 41 import com.android.location.fused.FusedLocationProvider; 42 43 import org.junit.After; 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 import java.io.ByteArrayOutputStream; 49 import java.io.FileInputStream; 50 import java.io.IOException; 51 import java.util.List; 52 import java.util.Random; 53 import java.util.concurrent.LinkedBlockingQueue; 54 import java.util.concurrent.TimeUnit; 55 56 @RunWith(AndroidJUnit4.class) 57 public class FusedLocationServiceTest { 58 59 private static final String TAG = "FusedLocationServiceTest"; 60 61 private static final long TIMEOUT_MS = 5000; 62 63 private Random mRandom; 64 private LocationManager mLocationManager; 65 66 private ILocationProvider mProvider; 67 private LocationProviderManagerCapture mManager; 68 69 @Before setUp()70 public void setUp() throws Exception { 71 long seed = System.currentTimeMillis(); 72 Log.i(TAG, "location seed: " + seed); 73 74 Context context = ApplicationProvider.getApplicationContext(); 75 mRandom = new Random(seed); 76 mLocationManager = context.getSystemService(LocationManager.class); 77 78 setMockLocation(true); 79 80 mManager = new LocationProviderManagerCapture(); 81 mProvider = ILocationProvider.Stub.asInterface( 82 new FusedLocationProvider(context).getBinder()); 83 mProvider.setLocationProviderManager(mManager); 84 85 mLocationManager.addTestProvider(NETWORK_PROVIDER, 86 true, 87 false, 88 true, 89 false, 90 false, 91 false, 92 false, 93 Criteria.POWER_MEDIUM, 94 Criteria.ACCURACY_FINE); 95 mLocationManager.setTestProviderEnabled(NETWORK_PROVIDER, true); 96 mLocationManager.addTestProvider(GPS_PROVIDER, 97 true, 98 false, 99 true, 100 false, 101 false, 102 false, 103 false, 104 Criteria.POWER_MEDIUM, 105 Criteria.ACCURACY_FINE); 106 mLocationManager.setTestProviderEnabled(GPS_PROVIDER, true); 107 } 108 109 @After tearDown()110 public void tearDown() throws Exception { 111 for (String provider : mLocationManager.getAllProviders()) { 112 mLocationManager.removeTestProvider(provider); 113 } 114 115 setMockLocation(false); 116 } 117 118 @Test testNetworkRequest()119 public void testNetworkRequest() throws Exception { 120 mProvider.setRequest( 121 new ProviderRequest.Builder() 122 .setIntervalMillis(1000) 123 .build()); 124 125 Location location = createLocation(NETWORK_PROVIDER, mRandom); 126 mLocationManager.setTestProviderLocation(NETWORK_PROVIDER, location); 127 128 assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location); 129 } 130 131 @Test testGpsRequest()132 public void testGpsRequest() throws Exception { 133 mProvider.setRequest( 134 new ProviderRequest.Builder() 135 .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) 136 .setIntervalMillis(1000) 137 .build()); 138 139 Location location = createLocation(GPS_PROVIDER, mRandom); 140 mLocationManager.setTestProviderLocation(GPS_PROVIDER, location); 141 142 assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location); 143 } 144 145 private static class LocationProviderManagerCapture extends ILocationProviderManager.Stub { 146 147 private final LinkedBlockingQueue<Location> mLocations; 148 LocationProviderManagerCapture()149 private LocationProviderManagerCapture() { 150 mLocations = new LinkedBlockingQueue<>(); 151 } 152 153 @Override onInitialize(boolean allowed, ProviderProperties properties, String attributionTag)154 public void onInitialize(boolean allowed, ProviderProperties properties, 155 String attributionTag) {} 156 157 @Override onSetAllowed(boolean allowed)158 public void onSetAllowed(boolean allowed) {} 159 160 @Override onSetProperties(ProviderProperties properties)161 public void onSetProperties(ProviderProperties properties) {} 162 163 @Override onReportLocation(Location location)164 public void onReportLocation(Location location) { 165 mLocations.add(location); 166 } 167 168 @Override onReportLocations(List<Location> locations)169 public void onReportLocations(List<Location> locations) { 170 mLocations.addAll(locations); 171 } 172 173 @Override onFlushComplete()174 public void onFlushComplete() {} 175 getNextLocation(long timeoutMs)176 public Location getNextLocation(long timeoutMs) throws InterruptedException { 177 return mLocations.poll(timeoutMs, TimeUnit.MILLISECONDS); 178 } 179 } 180 181 private static final double MIN_LATITUDE = -90D; 182 private static final double MAX_LATITUDE = 90D; 183 private static final double MIN_LONGITUDE = -180D; 184 private static final double MAX_LONGITUDE = 180D; 185 186 private static final float MIN_ACCURACY = 1; 187 private static final float MAX_ACCURACY = 100; 188 createLocation(String provider, Random random)189 private static Location createLocation(String provider, Random random) { 190 return createLocation(provider, 191 MIN_LATITUDE + random.nextDouble() * (MAX_LATITUDE - MIN_LATITUDE), 192 MIN_LONGITUDE + random.nextDouble() * (MAX_LONGITUDE - MIN_LONGITUDE), 193 MIN_ACCURACY + random.nextFloat() * (MAX_ACCURACY - MIN_ACCURACY)); 194 } 195 createLocation(String provider, double latitude, double longitude, float accuracy)196 private static Location createLocation(String provider, double latitude, double longitude, 197 float accuracy) { 198 Location location = new Location(provider); 199 location.setLatitude(latitude); 200 location.setLongitude(longitude); 201 location.setAccuracy(accuracy); 202 location.setTime(System.currentTimeMillis()); 203 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 204 return location; 205 } 206 setMockLocation(boolean allowed)207 private static void setMockLocation(boolean allowed) throws IOException { 208 ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation() 209 .executeShellCommand("appops set " 210 + InstrumentationRegistry.getTargetContext().getPackageName() 211 + " android:mock_location " + (allowed ? "allow" : "deny")); 212 try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { 213 ByteArrayOutputStream os = new ByteArrayOutputStream(); 214 byte[] buffer = new byte[32768]; 215 int count; 216 try { 217 while ((count = fis.read(buffer)) != -1) { 218 os.write(buffer, 0, count); 219 } 220 fis.close(); 221 } catch (IOException e) { 222 throw new RuntimeException(e); 223 } 224 Log.e(TAG, new String(os.toByteArray())); 225 } 226 } 227 } 228