com.parse.hangout.MapActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.parse.hangout.MapActivity.java

Source

/*
 * Copyright (c) 2015-present, Parse, LLC.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
package com.parse.hangout;

import android.Manifest;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.parse.DeleteCallback;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseGeoPoint;
import com.parse.ParseQuery;
import com.parse.ParseUser;
import com.parse.SaveCallback;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;

/**
 * Activity for the map screen
 */
public class MapActivity extends AppCompatActivity
        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
        LocationListener, OnMapReadyCallback, ResultCallback<LocationSettingsResult> {

    private GoogleApiClient mApiClient;
    private GoogleMap map;
    private LocationRequest mLocationRequest;
    private Location mLastLocation;
    private Location mCurrentLocation;
    private Marker marker;
    private final int LOCATION_REQUEST_INTERVAL = 500000;

    protected static final String TAG = "MapActivity";
    protected static final int REQUEST_CHECK_SETTINGS = 0x1;

    private final Map<String, Marker> mapMarkers = new HashMap<String, Marker>();
    private final Map<Marker, HangoutEvent> markerHangoutEventMap = new HashMap<Marker, HangoutEvent>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        mApiClient = new GoogleApiClient.Builder(this).addApi(LocationServices.API).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();

        try {
            new EventfulService().execute().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStart() {
        createLocationRequest();
        mApiClient.connect();
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // create our map if it already isn't created
        if (map == null) {
            MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);

            mapFragment.getMapAsync(this);
        }

        checkSelfPermission();
        LocationServices.FusedLocationApi.getLastLocation(mApiClient);

    }

    @Override
    protected void onPause() {
        super.onPause();
        LocationServices.FusedLocationApi.removeLocationUpdates(mApiClient, this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        mApiClient.disconnect();
    }

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(LOCATION_REQUEST_INTERVAL);
        mLocationRequest.setFastestInterval(LOCATION_REQUEST_INTERVAL);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    }

    protected void checkSelfPermission() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION }, 1);

        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.map_screen:
            startActivity(new Intent(this, MapActivity.class));
            return true;
        case R.id.list_screen:
            startActivity(new Intent(this, EventListActivity.class));
            return true;
        case R.id.post_screen:
            startActivity(new Intent(this, PostEventActivity.class));
            return true;
        case R.id.signout:
            AccountUtilities.signout();
            startActivity(new Intent(this, LoginActivity.class));
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(mLocationRequest);

        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi
                .checkLocationSettings(mApiClient, builder.build());

        result.setResultCallback(this);
        createLocationRequest();

        checkSelfPermission();
        LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient, mLocationRequest, this);
    }

    //the call back of location setting result
    @Override
    public void onResult(LocationSettingsResult locationSettingsResult) {
        final Status status = locationSettingsResult.getStatus();
        switch (status.getStatusCode()) {
        case LocationSettingsStatusCodes.SUCCESS:
            Log.i(TAG, "All location settings are satisfied.");
            break;
        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
            Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to "
                    + "upgrade location settings ");

            try {
                // Show the dialog by calling startResolutionForResult(), and check the result
                // in onActivityResult().
                status.startResolutionForResult(MapActivity.this, REQUEST_CHECK_SETTINGS);
            } catch (IntentSender.SendIntentException e) {
                Log.i(TAG, "PendingIntent unable to execute request.");
            }
            break;
        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
            Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " + "not created.");
            break;
        }
    }

    // the call back of status.startResolutionForResult
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case REQUEST_CHECK_SETTINGS:
            // the case for location change
            switch (resultCode) {
            case Activity.RESULT_OK:
                // All required changes were successfully made
                Log.i(TAG, "User agreed to make required location settings changes.");
                break;
            case Activity.RESULT_CANCELED:
                // The user was asked to change settings, but chose not to
                Log.i(TAG, "User chose not to make required location settings changes.");
                break;
            default:
                break;
            }
            break;
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, "Connection suspended");
        mApiClient.connect();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (mCurrentLocation != null) {
            mCurrentLocation = mLastLocation;
        }
        mCurrentLocation = location;

        //remove previous current location Marker
        if (marker != null) {
            marker.remove();
        }

        double dLatitude = mCurrentLocation.getLatitude();
        double dLongitude = mCurrentLocation.getLongitude();
        marker = map.addMarker(new MarkerOptions().position(new LatLng(dLatitude, dLongitude)).title("My Location")
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));

        // show the info window for your location and center camera around it
        marker.showInfoWindow();
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(dLatitude, dLongitude), 16.0f));

        // update our map when the user's location changes
        doMapQuery();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
    }

    /**
     * Sets up our map
     */
    @Override
    public void onMapReady(GoogleMap retMap) {

        map = retMap;

        setUpMap();

    }

    /**
     * Helper called by onMapReady callback
     */
    public void setUpMap() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION }, 1);
            //            return;
        }
        map.setMyLocationEnabled(true);

        map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
            public void onCameraChange(CameraPosition position) {
                doMapQuery();
            }
        });

        map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {

            // Use default InfoWindow frame
            @Override
            public View getInfoWindow(Marker arg0) {
                return null;
            }

            // Defines the contents of the InfoWindow
            @Override
            public View getInfoContents(Marker marker) {

                final ParseUser user = ParseUser.getCurrentUser();
                final HangoutEvent event = markerHangoutEventMap.get(marker);

                // Getting view from the layout file info_window_layout
                View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);

                TextView title = (TextView) v.findViewById(R.id.event_title);
                title.setText(marker.getTitle());

                final TextView membersAttending = (TextView) v.findViewById(R.id.members_attending);
                Button joinButton = (Button) v.findViewById(R.id.join_button);
                TextView startTimeEditText = (TextView) v.findViewById(R.id.start_time);
                TextView stopTimeEditText = (TextView) v.findViewById(R.id.stop_time);

                // remove irrelevant ui components on marker for the "my location" marker
                if (marker.getTitle().equals("My Location")) {
                    membersAttending.setVisibility(View.GONE);
                    joinButton.setVisibility(View.GONE);
                    startTimeEditText.setVisibility(View.GONE);
                    stopTimeEditText.setVisibility(View.GONE);
                    return v;
                }

                // add start and stop times
                Date startTime = event.getStartTime();
                Date stopTime = event.getStopTime();

                if (startTime != null) {
                    startTimeEditText.setText("Start Time: " + startTime.toString());
                } else if (startTime == null) {
                    startTimeEditText.setVisibility(View.GONE);
                }

                if (stopTime != null) {
                    stopTimeEditText.setText("Stop Time: " + stopTime.toString());
                } else if (stopTime == null) {
                    stopTimeEditText.setVisibility(View.GONE);
                }

                int numMembers = 0;
                boolean isUserAttending = false;

                ParseQuery<EventMembership> mapQuery = ParseQuery.getQuery(EventMembership.class);
                mapQuery.whereEqualTo("hangoutEvent", event);

                // see who is attending this event
                List<EventMembership> memberships = new ArrayList<EventMembership>();
                try {
                    memberships = mapQuery.find();
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                for (EventMembership membership : memberships) {
                    if (membership.getEventMember().getObjectId().equals(user.getObjectId())) {
                        isUserAttending = true;
                    }
                }
                numMembers = memberships.size();

                membersAttending.setText("Members attending: " + numMembers);

                if (isUserAttending == true) {
                    joinButton.setText("Unjoin");
                } else {
                    joinButton.setText("Join");
                }

                // Returning the view containing InfoWindow contents
                return v;

            }
        });

        // listener that handles joining/leaving an event on the map
        map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
            @Override
            public void onInfoWindowClick(final Marker marker) {

                View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);

                final ParseUser user = ParseUser.getCurrentUser();
                final HangoutEvent event = markerHangoutEventMap.get(marker);

                ParseQuery<EventMembership> mapQuery = ParseQuery.getQuery(EventMembership.class);
                mapQuery.whereEqualTo("hangoutEvent", event);
                mapQuery.whereEqualTo("member", user);
                mapQuery.include("hangoutEvent");
                mapQuery.findInBackground(new FindCallback<EventMembership>() {
                    @Override
                    public void done(List<EventMembership> objects, ParseException e) {
                        if (objects.size() == 0) {
                            EventMembership membership = new EventMembership();
                            membership.setEvent(event);
                            membership.setEventMember(user);
                            membership.saveInBackground(new SaveCallback() {
                                @Override
                                public void done(ParseException e) {
                                    if (e == null) {
                                        // once the EventMembership is saved,
                                        // refresh the info window to show this user is attending the event
                                        marker.showInfoWindow();
                                    }
                                }
                            });
                        }
                        // leave the event if the user has joined it
                        else if (objects.size() == 1) {
                            objects.get(0).deleteInBackground(new DeleteCallback() {
                                @Override
                                public void done(ParseException e) {
                                    if (e == null) {
                                        // refresh info window once deleted
                                        marker.showInfoWindow();
                                    }
                                }
                            });

                        }
                    }
                });
                //test sendNotification() method
                //sendNotification();
            }
        });
    }

    /**
     * Adds map markers for all of the events nearby the current user
     */
    private void doMapQuery() {
        Location myLoc = mCurrentLocation;
        if (myLoc == null) {
            cleanUpMarkers(new HashSet<String>());
            return;
        }

        final ParseGeoPoint myPoint = geoPointFromLocation(myLoc);
        ParseQuery<HangoutEvent> mapQuery = ParseQuery.getQuery(HangoutEvent.class);
        //        mapQuery.whereWithinKilometers("location", myPoint, 100);
        //        mapQuery.include("user");
        mapQuery.orderByDescending("createdAt");

        mapQuery.findInBackground(new FindCallback<HangoutEvent>() {
            @Override
            public void done(List<HangoutEvent> objects, ParseException e) {

                Set<String> toKeep = new HashSet<String>();

                for (HangoutEvent event : objects) {

                    toKeep.add(event.getObjectId());

                    Marker oldMarker = mapMarkers.get(event.getObjectId());

                    // if it already exists on the map, dont add another one
                    if (oldMarker != null) {
                        continue;
                    } else {

                        // add the marker to the map
                        MarkerOptions markerOpts = new MarkerOptions()
                                .position(new LatLng(event.getLocation().getLatitude(),
                                        event.getLocation().getLongitude()))
                                .title(event.getTitle())
                                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));

                        Marker marker = map.addMarker(markerOpts);
                        mapMarkers.put(event.getObjectId(), marker);
                        markerHangoutEventMap.put(marker, event);

                    }
                }

                cleanUpMarkers(toKeep);
            }
        });
    }

    /**
     * Helper method to convert a Location to ParseGeoPoint
     */
    private ParseGeoPoint geoPointFromLocation(Location loc) {
        return new ParseGeoPoint(loc.getLatitude(), loc.getLongitude());
    }

    /**
     * Method to remove old markers, and keeps the markers we provide
     */
    private void cleanUpMarkers(Set<String> markersToKeep) {
        for (String objId : new HashSet<String>(mapMarkers.keySet())) {
            if (!markersToKeep.contains(objId)) {
                Marker marker = mapMarkers.get(objId);
                marker.remove();
                mapMarkers.get(objId).remove();
                mapMarkers.remove(objId);
            }
        }
    }

    /**
     * Method to build a notification and send it to the creator of the event
     * if the creator exists in the database
     */
    private void sendNotification() {
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher).setContentTitle("Hangout Notification")
                .setContentText("A new member have added your event!");

        NotificationManager mNotificationManager = (NotificationManager) getSystemService(
                Context.NOTIFICATION_SERVICE);
        int notifyID = 1;
        int numMessage = 0;
        mBuilder.setNumber(++numMessage);
        // mId allows you to update the notification later on.
        mNotificationManager.notify(notifyID, mBuilder.build());
    }
}