This repository has been archived by the owner on Aug 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[android] - derived source attribution #8630
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
169 changes: 169 additions & 0 deletions
169
.../MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package com.mapbox.mapboxsdk.maps; | ||
|
||
import android.content.Context; | ||
import android.content.DialogInterface; | ||
import android.content.Intent; | ||
import android.net.Uri; | ||
import android.support.annotation.NonNull; | ||
import android.support.v7.app.AlertDialog; | ||
import android.text.Html; | ||
import android.text.SpannableStringBuilder; | ||
import android.text.TextUtils; | ||
import android.text.style.URLSpan; | ||
import android.view.View; | ||
import android.widget.ArrayAdapter; | ||
|
||
import com.mapbox.mapboxsdk.R; | ||
import com.mapbox.mapboxsdk.camera.CameraPosition; | ||
import com.mapbox.mapboxsdk.style.sources.Source; | ||
import com.mapbox.services.android.telemetry.MapboxTelemetry; | ||
|
||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Locale; | ||
|
||
/** | ||
* Responsible for managing attribution interactions on the map. | ||
* <p> | ||
* When the user clicks the attribution icon, {@link AttributionDialogManager#onClick(View)} will be invoked. | ||
* An attribution dialog will be shown to the user with contents based on the attributions found in the map style. | ||
* Additionally an telemetry option item is shown to configure telemetry settings. | ||
* </p> | ||
*/ | ||
class AttributionDialogManager implements View.OnClickListener, DialogInterface.OnClickListener { | ||
|
||
private static final String MAP_FEEDBACK_URL = "https://www.mapbox.com/map-feedback"; | ||
private static final String MAP_FEEDBACK_LOCATION_FORMAT = MAP_FEEDBACK_URL + "/#/%f/%f/%d"; | ||
|
||
private final Context context; | ||
private final MapboxMap mapboxMap; | ||
private String[] attributionKeys; | ||
private HashMap<String, String> attributionMap; | ||
|
||
AttributionDialogManager(@NonNull Context context, @NonNull MapboxMap mapboxMap) { | ||
this.context = context; | ||
this.mapboxMap = mapboxMap; | ||
} | ||
|
||
// Called when someone presses the attribution icon on the map | ||
@Override | ||
public void onClick(View view) { | ||
attributionMap = new AttributionBuilder(context, mapboxMap).build(); | ||
showAttributionDialog(); | ||
} | ||
|
||
private void showAttributionDialog() { | ||
attributionKeys = attributionMap.keySet().toArray(new String[attributionMap.size()]); | ||
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle); | ||
builder.setTitle(R.string.mapbox_attributionsDialogTitle); | ||
builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, attributionKeys), this); | ||
builder.show(); | ||
} | ||
|
||
// Called when someone selects an attribution or telemetry settings from the dialog | ||
@Override | ||
public void onClick(DialogInterface dialog, int which) { | ||
if (isLatestEntry(which)) { | ||
showTelemetryDialog(); | ||
} else { | ||
showAttributionWebPage(which); | ||
} | ||
} | ||
|
||
private boolean isLatestEntry(int attributionKeyIndex) { | ||
return attributionKeyIndex == attributionKeys.length - 1; | ||
} | ||
|
||
private void showTelemetryDialog() { | ||
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle); | ||
builder.setTitle(R.string.mapbox_attributionTelemetryTitle); | ||
builder.setMessage(R.string.mapbox_attributionTelemetryMessage); | ||
builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() { | ||
@Override | ||
public void onClick(DialogInterface dialog, int which) { | ||
MapboxTelemetry.getInstance().setTelemetryEnabled(true); | ||
dialog.cancel(); | ||
} | ||
}); | ||
builder.setNeutralButton(R.string.mapbox_attributionTelemetryNeutral, new DialogInterface.OnClickListener() { | ||
@Override | ||
public void onClick(DialogInterface dialog, int which) { | ||
String url = context.getResources().getString(R.string.mapbox_telemetryLink); | ||
Intent intent = new Intent(Intent.ACTION_VIEW); | ||
intent.setData(Uri.parse(url)); | ||
context.startActivity(intent); | ||
dialog.cancel(); | ||
} | ||
}); | ||
builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() { | ||
@Override | ||
public void onClick(DialogInterface dialog, int which) { | ||
MapboxTelemetry.getInstance().setTelemetryEnabled(false); | ||
dialog.cancel(); | ||
} | ||
}); | ||
builder.show(); | ||
} | ||
|
||
private void showAttributionWebPage(int which) { | ||
Intent intent = new Intent(Intent.ACTION_VIEW); | ||
String url = attributionMap.get(attributionKeys[which]); | ||
if (url.contains(MAP_FEEDBACK_URL)) { | ||
url = buildMapFeedbackMapUrl(mapboxMap.getCameraPosition()); | ||
} | ||
intent.setData(Uri.parse(url)); | ||
context.startActivity(intent); | ||
} | ||
|
||
private String buildMapFeedbackMapUrl(CameraPosition cameraPosition) { | ||
// appends current location to the map feedback url if available | ||
return cameraPosition != null ? String.format(Locale.getDefault(), | ||
MAP_FEEDBACK_LOCATION_FORMAT, cameraPosition.target.getLongitude(), cameraPosition.target.getLatitude(), | ||
(int) cameraPosition.zoom) : MAP_FEEDBACK_URL; | ||
} | ||
|
||
private static class AttributionBuilder { | ||
|
||
private final HashMap<String, String> map = new LinkedHashMap<>(); | ||
private final Context context; | ||
private final MapboxMap mapboxMap; | ||
|
||
AttributionBuilder(Context context, MapboxMap mapboxMap) { | ||
this.context = context.getApplicationContext(); | ||
this.mapboxMap = mapboxMap; | ||
} | ||
|
||
private HashMap<String, String> build() { | ||
for (Source source : mapboxMap.getSources()) { | ||
parseAttribution(source.getAttribution()); | ||
} | ||
addTelemetryEntryToAttributionMap(); | ||
return map; | ||
} | ||
|
||
private void parseAttribution(String attributionSource) { | ||
if (!TextUtils.isEmpty(attributionSource)) { | ||
SpannableStringBuilder htmlBuilder = (SpannableStringBuilder) Html.fromHtml(attributionSource); | ||
URLSpan[] urlSpans = htmlBuilder.getSpans(0, htmlBuilder.length(), URLSpan.class); | ||
for (URLSpan urlSpan : urlSpans) { | ||
map.put(resolveAnchorValue(htmlBuilder, urlSpan), urlSpan.getURL()); | ||
} | ||
} | ||
} | ||
|
||
private String resolveAnchorValue(SpannableStringBuilder htmlBuilder, URLSpan urlSpan) { | ||
int start = htmlBuilder.getSpanStart(urlSpan); | ||
int end = htmlBuilder.getSpanEnd(urlSpan); | ||
int length = end - start; | ||
char[] charKey = new char[length]; | ||
htmlBuilder.getChars(start, end, charKey, 0); | ||
return String.valueOf(charKey); | ||
} | ||
|
||
private void addTelemetryEntryToAttributionMap() { | ||
String telemetryKey = context.getString(R.string.mapbox_telemetrySettings); | ||
String telemetryLink = context.getString(R.string.mapbox_telemetryLink); | ||
map.put(telemetryKey, telemetryLink); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 0 additions & 16 deletions
16
platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn’t hard-code this URL, because sources other than Mapbox Streets are free to provide their own map feedback URLs. Look for
<a>
tags withclass
set tomapbox-improve-map
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ticketed this out as tail work in #8730, since custom feedback links are admittedly quite an edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for ticketing that out, will fix it separately from this PR.