Mock GPS는 GPS 어플을 개발할때 모의로 테스트 해볼 수 있게 API가 마련되어있습니다.
하지만 구글 문서에서는 예제를 정확히 찾기가 어려워서 예제를 만들어 보았습니다.
이글은 정상적으로 Mock GPS API를 사용하는 예제입니다.
아래 첫번째 소스 코드는 Mock GPS를 사용하지 않았는지 속이기 위한 Fake GPS 소스 코드가 아닙니다. (isFromMockProvider()를 이용하면 Mock 위치 정보인지 알 수 있습니다.)
두번째 소스는 isFromMockProvider() 값이 false가 리턴됩니다.
여기에 있는 소스들 실행시 실행후 취소키를 누르게 되면 앱이 종료됩니다.
홈키를 눌러 thread가 살아 있을수 있게 해서 테스트 해야 합니다.
사용하기 위해서는 아래와 같이 설정을 미리 해야합니다.
(삼성폰예) Mock GPS를 이용하기 전에 개발자 옵션를 on해야하며 (환경설정>디바이스정보>소프트웨어 정보>빌드번호 연속으로 터치)(환경설정>개발자옵션)모위 위치 앱을 설정(모의 위치 앱으로 사용하고자 하는 앱 설정 한번에 하나만 사용가능) 해야 합니다.
이부분은 fly GPS로 마켓을 검색해보면 세팅하는 방법이 자세히 나와있습니다.
참고
http://programmingjungle.blogspot.kr/2012/08/how-to-use-mocking-location-on-android.html
권한은 아래 권한이 필요합니다.
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />사용할 Provider를 아래 메소드를 이용하여 등록하고
addTestProvider
setTestProviderEnabled
아래 메소드는 위치 정보를 변경할때 사용합니다.
setTestProviderLocation
그리고 필요없으면 삭제하는 메소드로 구성되어 있습니다.
removeTestProvider
Mock 소스
package com.example.xxx.mockgps; import android.content.Context; import android.location.Location; import android.location.LocationManager; import android.os.SystemClock; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity { Button btn1; Button btn2; Button btn3; Button btn4; EditText editText; MockUpdateGPSThread thread; FakeUpdateGPSThread fakethread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupButton(); } private void setupButton() { editText = (EditText) findViewById(R.id.editText); btn1 = (Button) findViewById(R.id.button); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startMockGps(); editText.append("Start\n"); } }); btn2 = (Button) findViewById(R.id.button2); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopMockGps(); editText.append("Stop\n"); } }); btn3 = (Button) findViewById(R.id.button3); btn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startFakeGps(); } }); btn4 = (Button) findViewById(R.id.button4); btn4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopFakeGps(); } }); } class MockUpdateGPSThread extends Thread { final int TIME_UPDATES_MS = 5000; public boolean Running; private double curLat = 34.526456 , curLong = 127.3298; @Override public void run() { Log.i("zzz", "Starting Mock GPSThread"); Running = true; LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); addSetProvider(locationManager,"gps"); addSetProvider(locationManager,"network"); while (Running) { setPLocation(locationManager ,"gps", curLat, curLong); setPLocation(locationManager ,"network", curLat, curLong); try { Thread.sleep(TIME_UPDATES_MS); } catch (Exception e) { Running = false; break; } curLat = curLat + 0.01; } delProvider(locationManager, "gps"); delProvider(locationManager, "network"); Log.i("zzz", "Ending Mock GPSThread"); } } private void addSetProvider(LocationManager locationManager,String provider) { locationManager.addTestProvider(provider, false, false, false, false, false, false, false, 1, 1); if( !locationManager.isProviderEnabled(provider) ) locationManager.setTestProviderEnabled(provider, true); } public void setPLocation(LocationManager locationManager,String provider, double curLat, double curLong) { Location loc = new Location(provider); loc.setTime(System.currentTimeMillis()); loc.setLatitude(curLat); loc.setLongitude(curLong); loc.setBearing(0); loc.setAccuracy(1.0f); loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); loc.setSpeed((float) 0); locationManager.setTestProviderLocation(provider, loc); } public void delProvider(LocationManager locationManager, String provider) { if( locationManager.isProviderEnabled(provider) ) locationManager.setTestProviderEnabled(provider, false); locationManager.removeTestProvider(provider); } private void startMockGps() { if( thread == null ) { thread = new MockUpdateGPSThread(); thread.start(); } } private void stopMockGps() { if( thread!= null) { thread.interrupt(); } } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.xxxx.mockgps"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> </manifest>
-------------------------------------------------------------------
Fake GPS
이 글은 안드로이드 6.0 M OS 에서 테스트 되어졌습니다.
그 이유는 버그를 이용하기 때문입니다.
아래가 핵심 부분입니다.
provider는 network을 만들고 setTestProviderLocation 함수 인자를 넘겨줄때 provider는 network을 넘겨주지만 Location으로 만든 Provider는 GPS를 넘겨주는 방법을 사용합니다.
아래 코드 참조
addSetProvider(locationManager,"network");
setFakeLocation(locationManager ,"gps","network", curLat, curLong);
public void setFakeLocation(LocationManager locationManager,String provider1, String provider2, double curLat, double curLong) {
Location loc = new Location("");
loc.setProvider(provider1);
loc.setTime(System.currentTimeMillis());
loc.setLatitude(curLat);
loc.setLongitude(curLong);
loc.setBearing(0);
loc.setAccuracy(1.0f);
loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
loc.setSpeed((float) 0);
locationManager.setTestProviderLocation(provider2, loc);
}
그리고 제대로 사용하려면 network에서 위치정보 신호가 들어오면 안됩니다. 왜냐하면 network은 test provider설정이 되어있기 때문입니다. 따라서 GPS 환경 설정에서 위치 인식 방법중 GPS만 사용 설정을 해야합니다. 또한 GPS쪽으로도 위치정보 신호가 들어오면 안됩니다. 순간 이동을 하게 됩니다.
여기에 있는 소스들 실행시 실행후 취소키를 누르게 되면 앱이 종료됩니다.
홈키를 눌러 thread가 살아 있을수 있게 해서 테스트 해야 합니다.
동작 화면
Fake 모드 소스
package com.example.xxxx.mockgps; import android.content.Context; import android.location.Location; import android.location.LocationManager; import android.os.SystemClock; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity { Button btn1; Button btn2; Button btn3; Button btn4; EditText editText; MockUpdateGPSThread thread; FakeUpdateGPSThread fakethread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupButton(); } private void setupButton() { editText = (EditText) findViewById(R.id.editText); btn1 = (Button) findViewById(R.id.button); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startMockGps(); editText.append("Start\n"); } }); btn2 = (Button) findViewById(R.id.button2); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopMockGps(); editText.append("Stop\n"); } }); btn3 = (Button) findViewById(R.id.button3); btn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startFakeGps(); editText.append("Fake Start\n"); } }); btn4 = (Button) findViewById(R.id.button4); btn4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopFakeGps(); editText.append("Fake Stop\n"); } }); } class MockUpdateGPSThread extends Thread { final int TIME_UPDATES_MS = 5000; public boolean Running; private double curLat = 34.526456 , curLong = 127.3298; @Override public void run() { Log.i("zzz", "Starting Mock GPSThread"); Running = true; LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); addSetProvider(locationManager,"gps"); addSetProvider(locationManager,"network"); while (Running) { setPLocation(locationManager ,"gps", curLat, curLong); setPLocation(locationManager ,"network", curLat, curLong); try { Thread.sleep(TIME_UPDATES_MS); } catch (Exception e) { Running = false; break; } curLat = curLat + 0.01; } delProvider(locationManager, "gps"); delProvider(locationManager, "network"); Log.i("zzz", "Ending Mock GPSThread"); } } private void addSetProvider(LocationManager locationManager,String provider) { locationManager.addTestProvider(provider, false, false, false, false, false, false, false, 1, 1); if( !locationManager.isProviderEnabled(provider) ) locationManager.setTestProviderEnabled(provider, true); } public void setPLocation(LocationManager locationManager,String provider, double curLat, double curLong) { Location loc = new Location(provider); loc.setTime(System.currentTimeMillis()); loc.setLatitude(curLat); loc.setLongitude(curLong); loc.setBearing(0); loc.setAccuracy(1.0f); loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); loc.setSpeed((float) 0); locationManager.setTestProviderLocation(provider, loc); } public void delProvider(LocationManager locationManager, String provider) { if( locationManager.isProviderEnabled(provider) ) locationManager.setTestProviderEnabled(provider, false); locationManager.removeTestProvider(provider); } private void startMockGps() { if( thread == null ) { thread = new MockUpdateGPSThread(); thread.start(); } } private void stopMockGps() { if( thread!= null) { thread.interrupt(); } } class FakeUpdateGPSThread extends Thread { final int TIME_UPDATES_MS = 5000; public boolean Running; private double curLat = 34.526456 , curLong = 127.3298; @Override public void run() { Log.i("zzz", "Starting fake GPSThread"); Running = true; LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); addSetProvider(locationManager,"network"); while (Running) { setFakeLocation(locationManager ,"gps","network", curLat, curLong); try { Thread.sleep(TIME_UPDATES_MS); } catch (Exception e) { Running = false; break; } curLat = curLat + 0.01; } delProvider(locationManager, "network"); Log.i("zzz", "Ending fake GPSThread"); } } public void setFakeLocation(LocationManager locationManager,String provider1, String provider2, double curLat, double curLong) { Location loc = new Location(""); loc.setProvider(provider1); loc.setTime(System.currentTimeMillis()); loc.setLatitude(curLat); loc.setLongitude(curLong); loc.setBearing(0); loc.setAccuracy(1.0f); loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); loc.setSpeed((float) 0); locationManager.setTestProviderLocation(provider2, loc); } private void startFakeGps() { if( fakethread == null ) { fakethread = new FakeUpdateGPSThread(); fakethread.start(); } } private void stopFakeGps() { if( fakethread!= null) { fakethread.interrupt(); } } }
여기에 사용된 좌표는 임의의 좌표입니다.