转载地址:http://mobiarch.wordpress.com/2012/07/17/testing-with-mock-location-data-in-android/
The DDMS tool can be used to push out test location during testing. However, it has two serious limitations:
- DDMS sets location for GPS location provider only. If your application uses network provider then you are out of luck.
- DDMS can set location for an emulator device only. You can not do testing using a real device.
If you need to test with real device or using the network location provider, you will need to develop a mock provider within the application. A mock provider can represent any location provider – network or GPS. Writing a mock provider itself is easy. Just be careful about removing the feature before publishing your application.
In this article, we will see how to create a mock location provider.
First, we will develop a class that will encapsulate the details:
public class MockLocationProvider { String providerName; Context ctx; public MockLocationProvider(String name, Context ctx) { this.providerName = name; this.ctx = ctx; LocationManager lm = (LocationManager) ctx.getSystemService( Context.LOCATION_SERVICE); lm.addTestProvider(providerName, false, false, false, false, false, true, true, 0, 5); lm.setTestProviderEnabled(providerName, true); } public void pushLocation(double lat, double lon) { LocationManager lm = (LocationManager) ctx.getSystemService( Context.LOCATION_SERVICE); Location mockLocation = new Location(providerName); mockLocation.setLatitude(lat); mockLocation.setLongitude(lon); mockLocation.setAltitude(0); mockLocation.setTime(System.currentTimeMillis()); lm.setTestProviderLocation(providerName, mockLocation); } public void shutdown() { LocationManager lm = (LocationManager) ctx.getSystemService( Context.LOCATION_SERVICE); lm.removeTestProvider(providerName); } }
A brief description of the MockLocationProvider class may be helpful:
- The constructor takes the name of the location provider that this mock provider will replace. For example, LocationManager.GPS_PROVIDER. The calls to the addTestProvider() and setTestProviderEnabled() tells the LocationManager that the given provider will be replaced by mock data.
- The pushLocation() method supplies mock location data for a given provider.
Any activity or service can easily use the class. Here, we are replacing the network provider with a mock one.
public class MainActivity extends Activity { MockLocationProvider mock; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mock = new MockLocationProvider(LocationManager.NETWORK_PROVIDER, this); //Set test location mock.pushLocation(-12.34, 23.45); LocationManager locMgr = (LocationManager) getSystemService(LOCATION_SERVICE); LocationListener lis = new LocationListener() { public void onLocationChanged(Location location) { //You will get the mock location } //... }; locMgr.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1, lis); } protected void onDestroy() { mock.shutdown(); super.onDestroy(); } }
Setting up Security
For mock location to work, certain permissions have to be set.
You will need to request the android.permission.ACCESS_MOCK_LOCATION permission, in addition to any other permission.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
Finally, you will need to enable mock locations for the device using Settings > Developer options > Allow mock locations.
Disabling Mock Location
It is important that you hide the mock location provider business from the release build. A good way to do that is to enable mock location only if the application is being run in debug mode. In your code, check if debuggable flag is set:
if ((getApplication().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { mock = new MockLocationProvider( LocationManager.NETWORK_PROVIDER, this); //Set test location mock.pushLocation(-12.34, 23.45); }
When you test the app using USB debugging or using the emulator, the debug flag is set automatically.