Java tutorial
/* * Copyright 2015 Google Inc. All Rights Reserved. * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 com.melkir.ourstreets.fragment; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.transition.ChangeBounds; import android.transition.Fade; import android.transition.Transition; import android.transition.TransitionInflater; import android.transition.TransitionManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.MapView; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.maps.android.clustering.ClusterManager; import com.melkir.ourstreets.R; import com.melkir.ourstreets.data.DataView; import com.melkir.ourstreets.data.DetailPresenter; import com.melkir.ourstreets.data.IntentKeys; import com.melkir.ourstreets.map.DetailClusterManager; import com.melkir.ourstreets.map.OnCameraPositionUpdateListener; import com.melkir.ourstreets.model.Detail; import com.melkir.ourstreets.model.Gallery; import com.melkir.ourstreets.view.ViewUtils; import java.util.List; /** * A {@link Fragment} that displays {@link Detail}s. * and a {@link com.google.android.gms.maps.MapView}. */ public class DetailFragment extends Fragment implements DataView<Detail> { public static final String TAG = "DetailFragment"; private MapView mMapView; private FloatingActionButton mFloatingActionButton; private Gallery mGallery; private CameraPosition mCameraPosition; private int mMapPadding; private OnCameraPositionUpdateListener mCameraListener; private ClusterManager.OnClusterItemClickListener<Detail> mOnClusterItemClickListener; private GoogleMap.OnMapClickListener mOnMapClickListener; private Detail mSelectedDetail; private Transition mDescriptionChange; /** * Create a new instance with details for a given {@link Gallery}. * * @param context The context this runs in. * @param gallery The gallery of which the details should be displayed. * @return A newly instantiated fragment. */ public static DetailFragment newInstance(@NonNull Context context, @NonNull Gallery gallery, @NonNull CameraPosition cameraPosition) { DetailFragment fragment = new DetailFragment(); Bundle args = new Bundle(); args.putParcelable(IntentKeys.GALLERY, gallery); args.putParcelable(IntentKeys.CAMERA_POSITION, cameraPosition); fragment.setArguments(args); final TransitionInflater inflater = TransitionInflater.from(context); fragment.setSharedElementEnterTransition(inflater.inflateTransition(R.transition.detail_shared_enter)); fragment.setEnterTransition(new Fade()); return fragment; } public DetailFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mMapPadding = getResources().getDimensionPixelSize(R.dimen.padding_map); if (savedInstanceState != null) { mCameraPosition = savedInstanceState.getParcelable(IntentKeys.CAMERA_POSITION); mSelectedDetail = savedInstanceState.getParcelable(IntentKeys.DETAIL); } Bundle arguments; if ((arguments = getArguments()) != null) { mGallery = arguments.getParcelable(IntentKeys.GALLERY); if (mCameraPosition == null) { mCameraPosition = arguments.getParcelable(IntentKeys.CAMERA_POSITION); } } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewUtils.setStatusBarColor(getActivity(), R.color.status_bar_color); View contentView = inflater.inflate(R.layout.fragment_detail, container, false); mFloatingActionButton = (FloatingActionButton) contentView.findViewById(R.id.fab); mFloatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mSelectedDetail == null) { return; } showStreetViewFragment(mSelectedDetail); } }); if (mMapView == null) { mMapView = (MapView) contentView.findViewById(R.id.map_view); mMapView.onCreate(null); } return contentView; } @Override public void onViewCreated(final View view, Bundle savedInstanceState) { mDescriptionChange = new ChangeBounds(); mDescriptionChange.addListener(new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) { } @Override public void onTransitionEnd(Transition transition) { applyMapPadding(); } @Override public void onTransitionCancel(Transition transition) { } @Override public void onTransitionPause(Transition transition) { } @Override public void onTransitionResume(Transition transition) { } }); if (ViewUtils.isMainDisplayInLandscape(getContext())) { ViewUtils.applyTopWindowInsetsForView(view.findViewById(R.id.description_layout)); } loadDetails(); if (mSelectedDetail == null) { setDescriptionText(mGallery); } else { setDescriptionText(mSelectedDetail); } applyMapPadding(); } private void applyMapPadding() { if (mMapView == null) { return; } mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { View descriptionLayout = getView().findViewById(R.id.description_layout); googleMap.setPadding(0, 0, 0, descriptionLayout.getMeasuredHeight()); } }); } @Override public void onDestroyView() { mFloatingActionButton = null; super.onDestroyView(); } @Override public void onResume() { mMapView.onResume(); super.onResume(); } @Override public void onSaveInstanceState(final Bundle outState) { mMapView.onSaveInstanceState(outState); outState.putParcelable(IntentKeys.CAMERA_POSITION, mCameraPosition); outState.putParcelable(IntentKeys.DETAIL, mSelectedDetail); super.onSaveInstanceState(outState); } @Override public void onPause() { mMapView.onPause(); super.onPause(); } @Override public void onDestroy() { mMapView.onDestroy(); super.onDestroy(); } @Override public void onLowMemory() { mMapView.onLowMemory(); super.onLowMemory(); } @Override public void showData(List<Detail> data) { mGallery.replaceDetails(data); initMapAsync(); } @Override public void showError() { // TODO: implement failed view Log.i(TAG, "showError: Loading failed"); } /** * Enable updating of detail information. * * @param gallery The new gallery to display. * @param cameraPosition The initial camera position for the details. */ public void setNewDetailInformation(@NonNull Gallery gallery, @NonNull CameraPosition cameraPosition) { mGallery = gallery; mCameraPosition = cameraPosition; loadDetails(); } private void initMapAsync() { mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { initializeMap(googleMap); } }); } private void initializeMap(final GoogleMap googleMap) { googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition)); googleMap.setOnMapLoadedCallback(getOnMapLoadedCallback(googleMap)); setMarkers(googleMap); } private void setDescriptionText(@NonNull Gallery gallery) { setDescriptionText(gallery.getTitle(), gallery.getDescription()); mFloatingActionButton.hide(); } private void setDescriptionText(@NonNull Detail detail) { mSelectedDetail = detail; setDescriptionText(detail.getTitle(), detail.getDescription()); mFloatingActionButton.show(); } private void setDescriptionText(@NonNull String title, @NonNull String detail) { View view = getView(); if (view == null) { return; } TransitionManager.beginDelayedTransition(((ViewGroup) view), mDescriptionChange); ViewUtils.setTextOn(view, R.id.text_title, title); ViewUtils.setTextOn(view, R.id.text_detail, detail); } private void setMarkers(GoogleMap googleMap) { final List<Detail> locations = mGallery.getDetails(); ClusterManager<Detail> clusterManager = getClusterManager(googleMap); clusterManager.addItems(locations); googleMap.setOnCameraChangeListener(clusterManager); } @NonNull private DetailClusterManager getClusterManager(GoogleMap googleMap) { return new DetailClusterManager(getContext(), googleMap, getOnClusterItemClickListener(), getOnMapClickListener(), getOnCameraPositionUpdateListener()); } @NonNull private GoogleMap.OnMapClickListener getOnMapClickListener() { if (mOnMapClickListener == null) { mOnMapClickListener = new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { setDescriptionText(mGallery); } }; } return mOnMapClickListener; } @NonNull private ClusterManager.OnClusterItemClickListener<Detail> getOnClusterItemClickListener() { if (mOnClusterItemClickListener == null) { mOnClusterItemClickListener = new ClusterManager.OnClusterItemClickListener<Detail>() { @Override public boolean onClusterItemClick(Detail detail) { setDescriptionText(detail); return false; } }; } return mOnClusterItemClickListener; } private OnCameraPositionUpdateListener getOnCameraPositionUpdateListener() { if (mCameraListener == null) { mCameraListener = new OnCameraPositionUpdateListener() { @Override public void onCameraPositionUpdate(CameraPosition cameraPosition) { mCameraPosition = cameraPosition; } }; } return mCameraListener; } private void showStreetViewFragment(Detail detail) { StreetViewFragment streetViewFragment = getStreetViewFragment(detail); FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); /* The StreetViewFragment has to be added (not replaced) in order to get the transition animation right. */ transaction.add(android.R.id.content, streetViewFragment, StreetViewFragment.TAG) .addToBackStack(StreetViewFragment.TAG); transaction.commit(); } @NonNull private GoogleMap.OnMapLoadedCallback getOnMapLoadedCallback(final GoogleMap googleMap) { return new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { googleMap.getUiSettings().setMapToolbarEnabled(false); if (mGallery.hasDetails()) { googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(mGallery.getBounds(), mMapPadding)); } } }; } @NonNull private StreetViewFragment getStreetViewFragment(Detail detail) { FragmentManager supportFragmentManager = getActivity().getSupportFragmentManager(); StreetViewFragment streetViewFragment = (StreetViewFragment) supportFragmentManager .findFragmentByTag(StreetViewFragment.TAG); if (streetViewFragment == null) { streetViewFragment = StreetViewFragment.newInstance(detail, ViewUtils.getCenterForView(mFloatingActionButton), mFloatingActionButton.getWidth()); } else { streetViewFragment.setDetail(detail); } return streetViewFragment; } private void loadDetails() { if (mGallery == null) { Log.w(TAG, "loadDetails: can't load data for null gallery"); showError(); return; } else if (mGallery.hasDetails()) { initMapAsync(); return; } new DetailPresenter(this, mGallery.getGalleryId()).getData(); } }