/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.example.mapdemo;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
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 android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.FragmentActivity;
import java.util.Random;
/**
* This activity shows how to save the state of a MapFragment when the activity is recreated, like
* after rotation of the device.
*/
public class SaveStateDemoActivity extends FragmentActivity {
/** Default marker position when the activity is first created. */
private static final LatLng DEFAULT_MARKER_POSITION = new LatLng(48.858179, 2.294576);
/** List of hues to use for the marker */
private static final float[] MARKER_HUES = new float[]{
BitmapDescriptorFactory.HUE_RED,
BitmapDescriptorFactory.HUE_ORANGE,
BitmapDescriptorFactory.HUE_YELLOW,
BitmapDescriptorFactory.HUE_GREEN,
BitmapDescriptorFactory.HUE_CYAN,
BitmapDescriptorFactory.HUE_AZURE,
BitmapDescriptorFactory.HUE_BLUE,
BitmapDescriptorFactory.HUE_VIOLET,
BitmapDescriptorFactory.HUE_MAGENTA,
BitmapDescriptorFactory.HUE_ROSE,
};
// Bundle keys.
private static final String OTHER_OPTIONS = "options";
private static final String MARKER_POSITION = "markerPosition";
private static final String MARKER_INFO = "markerInfo";
/**
* Extra info about a marker.
*/
static class MarkerInfo implements Parcelable {
public static final Parcelable.Creator<MarkerInfo> CREATOR =
new Parcelable.Creator<MarkerInfo>() {
@Override
public MarkerInfo createFromParcel(Parcel in) {
return new MarkerInfo(in);
}
@Override
public MarkerInfo[] newArray(int size) {
return new MarkerInfo[size];
}
};
float mHue;
public MarkerInfo(float color) {
mHue = color;
}
private MarkerInfo(Parcel in) {
mHue = in.readFloat();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeFloat(mHue);
}
}
/**
* Example of a custom {@code MapFragment} showing how the position of a marker and other custom
* {@link Parcelable}s objects can be saved after rotation of the device.
* <p>
* Storing custom {@link Parcelable} objects directly in the {@link Bundle} provided by the
* {@link #onActivityCreated(Bundle)} method will throw a {@code ClassNotFoundException}. This
* is due to the fact that this Bundle is parceled (thus losing its ClassLoader attribute at
* this moment) and unparceled later in a different ClassLoader.
* <br>
* A workaround to store these objects is to wrap the custom {@link Parcelable} objects in a new
* {@link Bundle} object.
* <p>
* However, note that it is safe to store {@link Parcelable} objects from the Maps API (eg.
* MarkerOptions, LatLng, etc.) directly in the Bundle provided by the
* {@link #onActivityCreated(Bundle)} method.
*/
public static class SaveStateMapFragment extends SupportMapFragment
implements OnMarkerClickListener, OnMarkerDragListener {
private GoogleMap mMap;
private LatLng mMarkerPosition;
private MarkerInfo mMarkerInfo;
private boolean mMoveCameraToMarker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// Activity created for the first time.
mMarkerPosition = DEFAULT_MARKER_POSITION;
mMarkerInfo = new MarkerInfo(BitmapDescriptorFactory.HUE_RED);
mMoveCameraToMarker = true;
} else {
// Extract the state of the MapFragment:
// - Objects from the API (eg. LatLng, MarkerOptions, etc.) were stored directly in
// the savedInsanceState Bundle.
// - Custom Parcelable objects were wrapped in another Bundle.
mMarkerPosition = savedInstanceState.getParcelable(MARKER_POSITION);
Bundle bundle = savedInstanceState.getBundle(OTHER_OPTIONS);
mMarkerInfo = bundle.getParcelable(MARKER_INFO);
mMoveCameraToMarker = false;
}
setUpMapIfNeeded();
}
@Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// All Parcelable objects of the API (eg. LatLng, MarkerOptions, etc.) can be set
// directly in the given Bundle.
outState.putParcelable(MARKER_POSITION, mMarkerPosition);
// All other custom Parcelable objects must be wrapped in another Bundle. Indeed,
// failing to do so would throw a ClassNotFoundException. This is due to the fact that
// this Bundle is being parceled (losing its ClassLoader at this time) and unparceled
// later in a different ClassLoader.
Bundle bundle = new Bundle();
bundle.putParcelable(MARKER_INFO, mMarkerInfo);
outState.putBundle(OTHER_OPTIONS, bundle);
}
@Override
public boolean onMarkerClick(Marker marker) {
float newHue = MARKER_HUES[new Random().nextInt(MARKER_HUES.length)];
mMarkerInfo.mHue = newHue;
marker.setIcon(BitmapDescriptorFactory.defaultMarker(newHue));
return true;
}
private 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 = getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
MarkerOptions markerOptions = new MarkerOptions()
.position(mMarkerPosition)
.icon(BitmapDescriptorFactory.defaultMarker(mMarkerInfo.mHue))
.draggable(true);
mMap.addMarker(markerOptions);
mMap.setOnMarkerDragListener(this);
mMap.setOnMarkerClickListener(this);
if (mMoveCameraToMarker) {
mMap.animateCamera(CameraUpdateFactory.newLatLng(mMarkerPosition));
}
}
@Override
public void onMarkerDragStart(Marker marker) {}
@Override
public void onMarkerDrag(Marker marker) {}
@Override
public void onMarkerDragEnd(Marker marker) {
mMarkerPosition = marker.getPosition();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.save_state_demo);
}
}