Add LocationPickerActivity

pull/281/head
Alex Baker 11 years ago
parent 42f4587c01
commit 7222b3824e

@ -1,17 +1,27 @@
package org.tasks.dialogs;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import org.tasks.activities.LocationPickerActivity;
import org.tasks.location.OnLocationPickedHandler;
@SuppressWarnings("EmptyMethod")
public class LocationPickerDialog {
@SuppressWarnings({"EmptyMethod", "UnusedParameters"})
public class LocationPickerDialog extends DialogFragment {
public LocationPickerDialog(OnLocationPickedHandler onLocationPickedHandler) {
public LocationPickerDialog() {
}
public void show(FragmentManager childFragmentManager, String fragTagLocationPicker) {
}
public void setOnLocationPickedHandler(LocationPickerActivity locationPickerActivity) {
}
public void setOnCancelListener(LocationPickerActivity locationPickerActivity) {
}
}

@ -1,5 +1,7 @@
package org.tasks.dialogs;
import android.content.DialogInterface;
import android.content.IntentSender;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
@ -14,6 +16,8 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.PlaceBuffer;
@ -24,29 +28,31 @@ import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.injection.InjectingDialogFragment;
import org.tasks.location.Geofence;
import org.tasks.location.ManagedGoogleApi;
import org.tasks.location.GoogleApi;
import org.tasks.location.OnLocationPickedHandler;
import org.tasks.location.PlaceAutocompleteAdapter;
import javax.inject.Inject;
public class LocationPickerDialog extends InjectingDialogFragment {
public class LocationPickerDialog extends InjectingDialogFragment implements GoogleApiClient.OnConnectionFailedListener {
private static final Logger log = LoggerFactory.getLogger(LocationPickerDialog.class);
private static final int RC_RESOLVE_GPS_ISSUE = 10009;
private PlaceAutocompleteAdapter mAdapter;
@Inject ManagedGoogleApi managedGoogleApi;
@Inject FragmentActivity fragmentActivity;
@Inject GoogleApi googleApi;
private OnLocationPickedHandler onLocationPickedHandler;
private DialogInterface.OnCancelListener onCancelListener;
public LocationPickerDialog(OnLocationPickedHandler onLocationPickedHandler) {
public void setOnLocationPickedHandler(OnLocationPickedHandler onLocationPickedHandler) {
this.onLocationPickedHandler = onLocationPickedHandler;
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
managedGoogleApi.connect();
googleApi.connect(this);
View layout = inflater.inflate(R.layout.location_picker_dialog, null);
EditText addressEntry = (EditText) layout.findViewById(R.id.address_entry);
@ -63,7 +69,7 @@ public class LocationPickerDialog extends InjectingDialogFragment {
}
});
mAdapter = new PlaceAutocompleteAdapter(managedGoogleApi, fragmentActivity, android.R.layout.simple_list_item_1);
mAdapter = new PlaceAutocompleteAdapter(googleApi, fragmentActivity, android.R.layout.simple_list_item_1);
ListView list = (ListView) layout.findViewById(R.id.list);
list.setAdapter(mAdapter);
list.setOnItemClickListener(mAutocompleteClickListener);
@ -71,6 +77,13 @@ public class LocationPickerDialog extends InjectingDialogFragment {
return layout;
}
@Override
public void onDestroyView() {
super.onDestroyView();
googleApi.disconnect();
}
private void error(String text) {
log.error(text);
Toast.makeText(fragmentActivity, text, Toast.LENGTH_LONG).show();
@ -83,7 +96,7 @@ public class LocationPickerDialog extends InjectingDialogFragment {
final PlaceAutocompleteAdapter.PlaceAutocomplete item = mAdapter.getItem(position);
final String placeId = String.valueOf(item.placeId);
log.info("Autocomplete item selected: " + item.description);
managedGoogleApi.getPlaceDetails(placeId, mUpdatePlaceDetailsCallback);
googleApi.getPlaceDetails(placeId, mUpdatePlaceDetailsCallback);
}
};
@ -104,4 +117,33 @@ public class LocationPickerDialog extends InjectingDialogFragment {
places.release();
}
};
public void setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
this.onCancelListener = onCancelListener;
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (onCancelListener != null) {
onCancelListener.onCancel(dialog);
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(fragmentActivity, RC_RESOLVE_GPS_ISSUE);
} catch (IntentSender.SendIntentException e) {
log.error(e.getMessage(), e);
}
} else {
Toast.makeText(fragmentActivity, String.format("%s: %s\n%s",
fragmentActivity.getString(R.string.app_name),
fragmentActivity.getString(R.string.common_google_play_services_notification_ticker),
connectionResult.getErrorCode()), Toast.LENGTH_LONG).show();
}
}
}

