package com.example.geofencingsample;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentSender;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
public class MainActivity extends FragmentActivity
implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationClient.OnAddGeofencesResultListener,
LocationClient.OnRemoveGeofencesResultListener {
private static final String TAG = MainActivity.class.getSimpleName();
// 東京スカイツリーの緯度・経度が中心。
// 自分の所在地の緯度・経度を入れると試験しやすい。
private static final double FENCE_LATITUDE = 35.710057714926265;
private static final double FENCE_LONGITUDE = 139.81071829999996;
// 半径200m
private final static float FENCE_RADIUS = 200.0f;
// 設置するジオフェンスのID
private final static String SKYTREE = "tokyo_skytree";
// スカイツリーの公式ウェブサイトURL
private final static String SKYTREE_URL = "http://www.tokyo-skytree.jp/";
// フェンスの追加・削除リクエストを示す定数
private final static int ADD_FENCE = 0;
private final static int REMOVE_FENCE = 1;
// Google Play Services へのリクエストコード
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
// エラーダイアログの引数保持に使用するキー名
public static final String ERROR_CODE = "ERROR_CODE";
// LocationClientのインスタンス
private LocationClient mLocationClient;
// LocationClientへの処理要求中かどうかを管理するフラグ
private boolean mInProgress;
// LocationClientに要求する処理の種類 (ADD_FENCE または REMOVE_FENCE)
private int mRequestType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInProgress = false;
Button startButton = (Button) findViewById(R.id.start_service_btn);
Button stopButton = (Button) findViewById(R.id.stop_service_btn);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mRequestType = ADD_FENCE;
if (!mInProgress) {
requestConnectLocationClient();
}
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mRequestType = REMOVE_FENCE;
if (!mInProgress) {
requestConnectLocationClient();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CONNECTION_FAILURE_RESOLUTION_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
// Google Play Services が問題を解決した場合、再接続する
if (mRequestType == ADD_FENCE || mRequestType == REMOVE_FENCE) {
mInProgress = false;
requestConnectLocationClient();
}
} else {
// Google Play Servicesで問題が解決されなかった場合、ログ出力
Log.d(TAG, "google play no resolution error");
}
} else {
Log.d(TAG, "unknown request code: " + requestCode);
}
}
// LocationClient に接続する
private void requestConnectLocationClient() {
getLocationClient().connect();
}
// LocationClientのインスタンスを取得する
private LocationClient getLocationClient() {
if (mLocationClient == null) {
mLocationClient = new LocationClient(this, this, this);
}
return mLocationClient;
}
// Google Play Services への接続チェック
private boolean servicesConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS) {
return true;
} else {
// エラーダイアログ表示
showErrorDialog(resultCode);
return false;
}
}
// ジオフェンスを登録する
private void addFence(double latitude, double longitude, float radius,
String requestId, String broadcastUri) {
if (!servicesConnected()) {
return;
}
Geofence.Builder builder = new Geofence.Builder();
builder.setRequestId(requestId);
builder.setCircularRegion(latitude, longitude, radius);
builder.setExpirationDuration(Geofence.NEVER_EXPIRE); // 無期限
builder.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER);
// フェンスのListを作成する。
List<Geofence> fenceList = new ArrayList<Geofence>();
fenceList.add(builder.build());
// フェンス内に入った時に、指定のURIを表示するインテントを投げるようにする。
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(broadcastUri));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
mLocationClient.addGeofences(fenceList, pendingIntent, this);
}
// 指定されたIDのジオフェンスを削除
private void removeFence(String requestId) {
if (!servicesConnected()) {
return;
}
List<String> fenceIdList = new ArrayList<String>();
fenceIdList.add(requestId);
mLocationClient.removeGeofences(fenceIdList, this);
}
// LocationClientに接続したら呼ばれる
@Override
public void onConnected(Bundle bundle) {
switch (mRequestType) {
case ADD_FENCE:
addFence(FENCE_LATITUDE,
FENCE_LONGITUDE,
FENCE_RADIUS,
SKYTREE,
SKYTREE_URL);
break;
case REMOVE_FENCE:
removeFence(SKYTREE);
break;
default:
break;
}
}
// LocationClientから切断したら呼ばれる
@Override
public void onDisconnected() {
mInProgress = false;
mLocationClient = null;
}
// Google Play services への接続に失敗した場合に呼ばれる。
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
/*
* Google Play services が問題解決できる場合、Google Play servicesを 呼び出して、解決を要求する。
*/
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
// エラーダイアログ表示
showErrorDialog(connectionResult.getErrorCode());
}
}
// Google Play services が作成するエラーダイアログを表示する。
// Google Play servicesのバージョンが古い場合に更新を促すなど、
// よきにはからってくれる。
private void showErrorDialog(int errorCode) {
ErrorDialogFragment errorDialogFragment = ErrorDialogFragment.newInstance(errorCode);
errorDialogFragment.show(getSupportFragmentManager(),
"Geofence Sample");
}
@Override
public void onAddGeofencesResult(int i, String[] strings) {
mInProgress = false;
mLocationClient.disconnect();
}
@Override
public void onRemoveGeofencesByRequestIdsResult(int i,
String[] strings) {
mInProgress = false;
mLocationClient.disconnect();
}
@Override
public void onRemoveGeofencesByPendingIntentResult(
int i,
PendingIntent pendingIntent) {
mInProgress = false;
mLocationClient.disconnect();
}
// エラーダイアログを表示するフラグメント
public static class ErrorDialogFragment extends DialogFragment {
public static ErrorDialogFragment newInstance(int errorCode) {
ErrorDialogFragment fragment = new ErrorDialogFragment();
// 画面回転などでのフラグメント再生成を考慮して、必要な引数はsetArguments()で保持する
Bundle args = fragment.getArguments();
if (args == null) {
args = new Bundle();
}
args.putInt(ERROR_CODE, errorCode);
fragment.setArguments(args);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// getArguments()でエラーダイアログ生成に必要な引数を修得する
int errorCode = getArguments().getInt(ERROR_CODE);
// Google Play servicesでエラーダイアログを生成する
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
getActivity(),
CONNECTION_FAILURE_RESOLUTION_REQUEST
);
return errorDialog;
}
}
}