com.wheelly.fragments.LocationsMapFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.wheelly.fragments.LocationsMapFragment.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Denis Solonenko.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Denis Solonenko - initial API and implementation
 ******************************************************************************/
package com.wheelly.fragments;

import ru.orangesoftware.financisto.activity.LocationActivity;
import com.google.android.apps.mytracks.MapContextActionCallback;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
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.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.api.client.util.Strings;
import com.squareup.otto.Subscribe;
import com.squareup.otto.sample.BusProvider;
import com.wheelly.R;
import com.wheelly.bus.LocationSelectedEvent;
import com.wheelly.bus.LocationsLoadedEvent;
import com.wheelly.db.LocationBroker;
import com.wheelly.util.LocationUtils;
import com.wheelly.util.LocationUtils.AddressResolveCallback;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ContentValues;
import android.content.Intent;
import android.graphics.Color;
import android.location.Address;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.support.v4.view.MenuCompat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;

public class LocationsMapFragment extends SupportMapFragment {
    static final int NEW_LOCATION_REQUEST = 1;
    static final int EDIT_LOCATION_REQUEST = 2;

    private GoogleMap googleMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View layout = super.onCreateView(inflater, container, savedInstanceState);

        /*
         * At this point, after super.onCreateView, getMap will not return null
         * and we can initialize googleMap. However, onCreateView can be called
         * multiple times, e.g., when the user switches tabs. With
         * GoogleMapOptions.useViewLifecycleInFragment == false, googleMap
         * lifecycle is tied to the fragment lifecycle and the same googleMap
         * object is returned in getMap. Thus we only need to initialize
         * googleMap once, when it is null.
         */
        if (googleMap == null) {
            googleMap = getMap();
            googleMap.setMyLocationEnabled(true);

            googleMap.getUiSettings().setMyLocationButtonEnabled(true);
            googleMap.getUiSettings().setAllGesturesEnabled(true);
            googleMap.setIndoorEnabled(true);

            googleMap.setOnMarkerClickListener(new OnMarkerClickListener() {
                @Override
                public boolean onMarkerClick(Marker marker) {
                    final long id = Long.parseLong(marker.getSnippet());
                    BusProvider.getInstance().post(new LocationSelectedEvent(id, LocationsMapFragment.this));
                    return false;
                }
            });

            googleMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {

                @Override
                public void onInfoWindowClick(Marker marker) {
                    final long id = Long.parseLong(marker.getSnippet());
                    if (isResumed()) {
                        startActivityForResult(new Intent(getActivity(), LocationActivity.class) {
                            {
                                putExtra(LocationActivity.LOCATION_ID_EXTRA, id);
                            }
                        }, EDIT_LOCATION_REQUEST);
                    }
                }
            });
        }

        return layout;
    }

    private boolean inSelectMode;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        MenuCompat.setShowAsAction(
                menu.add(Menu.NONE, 1, Menu.NONE, R.string.item_add).setIcon(android.R.drawable.ic_menu_add),
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        BusProvider.getInstance().register(this);

        inSelectMode = getActivity().getIntent().hasExtra(LocationActivity.LOCATION_ID_EXTRA);

        // Getting Google Play availability status
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());

        // Showing status
        if (status != ConnectionResult.SUCCESS) { // Google Play Services are not available

            int requestCode = 10;
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, getActivity(), requestCode);
            dialog.show();

        } else { // Google Play Services are available

            // Getting GoogleMap object from the fragment
            googleMap = getMap();
        }

        ApiAdapterFactory.getApiAdapter().configureMapViewContextualMenu(this, new MapContextActionCallback() {
            private EditText editText;

            @Override
            public void onPrepare(Menu menu, Marker marker) {
                configureTitleWidget(marker);
            }

            @SuppressLint("NewApi")
            @Override
            public void onCreate(Menu menu) {
                editText = (EditText) menu.add(0, 0, 0, "name").setIcon(android.R.drawable.ic_menu_edit)
                        .setActionView(R.layout.location_edit).getActionView().findViewById(R.id.location_name);

                menu.add(0, 1, 0, R.string.item_add).setIcon(android.R.drawable.ic_menu_save);
            }

            private void configureTitleWidget(Marker marker) {
                if (null != marker && null != editText) {
                    try {
                        final long id = Long.parseLong(marker.getSnippet());
                        editText.setText(new LocationBroker(getActivity()).loadOrCreate(id).getAsString("name"));
                    } catch (NumberFormatException nfex) {
                        LocationUtils.resolveAddress(getActivity(), marker.getPosition(), "",
                                new AddressResolveCallback() {
                                    @Override
                                    public void onResolved(Address address) {
                                        if (getResources().getString(R.string.new_location)
                                                .equals(editText.getText().toString()) && null != address) {
                                            editText.setText(LocationUtils.formatAddress(address));
                                        }
                                    }
                                });
                    }
                }
            }

            @Override
            public boolean onClick(MenuItem item, Marker marker) {
                if (null != marker) {
                    final ContentValues myLocation = new ContentValues();

                    try {
                        final long id = Long.parseLong(marker.getSnippet());
                        myLocation.put(BaseColumns._ID, id);
                    } catch (NumberFormatException nfex) {
                        myLocation.put("provider", "fusion");
                    }

                    if (null != editText) {
                        myLocation.put("name", editText.getText().toString());
                    }

                    myLocation.put("latitude", marker.getPosition().latitude);
                    myLocation.put("longitude", marker.getPosition().longitude);
                    myLocation.put("datetime", System.currentTimeMillis());

                    LocationUtils.resolveAddress(getActivity(), marker.getPosition(),
                            myLocation.getAsString("name"), new AddressResolveCallback() {
                                @Override
                                public void onResolved(Address address) {
                                    if (null != address) {
                                        myLocation.put("resolved_address", LocationUtils.formatAddress(address));
                                    }

                                    new LocationBroker(getActivity()).updateOrInsert(myLocation);
                                }
                            });

                    return true;
                }
                return false;
            }
        });
    }

    private interface Aggregate {
        void seed(LatLng l, long id);

        CameraUpdate result();
    }

    private Aggregate buildCameraUpdateDelegate() {
        return !inSelectMode ? new Aggregate() {
            private final LatLngBounds.Builder b = LatLngBounds.builder();

            @Override
            public void seed(LatLng l, long id) {
                b.include(l);
            }

            @Override
            public CameraUpdate result() {
                return CameraUpdateFactory.newLatLngBounds(b.build(), 15);
            }
        } : new Aggregate() {
            private final long selectedId = getActivity().getIntent()
                    .getLongExtra(LocationActivity.LOCATION_ID_EXTRA, -1);
            private LatLng selected = null;

            @Override
            public void seed(LatLng l, long id) {
                if (id == selectedId) {
                    selected = l;
                }
            }

            @Override
            public CameraUpdate result() {
                return CameraUpdateFactory.newLatLngZoom(selected, 17);
            }
        };
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        BusProvider.getInstance().unregister(this);
    }

    @Subscribe
    public void onLoadFinished(LocationsLoadedEvent event) {
        googleMap.clear();

        if (null != event.cursor && event.cursor.moveToFirst()) {
            final int latIdx = event.cursor.getColumnIndex("latitude");
            final int lonIdx = event.cursor.getColumnIndex("longitude");
            final int nameIdx = event.cursor.getColumnIndex("name");
            final int idIdx = event.cursor.getColumnIndex(BaseColumns._ID);
            final int colorIdx = event.cursor.getColumnIndex("color");

            final Aggregate delegate = buildCameraUpdateDelegate();

            do {
                final LatLng l = new LatLng(event.cursor.getDouble(latIdx), event.cursor.getDouble(lonIdx));
                final long id = event.cursor.getLong(idIdx);
                final MarkerOptions markerOptions = new MarkerOptions().position(l)
                        .title(event.cursor.getString(nameIdx)).snippet(Long.toString(id)).draggable(true);

                final String argb = event.cursor.getString(colorIdx);

                if (!Strings.isNullOrEmpty(argb)) {
                    float[] hsv = new float[3];
                    Color.colorToHSV(Color.parseColor(argb), hsv);
                    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(hsv[0]));
                }

                // Adding marker on the Google Map
                googleMap.addMarker(markerOptions);
                delegate.seed(l, id);
            } while (event.cursor.moveToNext());

            //googleMap.animateCamera(delegate.result());
            googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {
                @Override
                public void onCameraChange(CameraPosition paramCameraPosition) {
                    googleMap.animateCamera(delegate.result());
                    googleMap.setOnCameraChangeListener(null);
                }
            });
        }
    }

    @Subscribe
    public void onSelectionChanged(final LocationSelectedEvent event) {
        if (this != event.sender) {
            final ContentValues c = new LocationBroker(getActivity()).loadOrCreate(event.id);
            final LatLng selected = new LatLng(c.getAsDouble("latitude"), c.getAsDouble("longitude"));
            googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(selected, 17));
        }
    }
}