package actions;
import geo.GeoUtils;
import system.EventManager;
import android.app.Activity;
import android.app.Dialog;
import android.location.Location;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.rwth.R;
public abstract class ActionWaitForAccuracy extends Action {
private static final String TEXT_DIALOG_TITLE = "Do you want to cancel the accuracy detection?";
private static final String TEXT_POSITION_ACCURACY = "Position Accuracy ";
private static final String TEXT_SKIP_ACCURACY_DETECTION = "Skip accuracy detection (not recomended!)";
// 1 minutes in ms:
private static final long MAX_TIME_SINCE_LAST_UPDATE_IN_MS = 1000 * 60 * 1;
private static final String LOG_TAG = "ActionWaitForAccuracy";
private float myCurrentAccuracy;
private float myMinAccuracy;
private boolean firstTimeReached = false;
private int myMaxPosUpdateCount;
private int stepCounter = 0;
private Activity myActivity;
private TextView accText;
private ProgressBar steps;
private View viewContainer;
private Button warningText;
/**
* @param context
* @param minAccuracy
* should be >= 25m
* @param maxPosUpdateCount
* The max number of update events before the position should be
* accurate enough (something around 6)
*/
public ActionWaitForAccuracy(Activity context, float minAccuracy,
int maxPosUpdateCount) {
myActivity = context;
myMinAccuracy = minAccuracy;
myMaxPosUpdateCount = maxPosUpdateCount;
analyseInitLocation(GeoUtils.getCurrentLocation(context));
}
private void analyseInitLocation(Location l) {
if (l != null) {
myCurrentAccuracy = l.getAccuracy();
long passedTime = System.currentTimeMillis() - l.getTime();
Log.i(LOG_TAG, "Last known pos accuracy=" + myCurrentAccuracy);
Log.i(LOG_TAG, "Last known pos age=" + (passedTime / 1000f / 10f)
+ " minutes");
if (passedTime <= MAX_TIME_SINCE_LAST_UPDATE_IN_MS) {
onLocationChanged(l);
} else {
Log.i(LOG_TAG, "Last known pos age was to old to use it "
+ "as a current position, will now wait "
+ "for position signal");
myCurrentAccuracy = 1000; // 1000m
}
} else {
GeoUtils.enableLocationProvidersIfNeeded(myActivity);
}
}
@Override
public boolean onLocationChanged(Location l) {
Log.d(LOG_TAG, "Current signal accuracy=" + l.getAccuracy());
Log.d(LOG_TAG, "Minimum needed accuracy=" + myMinAccuracy);
Log.d(LOG_TAG, "Current pos update count=" + stepCounter);
Log.d(LOG_TAG, "Max pos updates=" + myMaxPosUpdateCount);
stepCounter++;
myCurrentAccuracy = l.getAccuracy();
updateUI();
if ((myCurrentAccuracy != 0 && myCurrentAccuracy <= myMinAccuracy)
|| (stepCounter >= myMaxPosUpdateCount)) {
callFirstTimeAccReachedIfNotYetCalled(l);
hideUI();
return false;
}
return true;
}
private void callFirstTimeAccReachedIfNotYetCalled(Location location) {
if (!firstTimeReached) {
firstTimeReached = true;
Log.d(LOG_TAG, "Required accuracy was reached!");
minAccuracyReachedFirstTime(location, this);
} else
Log.w(LOG_TAG, "callFirstTimeAccReachedIfNotYetCalled was "
+ "called more then one time! This action should "
+ "be removed once the accuracy was reached!");
}
/**
* @param location
* The {@link Location} object that was accurate enough
* @param a
* the {@link ActionWaitForAccuracy} object which can be used to
* remove it from the {@link EventListenerGroup} it was contained
* in (e.g. the {@link EventManager#onLocationChangedList})
*/
public abstract void minAccuracyReachedFirstTime(Location location,
ActionWaitForAccuracy a);
public View getView() {
viewContainer = View.inflate(myActivity,
R.layout.action_wait_for_accuracy_view, null);
accText = (TextView) viewContainer.findViewById(R.id.awfa_accText);
warningText = (Button) viewContainer.findViewById(R.id.awfa_warning);
warningText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (GeoUtils.enableGPS(myActivity)) {
warningText.setVisibility(View.GONE);
waitSomeSecondsAndThenRegisterForGPSEvents();
}
}
});
ImageView i = (ImageView) viewContainer.findViewById(R.id.awfa_image);
i.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showSkipPositionDetectionDialog();
}
});
steps = (ProgressBar) viewContainer.findViewById(R.id.awfa_steps);
showDebugInfosAboutTheUiElements();
updateUI();
return viewContainer;
}
private void waitSomeSecondsAndThenRegisterForGPSEvents() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
EventManager.getInstance().registerLocationUpdates();
onGPSActivatedEvent();
}
}).start();
}
/**
* Override this if you need additional custom behavior as soon as the user
* activates GPS
*/
public void onGPSActivatedEvent() {
// on default do nothing
}
private void showDebugInfosAboutTheUiElements() {
Log.d(LOG_TAG, "viewContainer=" + viewContainer);
Log.d(LOG_TAG, " > accText=" + accText);
Log.d(LOG_TAG, " > warningText=" + warningText);
Log.d(LOG_TAG, " > steps=" + steps);
Log.d(LOG_TAG, " > stepCounter=" + stepCounter);
}
private void showSkipPositionDetectionDialog() {
final Dialog dialog = new Dialog(myActivity);
Button b = new Button(myActivity);
b.setText(TEXT_SKIP_ACCURACY_DETECTION);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d(LOG_TAG, "Trying to skip accuracy detection");
callFirstTimeAccReachedIfNotYetCalled(GeoUtils
.getCurrentLocation(myActivity));
hideUI();
dialog.dismiss();
}
});
dialog.setContentView(b);
dialog.setTitle(TEXT_DIALOG_TITLE);
dialog.setCanceledOnTouchOutside(true);
dialog.show();
}
private void updateUI() {
if (accText != null && steps != null && warningText != null)
myActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
accText.setText(TEXT_POSITION_ACCURACY
+ (int) (myMinAccuracy / myCurrentAccuracy * 100)
+ "%");
steps.setMax(myMaxPosUpdateCount);
steps.setProgress(stepCounter);
showWarningIfGPSOff();
}
});
}
private void hideUI() {
if (viewContainer != null)
myActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(LOG_TAG, "Setting view container to invisible");
viewContainer.setVisibility(View.GONE);
}
});
}
private void showWarningIfGPSOff() {
if (GeoUtils.isGPSDisabled(myActivity)) {
Log.d(LOG_TAG, "GPS disabled!");
warningText.setVisibility(View.VISIBLE);
warningText.setText("Enable GPS");
} else {
Log.d(LOG_TAG, "GPS enabled!");
warningText.setVisibility(View.GONE);
}
}
}