/*
* CentralMapExtraActivity.java
* Copyright (C) 2015 Nicholas Killewald
*
* This file is distributed under the terms of the BSD license.
* The source package should have a LICENSE file at the toplevel.
*/
package net.exclaimindustries.geohashdroid.activities;
import android.Manifest;
import android.app.FragmentManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import net.exclaimindustries.geohashdroid.R;
import net.exclaimindustries.geohashdroid.fragments.CentralMapExtraFragment;
import net.exclaimindustries.geohashdroid.util.GHDConstants;
import net.exclaimindustries.geohashdroid.util.Info;
import net.exclaimindustries.tools.AndroidUtil;
import java.text.DateFormat;
/**
* Similar to <code>CentralMapExtraFragment</code>, <code>CentralMapExtraActivity</code>
* encompasses the common methods to all Activities that hold those Fragments on
* phone layouts. Turns out those Activities are really very simple and share
* quite a lot in common.
*/
public abstract class CentralMapExtraActivity extends BaseGHDThemeActivity
implements CentralMapExtraFragment.CloseListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
/**
* The key for the Intent extra containing the Info object. This should
* very seriously NOT be null. If it is, you did something very wrong.
*/
public static final String INFO = "info";
private CentralMapExtraFragment mFrag;
private GoogleApiClient mGoogleClient;
protected Info mInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResource());
// Grab the fragment. We know it's there, it's right there in the
// layout.
FragmentManager manager = getFragmentManager();
mFrag = (CentralMapExtraFragment) manager.findFragmentById(getFragmentResource());
// We'd BETTER have an Intent.
Intent intent = getIntent();
// And that intent BETTER have an Info.
mInfo = intent.getParcelableExtra(INFO);
// Since the fragment's part of the layout, we can't set an argument
// anymore. So, just update the Info.
mFrag.setCloseListener(this);
mFrag.setInfo(mInfo);
// Let's get the client fired up, since CentralMap won't be around to
// handle updating the location.
mGoogleClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
@Override
protected void onStart() {
super.onStart();
// Fire up the client!
mGoogleClient.connect();
}
@Override
protected void onStop() {
// Client goes down, and so does the listener!
stopListening();
mGoogleClient.disconnect();
super.onStop();
}
/**
* Returns the resource of the options menu this Activity uses.
*
* @return a menu's resource ID
*/
protected abstract int getMenuResource();
/**
* Returns the resource of the Fragment this Activity deals with.
*
* @return a Fragment's resource ID
*/
protected abstract int getFragmentResource();
/**
* Returns the resource of the layout this Activity wants.
*
* @return a layout's resource ID
*/
protected abstract int getLayoutResource();
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(getMenuResource(), menu);
// Now, some menu items may not be available if we can't get to them.
// Like, for instance, Send To Maps. If Google Maps (or anything that
// can receive the Intent) isn't there, we can't do that.
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("geo:0,0?q=loc:0,0"));
if(!AndroidUtil.isIntentAvailable(this, i))
menu.removeItem(R.id.action_send_to_maps);
// Or the Radar intent.
if(!AndroidUtil.isIntentAvailable(this, GHDConstants.ACTION_SHOW_RADAR))
menu.removeItem(R.id.action_send_to_radar);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_wiki: {
// Wiki time! Wiki time! It's time for wiki time!
if(mInfo != null) {
// Since we're in the activity version of Detailed Info, we
// know we're just starting the wiki activity.
Intent i = new Intent(this, WikiActivity.class);
i.putExtra(WikiActivity.INFO, mInfo);
startActivity(i);
} else {
Toast.makeText(this, R.string.error_no_data_to_wiki, Toast.LENGTH_LONG).show();
}
return true;
}
case R.id.action_preferences: {
// We've got preferences, so we've got an Activity.
Intent i = new Intent(this, PreferencesScreen.class);
startActivity(i);
return true;
}
case R.id.action_send_to_maps: {
if(mInfo != null) {
// To the map!
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
// Assemble the location. This is a simple latitude,longitude
// setup.
String location = mInfo.getLatitude() + "," + mInfo.getLongitude();
// Then, toss the location out the door and hope whatever map
// we're using is paying attention.
i.setData(Uri.parse("geo:0,0?q=loc:"
+ location
+ "("
+ this.getString(
R.string.send_to_maps_point_name,
DateFormat.getDateInstance(DateFormat.LONG).format(
mInfo.getCalendar().getTime())) + ")&z=15"));
startActivity(i);
} else {
Toast.makeText(this, R.string.error_no_data_to_maps, Toast.LENGTH_LONG).show();
}
return true;
}
case R.id.action_send_to_radar: {
if(mInfo != null) {
Intent i = new Intent(GHDConstants.ACTION_SHOW_RADAR);
i.putExtra("latitude", (float) mInfo.getLatitude());
i.putExtra("longitude", (float) mInfo.getLongitude());
startActivity(i);
} else {
Toast.makeText(this, R.string.error_no_data_to_radar, Toast.LENGTH_LONG).show();
}
return true;
}
}
return false;
}
@Override
public void extraFragmentClosing(CentralMapExtraFragment fragment) {
// Easy enough, just finish the Activity.
finish();
}
@Override
public void extraFragmentDestroying(CentralMapExtraFragment fragment) {
// Nothing happens here; we're already on our way out.
}
@Override
public void onConnected(Bundle bundle) {
// We have a connection! Yay!
mFrag.permissionsDenied(false);
// Start listening! If we have permission, that is. If not, well...
startListening();
}
@Override
public void onConnectionSuspended(int i) {
stopListening();
}
private void startListening() {
// While starting up, we also report to the fragment what happened with
// the permissions checks.
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mFrag.permissionsDenied(false);
LocationRequest lRequest = LocationRequest.create();
lRequest.setInterval(1000);
lRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleClient, lRequest, this);
} else {
mFrag.permissionsDenied(true);
}
}
private void stopListening() {
if(mGoogleClient != null && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleClient, this);
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// If the connection failed, forget it. That means the user's already
// denied permission somehow, so we're not asking again.
mFrag.permissionsDenied(true);
}
@Override
public void onLocationChanged(Location location) {
// When we get a location, let the fragment know. We're sort of acting
// like an ersatz ExpeditionMode at this point.
mFrag.onLocationChanged(location);
}
}