diff --git a/frontend/Movie_Pigeon/app/src/main/AndroidManifest.xml b/frontend/Movie_Pigeon/app/src/main/AndroidManifest.xml index 570fc94..09ebda1 100644 --- a/frontend/Movie_Pigeon/app/src/main/AndroidManifest.xml +++ b/frontend/Movie_Pigeon/app/src/main/AndroidManifest.xml @@ -5,6 +5,8 @@ + + + \ No newline at end of file diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java index 4db4277..105279d 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java @@ -1,12 +1,21 @@ package org.example.team_pigeon.movie_pigeon; +import android.Manifest; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.graphics.Color; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.location.LocationProvider; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; +import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.util.AttributeSet; import android.util.Log; @@ -52,7 +61,7 @@ import okhttp3.Request; import okhttp3.Response; -public class CinemaFragment extends Fragment implements AdapterView.OnItemSelectedListener,AdapterView.OnItemClickListener{ +public class CinemaFragment extends Fragment implements AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener { private static final String TAG = "CinemaFragment"; private static final String PROVIDER_GV = "gv"; private static final String PROVIDER_SB = "sb"; @@ -86,12 +95,14 @@ public class CinemaFragment extends Fragment implements AdapterView.OnItemSelect private TimeUtil timeUtil = new TimeUtil(); private GlobalReceiver receiver; private final int cinemasLoaded = 1; + private final int locationLoaded = 0; private TableLayout cinemaTable; private ScrollView sv; private LinearLayout ll; private CinemaListAdapter cinemaListAdapter; private ListView cinemaList; - + private boolean isGpsEnabled = false; + Location userLocation; public CinemaFragment() { } @@ -118,23 +129,37 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, // cinemaTable = new TableLayout(getContext()); // cinemaTable.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.MATCH_PARENT)); // sv.addView(cinemaTable); - cinemaList = (ListView) view.findViewById(R.id.cinema_list); - if (!isCinemasLoaded) { // make sure cinemaTable is loaded - loadCinemaList(); + String permission = "android.permission.ACCESS_FINE_LOCATION"; + int res = getContext().checkCallingOrSelfPermission(permission); + isGpsEnabled = (res == PackageManager.PERMISSION_GRANTED); + if (!isGpsEnabled) { + ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); + Log.i(TAG, "onCreateView: asking for gps permission"); } + cinemaList = (ListView) view.findViewById(R.id.cinema_list); receiver = new GlobalReceiver(new Handler() { public void handleMessage(Message msg) { final int what = msg.what; - switch(what) { + switch (what) { case cinemasLoaded: Log.i(TAG, "Successfully loaded cinemas"); showCinemas(); break; + case locationLoaded: + Log.i(TAG, "Successfully loaded location"); + Bundle coordinates = msg.getData(); + userLocation = new Location("user"); + userLocation.setLatitude(coordinates.getDouble("lat")); + userLocation.setLongitude(coordinates.getDouble("lon")); + Log.i(TAG, "User location is " + userLocation); + loadCinemaList(); + break; } } }); IntentFilter filter = new IntentFilter(); filter.addAction("cinemasLoaded"); + filter.addAction("locationLoaded"); getContext().registerReceiver(receiver, filter); view.requestFocus(); return view; @@ -147,7 +172,7 @@ private void loadCinemaList() { } @Override - public void onResume(){ + public void onResume() { super.onResume(); } @@ -155,7 +180,9 @@ public void onResume(){ public void onPause() { super.onPause(); Log.i(TAG, "Cinema fragment paused"); - getContext().unregisterReceiver(receiver); + if (isGpsEnabled) { + getContext().unregisterReceiver(receiver); + } } private void showCinemas() { @@ -178,17 +205,17 @@ private void bindViews(View view) { movieListView.setOnItemClickListener(this); } - private ArrayList> getOneWeekMovieList (ArrayList movieList, List dateList) throws ParseException { + private ArrayList> getOneWeekMovieList(ArrayList movieList, List dateList) throws ParseException { ArrayList> oneWeekMovieList = new ArrayList<>(); - for(int i=0;i<7;i++){ + for (int i = 0; i < 7; i++) { oneWeekMovieList.add(new ArrayList()); } - for(int i = 0; i showTime = convertToShowTimeArray(date,movie.getSchedule()); - if(!showTime.isEmpty()){ + ArrayList showTime = convertToShowTimeArray(date, movie.getSchedule()); + if (!showTime.isEmpty()) { movie.setShowTimes(showTime); oneWeekMovieList.get(i).add(movie); } @@ -211,7 +238,7 @@ private ArrayList convertToShowTimeArray(Date date, ArrayList try { time = stringToDate.parse(timeString); } catch (ParseException e) { - Log.d(TAG,"Parsing schedule with a mistake. TimeString:"+timeString); + Log.d(TAG, "Parsing schedule with a mistake. TimeString:" + timeString); return null; } calendarTwo.setTime(time); @@ -225,55 +252,51 @@ private ArrayList convertToShowTimeArray(Date date, ArrayList @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { String cinemaId; - if(isCinemasLoaded) { + if (isCinemasLoaded) { switch (parent.getId()) { case R.id.spinner_cinema_brand: cinemaAdapter = getOutletSpinnerAdapter(position); - if(cinemaAdapter!=null) { + if (cinemaAdapter != null) { outletSpinner.setAdapter(cinemaAdapter); outletSpinner.setVisibility(View.VISIBLE); dateSpinner.setVisibility(View.INVISIBLE); - } - else{ + } else { outletSpinner.setVisibility(View.GONE); } dateSpinner.setVisibility(View.GONE); movieListView.setVisibility(View.GONE); break; case R.id.spinner_cinema_outlet: - if(position!=0) { + if (position != 0) { cinemaId = cinemaAdapter.getItem(position).getId(); nowShowingTask = new NowShowingTask(); nowShowingTask.execute(GET_MOVIES, cinemaId); - } - else { + } else { dateSpinner.setVisibility(View.GONE); } movieListView.setVisibility(View.GONE); break; case R.id.spinner_date: - if(position!=0) { - currentDay = position-1; - if(nowShowingListAdapter==null) { + if (position != 0) { + currentDay = position - 1; + if (nowShowingListAdapter == null) { //init adapter moviesOfTheDay.addAll(oneWeekMovieList.get(currentDay)); - if(moviesOfTheDay.isEmpty()){ + if (moviesOfTheDay.isEmpty()) { Toast.makeText(getActivity(), "Opps, there is no movie schedule on this day yet.", Toast.LENGTH_SHORT).show(); } nowShowingListAdapter = new NowShowingListAdapter(moviesOfTheDay, this.getActivity()); movieListView.setAdapter(nowShowingListAdapter); - } - else{ + } else { moviesOfTheDay.clear(); moviesOfTheDay.addAll(oneWeekMovieList.get(currentDay)); - if(moviesOfTheDay.isEmpty()){ + if (moviesOfTheDay.isEmpty()) { Toast.makeText(getActivity(), "Opps, there is no movie schedule on this day yet.", Toast.LENGTH_SHORT).show(); } nowShowingListAdapter.notifyDataSetChanged(); } movieListView.setVisibility(View.VISIBLE); - } - else { + } else { movieListView.setVisibility(View.GONE); } break; @@ -285,9 +308,9 @@ public void onItemSelected(AdapterView parent, View view, int position, long public void onItemClick(AdapterView parent, View view, int position, long id) { Intent displayActivityIntent = new Intent(getActivity(), DisplayActivity.class); Bundle arguments = new Bundle(); - arguments.putSerializable("movie",nowShowingListAdapter.getItem(position)); + arguments.putSerializable("movie", nowShowingListAdapter.getItem(position)); arguments.putString("type", "moviePage"); - arguments.putInt("position",position); + arguments.putInt("position", position); arguments.putString("title", nowShowingListAdapter.getItem(position).getTitle()); displayActivityIntent.putExtra("bundle", arguments); getActivity().startActivity(displayActivityIntent); @@ -311,24 +334,24 @@ public void onNothingSelected(AdapterView parent) { } @Subscribe - public void onAddMovieToMovieListEvent(AddMovieToMovieListEvent event){ - if(nowShowingListAdapter!=null) { + public void onAddMovieToMovieListEvent(AddMovieToMovieListEvent event) { + if (nowShowingListAdapter != null) { nowShowingListAdapter.addMovieItemToAdapter(event.movie, event.position); Log.i(TAG, "New movie is added to local list"); } } @Subscribe - public void onDeleteMovieFromMovieListEvent(DeleteMovieFromMovieListEvent event){ - if(nowShowingListAdapter!=null) { + public void onDeleteMovieFromMovieListEvent(DeleteMovieFromMovieListEvent event) { + if (nowShowingListAdapter != null) { nowShowingListAdapter.removeMovieItemToAdapter(event.position); Log.i(TAG, "A movie is removed from local list"); } } @Subscribe - public void onUpdateMovieListEvent(UpdateMovieListEvent event){ - if(nowShowingListAdapter!=null) { + public void onUpdateMovieListEvent(UpdateMovieListEvent event) { + if (nowShowingListAdapter != null) { nowShowingListAdapter.updateMovieItemToAdapter(event.movie, event.position); Log.i(TAG, "A movie is updated to local list at pos " + String.valueOf(event.position)); } @@ -347,7 +370,9 @@ private class NowShowingTask extends AsyncTask { private final int NO_RESULT = 3; private final int NO_INTERNET = 4; private String requestType, cinemaId; + private Location cinemaLocation; int status; + private UserInfoSingleton userInfoBulk = UserInfoSingleton.getInstance(); @Override protected Void doInBackground(String... params) { @@ -418,17 +443,18 @@ protected void getCinemas() { } else { status = SUCCESSFUL_CINEMALIST; for (Cinema cinema : cinemas) { -// switch (cinema.getProvider()) { -// case PROVIDER_CATHAY: -// cathayCinemas.add(cinema); -// break; -// case PROVIDER_GV: -// gvCinemas.add(cinema); -// break; -// case PROVIDER_SB: -// sbCinemas.add(cinema); -// break; -// } + if (userLocation != null) { + cinemaLocation = new Location(cinema.getName()); + cinemaLocation.setLatitude(Double.valueOf(cinema.getLatitude())); + cinemaLocation.setLongitude(Double.valueOf(cinema.getLongitude())); +// Log.e(TAG, "Lat and lon stored are " + Double.valueOf(cinema.getLatitude()) + " " + Double.valueOf(cinema.getLongitude())); +// Log.e(TAG, "User location is " + userLocation.getLatitude() + " " + userLocation.getLongitude()); + int distance = (int) userLocation.distanceTo(cinemaLocation); + Log.e(TAG, "getCinemas: distance is " + distance); + cinema.setDistance(distance); + } else { +// Log.e(TAG, "getCinemas: user location is null"); + } allCinemas.add(cinema); } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaListAdapter.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaListAdapter.java index b772f8f..6abb0f0 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaListAdapter.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaListAdapter.java @@ -48,7 +48,7 @@ public View getView(int position, View convertView, ViewGroup parent) { name.setText(cinema.getName()); TextView distance = (TextView) convertView.findViewById(R.id.cinema_distance); // TODO set distance - distance.setText("Distance"); + distance.setText(cinema.getDistance() + "m"); return convertView; } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GPSService.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GPSService.java new file mode 100644 index 0000000..d885b68 --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GPSService.java @@ -0,0 +1,102 @@ +package org.example.team_pigeon.movie_pigeon; + +import android.Manifest; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; + +/** + * Created by Guo Mingxuan on 23/3/2017. + */ + +public class GPSService extends Service { + // location update intervals are 10s and 50m + private static final int LOCATION_INTERVAL = 10000; + private static final float LOCATION_DISTANCE = 50; + private LocationManager mLocationManager; + private String TAG = "GPSService"; + + private class GPSListener implements LocationListener { + Location lastLocation; + + public GPSListener(String provider) { + Log.i(TAG, "Provider is " + provider); + lastLocation = new Location(provider); + } + + @Override + public void onLocationChanged(Location location) { + Log.i(TAG, "onLocationChanged: " + location); + lastLocation.set(location); +// userInfoBulk.setUserLocation(lastLocation); + Intent intent = new Intent("locationLoaded"); + Bundle bundle = new Bundle(); + bundle.putDouble("lat", lastLocation.getLatitude()); + bundle.putDouble("lon", lastLocation.getLongitude()); + intent.putExtras(bundle); + sendBroadcast(intent); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + Log.e(TAG, "onStatusChanged: " + provider); + } + + @Override + public void onProviderEnabled(String provider) { + Log.i(TAG, "onProviderEnabled: " + provider); + } + + @Override + public void onProviderDisabled(String provider) { + Log.e(TAG, "onProviderDisabled: " + provider); + } + } + + GPSListener[] listeners = new GPSListener[]{ + new GPSListener(LocationManager.NETWORK_PROVIDER), new GPSListener(LocationManager.GPS_PROVIDER) + }; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + Log.i(TAG, "onCreate"); + // init location manager + if (mLocationManager == null) { + mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); + } + boolean isNetworkProviderWorking = true; + // network provider + try { + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE, listeners[0]); + } catch (java.lang.SecurityException e) { + Log.e(TAG, "failed to request location update from network provider"); + isNetworkProviderWorking = false; + } catch (IllegalArgumentException e) { + Log.d(TAG, "network provider does not exist, " + e.getMessage()); + isNetworkProviderWorking = false; + } + // gps provider only after trying for network provider + // as gps provider is more power consuming + if (!isNetworkProviderWorking) { + try { + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE, listeners[1]); + } catch (java.lang.SecurityException e) { + Log.i(TAG, "failed to request location update from gps provider"); + } catch (IllegalArgumentException e) { + Log.d(TAG, "gps provider does not exist " + e.getMessage()); + } + } + } +} diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GlobalReceiver.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GlobalReceiver.java index 620f889..6fb01c3 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GlobalReceiver.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/GlobalReceiver.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.os.Message; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -20,6 +21,7 @@ class GlobalReceiver extends BroadcastReceiver { private final static int VCodeSuccess = 0; private final static int ResetSuccess = 1; private final static int cinemasLoaded = 1; + private final static int locationLoaded = 0; private static UserInfoSingleton userInfoBulk = UserInfoSingleton.getInstance(); GlobalReceiver() { @@ -103,6 +105,15 @@ public void onReceive(Context context, Intent intent) { Log.i(TAG, "Received msg that cinemas loaded"); uiHandler.sendEmptyMessage(cinemasLoaded); break; + + case "locationLoaded": + Log.i(TAG, "Received msg that location loaded"); + bundle = intent.getExtras(); + Message msg = new Message(); + msg.setData(bundle); + msg.what = locationLoaded; + uiHandler.sendMessage(msg); + break; } } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/HomePageActivity.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/HomePageActivity.java index 1afc9d3..5dc3241 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/HomePageActivity.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/HomePageActivity.java @@ -1,6 +1,7 @@ package org.example.team_pigeon.movie_pigeon; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; @@ -41,6 +42,9 @@ public class HomePageActivity extends AppCompatActivity implements RadioGroup.On @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // start gps service + Intent intent = new Intent(this, GPSService.class); + startService(intent); //Disable Landscape Mode setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); initImageLoaderConfig(); diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Cinema.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Cinema.java index 2b4e155..bc9ad74 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Cinema.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Cinema.java @@ -18,6 +18,14 @@ public class Cinema implements Serializable{ private String name; @Expose private String provider; + @Expose + @SerializedName("location_x") + private String latitude; + @Expose + @SerializedName("location_y") + private String longitude; + + private int distance = 0; public String getProvider() { return provider; @@ -42,4 +50,28 @@ public String getId() { public void setId(String id) { this.id = id; } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public int getDistance() { + return distance; + } + + public void setDistance (int distance) { + this.distance = distance; + } }