1d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian/*
2d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Copyright (C) 2017 The Android Open Source Project
3d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
4d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * you may not use this file except in compliance with the License.
6d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * You may obtain a copy of the License at
7d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
8d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
10d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * See the License for the specific language governing permissions and
14d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * limitations under the License
15d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */
16d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
17d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianpackage com.android.incallui.calllocation.impl;
18d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
19d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.Context;
20d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.Intent;
21d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.content.res.Resources;
22d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.location.Location;
23d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.net.Uri;
24d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.support.annotation.Nullable;
25d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.support.annotation.VisibleForTesting;
26d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.Locale;
27d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
28d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianclass LocationUrlBuilder {
29d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
30d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  // Static Map API path constants.
31d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String HTTPS_SCHEME = "https";
32d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MAPS_API_DOMAIN = "maps.googleapis.com";
33d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MAPS_PATH = "maps";
34d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String API_PATH = "api";
35d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String STATIC_MAP_PATH = "staticmap";
36d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String GEOCODE_PATH = "geocode";
37d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String GEOCODE_OUTPUT_TYPE = "json";
38d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
39d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  // Static Map API parameter constants.
40d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String KEY_PARAM_KEY = "key";
41d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String CENTER_PARAM_KEY = "center";
42d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String ZOOM_PARAM_KEY = "zoom";
43d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String SCALE_PARAM_KEY = "scale";
44d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String SIZE_PARAM_KEY = "size";
45d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MARKERS_PARAM_KEY = "markers";
46d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
47d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String ZOOM_PARAM_VALUE = Integer.toString(16);
48d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
49d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String LAT_LONG_DELIMITER = ",";
50d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
51d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MARKER_DELIMITER = "|";
52d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MARKER_STYLE_DELIMITER = ":";
53d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MARKER_STYLE_COLOR = "color";
54d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String MARKER_STYLE_COLOR_RED = "red";
55d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
56d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String LAT_LNG_PARAM_KEY = "latlng";
57d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
58d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String ANDROID_API_KEY_VALUE = "AIzaSyAXdDnif6B7sBYxU8hzw9qAp3pRPVHs060";
59d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String BROWSER_API_KEY_VALUE = "AIzaSyBfLlvWYndiQ3RFEHli65qGQH36QIxdyCI";
60d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
61d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  /**
62d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * Generates the URL to a static map image for the given location.
63d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
64d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * <p>This image has the following characteristics:
65d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
66d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * <p>- It is centered at the given latitude and longitutde. - It is scaled according to the
67d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * device's pixel density. - There is a red marker at the given latitude and longitude.
68d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
69d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * <p>Source: https://developers.google.com/maps/documentation/staticmaps/
70d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
71d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @param contxt The context.
72d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @param Location A location.
73d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @return The URL of a static map image url of the given location.
74d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   */
75d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static String getStaticMapUrl(Context context, Location location) {
76d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    final Uri.Builder builder = new Uri.Builder();
77d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    Resources res = context.getResources();
78d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    String size =
79d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        res.getDimensionPixelSize(R.dimen.location_map_width)
80d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian            + "x"
81d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian            + res.getDimensionPixelSize(R.dimen.location_map_height);
82d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
83d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    builder
84d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .scheme(HTTPS_SCHEME)
85d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .authority(MAPS_API_DOMAIN)
86d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(MAPS_PATH)
87d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(API_PATH)
88d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(STATIC_MAP_PATH)
89d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(CENTER_PARAM_KEY, getFormattedLatLng(location))
90d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(ZOOM_PARAM_KEY, ZOOM_PARAM_VALUE)
91d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(SIZE_PARAM_KEY, size)
92d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(SCALE_PARAM_KEY, Float.toString(res.getDisplayMetrics().density))
93d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(MARKERS_PARAM_KEY, getMarkerUrlParamValue(location))
94d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(KEY_PARAM_KEY, ANDROID_API_KEY_VALUE);
95d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
96d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    return builder.build().toString();
97d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
98d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
99d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  /**
100d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * Generates the URL for a request to reverse geocode the given location.
101d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
102d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * <p>Source: https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding
103d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
104d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @param Location A location.
105d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   */
106d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static String getReverseGeocodeUrl(Location location) {
107d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    final Uri.Builder builder = new Uri.Builder();
108d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
109d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    builder
110d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .scheme(HTTPS_SCHEME)
111d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .authority(MAPS_API_DOMAIN)
112d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(MAPS_PATH)
113d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(API_PATH)
114d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(GEOCODE_PATH)
115d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendPath(GEOCODE_OUTPUT_TYPE)
116d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(LAT_LNG_PARAM_KEY, getFormattedLatLng(location))
117d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        .appendQueryParameter(KEY_PARAM_KEY, BROWSER_API_KEY_VALUE);
118d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
119d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    return builder.build().toString();
120d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
121d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
122d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static Intent getShowMapIntent(
123d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      Location location, @Nullable CharSequence addressLine1, @Nullable CharSequence addressLine2) {
124d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
125d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    String latLong = getFormattedLatLng(location);
126d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    String url = String.format(Locale.US, "geo: %s?q=%s", latLong, latLong);
127d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
128d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    // Add a map label
129d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    if (addressLine1 != null) {
130d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      if (addressLine2 != null) {
131d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        url +=
132d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian            String.format(Locale.US, "(%s, %s)", addressLine1.toString(), addressLine2.toString());
133d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      } else {
134d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        url += String.format(Locale.US, "(%s)", addressLine1.toString());
135d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      }
136d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    } else {
13710ae593a59aa50963e1d3159747da2d65ca79bedEric Erfanian      // TODO: i18n
138d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      url +=
139d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian          String.format(
140d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian              Locale.US,
141d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian              "(Latitude: %f, Longitude: %f)",
142d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian              location.getLatitude(),
143d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian              location.getLongitude());
144d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
145d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
146d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
147d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    intent.setPackage("com.google.android.apps.maps");
148d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    return intent;
149d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
150d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
151d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  /**
152d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * Returns a comma-separated latitude and longitude pair, formatted for use as a URL parameter
153d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * value.
154d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
155d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @param location A location.
156d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @return The comma-separated latitude and longitude pair of that location.
157d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   */
158d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  @VisibleForTesting
159d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  static String getFormattedLatLng(Location location) {
160d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    return location.getLatitude() + LAT_LONG_DELIMITER + location.getLongitude();
161d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
162d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
163d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  /**
164d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * Returns the URL parameter value for the marker, specifying its style and position.
165d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   *
166d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @param location A location.
167d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * @return The URL parameter value for the marker.
168d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   */
169d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  @VisibleForTesting
170d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  static String getMarkerUrlParamValue(Location location) {
171d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    return MARKER_STYLE_COLOR
172d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        + MARKER_STYLE_DELIMITER
173d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        + MARKER_STYLE_COLOR_RED
174d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        + MARKER_DELIMITER
175d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        + getFormattedLatLng(location);
176d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
177d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian}
178