/*
* Copyright (C) 2009 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.odk.collect.android.activities;
import java.text.DecimalFormat;
import java.util.Set;
import org.odk.collect.android.R;
import org.odk.collect.android.application.GeoProgressDialog;
import org.odk.collect.android.utilities.GeoUtils;
import org.odk.collect.android.listeners.TimerListener;
import org.odk.collect.android.utilities.ODKTimer;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
public class GeoPointActivity extends Activity implements LocationListener, TimerListener {
private GeoProgressDialog mLocationDialog;
private LocationManager mLocationManager;
private Location mLocation;
private Set<String> mProviders;
private int millisToWait = 60000; //allow to accept location after 60 seconds
private ODKTimer mTimer;
/*
* (non-Javadoc)
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(getString(R.string.app_name) + " > " + getString(R.string.get_location));
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mProviders = GeoUtils.evaluateProviders(mLocationManager);
setupLocationDialog();
long mLong = -1;
if(savedInstanceState != null){
mLong = savedInstanceState.getLong("millisRemaining",-1);
}
if(mLong > 0){
mTimer = new ODKTimer(mLong, this);
}else{
mTimer = new ODKTimer(millisToWait, this);
}
mTimer.start();
}
/*
* (non-Javadoc)
* @see android.app.Activity#onPause()
*/
@Override
protected void onPause() {
super.onPause();
// stops the GPS. Note that this will turn off the GPS if the screen goes to sleep.
mLocationManager.removeUpdates(this);
// We're not using managed dialogs, so we have to dismiss the dialog to prevent it from
// leaking memory.
if (mLocationDialog != null && mLocationDialog.isShowing())
mLocationDialog.dismiss();
}
/*
* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
protected void onResume() {
super.onResume();
mProviders = GeoUtils.evaluateProviders(mLocationManager);
if (mProviders.isEmpty()) {
DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() {
/*
* (non-Javadoc)
* @see android.content.DialogInterface.OnCancelListener#onCancel(android.content.DialogInterface)
*/
@Override
public void onCancel(DialogInterface dialog) {
mLocation = null;
GeoPointActivity.this.finish();
}
};
DialogInterface.OnClickListener onChangeListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) {
switch (i) {
case DialogInterface.BUTTON_POSITIVE:
Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
break;
case DialogInterface.BUTTON_NEGATIVE:
mLocation = null;
GeoPointActivity.this.finish();
break;
}
}
};
GeoUtils.showNoGpsDialog(this, onChangeListener, onCancelListener);
} else {
for (String provider : mProviders) {
mLocationManager.requestLocationUpdates(provider, 0, 0, this);
}
mLocationDialog.show();
}
}
/**
* Sets up the look and actions for the progress dialog while the GPS is searching.
*/
private void setupLocationDialog() {
// dialog displayed while fetching gps location
OnClickListener cancelButtonListener = new OnClickListener() {
/*
* (non-Javadoc)
* @see android.view.View.OnClickListener#onClick(android.view.View)
*/
@Override
public void onClick(View v){
mLocation = null;
finish();
}
};
OnClickListener okButtonListener = new OnClickListener() {
public void onClick(View v){
returnLocation();
}
};
mLocationDialog = new GeoProgressDialog(this, getString(R.string.found_location), getString(R.string.finding_location));
// back button doesn't cancel
mLocationDialog.setCancelable(false);
mLocationDialog.setImage(getResources().getDrawable(R.drawable.green_check_mark));
mLocationDialog.setMessage(getString(R.string.please_wait_long));
mLocationDialog.setOKButton(getString(R.string.accept_location),
okButtonListener);
mLocationDialog.setCancelButton(getString(R.string.cancel_location),
cancelButtonListener);
}
private void returnLocation() {
if (mLocation != null) {
Intent i = new Intent();
i.putExtra(FormEntryActivity.LOCATION_RESULT, GeoUtils.locationToString(mLocation));
setResult(RESULT_OK, i);
}
finish();
}
/*
* (non-Javadoc)
* @see android.location.LocationListener#onLocationChanged(android.location.Location)
*/
@Override
public void onLocationChanged(Location location) {
mLocation = location;
if (mLocation != null) {
mLocationDialog.setMessage(getString(R.string.location_provider_accuracy,
mLocation.getProvider(), truncateDouble(mLocation.getAccuracy())));
// If location is accurate, we're done
if (mLocation.getAccuracy() <= GeoUtils.GOOD_ACCURACY) {
returnLocation();
}
// If location isn't great but might be acceptable, notify
// the user and let them decide whether or not to record it
mLocationDialog.setLocationFound(
mLocation.getAccuracy() < GeoUtils.ACCEPTABLE_ACCURACY
|| mTimer.getMillisUntilFinished() == 0
);
}
}
private String truncateDouble(float number) {
DecimalFormat df = new DecimalFormat("#.##");
return df.format(number);
}
/*
* (non-Javadoc)
* @see android.location.LocationListener#onProviderDisabled(java.lang.String)
*/
@Override
public void onProviderDisabled(String provider) {
}
/*
* (non-Javadoc)
* @see android.location.LocationListener#onProviderEnabled(java.lang.String)
*/
@Override
public void onProviderEnabled(String provider) {
}
/*
* (non-Javadoc)
* @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle)
*/
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
case LocationProvider.AVAILABLE:
if (mLocation != null) {
mLocationDialog.setMessage(getString(R.string.location_accuracy,
(int) mLocation.getAccuracy()));
}
break;
case LocationProvider.OUT_OF_SERVICE:
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
break;
}
}
/*
* (non-Javadoc)
* @see org.odk.collect.android.listeners.TimerListener#notifyTimerFinished()
*/
@Override
public void notifyTimerFinished() {
onLocationChanged(mLocation);
}
/*
* (non-Javadoc)
* @see android.app.Activity#onSaveInstanceState(android.os.Bundle)
*/
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putLong("millisRemaining",mTimer.getMillisUntilFinished());
super.onSaveInstanceState(savedInstanceState);
}
}