[android] Setting up LocationPickerActivity infrastructure

Fixes #5282
This commit is contained in:
Brad Leege
2016-06-08 13:07:52 -05:00
committed by Ivo van Dongen
parent 11dd4afc5b
commit 2591147e25
15 changed files with 772 additions and 91 deletions

View File

@@ -90,13 +90,8 @@ dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
// Directions SDK
compile('com.mapbox.mapboxsdk:mapbox-android-directions:1.0.0@aar') {
transitive = true
}
// Geocoder SDK
compile('com.mapbox.mapboxsdk:mapbox-android-geocoder:1.0.0@aar') {
// Mapbox Android Services
compile('com.mapbox.mapboxsdk:mapbox-android-services:1.1.0@aar') {
transitive = true
}

View File

@@ -270,6 +270,14 @@
android:value="@string/category_annotation" />
</activity>
<activity android:name=".activity.navigation.LocationPickerActivity"
android:description="@string/description_location_picker"
android:label="@string/activity_location_picker">
<meta-data
android:name="@string/category"
android:value="@string/category_navigation" />
</activity>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"

View File

@@ -8,12 +8,6 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import com.mapbox.directions.DirectionsCriteria;
import com.mapbox.directions.MapboxDirections;
import com.mapbox.directions.service.models.DirectionsResponse;
import com.mapbox.directions.service.models.DirectionsRoute;
import com.mapbox.directions.service.models.Waypoint;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -23,12 +17,18 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.maps.MapView;
import java.util.List;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import com.mapbox.services.Constants;
import com.mapbox.services.commons.ServicesException;
import com.mapbox.services.commons.geojson.LineString;
import com.mapbox.services.commons.models.Position;
import com.mapbox.services.directions.v4.DirectionsCriteria;
import com.mapbox.services.directions.v4.MapboxDirections;
import com.mapbox.services.directions.v4.models.DirectionsResponse;
import com.mapbox.services.directions.v4.models.DirectionsRoute;
import com.mapbox.services.directions.v4.models.Waypoint;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class DirectionsActivity extends AppCompatActivity {
@@ -94,49 +94,55 @@ public class DirectionsActivity extends AppCompatActivity {
}
private void getRoute(Waypoint origin, Waypoint destination) {
MapboxDirections md = new MapboxDirections.Builder()
.setAccessToken(getString(R.string.mapbox_access_token))
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_WALKING)
.build();
try {
MapboxDirections md = new MapboxDirections.Builder()
.setAccessToken(getString(R.string.mapbox_access_token))
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_WALKING)
.build();
md.enqueue(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Response<DirectionsResponse> response, Retrofit retrofit) {
// You can get generic HTTP info about the response
Log.d(LOG_TAG, "Response code: " + response.code());
md.enqueueCall(new Callback<DirectionsResponse>() {
// Print some info about the route
DirectionsRoute currentRoute = response.body().getRoutes().get(0);
Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance());
@Override
public void onFailure(Call<DirectionsResponse> call, Throwable t) {
Log.e(LOG_TAG, "Error: " + t.getMessage());
}
// Draw the route on the map
drawRoute(currentRoute);
}
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get generic HTTP info about the response
Log.d(LOG_TAG, "Response code: " + response.code());
@Override
public void onFailure(Throwable t) {
Log.e(LOG_TAG, "Error: " + t.getMessage());
}
});
// Print some info about the route
DirectionsRoute currentRoute = response.body().getRoutes().get(0);
Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance());
// Draw the route on the map
drawRoute(currentRoute);
}
});
} catch (ServicesException e) {
Log.e(LOG_TAG, "Error displaying route: " + e.toString());
e.printStackTrace();
}
}
private void drawRoute(DirectionsRoute route) {
// Convert List<Waypoint> into LatLng[]
List<Waypoint> waypoints = route.getGeometry().getWaypoints();
LatLng[] point = new LatLng[waypoints.size()];
for (int i = 0; i < waypoints.size(); i++) {
point[i] = new LatLng(
waypoints.get(i).getLatitude(),
waypoints.get(i).getLongitude());
PolylineOptions builder = new PolylineOptions();
builder.color(Color.parseColor("#3887be"));
builder.alpha(0.5f);
builder.width(5);
builder.width(5);
LineString lineString = route.asLineString(Constants.OSRM_PRECISION_V4);
for (Position coordinates : lineString.getCoordinates()) {
builder.add(new LatLng(coordinates.getLatitude(), coordinates.getLongitude()));
}
// Draw Points on MapView
mMapboxMap.addPolyline(new PolylineOptions()
.add(point)
.color(Color.parseColor("#3887be"))
.width(5));
mMapboxMap.addPolyline(builder);
}
@Override

View File

@@ -14,11 +14,6 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.mapbox.geocoder.GeocoderCriteria;
import com.mapbox.geocoder.MapboxGeocoder;
import com.mapbox.geocoder.service.models.GeocoderFeature;
import com.mapbox.geocoder.service.models.GeocoderResponse;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -27,12 +22,19 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Projection;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.services.commons.ServicesException;
import com.mapbox.services.commons.models.Position;
import com.mapbox.services.geocoding.v5.GeocodingCriteria;
import com.mapbox.services.geocoding.v5.MapboxGeocoding;
import com.mapbox.services.geocoding.v5.models.GeocodingFeature;
import com.mapbox.services.geocoding.v5.models.GeocodingResponse;
import java.util.List;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class GeocoderActivity extends AppCompatActivity {
@@ -123,40 +125,38 @@ public class GeocoderActivity extends AppCompatActivity {
*/
private void geocode(final LatLng point) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
MapboxGeocoder client = new MapboxGeocoder.Builder()
.setAccessToken(getString(R.string.mapbox_access_token))
.setCoordinates(point.getLongitude(), point.getLatitude())
.setType(GeocoderCriteria.TYPE_POI)
.build();
try {
MapboxGeocoding client = new MapboxGeocoding.Builder()
.setAccessToken(getString(R.string.mapbox_access_token))
.setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
.setType(GeocodingCriteria.TYPE_POI)
.build();
client.enqueue(new Callback<GeocoderResponse>()
client.enqueueCall(new Callback<GeocodingResponse>() {
@Override
public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
{
@Override
public void onResponse(Response<GeocoderResponse> response, Retrofit retrofit) {
List<GeocoderFeature> results = response.body().getFeatures();
if (results.size() > 0) {
String placeName = results.get(0).getPlaceName();
setSuccess(placeName);
} else {
setMessage("No results.");
}
}
List<GeocodingFeature> results = response.body().getFeatures();
if (results.size() > 0) {
String placeName = results.get(0).getPlaceName();
setSuccess(placeName);
} else {
setMessage("No results.");
}
@Override
public void onFailure(Throwable t) {
setError(t.getMessage());
}
}
}
);
return null;
}
}.execute();
@Override
public void onFailure(Call<GeocodingResponse> call, Throwable t) {
setError(t.getMessage());
}
});
} catch (ServicesException e) {
Log.e(LOG_TAG, "Error geocoding: " + e.toString());
e.printStackTrace();
setError(e.getMessage());
}
}
/*

View File

@@ -0,0 +1,467 @@
package com.mapbox.mapboxsdk.testapp.activity.navigation;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.location.LocationListener;
import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerView;
import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerViewOptions;
import com.mapbox.services.commons.ServicesException;
import com.mapbox.services.commons.models.Position;
import com.mapbox.services.geocoding.v5.GeocodingCriteria;
import com.mapbox.services.geocoding.v5.MapboxGeocoding;
import com.mapbox.services.geocoding.v5.models.GeocodingFeature;
import com.mapbox.services.geocoding.v5.models.GeocodingResponse;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Sample Activity to show a typical location picker use case
*/
public class LocationPickerActivity extends AppCompatActivity {
private static final String TAG = "LocationPickerActivity";
private static final int REQUEST_PERMISSIONS = 101;
private MapView mapView;
private MapboxMap mapboxMap;
private ImageView dropPinView;
private Marker addressPin;
private ImageButton clearDisplayViewButton;
private MarkerView userMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_picker);
setupActionBar();
//Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
//Create ui elements
createDropPin();
createSelectLocationButton();
createClearSelectionButton();
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(MapboxMap map) {
//Store for later
mapboxMap = map;
//Add user marker
mapboxMap.getMarkerViewManager().addMarkerViewAdapter(new PulseMarkerViewAdapter(LocationPickerActivity.this));
userMarker = createCustomUserMarker(new LatLng(0, 0));
//Fix the focal point to the center of the map
PointF focalPoint = new PointF((mapView.getX() + mapView.getWidth() / 2), (mapView.getY() + mapView.getHeight() / 2));
mapboxMap.getUiSettings().setFocalPoint(focalPoint);
//Track camera updates to animate the user location views
trackUserLocationView(userMarker);
}
});
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
//Check permissions
if (arePermissionsGranted()) {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(final MapboxMap mapboxMap) {
//Get the user's location
final LocationServices locationServices = LocationServices.getLocationServices(getApplicationContext());
Location location = locationServices.getLastLocation();
if (location != null) {
zoomInOn(location);
userMarker.setPosition(new LatLng(location));
} else {
final ProgressDialog loadingDialog = ProgressDialog.show(LocationPickerActivity.this, "Loading", "Getting user location", false);
locationServices.addLocationListener(new LocationListener() {
@Override
public void onLocationChanged(@Nullable Location location) {
//Move the camera to the user
if (location != null) {
zoomInOn(location);
userMarker.setPosition(new LatLng(location));
locationServices.removeLocationListener(this);
loadingDialog.hide();
}
}
});
}
locationServices.toggleGPS(true);
}
});
}
}
private void zoomInOn(Location location) {
//Move the camera to the user
if (location != null) {
mapboxMap.setCameraPosition(new CameraPosition.Builder()
.target(new LatLng(location))
.zoom(16)
.bearing(0)
.tilt(0)
.build());
}
}
/**
* Tracks the camera to animate the marker when overlapping with the picker.
* Makes sure the marker actually points to the user's position by tracking it.
*/
private void trackUserLocationView(final MarkerView markerView) {
final float circleDiameterSize = getResources().getDimension(R.dimen.circle_size);
//Track camera changes to check for overlap
mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
private Animation pulseAnimation;
@Override
public void onCameraChange(CameraPosition position) {
if (markerView == null) {
return;
}
//Make drop pin visible, if it wasn't already
showDropPin();
//Get the distance from the tip of the location picker to the MarkerView
double distance = getLocationPickerLocation().distanceTo(markerView.getPosition());
//If closeby, animate, otherwise, stop animation
View view = mapboxMap.getMarkerViewManager().getView(markerView);
if (view != null) {
View backgroundView = view.findViewById(R.id.background_imageview);
if (pulseAnimation == null && distance < 0.5f * circleDiameterSize) {
pulseAnimation = AnimationUtils.loadAnimation(LocationPickerActivity.this, R.anim.pulse);
pulseAnimation.setRepeatCount(Animation.INFINITE);
pulseAnimation.setRepeatMode(Animation.RESTART);
backgroundView.startAnimation(pulseAnimation);
} else if (pulseAnimation != null && distance >= 0.5f * circleDiameterSize) {
backgroundView.clearAnimation();
pulseAnimation = null;
}
}
}
});
//Track location updates to move the user marker
LocationServices.getLocationServices(getApplicationContext()).addLocationListener(new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (location != null && markerView != null) {
markerView.setPosition(new LatLng(location));
}
}
});
}
private MarkerView createCustomUserMarker(LatLng markerPosition) {
return mapboxMap.addMarker(new PulseMarkerViewOptions()
.icon(IconFactory.getInstance(getApplicationContext()).fromResource(R.drawable.ic_my_location_24dp))
.position(markerPosition)
);
}
private void createClearSelectionButton() {
clearDisplayViewButton = (ImageButton) findViewById(R.id.clearDisplayViewButton);
clearDisplayViewButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeAddressPin();
hide(clearDisplayViewButton);
showDropPin();
}
});
}
private void createSelectLocationButton() {
Button selectLocationButton = (Button) findViewById(R.id.selectLocationButton);
//noinspection ConstantConditions
selectLocationButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "Location Selected!");
if (mapboxMap != null) {
//Control button's state
clearDisplayViewButton.setVisibility(View.VISIBLE);
dropPinView.setVisibility(View.INVISIBLE);
//Get position for the drop pin
LatLng position = getLocationPickerLocation();
//Show the address pin (result)
showAddressPin(position);
//Get the address for that location and update the marker
geocode(position, new GeocodeCallbacks() {
@Override
public void onResult(String result) {
updateAddressPin(result);
}
@Override
public void onFailure(Throwable failure) {
showFeedbackMessage("Could not retrieve address: " + failure.getMessage());
}
});
}
}
}
);
}
private void createDropPin() {
float density = getResources().getDisplayMetrics().density;
dropPinView = new ImageView(this);
dropPinView.setImageResource(R.drawable.ic_droppin_24dp);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
params.bottomMargin = (int) (12 * density);
dropPinView.setLayoutParams(params);
mapView.addView(dropPinView);
}
private void showDropPin() {
if (dropPinView != null && dropPinView.getVisibility() != View.VISIBLE) {
dropPinView.setVisibility(View.VISIBLE);
}
}
private void hide(View view) {
if (view != null) {
view.setVisibility(View.INVISIBLE);
}
}
private void setupActionBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
}
}
/**
* Get address for the given location
*/
private void geocode(LatLng point, final GeocodeCallbacks callbacks) {
try {
//Create Geocoding client
MapboxGeocoding client = new MapboxGeocoding.Builder()
.setAccessToken(getString(R.string.mapbox_access_token))
.setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
.setType(GeocodingCriteria.TYPE_ADDRESS)
.build();
//Place the request
client.enqueueCall(new Callback<GeocodingResponse>() {
@Override
public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
List<GeocodingFeature> results = response.body().getFeatures();
String address = null;
if (results.size() > 0) {
GeocodingFeature feature = results.get(0);
address = feature.getAddress() + " " + feature.getText();
Log.i(TAG, "address " + address);
} else {
showFeedbackMessage("No results for search.");
}
callbacks.onResult(address);
}
@Override
public void onFailure(Call<GeocodingResponse> call, Throwable t) {
Log.e(TAG, "Geocoding Failure: " + t.getMessage());
callbacks.onFailure(t);
}
});
} catch (ServicesException e) {
Log.e(TAG, "Error geocoding: " + e.toString());
callbacks.onFailure(e);
}
}
private LatLng getLocationPickerLocation() {
return mapboxMap.getProjection().fromScreenLocation(
new PointF(dropPinView.getLeft() + (dropPinView.getWidth() / 2), dropPinView.getBottom())
);
}
private Marker showAddressPin(LatLng position) {
if (addressPin != null) {
//Remove previous pin
removeAddressPin();
}
//Create new one
addressPin = mapboxMap.addMarker(new MarkerViewOptions().title("Loading address...").position(position));
mapboxMap.selectMarker(addressPin);
return addressPin;
}
private void removeAddressPin() {
if (mapboxMap != null && addressPin != null) {
mapboxMap.removeMarker(addressPin);
}
}
private void updateAddressPin(@Nullable String address) {
if (addressPin != null) {
addressPin.setTitle(address == null ? "No address found" : address);
}
}
private void showFeedbackMessage(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
private boolean arePermissionsGranted() {
if (Build.VERSION.SDK_INT >= 23 &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Requesting permissions");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS);
return false;
}
Log.i(TAG, "Permissions already granted");
return true;
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Custom MarkerViewAdapter for the pulsing marker
*/
private static class PulseMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<PulseMarkerView> {
private LayoutInflater inflater;
public PulseMarkerViewAdapter(@NonNull Context context) {
super(context);
this.inflater = LayoutInflater.from(context);
}
@Nullable
@Override
public View getView(@NonNull PulseMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.view_pulse_marker, parent, false);
viewHolder.foregroundImageView = (ImageView) convertView.findViewById(R.id.foreground_imageView);
viewHolder.backgroundImageView = (ImageView) convertView.findViewById(R.id.background_imageview);
convertView.setTag(viewHolder);
}
return convertView;
}
private static class ViewHolder {
ImageView foregroundImageView;
ImageView backgroundImageView;
}
}
private interface GeocodeCallbacks {
void onResult(String result);
void onFailure(Throwable failure);
}
}

