Java tutorial
/** * Copyright 2015-present Amberfog * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fashiome.android.fragments; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; 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.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptor; 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 org.parceler.Parcels; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.BounceInterpolator; import android.widget.ListView; import java.util.ArrayList; import java.util.HashMap; import fashiome.android.R; import fashiome.android.activities.MapFullScreenActivity; import fashiome.android.v2.activities.ProductDetailsActivity; import fashiome.android.adapters.HeaderAdapter; import fashiome.android.helpers.ItemClickSupport; import fashiome.android.helpers.LockableRecyclerView; import fashiome.android.models.Item; import fashiome.android.models.Product; import fashiome.android.utils.AppStarter; import permissions.dispatcher.NeedsPermission; import permissions.dispatcher.PermissionUtils; import permissions.dispatcher.RuntimePermissions; import sothree.slidinguppanel.SlidingUpPanelLayout; @RuntimePermissions public class MapListFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, SlidingUpPanelLayout.PanelSlideListener, LocationListener, HeaderAdapter.ItemClickListener { private static final String ARG_LOCATION = "arg.location"; // private LockableListView mListView; private LockableRecyclerView mListView; private SlidingUpPanelLayout mSlidingUpPanelLayout; //data of items to be shown private ArrayList<Item> mItems; private HashMap<String, Item> mMarkers = new HashMap<String, Item>(); // ListView stuff //private View mTransparentHeaderView; //private View mSpaceView; private View mTransparentView; private View mWhiteSpaceView; private HeaderAdapter mHeaderAdapter; private LatLng mLocation; private Marker mLocationMarker; private SupportMapFragment mMapFragment; private GoogleMap mMap; private boolean mIsNeedLocationUpdate = true; private GoogleApiClient mGoogleApiClient; private LocationRequest mLocationRequest; public MapListFragment() { } public static MapListFragment newInstance(LatLng location) { MapListFragment f = new MapListFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_LOCATION, location); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); mListView = (LockableRecyclerView) rootView.findViewById(android.R.id.list); mListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER); mSlidingUpPanelLayout = (SlidingUpPanelLayout) rootView.findViewById(R.id.slidingLayout); mSlidingUpPanelLayout.setEnableDragViewTouchEvents(true); int mapHeight = getResources().getDimensionPixelSize(R.dimen.map_height); mSlidingUpPanelLayout.setPanelHeight(mapHeight); // you can use different height here mSlidingUpPanelLayout.setScrollableView(mListView, mapHeight); mSlidingUpPanelLayout.setPanelSlideListener(this); // transparent view at the top of ListView mTransparentView = rootView.findViewById(R.id.transparentView); mWhiteSpaceView = rootView.findViewById(R.id.whiteSpaceView); // init header view for ListView // mTransparentHeaderView = inflater.inflate(R.layout.transparent_header_view, mListView, false); // mSpaceView = mTransparentHeaderView.findViewById(R.id.space); collapseMap(); mSlidingUpPanelLayout.getViewTreeObserver() .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mSlidingUpPanelLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); mSlidingUpPanelLayout.onPanelDragged(0); } }); return rootView; } // @NeedsPermission({fashiome.android.Manifest.permission.ACCESS_FINE_LOCATION, fashiome.android.Manifest.permission.ACCESS_COARSE_LOCATION}) @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mLocation = getArguments().getParcelable(ARG_LOCATION); if (mLocation == null) { mLocation = getLastKnownLocation(false); } mMapFragment = SupportMapFragment.newInstance(); FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.mapContainer, mMapFragment, "map"); fragmentTransaction.commit(); mItems = new ArrayList<Item>(100); mItems.addAll(Item.loadItems()); // show white bg if there are not too many items // mWhiteSpaceView.setVisibility(View.VISIBLE); // ListView approach /*mListView.addHeaderView(mTransparentHeaderView); mListView.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.simple_list_item, testData)); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mSlidingUpPanelLayout.collapsePane(); } });*/ mHeaderAdapter = new HeaderAdapter(getActivity(), mItems, this); mListView.setItemAnimator(null); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); mListView.setLayoutManager(layoutManager); mListView.setAdapter(mHeaderAdapter); ItemClickSupport.addTo(mListView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { // do it //Item item = mItems.get(position); //moveToLocation(item.getPoint(), true); Intent i = new Intent(getActivity(), ProductDetailsActivity.class); startActivity(i); } }); mGoogleApiClient = new GoogleApiClient.Builder(getActivity()).addApi(LocationServices.API) .addConnectionCallbacks(this).addOnConnectionFailedListener(this).build(); setUpMapIfNeeded(); getMyLocation(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); listenerForActivity = (OnMarkerClickedListener_Activity) activity; } @NeedsPermission({ fashiome.android.Manifest.permission.ACCESS_FINE_LOCATION, fashiome.android.Manifest.permission.ACCESS_COARSE_LOCATION }) void getMyLocation() { if (mMap != null) { // Now that map has loaded, let's get our location! try { mMap.setMyLocationEnabled(true); } catch (SecurityException e) { e.printStackTrace(); } mGoogleApiClient = new GoogleApiClient.Builder(getActivity()).addApi(LocationServices.API) .addConnectionCallbacks(this).addOnConnectionFailedListener(this).build(); connectClient(); } } protected void connectClient() { // Connect the client. if (isGooglePlayServicesAvailable() && mGoogleApiClient != null) { mGoogleApiClient.connect(); } } private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; private boolean isGooglePlayServicesAvailable() { // Check that Google Play services is available int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()); // If Google Play services is available if (ConnectionResult.SUCCESS == resultCode) { // In debug mode, log the status Log.d("Location Updates", "Google Play services is available."); return true; } else { // Get the error dialog from Google Play services Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(), CONNECTION_FAILURE_RESOLUTION_REQUEST); // If Google Play services can provide an error dialog if (errorDialog != null) { // Create a new DialogFragment for the error dialog MapFullScreenActivity.ErrorDialogFragment errorFragment = new MapFullScreenActivity.ErrorDialogFragment(); errorFragment.setDialog(errorDialog); errorFragment.show(getActivity().getSupportFragmentManager(), "Location Updates"); } return false; } } public interface OnMarkerClickedListener_Activity { void OnClick(Item item); } OnMarkerClickedListener_Activity listenerForActivity; @NeedsPermission({ fashiome.android.Manifest.permission.ACCESS_FINE_LOCATION, fashiome.android.Manifest.permission.ACCESS_COARSE_LOCATION }) void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { // Try to obtain the map from the SupportMapFragment. mMap = mMapFragment.getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { try { mMap.setMyLocationEnabled(true); } catch (SecurityException e) { e.printStackTrace(); } mMap.getUiSettings().setCompassEnabled(false); mMap.getUiSettings().setZoomControlsEnabled(false); mMap.getUiSettings().setMyLocationButtonEnabled(true); LatLng update = getLastKnownLocation(); if (update != null) { mMap.moveCamera( CameraUpdateFactory.newCameraPosition(CameraPosition.fromLatLngZoom(update, 11.0f))); } mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { Intent i = new Intent(getActivity(), MapFullScreenActivity.class); i.putExtra("items", Parcels.wrap(mItems)); startActivity(i); } }); mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() { public boolean onMarkerClick(Marker marker) { // Handle marker click here //send first item for now //listenerForActivity.OnClick(mItems.get(0)); return true; } }); } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); MapListFragmentPermissionDispatcher.onRequestPermissionsResult(this, requestCode, grantResults); } private void dropPinEffect(final Marker marker) { // Handler allows us to repeat a code block after a specified delay final android.os.Handler handler = new android.os.Handler(); final long start = SystemClock.uptimeMillis(); final long duration = 1500; // Use the bounce interpolator final android.view.animation.Interpolator interpolator = new BounceInterpolator(); // Animate marker with a bounce updating its position every 15ms handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; // Calculate t for bounce based on elapsed time float t = Math.max(1 - interpolator.getInterpolation((float) elapsed / duration), 0); // Set the anchor marker.setAnchor(0.5f, 1.0f + 14 * t); if (t > 0.0) { // Post this event again 15ms from now. handler.postDelayed(this, 15); } else { // done elapsing, show window marker.showInfoWindow(); } } }); } public void loadMarkersFromItems(ArrayList<Item> items) { for (int i = 0; i < items.size(); i++) { Item item = items.get(i); BitmapDescriptor defaultMarker = BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_AZURE); Marker marker = mMap.addMarker(new MarkerOptions().position(item.getPoint()).title(item.getName()) .snippet(item.getName()).icon(defaultMarker)); mMarkers.put(marker.getId(), item); LatLng latLng = new LatLng(item.getPoint().latitude, item.getPoint().longitude); CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 12); mMap.animateCamera(cameraUpdate); dropPinEffect(marker); } } @Override public void onResume() { super.onResume(); // In case Google Play services has since become available. setUpMapIfNeeded(); } @Override public void onStart() { super.onStart(); // Connect the client. mGoogleApiClient.connect(); } @Override public void onStop() { // Disconnecting the client invalidates it. mGoogleApiClient.disconnect(); super.onStop(); } private LatLng getLastKnownLocation() { return getLastKnownLocation(true); } private LatLng getLastKnownLocation(boolean isMoveMarker) { LocationManager lm = (LocationManager) AppStarter.getAppContext() .getSystemService(Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_LOW); String provider = lm.getBestProvider(criteria, true); if (provider == null) { return null; } Activity activity = getActivity(); if (activity == null) { return null; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (activity.checkSelfPermission( Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && activity.checkSelfPermission( Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return null; } } Location loc = lm.getLastKnownLocation(provider); if (loc != null) { LatLng latLng = new LatLng(loc.getLatitude(), loc.getLongitude()); if (isMoveMarker) { moveMarker(latLng); } return latLng; } return null; } private void moveMarker(LatLng latLng) { if (mLocationMarker != null) { mLocationMarker.remove(); } mLocationMarker = mMap.addMarker(new MarkerOptions().position(latLng).anchor(0.5f, 0.5f)); //.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker_my_location)) } private void moveToLocation(Location location) { if (location == null) { return; } LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); moveToLocation(latLng); } private void moveToLocation(LatLng latLng) { moveToLocation(latLng, true); } private void moveToLocation(LatLng latLng, final boolean moveCamera) { if (latLng == null) { return; } moveMarker(latLng); mLocation = latLng; mListView.post(new Runnable() { @Override public void run() { if (mMap != null && moveCamera) { mMap.moveCamera( CameraUpdateFactory.newCameraPosition(CameraPosition.fromLatLngZoom(mLocation, 11.0f))); } } }); } private void collapseMap() { if (mHeaderAdapter != null) { mHeaderAdapter.showSpace(); } mTransparentView.setVisibility(View.GONE); if (mMap != null && mLocation != null) { mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mLocation, 11f), 1000, null); } mListView.setScrollingEnabled(true); } private void expandMap() { if (mHeaderAdapter != null) { mHeaderAdapter.hideSpace(); } mTransparentView.setVisibility(View.INVISIBLE); if (mMap != null) { mMap.animateCamera(CameraUpdateFactory.zoomTo(14f), 1000, null); } mListView.setScrollingEnabled(false); } @Override public void onPanelSlide(View view, float v) { } @Override public void onPanelCollapsed(View view) { expandMap(); } @Override public void onPanelExpanded(View view) { collapseMap(); } @Override public void onPanelAnchored(View view) { } @Override public void onLocationChanged(Location location) { if (mIsNeedLocationUpdate) { moveToLocation(location); } } @NeedsPermission({ fashiome.android.Manifest.permission.ACCESS_FINE_LOCATION, fashiome.android.Manifest.permission.ACCESS_COARSE_LOCATION }) @Override public void onConnected(Bundle bundle) { mLocationRequest = LocationRequest.create(); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setNumUpdates(1); try { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } catch (SecurityException e) { e.printStackTrace(); } } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } @Override public void onItemClicked(int position) { mSlidingUpPanelLayout.collapsePane(); } } final class MapListFragmentPermissionDispatcher { private static final int REQUEST_GETMYLOCATION = 0; private static final String[] PERMISSION_GETMYLOCATION = new String[] { "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION" }; private MapListFragmentPermissionDispatcher() { } static void getMyLocationWithCheck(MapListFragment target) { if (PermissionUtils.hasSelfPermissions(target.getActivity(), PERMISSION_GETMYLOCATION)) { target.getMyLocation(); } else { ActivityCompat.requestPermissions(target.getActivity(), PERMISSION_GETMYLOCATION, REQUEST_GETMYLOCATION); } } protected static void onRequestPermissionsResult(MapListFragment target, int requestCode, int[] grantResults) { switch (requestCode) { case REQUEST_GETMYLOCATION: if (PermissionUtils.getTargetSdkVersion(target.getActivity()) < 23 && !PermissionUtils.hasSelfPermissions(target.getActivity(), PERMISSION_GETMYLOCATION)) { return; } if (PermissionUtils.verifyPermissions(grantResults)) { target.getMyLocation(); } break; default: break; } } }