Java tutorial
/* * ================================================================================================= * Copyright (C) 2014 Martin Albedinsky * ================================================================================================= * Licensed under the Apache License, Version 2.0 or later (further "License" only). * ------------------------------------------------------------------------------------------------- * You may use this file only in compliance with the License. More details and copy of this License * you may obtain at * * http://www.apache.org/licenses/LICENSE-2.0 * * You can redistribute, modify or publish any part of the code written within this file but as it * is described in the License, the software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND. * * See the License for the specific language governing permissions and limitations under the License. * ================================================================================================= */ package com.albedinsky.android.support.intent; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.support.annotation.FloatRange; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.util.Log; /** * A {@link BaseIntent} builder implementation providing API for building of intents targeting * a <b>maps</b> related applications. * * <h3>Location via latitude + longitude</h3> * Simple intent to show map at a specific location can be created by specifying just latitude and * longitude via {@link #location(double, double)}. You can also specify either label for the requested * location via {@link #label(String)} or its resource related method {@link #label(int)} or * zoom level via {@link #zoomLevel(int)}. * * <h3>Location via query</h3> * In case when you want to show map at a specific location, but you do not know its exact location * (lat + lng), you can specify location query via {@link #locationQuery(String)}, which can contain * name of place (town/city) and state that you want to show on map. In this case you can also * specify the location label via {@link #label(String)} as for lat + lng based map intent. * * @author Martin Albedinsky */ public class MapIntent extends BaseIntent<MapIntent> { /** * Interface =================================================================================== */ /** * Constants =================================================================================== */ /** * Log TAG. */ private static final String TAG = "MapIntent"; /** * Uri scheme for <b>map</b> targeting intents. * <p> * Constant value: <b>geo</b> */ public static final String URI_SCHEME = "geo"; /** * Static members ============================================================================== */ /** * Members ===================================================================================== */ /** * Longitude value for map location query. */ private double mLng; /** * Latitude value for map location query. */ private double mLat; /** * Zoom level for map camera. */ private int mZoomLevel; /** * Label for map location query. */ private String mLabel; /** * Location query for map data. */ private String mLocationQuery; /** * Flag indicating whether there was latitude + longitude set or not. */ private boolean mLatLngSet; /** * Constructors ================================================================================ */ /** * Creates a new instance of MapIntent for the given <var>activity</var> context. * See {@link com.albedinsky.android.support.intent.BaseIntent#BaseIntent(Activity)} * for additional info. */ public MapIntent(@NonNull Activity activity) { super(activity); } /** * Creates a new instance of MapIntent for the given <var>fragment</var> context. * See {@link com.albedinsky.android.support.intent.BaseIntent#BaseIntent(android.support.v4.app.Fragment)} * for additional info. */ public MapIntent(@NonNull Fragment fragment) { super(fragment); } /** * Methods ===================================================================================== */ /** * Sets latitude and longitude of a location to show on a map. * * @param lat The desired location's latitude position in the range {@code [-90, 90]}. * @param lng The desired location's longitude position in the range {@code [-180, 180]}. * @return This intent builder to allow methods chaining. */ public MapIntent location(@FloatRange(from = -90, to = 90) double lat, @FloatRange(from = -180, to = 180) double lng) { this.mLat = lat >= -90 && lat <= 90 ? lat : 0; this.mLng = lng >= -180 && lng <= 180 ? lng : 0; this.mLatLngSet = true; return this; } /** * Returns the latitude position of a location to show on map. * * @return Latitude position on a map from the range {@code [-90, 90]}, {@code 0} by default. * @see #location(double, double) * @see #lng() */ @FloatRange(from = -90, to = 90) public double lat() { return mLat; } /** * Returns the longitude position of a location to show on map. * * @return Longitude position on a map from the range {@code [-180, 180]}, {@code 0} by default. * @see #location(double, double) * @see #lat() */ @FloatRange(from = -180, to = 180) public double lng() { return mLng; } /** * Same as {@link #locationQuery(String)} for resource id. * * @param resId Resource id of the desired location query string. */ public MapIntent locationQuery(@StringRes int resId) { return locationQuery(obtainString(resId)); } /** * Sets a location query that will be used to target a desired location on a map. * * @param query The desired location query. Can be for example name of a desired town with street * address and address number to show on a map. * @return This intent builder to allow methods chaining. */ public MapIntent locationQuery(@Nullable String query) { this.mLocationQuery = query; return this; } /** * Returns the location query targeting a specific location on a map. * * @return Location query or empty string in not specified yet. */ @NonNull public String locationQuery() { return mLocationQuery != null ? mLocationQuery : ""; } /** * Sets a zoom level at which should be a desired location on a map displayed to a user. * * @param level The desired zoom level in the range {@code [1, 23]}. The highest level, the closest * to map. * @return This intent builder to allow methods chaining. */ public MapIntent zoomLevel(@IntRange(from = 1, to = 23) int level) { this.mZoomLevel = level >= 1 && level <= 23 ? level : 0; return this; } /** * Returns the zoom level at which will be map displayed. * * @return Zoom level from the range {@code [1, 23]} or {@code 0} by default. */ @IntRange(from = 0, to = 23) public int zoomLevel() { return mZoomLevel; } /** * Same as {@link #label(String)} for resource id. * * @param resId Resource id of the desired label text. */ public MapIntent label(@StringRes int resId) { return label(obtainString(resId)); } /** * Sets a text by which should be labeled the requested location on map. * * @param label The desired label text. * @return This intent builder to allow methods chaining. */ public MapIntent label(@Nullable String label) { this.mLabel = label; return this; } /** * Returns the label text for the requested map location. * * @return Label text. */ @NonNull public String label() { return mLabel != null ? mLabel : ""; } /** */ @Override protected void ensureCanBuildOrThrow() { super.ensureCanBuildOrThrow(); if (!mLatLngSet && TextUtils.isEmpty(mLocationQuery)) { throw cannotBuildIntentException("No latitude and longitude nor location query specified."); } } /** */ @NonNull @Override protected Intent onBuild() { final StringBuilder uriBuilder = new StringBuilder(64); if (mLatLngSet) { if (!TextUtils.isEmpty(mLabel)) { uriBuilder.append("0,0?q="); uriBuilder.append(mLat); uriBuilder.append(","); uriBuilder.append(mLng); this.appendLabel(uriBuilder); } else { uriBuilder.append(mLat); uriBuilder.append(","); uriBuilder.append(mLng); if (mZoomLevel != 0) { uriBuilder.append("?z="); uriBuilder.append(mZoomLevel); } if (!TextUtils.isEmpty(mLocationQuery)) { uriBuilder.append(mZoomLevel != 0 ? "&" : "?"); this.appendLocationQuery(uriBuilder); } } } else { uriBuilder.append("0,0?"); this.appendLocationQuery(uriBuilder); if (!TextUtils.isEmpty(mLabel)) { this.appendLabel(uriBuilder); } } final Uri locationUri = Uri.fromParts(URI_SCHEME, uriBuilder.toString(), null); if (IntentsConfig.DEBUG_LOG_ENABLED) { Log.d(TAG, "Building intent with uri('" + locationUri.toString() + "')."); } return new Intent(Intent.ACTION_VIEW, locationUri); } /** * Appends {@link #mLocationQuery} to the specified <var>uriBuilder</var>. * <p> * <b>Note</b>, that before adding value of the location query there will be added also * {@code q=} query parameter. Also location query will be encoded via {@link Uri#encode(String)}. * * @param uriBuilder The builder where to append the location query value. */ private void appendLocationQuery(StringBuilder uriBuilder) { uriBuilder.append("q=").append(Uri.encode(mLocationQuery)); } /** * Appends {@link #mLabel} to the specified <var>uriBuilder</var>. * <p> * <b>Note</b>, that label will be enclosed in "()" bracekts. * * @param uriBuilder The builder where to append the label value. */ private void appendLabel(StringBuilder uriBuilder) { uriBuilder.append("(").append(Uri.encode(mLabel)).append(")"); } /** * Inner classes =============================================================================== */ }