Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit f0f113b

Browse files
tobrunGuardiola31337
authored andcommitted
MapSnapshot attribution (#10362)
* [android] - add attribution * [android] - optimise attribution sources * [android] - rework datamodel to attribution class * [android] - refactor Attribution, add tests * [android] - add getter for attribution string * [android] - rework attribution to include small logo, add layout placement * [android] - finalise integration and layout logic
1 parent a9bd09c commit f0f113b

File tree

20 files changed

+1128
-77
lines changed

20 files changed

+1128
-77
lines changed

platform/android/MapboxGLAndroidSDK/build.gradle

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies {
1010
}
1111
testCompile rootProject.ext.dep.junit
1212
testCompile rootProject.ext.dep.mockito
13+
testCompile rootProject.ext.dep.robolectric
1314

1415
// Mapbox Android Services (GeoJSON support)
1516
compile(rootProject.ext.dep.mapboxJavaGeoJSON) {
@@ -126,7 +127,9 @@ android {
126127
}
127128

128129
testOptions {
129-
unitTests.returnDefaultValues = true
130+
unitTests{
131+
returnDefaultValues = true
132+
}
130133
}
131134

132135
buildTypes {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.mapbox.mapboxsdk.attribution;
2+
3+
public class Attribution {
4+
5+
private static final String OPENSTREETMAP = "OpenStreetMap";
6+
private static final String OPENSTREETMAP_ABBR = "OSM";
7+
static final String TELEMETRY = "Telemetry Settings";
8+
9+
static final String IMPROVE_MAP_URL = "https://www.mapbox.com/map-feedback/";
10+
static final String MAPBOX_URL = "https://www.mapbox.com/about/maps/";
11+
static final String TELEMETRY_URL = "https://www.mapbox.com/telemetry/";
12+
13+
private String title;
14+
private String url;
15+
16+
Attribution(String title, String url) {
17+
this.title = title;
18+
this.url = url;
19+
}
20+
21+
public String getTitle() {
22+
return title;
23+
}
24+
25+
public String getTitleAbbreviated() {
26+
if (title.equals(OPENSTREETMAP)) {
27+
return OPENSTREETMAP_ABBR;
28+
}
29+
return title;
30+
}
31+
32+
public String getUrl() {
33+
return url;
34+
}
35+
36+
@Override
37+
public boolean equals(Object o) {
38+
if (this == o) {
39+
return true;
40+
}
41+
if (o == null || getClass() != o.getClass()) {
42+
return false;
43+
}
44+
45+
Attribution that = (Attribution) o;
46+
47+
if (title != null ? !title.equals(that.title) : that.title != null) {
48+
return false;
49+
}
50+
return url != null ? url.equals(that.url) : that.url == null;
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
int result = title != null ? title.hashCode() : 0;
56+
result = 31 * result + (url != null ? url.hashCode() : 0);
57+
return result;
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.mapbox.mapboxsdk.attribution;
2+
3+
import android.graphics.Bitmap;
4+
import android.graphics.PointF;
5+
import android.support.annotation.Nullable;
6+
7+
public class AttributionLayout {
8+
9+
private Bitmap logo;
10+
private PointF anchorPoint;
11+
private boolean shortText;
12+
13+
public AttributionLayout(@Nullable Bitmap logo, @Nullable PointF anchorPoint, boolean shortText) {
14+
this.logo = logo;
15+
this.anchorPoint = anchorPoint;
16+
this.shortText = shortText;
17+
}
18+
19+
public Bitmap getLogo() {
20+
return logo;
21+
}
22+
23+
public PointF getAnchorPoint() {
24+
return anchorPoint;
25+
}
26+
27+
public boolean isShortText() {
28+
return shortText;
29+
}
30+
31+
@Override
32+
public boolean equals(Object o) {
33+
if (this == o) {
34+
return true;
35+
}
36+
if (o == null || getClass() != o.getClass()) {
37+
return false;
38+
}
39+
40+
AttributionLayout that = (AttributionLayout) o;
41+
42+
if (logo != null ? !logo.equals(that.logo) : that.logo != null) {
43+
return false;
44+
}
45+
return anchorPoint != null ? anchorPoint.equals(that.anchorPoint) : that.anchorPoint == null;
46+
}
47+
48+
@Override
49+
public int hashCode() {
50+
int result = logo != null ? logo.hashCode() : 0;
51+
result = 31 * result + (anchorPoint != null ? anchorPoint.hashCode() : 0);
52+
return result;
53+
}
54+
55+
@Override
56+
public String toString() {
57+
return "AttributionLayout{"
58+
+ "logo=" + logo
59+
+ ", anchorPoint=" + anchorPoint
60+
+ '}';
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package com.mapbox.mapboxsdk.attribution;
2+
3+
import android.graphics.Bitmap;
4+
import android.graphics.PointF;
5+
import android.widget.TextView;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
10+
public class AttributionMeasure {
11+
12+
private Bitmap logo;
13+
private Bitmap logoSmall;
14+
private Bitmap snapshot;
15+
private TextView textView;
16+
private TextView textViewShort;
17+
private float margin;
18+
19+
private boolean shorterText;
20+
21+
AttributionMeasure(Bitmap snapshot, Bitmap logo, Bitmap logoSmall, TextView tv, TextView tvShort, float margin) {
22+
this.snapshot = snapshot;
23+
this.logo = logo;
24+
this.logoSmall = logoSmall;
25+
this.textView = tv;
26+
this.textViewShort = tvShort;
27+
this.margin = margin;
28+
}
29+
30+
public AttributionLayout measure() {
31+
Chain chain = new Chain(
32+
new FullLogoLongTextCommand(),
33+
new FullLogoShortTextCommand(),
34+
new SmallLogoLongTextCommand(),
35+
new SmallLogoShortTextCommand(),
36+
new LongTextCommand(),
37+
new ShortTextCommand(),
38+
new NoTextCommand()
39+
);
40+
41+
AttributionLayout attributionLayout = chain.start(this);
42+
shorterText = attributionLayout.isShortText();
43+
return attributionLayout;
44+
}
45+
46+
47+
private static class FullLogoLongTextCommand implements Command {
48+
public AttributionLayout execute(AttributionMeasure measure) {
49+
float width = measure.getLogoContainerWidth() + measure.getTextViewContainerWidth();
50+
boolean fitBounds = width <= measure.getMaxSize();
51+
if (fitBounds) {
52+
PointF anchor = calculateAnchor(measure.snapshot, measure.textView, measure.margin);
53+
return new AttributionLayout(measure.logo, anchor, false);
54+
}
55+
return null;
56+
}
57+
}
58+
59+
private static class FullLogoShortTextCommand implements Command {
60+
@Override
61+
public AttributionLayout execute(AttributionMeasure measure) {
62+
float width = measure.getLogoContainerWidth() + measure.getTextViewShortContainerWidth();
63+
boolean fitBounds = width <= measure.getMaxSizeShort();
64+
if (fitBounds) {
65+
PointF anchor = calculateAnchor(measure.snapshot, measure.textView, measure.margin);
66+
return new AttributionLayout(measure.logo, anchor, true);
67+
}
68+
return null;
69+
}
70+
}
71+
72+
private static class SmallLogoLongTextCommand implements Command {
73+
@Override
74+
public AttributionLayout execute(AttributionMeasure measure) {
75+
float width = measure.getLogoSmallContainerWidth() + measure.getTextViewContainerWidth();
76+
boolean fitBounds = width <= measure.getMaxSize();
77+
if (fitBounds) {
78+
PointF anchor = calculateAnchor(measure.snapshot, measure.textView, measure.margin);
79+
return new AttributionLayout(measure.logoSmall, anchor, false);
80+
}
81+
return null;
82+
}
83+
}
84+
85+
private static class SmallLogoShortTextCommand implements Command {
86+
@Override
87+
public AttributionLayout execute(AttributionMeasure measure) {
88+
float width = measure.getLogoContainerWidth() + measure.getTextViewShortContainerWidth();
89+
boolean fitBounds = width <= measure.getMaxSizeShort();
90+
if (fitBounds) {
91+
PointF anchor = calculateAnchor(measure.snapshot, measure.textViewShort, measure.margin);
92+
return new AttributionLayout(measure.logoSmall, anchor, true);
93+
}
94+
return null;
95+
}
96+
}
97+
98+
private static class LongTextCommand implements Command {
99+
@Override
100+
public AttributionLayout execute(AttributionMeasure measure) {
101+
float width = measure.getTextViewContainerWidth() + measure.margin;
102+
boolean fitBounds = width <= measure.getMaxSize();
103+
if (fitBounds) {
104+
return new AttributionLayout(null, calculateAnchor(measure.snapshot, measure.textView, measure.margin), false);
105+
}
106+
return null;
107+
}
108+
}
109+
110+
private static class ShortTextCommand implements Command {
111+
@Override
112+
public AttributionLayout execute(AttributionMeasure measure) {
113+
float width = measure.getTextViewShortContainerWidth() + measure.margin;
114+
boolean fitBounds = width <= measure.getMaxSizeShort();
115+
if (fitBounds) {
116+
PointF anchor = calculateAnchor(measure.snapshot, measure.textViewShort, measure.margin);
117+
return new AttributionLayout(null, anchor, true);
118+
}
119+
return null;
120+
}
121+
}
122+
123+
private static class NoTextCommand implements Command {
124+
@Override
125+
public AttributionLayout execute(AttributionMeasure measure) {
126+
return new AttributionLayout(null, null, false);
127+
}
128+
}
129+
130+
private static PointF calculateAnchor(Bitmap snapshot, TextView textView, float margin) {
131+
return new PointF(
132+
snapshot.getWidth() - textView.getMeasuredWidth() - margin,
133+
snapshot.getHeight() - margin - textView.getMeasuredHeight()
134+
);
135+
}
136+
137+
public TextView getTextView() {
138+
return shorterText ? textViewShort : textView;
139+
}
140+
141+
private class Chain {
142+
public List<Command> commands;
143+
144+
Chain(Command... commands) {
145+
this.commands = Arrays.asList(commands);
146+
}
147+
148+
public AttributionLayout start(AttributionMeasure measure) {
149+
AttributionLayout attributionLayout = null;
150+
for (Command command : commands) {
151+
attributionLayout = command.execute(measure);
152+
if (attributionLayout != null) {
153+
break;
154+
}
155+
}
156+
return attributionLayout;
157+
}
158+
}
159+
160+
public interface Command {
161+
AttributionLayout execute(AttributionMeasure measure);
162+
}
163+
164+
private float getTextViewContainerWidth() {
165+
return textView.getMeasuredWidth() + margin;
166+
}
167+
168+
private float getLogoContainerWidth() {
169+
return logo.getWidth() + (2 * margin);
170+
}
171+
172+
private float getTextViewShortContainerWidth() {
173+
return textViewShort.getMeasuredWidth() + margin;
174+
}
175+
176+
private float getLogoSmallContainerWidth() {
177+
return logoSmall.getWidth() + (2 * margin);
178+
}
179+
180+
private float getMaxSize() {
181+
return snapshot.getWidth() * 8 / 10;
182+
}
183+
184+
private float getMaxSizeShort() {
185+
return snapshot.getWidth();
186+
}
187+
188+
public static class Builder {
189+
private Bitmap snapshot;
190+
private Bitmap logo;
191+
private Bitmap logoSmall;
192+
private TextView textView;
193+
private TextView textViewShort;
194+
private float marginPadding;
195+
196+
public Builder setSnapshot(Bitmap snapshot) {
197+
this.snapshot = snapshot;
198+
return this;
199+
}
200+
201+
public Builder setLogo(Bitmap logo) {
202+
this.logo = logo;
203+
return this;
204+
}
205+
206+
public Builder setLogoSmall(Bitmap logoSmall) {
207+
this.logoSmall = logoSmall;
208+
return this;
209+
}
210+
211+
public Builder setTextView(TextView textView) {
212+
this.textView = textView;
213+
return this;
214+
}
215+
216+
public Builder setTextViewShort(TextView textViewShort) {
217+
this.textViewShort = textViewShort;
218+
return this;
219+
}
220+
221+
public Builder setMarginPadding(float marginPadding) {
222+
this.marginPadding = marginPadding;
223+
return this;
224+
}
225+
226+
public AttributionMeasure build() {
227+
return new AttributionMeasure(snapshot, logo, logoSmall, textView, textViewShort, marginPadding);
228+
}
229+
}
230+
}

0 commit comments

Comments
 (0)