Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Feature/kak/add geofencing#44 #73

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ dependencies {
def playServicesVersion = '15.0.1'
implementation "com.google.android.gms:play-services-location:$playServicesVersion"
implementation "com.google.android.gms:play-services-maps:$playServicesVersion"
// Android WorkManager
implementation "android.arch.work:work-runtime:1.0.0-alpha02"
// Carousel
implementation 'com.github.flibbertigibbet:carouselview:1.0.5'
// Badges
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- Listen for reboot to set up geofences again -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
android:name=".GoPhillyGoApp"
android:allowBackup="true"
Expand Down Expand Up @@ -93,6 +96,23 @@
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />

<!-- Set up geofences again after reboot or location provider changes -->
<receiver android:name=".tasks.AddGeofencesBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- FIXME: implicit system broadcast intent cannot start background thread
<action android:name="android.location.PROVIDERS_CHANGED" /> -->
</intent-filter>
</receiver>

<!-- Listen to geofence transitions. -->
<receiver android:name=".tasks.GeofenceTransitionBroadcastReceiver"
android:exported="false" android:enabled="true">
<intent-filter>
<action android:name="com.gophillygo.app.tasks.ACTION_GEOFENCE_TRANSITION" />
</intent-filter>
</receiver>
</application>

</manifest>
14 changes: 13 additions & 1 deletion app/src/main/java/com/gophillygo/app/GoPhillyGoApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@

import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.util.Log;

import com.gophillygo.app.di.AppInjector;

import javax.inject.Inject;

import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;
import dagger.android.HasBroadcastReceiverInjector;

/**
* Based on:
* https://github.com/googlesamples/android-architecture-components/blob/178fe541643adb122d2a8925cf61a21950a4611c/GithubBrowserSample/app/src/main/java/com/android/example/github/GithubApp.java
*/


public class GoPhillyGoApp extends Application implements HasActivityInjector {
public class GoPhillyGoApp extends Application implements HasActivityInjector, HasBroadcastReceiverInjector {

private static final String LOG_LABEL = "GPGApp";

@SuppressWarnings("WeakerAccess")
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

@SuppressWarnings("WeakerAccess")
@Inject
DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;

@Override
public void onCreate() {
super.onCreate();
Expand All @@ -38,4 +45,9 @@ public void onCreate() {
public DispatchingAndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}

@Override
public AndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
return broadcastReceiverInjector;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.gophillygo.app.activities;

import android.arch.persistence.room.util.StringUtil;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
Expand All @@ -19,19 +18,41 @@
import com.gophillygo.app.data.models.AttractionInfo;
import com.gophillygo.app.data.models.DestinationInfo;
import com.gophillygo.app.data.models.DestinationLocation;
import com.gophillygo.app.data.models.EventInfo;
import com.gophillygo.app.tasks.AddGeofencesBroadcastReceiver;
import com.gophillygo.app.tasks.RemoveGeofenceWorker;
import com.synnapps.carouselview.CarouselView;

abstract class AttractionDetailActivity extends AppCompatActivity {
protected static final int COLLAPSED_LINE_COUNT = 4;
protected static final int EXPANDED_MAX_LINES = 50;
private static final String LOG_LABEL = "AttractionDetail";
protected DestinationInfo destinationInfo;

protected DestinationInfo destinationInfo;
protected View.OnClickListener toggleClickListener;

protected abstract Class getMapActivity();
protected abstract int getAttractionId();

protected void addOrRemoveGeofence(AttractionInfo info, Boolean haveExistingGeofence, Boolean settingGeofence) {
if (settingGeofence) {
if (haveExistingGeofence) {
Log.d(LOG_LABEL, "No change to geofence");
return;
}
// add geofence
Log.d(LOG_LABEL, "Add attraction geofence");
if (info instanceof EventInfo) {
AddGeofencesBroadcastReceiver.addOneGeofence((EventInfo)info);
} else if (info instanceof DestinationInfo) {
AddGeofencesBroadcastReceiver.addOneGeofence(((DestinationInfo) info).getDestination());
}
} else if (haveExistingGeofence) {
Log.e(LOG_LABEL, "Removing attraction geofence");
RemoveGeofenceWorker.removeOneGeofence(info);
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand Down Expand Up @@ -74,7 +95,6 @@ public void goToMap(View view) {
public void goToDirections(View view) {
// pass parameters destination and destinationText to https://gophillygo.org/
Uri directionsUri = new Uri.Builder().scheme("https").authority("gophillygo.org")
// TODO: #9 send current user location as origin
.appendQueryParameter("origin", "")
.appendQueryParameter("originText", "")
.appendQueryParameter("destination", destinationInfo.getDestination().getLocation().toString())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gophillygo.app.activities;

import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
Expand All @@ -10,11 +11,16 @@
import android.util.Log;

import com.gophillygo.app.data.DestinationViewModel;
import com.gophillygo.app.data.models.AttractionInfo;
import com.gophillygo.app.data.models.Destination;
import com.gophillygo.app.data.models.DestinationInfo;
import com.gophillygo.app.data.models.DestinationLocation;
import com.gophillygo.app.data.models.EventInfo;
import com.gophillygo.app.data.networkresource.Status;
import com.gophillygo.app.di.GpgViewModelFactory;
import com.gophillygo.app.tasks.AddGeofenceWorker;
import com.gophillygo.app.tasks.AddGeofencesBroadcastReceiver;
import com.gophillygo.app.tasks.RemoveGeofenceWorker;
import com.gophillygo.app.utils.GpgLocationUtils;
import com.gophillygo.app.utils.UserUuidUtils;

Expand Down Expand Up @@ -57,6 +63,26 @@ public abstract class BaseAttractionActivity extends AppCompatActivity
@SuppressWarnings("WeakerAccess")
DestinationViewModel viewModel;

protected void addOrRemoveGeofence(AttractionInfo info, Boolean haveExistingGeofence, Boolean settingGeofence) {
if (settingGeofence) {
if (haveExistingGeofence) {
Log.d(LOG_LABEL, "No change to geofence");
return;
}
// add geofence
Log.d(LOG_LABEL, "Add attraction geofence");
if (info instanceof EventInfo) {
AddGeofencesBroadcastReceiver.addOneGeofence((EventInfo)info);
} else if (info instanceof DestinationInfo) {
AddGeofencesBroadcastReceiver.addOneGeofence(((DestinationInfo) info).getDestination());
}

} else if (haveExistingGeofence) {
Log.e(LOG_LABEL, "Removing attraction geofence");
RemoveGeofenceWorker.removeOneGeofence(info);
}
}


private void setDefaultLocation() {
Log.w(LOG_LABEL, "Using City Hall as default location");
Expand Down Expand Up @@ -215,12 +241,25 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
if (requestCode == GpgLocationUtils.PERMISSION_REQUEST_ID) {
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(LOG_LABEL, "Re-requesting location after getting permissions");
Log.d(LOG_LABEL, "Re-requesting location after getting fine location permissions");
fetchLastLocationOrUseDefault();
} else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
GpgLocationUtils.displayPermissionRequestRationale(getApplicationContext());
}
}
} else if (requestCode == GpgLocationUtils.LOCATION_SETTINGS_REQUEST_ID) {
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(LOG_LABEL, "Re-requesting location after getting location network permissions");
fetchLastLocationOrUseDefault();
Log.d(LOG_LABEL, "Attempting to register geofences from database again");
Intent intent = new Intent(getApplicationContext(), AddGeofencesBroadcastReceiver.class);
intent.setAction(AddGeofenceWorker.ACTION_GEOFENCE_TRANSITION);
sendBroadcast(intent);
} else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
Log.w(LOG_LABEL, "Location network permissions not updated; geofencing may not work");
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
import com.gophillygo.app.R;
import com.gophillygo.app.data.DestinationViewModel;
import com.gophillygo.app.data.EventViewModel;
import com.gophillygo.app.data.models.AttractionFlag;
import com.gophillygo.app.data.models.DestinationInfo;
import com.gophillygo.app.data.models.Event;
import com.gophillygo.app.data.models.EventInfo;
import com.gophillygo.app.databinding.ActivityEventDetailBinding;
import com.gophillygo.app.di.GpgViewModelFactory;
import com.gophillygo.app.tasks.AddGeofencesBroadcastReceiver;
import com.gophillygo.app.tasks.RemoveGeofenceWorker;
import com.gophillygo.app.utils.FlagMenuUtils;
import com.gophillygo.app.utils.UserUuidUtils;
import com.synnapps.carouselview.CarouselView;
Expand Down Expand Up @@ -92,7 +95,7 @@ protected void onCreate(Bundle savedInstanceState) {
viewModel = ViewModelProviders.of(this, viewModelFactory).get(EventViewModel.class);
destinationViewModel = ViewModelProviders.of(this, viewModelFactory).get(DestinationViewModel.class);
viewModel.getEvent(eventId).observe(this, eventInfo -> {
// TODO: handle if event not found (go to list of events?)
// TODO: #61 handle if event not found (go to list of events?)
if (eventInfo == null || eventInfo.getEvent() == null) {
Log.e(LOG_LABEL, "No matching event found for ID " + eventId);
return;
Expand Down Expand Up @@ -185,9 +188,13 @@ private void displayEvent() {
Log.d(LOG_LABEL, "Clicked flags button");
PopupMenu menu = FlagMenuUtils.getFlagPopupMenu(this, flagOptionsCard, eventInfo.getFlag());
menu.setOnMenuItemClickListener(item -> {
Boolean haveExistingGeofence = eventInfo.getFlag().getOption()
.api_name.equals(AttractionFlag.Option.WantToGo.api_name);

eventInfo.updateAttractionFlag(item.getItemId());
viewModel.updateAttractionFlag(eventInfo.getFlag(), userUuid, getString(R.string.user_flag_post_api_key));

Boolean settingGeofence = destinationInfo.getFlag().getOption().api_name.equals(AttractionFlag.Option.WantToGo.api_name);
addOrRemoveGeofence(destinationInfo, haveExistingGeofence, settingGeofence);
return true;
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
import com.gophillygo.app.R;
import com.gophillygo.app.adapters.EventsListAdapter;
import com.gophillygo.app.data.EventViewModel;
import com.gophillygo.app.data.models.AttractionFlag;
import com.gophillygo.app.data.models.AttractionInfo;
import com.gophillygo.app.data.models.EventInfo;
import com.gophillygo.app.data.networkresource.Resource;
import com.gophillygo.app.data.networkresource.Status;
import com.gophillygo.app.databinding.ActivityEventsListBinding;
import com.gophillygo.app.databinding.FilterButtonBarBinding;
import com.gophillygo.app.di.GpgViewModelFactory;
import com.gophillygo.app.tasks.AddGeofencesBroadcastReceiver;
import com.gophillygo.app.tasks.RemoveGeofenceWorker;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -65,9 +68,22 @@ public void clickedAttraction(int position) {
}

public boolean clickedFlagOption(MenuItem item, AttractionInfo eventInfo, Integer position) {
Boolean haveExistingGeofence = eventInfo.getFlag()
.getOption().api_name.equals(AttractionFlag.Option.WantToGo.api_name);

eventInfo.updateAttractionFlag(item.getItemId());
viewModel.updateAttractionFlag(eventInfo.getFlag(), userUuid, getString(R.string.user_flag_post_api_key));
adapter.notifyItemChanged(position);

// do not attempt to add a geofence for an event with no location
if (((EventInfo)eventInfo).hasDestinationName()) {
Boolean settingGeofence = eventInfo.getFlag().getOption().api_name.equals(AttractionFlag.Option.WantToGo.api_name);
addOrRemoveGeofence(eventInfo, haveExistingGeofence, settingGeofence);
} else {
// TODO: notify user?
Log.w(LOG_LABEL, "Cannot add geofence for an event without an associated destination");
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
import com.gophillygo.app.CarouselViewListener;
import com.gophillygo.app.R;
import com.gophillygo.app.adapters.PlaceCategoryGridAdapter;
import com.gophillygo.app.data.models.AttractionFlag;
import com.gophillygo.app.data.models.Destination;
import com.synnapps.carouselview.CarouselView;

import java.util.List;


public class HomeActivity extends BaseAttractionActivity {

Expand Down Expand Up @@ -45,6 +48,7 @@ protected void onCreate(Bundle savedInstanceState) {

// initialize carousel if destinations already loaded
locationOrDestinationsChanged();

}

@Override
Expand Down
Loading