@ -1,28 +1,34 @@
package org.tasks.location;
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.AutocompletePredictionBuffer;
import com.google.android.gms.location.places.PlaceBuffer;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.injection.ForApplication;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
public class GoogleApi implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
public class GoogleApi implements GoogleApiClient.ConnectionCallbacks {
private static final Logger log = LoggerFactory.getLogger(GoogleApi.class);
private GoogleApiClient.Builder builder;
private GoogleApiClient googleApiClient;
private GoogleApiClientConnectionHandler googleApiClientConnectionHandler;
private boolean enableAutoManage;
public interface GoogleApiClientConnectionHandler {
void onConnect(GoogleApiClient client);
@ -30,29 +36,70 @@ public class GoogleApi implements GoogleApiClient.OnConnectionFailedListener, Go
@Inject
public GoogleApi(@ForApplication Context context) {
builder = new GoogleApiClient.Builder(context, this, this)
builder = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.addConnectionCallbacks(this);
}
public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) {
this.googleApiClientConnectionHandler = googleApiClientConnectionHandler;
googleApiClient = builder.build();
if (!enableAutoManage) {
googleApiClient.connect();
public void getPlaceDetails(final String placeId, final ResultCallback<PlaceBuffer> callback) {
Places.GeoDataApi.getPlaceById(googleApiClient, placeId).setResultCallback(new ResultCallback<PlaceBuffer>() {
@Override
public void onResult(PlaceBuffer places) {
callback.onResult(places);
}
});
}
public void getAutocompletePredictions(final String constraint, final ResultCallback<AutocompletePredictionBuffer> callback) {
final LatLngBounds bounds = LatLngBounds.builder().include(getLastKnownLocation(googleApiClient)).build();
Places.GeoDataApi.getAutocompletePredictions(googleApiClient, constraint, bounds, null)
.setResultCallback(new ResultCallback<AutocompletePredictionBuffer>() {
@Override
public void onResult(AutocompletePredictionBuffer autocompletePredictions) {
callback.onResult(autocompletePredictions);
}
}, 15, TimeUnit.SECONDS);
}
private LatLng getLastKnownLocation(GoogleApiClient googleApiClient) {
try {
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
return new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
} catch (Exception e) {
log.error(e.getMessage(), e);
return new LatLng(0, 0);
}
}
protected GoogleApi enableAutoManage(FragmentActivity fragmentActivity, GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {
enableAutoManage = true;
builder.enableAutoManage(fragmentActivity, hashCode(), onConnectionFailedListener);
return this;
public void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler) {
connect(googleApiClientConnectionHandler, new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
log.error("onConnectionFailed({})", connectionResult);
}
});
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
log.error("onConnectionFailed({})", connectionResult);
public void connect(final GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {
connect(new GoogleApiClientConnectionHandler() {
@Override
public void onConnect(GoogleApiClient client) {
log.info("onConnect({})", client);
}
}, onConnectionFailedListener);
}
private void connect(final GoogleApiClientConnectionHandler googleApiClientConnectionHandler, GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {
this.googleApiClientConnectionHandler = googleApiClientConnectionHandler;
googleApiClient = builder
.addOnConnectionFailedListener(onConnectionFailedListener)
.build();
googleApiClient.connect();
}
public void disconnect() {
googleApiClient.disconnect();
}
@Override

@ -1,97 +0,0 @@
package org.tasks.location;
import android.content.IntentSender;
import android.location.Location;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.AutocompletePredictionBuffer;
import com.google.android.gms.location.places.PlaceBuffer;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.R;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
public class ManagedGoogleApi extends GoogleApi implements GoogleApi.GoogleApiClientConnectionHandler {
private static final int RC_RESOLVE_GPS_ISSUE = 10009;
private static final Logger log = LoggerFactory.getLogger(ManagedGoogleApi.class);
private FragmentActivity fragmentActivity;
private GoogleApiClient googleApiClient;
@Inject
public ManagedGoogleApi(FragmentActivity fragmentActivity) {
super(fragmentActivity);
this.fragmentActivity = fragmentActivity;
enableAutoManage(fragmentActivity, this);
}
public void connect() {
if (googleApiClient == null) {
super.connect(this);
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(fragmentActivity, RC_RESOLVE_GPS_ISSUE);
} catch (IntentSender.SendIntentException e) {
log.error(e.getMessage(), e);
}
} else {
Toast.makeText(fragmentActivity, String.format("%s: %s\n%s",
fragmentActivity.getString(R.string.app_name),
fragmentActivity.getString(R.string.common_google_play_services_notification_ticker),
connectionResult.getErrorCode()), Toast.LENGTH_LONG).show();
}
}
@Override
public void onConnect(GoogleApiClient googleApiClient) {
this.googleApiClient = googleApiClient;
}
public void getPlaceDetails(final String placeId, final ResultCallback<PlaceBuffer> callback) {
Places.GeoDataApi.getPlaceById(googleApiClient, placeId).setResultCallback(new ResultCallback<PlaceBuffer>() {
@Override
public void onResult(PlaceBuffer places) {
callback.onResult(places);
}
});
}
public void getAutocompletePredictions(final String constraint, final ResultCallback<AutocompletePredictionBuffer> callback) {
final LatLngBounds bounds = LatLngBounds.builder().include(getLastKnownLocation(googleApiClient)).build();
Places.GeoDataApi.getAutocompletePredictions(googleApiClient, constraint, bounds, null)
.setResultCallback(new ResultCallback<AutocompletePredictionBuffer>() {
@Override
public void onResult(AutocompletePredictionBuffer autocompletePredictions) {
callback.onResult(autocompletePredictions);
}
}, 15, TimeUnit.SECONDS);
}
private LatLng getLastKnownLocation(GoogleApiClient googleApiClient) {
try {
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
return new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
} catch (Exception e) {
log.error(e.getMessage(), e);
return new LatLng(0, 0);
}
}
}

@ -20,13 +20,13 @@ public class PlaceAutocompleteAdapter
extends ArrayAdapter<PlaceAutocompleteAdapter.PlaceAutocomplete> {
private static final Logger log = LoggerFactory.getLogger(PlaceAutocompleteAdapter.class);
private final ManagedGoogleApi managedGoogleApi;
private final GoogleApi googleApi;
private List<PlaceAutocomplete> mResultList = new ArrayList<>();
public PlaceAutocompleteAdapter(ManagedGoogleApi managedGoogleApi, Context context, int resource) {
public PlaceAutocompleteAdapter(GoogleApi googleApi, Context context, int resource) {
super(context, resource);
this.managedGoogleApi = managedGoogleApi;
this.googleApi = googleApi;
}
@Override
@ -40,7 +40,7 @@ public class PlaceAutocompleteAdapter
}
public void getAutocomplete(CharSequence constraint) {
managedGoogleApi.getAutocompletePredictions(constraint.toString(), onResults);
googleApi.getAutocompletePredictions(constraint.toString(), onResults);
}
private ResultCallback<AutocompletePredictionBuffer> onResults = new ResultCallback<AutocompletePredictionBuffer>() {

@ -111,6 +111,10 @@
android:name=".activities.DateAndTimePickerActivity"
android:theme="@style/Tasks.Dialog" />
<activity
android:name=".activities.LocationPickerActivity"
android:theme="@style/Tasks.Dialog" />
<!-- Activity that displays task list -->
<activity
android:name="com.todoroo.astrid.activity.TaskListActivity"

@ -79,7 +79,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.activities.DateAndTimePickerActivity;
import org.tasks.activities.LocationPickerActivity;
import org.tasks.injection.InjectingFragment;
import org.tasks.location.Geofence;
import org.tasks.location.GeofenceService;
import org.tasks.notifications.NotificationManager;
import org.tasks.preferences.ActivityPreferences;
@ -927,6 +929,13 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
} else {
log.error("Invalid timestamp");
}
} else if (requestCode == ReminderControlSet.REQUEST_LOCATION_REMINDER && resultCode == Activity.RESULT_OK) {
Geofence geofence = (Geofence) data.getSerializableExtra(LocationPickerActivity.EXTRA_GEOFENCE);
if (geofence != null) {
reminderControlSet.addGeolocationReminder(geofence);
} else {
log.error("Invalid geofence");
}
} else if (editNotes != null && editNotes.activityResult(requestCode, resultCode, data)) {
return;
} else if (requestCode == REQUEST_CODE_RECORD && resultCode == Activity.RESULT_OK) {

@ -30,10 +30,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.activities.DateAndTimePickerActivity;
import org.tasks.dialogs.LocationPickerDialog;
import org.tasks.activities.LocationPickerActivity;
import org.tasks.location.Geofence;
import org.tasks.location.GeofenceService;
import org.tasks.location.OnLocationPickedHandler;
import java.util.ArrayList;
import java.util.Date;
@ -52,9 +51,9 @@ import static org.tasks.date.DateTimeUtils.newDateTime;
public class ReminderControlSet extends TaskEditControlSetBase implements AdapterView.OnItemSelectedListener {
private static final Logger log = LoggerFactory.getLogger(ReminderControlSet.class);
private static final String FRAG_TAG_LOCATION_PICKER = "frag_tag_location_picker";
public static final int REQUEST_NEW_ALARM = 12152;
public static final int REQUEST_LOCATION_REMINDER = 12153;
private Spinner mode;
private Spinner addSpinner;
@ -373,12 +372,7 @@ public class ReminderControlSet extends TaskEditControlSetBase implements Adapte
} else if (selected.equals(taskEditFragment.getString(R.string.pick_a_date_and_time))) {
addNewAlarm();
} else if (selected.equals(taskEditFragment.getString(R.string.pick_a_location))) {
new LocationPickerDialog(new OnLocationPickedHandler() {
@Override
public void onLocationPicked(Geofence geofence) {
addGeolocationReminder(geofence);
}
}).show(taskEditFragment.getChildFragmentManager(), FRAG_TAG_LOCATION_PICKER);
taskEditFragment.startActivityForResult(new Intent(taskEditFragment.getActivity(), LocationPickerActivity.class), REQUEST_LOCATION_REMINDER);
}
if (position != 0) {
updateSpinner();

@ -0,0 +1,47 @@
package org.tasks.activities;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import org.tasks.dialogs.LocationPickerDialog;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.location.Geofence;
import org.tasks.location.OnLocationPickedHandler;
public class LocationPickerActivity extends InjectingAppCompatActivity implements OnLocationPickedHandler, DialogInterface.OnCancelListener {
private static final String FRAG_TAG_LOCATION_PICKER = "frag_tag_location_picker";
public static final String EXTRA_GEOFENCE = "extra_geofence";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager supportFragmentManager = getSupportFragmentManager();
LocationPickerDialog dialog = (LocationPickerDialog) supportFragmentManager.findFragmentByTag(FRAG_TAG_LOCATION_PICKER);
if (dialog == null) {
dialog = new LocationPickerDialog();
dialog.show(supportFragmentManager, FRAG_TAG_LOCATION_PICKER);
}
dialog.setOnCancelListener(this);
dialog.setOnLocationPickedHandler(this);
}
@Override
public void onLocationPicked(final Geofence geofence) {
setResult(RESULT_OK, new Intent() {{
putExtra(EXTRA_GEOFENCE, geofence);
}});
finish();
}
@Override
public void onCancel(DialogInterface dialog) {
setResult(RESULT_CANCELED);
finish();
}
}

@ -31,6 +31,7 @@ import org.tasks.activities.DeleteCompletedActivity;
import org.tasks.activities.DeleteCompletedEventsActivity;
import org.tasks.activities.ExportTaskActivity;
import org.tasks.activities.ImportTaskActivity;
import org.tasks.activities.LocationPickerActivity;
import org.tasks.activities.PurgeDeletedActivity;
import org.tasks.preferences.AppearancePreferences;
import org.tasks.preferences.BackupPreferences;
@ -80,7 +81,8 @@ import dagger.Provides;
ClearGtaskDataActivity.class,
ReminderPreferences.class,
AppearancePreferences.class,
BackupPreferences.class
BackupPreferences.class,
LocationPickerActivity.class
})
public class ActivityModule {

@ -2,7 +2,9 @@ package org.tasks.location;
import com.todoroo.astrid.data.Metadata;
public class Geofence {
import java.io.Serializable;
public class Geofence implements Serializable {
private final String name;
private final double latitude;
private final double longitude;

Loading…
Cancel
Save