View File

@@ -0,0 +1,11 @@
package com.mapbox.mapboxsdk.testapp.model.annotations;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.MarkerView;
public class PulseMarkerView extends MarkerView {
public PulseMarkerView(BaseMarkerViewOptions baseMarkerViewOptions) {
super(baseMarkerViewOptions);
}
}

View File

@@ -0,0 +1,79 @@
package com.mapbox.mapboxsdk.testapp.model.annotations;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
public class PulseMarkerViewOptions extends BaseMarkerViewOptions<PulseMarkerView, PulseMarkerViewOptions> {
public PulseMarkerViewOptions() {
}
protected PulseMarkerViewOptions(Parcel in) {
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
snippet(in.readString());
title(in.readString());
flat(in.readByte() != 0);
anchor(in.readFloat(), in.readFloat());
selected = in.readByte() != 0;
rotation(in.readFloat());
if (in.readByte() != 0) {
// this means we have an icon
String iconId = in.readString();
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
Icon icon = IconFactory.recreate(iconId, iconBitmap);
icon(icon);
}
}
@Override
public PulseMarkerViewOptions getThis() {
return this;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(getPosition(), flags);
out.writeString(getSnippet());
out.writeString(getTitle());
out.writeByte((byte) (isFlat() ? 1 : 0));
out.writeFloat(getAnchorU());
out.writeFloat(getAnchorV());
out.writeFloat(getInfoWindowAnchorU());
out.writeFloat(getInfoWindowAnchorV());
out.writeByte((byte) (selected ? 1 : 0));
out.writeFloat(getRotation());
Icon icon = getIcon();
out.writeByte((byte) (icon != null ? 1 : 0));
if (icon != null) {
out.writeString(getIcon().getId());
out.writeParcelable(getIcon().getBitmap(), flags);
}
}
@Override
public PulseMarkerView getMarker() {
return new PulseMarkerView(this);
}
public static final Parcelable.Creator<CountryMarkerViewOptions> CREATOR
= new Parcelable.Creator<CountryMarkerViewOptions>() {
public CountryMarkerViewOptions createFromParcel(Parcel in) {
return new CountryMarkerViewOptions(in);
}
public CountryMarkerViewOptions[] newArray(int size) {
return new CountryMarkerViewOptions[size];
}
};
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<scale
android:duration="1000"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXScale="1.8"
android:toYScale="1.8"/>
<set android:startOffset="200">
<alpha
android:duration="800"
android:fromAlpha="1.0"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toAlpha="0.0"/>
</set>
</set>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/mapbox_blue"/>
<size
android:width="@dimen/circle_size"
android:height="@dimen/circle_size"/>
</shape>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/primary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"/>
<ImageButton
android:id="@+id/clearDisplayViewButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_clear_24dp"
android:background="@color/accent"
android:visibility="gone"
android:layout_marginLeft="@dimen/full_button_margin"
android:layout_above="@+id/selectLocationButton"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<Button
android:id="@+id/selectLocationButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/full_button_margin"
android:background="@color/primary"
android:text="@string/navigation_select_location_button_text"
android:textColor="@android:color/white"
android:layout_alignParentBottom="true"/>
</RelativeLayout>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="48dp"
android:layout_height="48dp">
<ImageView
android:id="@+id/foreground_imageView"
android:layout_width="@dimen/circle_size"
android:layout_height="@dimen/circle_size"
android:layout_gravity="center"
android:src="@drawable/ic_circle"/>
<ImageView
android:id="@+id/background_imageview"
android:layout_width="@dimen/circle_size"
android:layout_height="@dimen/circle_size"
android:layout_gravity="center"
android:alpha="0.5"
android:src="@drawable/ic_circle"/>
</FrameLayout>

View File

@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="circle_size">24dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="full_button_margin">8dp</dimen>
<dimen name="attr_margin">10dp</dimen>
<dimen name="coordinatebounds_margin">32dp</dimen>
<dimen name="map_padding_left">96dp</dimen>

View File

@@ -35,6 +35,9 @@
<string name="activity_directions">Directions</string>
<string name="activity_geocoder">Geocoder</string>
<!-- Navigation -->
<string name="activity_location_picker">Location Picker</string>
<!-- Other -->
<string name="activity_double_map">Double Map Activity</string>
<string name="activity_back_to_map">Back to map activity</string>
@@ -82,7 +85,7 @@
<string name="description_back_to_map">Restart map view after temporarily leaving to another activity</string>
<string name="description_view_marker">Use an Android SDK View as marker</string>
<string name="description_dynamic_info_window_adapter">Learn how to create a dynamic custom InfoWindow</string>
<string name="description_location_picker">Use a fixed Marker to select your location</string>
<string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>
<string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string>
<string name="menuitem_title_tracking_mode_dismiss_on_gesture">Dismiss location tracking on gesture</string>
@@ -101,6 +104,7 @@
<string name="category_maplayout">Map Layout</string>
<string name="category_offline">Offline</string>
<string name="category_userlocation">User Location</string>
<string name="category_navigation">Navigation</string>
<string name="action_visible_bounds_explanation">Center map around 2 markers</string>
<string name="action_remove_polylines">Remove polylines</string>
@@ -162,4 +166,6 @@
<string name="dynamic_marker_arsenal_title">Arsenal</string>
<string name="dynamic_marker_arsenal_snippet">Emirates Stadium</string>
<string name="navigation_select_location_button_text">Select Location!</string>
</resources>

View File

@@ -7,7 +7,7 @@ buildscript {
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.github.JakeWharton:sdk-manager-plugin:220bf7a88a7072df3ed16dc8466fb144f2817070'
// NOTE: Do not place your application dependencies here; they belong