Skip to content

Commit 3d4a798

Browse files
committed
Fix text span link bugs
1 parent 2e9daf6 commit 3d4a798

File tree

3 files changed

+128
-78
lines changed

3 files changed

+128
-78
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.firebase.ui.auth.ui.email;
2+
3+
import android.content.Context;
4+
import android.net.Uri;
5+
import android.support.annotation.ColorInt;
6+
import android.support.annotation.StringRes;
7+
import android.support.customtabs.CustomTabsIntent;
8+
import android.support.v4.content.ContextCompat;
9+
import android.text.SpannableStringBuilder;
10+
import android.text.TextUtils;
11+
import android.text.method.LinkMovementMethod;
12+
import android.text.style.ClickableSpan;
13+
import android.text.style.ForegroundColorSpan;
14+
import android.util.TypedValue;
15+
import android.view.View;
16+
import android.widget.TextView;
17+
18+
import com.firebase.ui.auth.R;
19+
import com.firebase.ui.auth.ui.FlowParameters;
20+
21+
public class PreambleHandler {
22+
private static final String TOS_TARGET = "%TOS%";
23+
private static final String PP_TARGET = "%PP%";
24+
25+
private final Context mContext;
26+
private final FlowParameters mFlowParameters;
27+
private final ForegroundColorSpan mLinkSpan;
28+
29+
private SpannableStringBuilder mBuilder;
30+
31+
public PreambleHandler(Context context, FlowParameters parameters) {
32+
mContext = context;
33+
mFlowParameters = parameters;
34+
mLinkSpan = new ForegroundColorSpan(ContextCompat.getColor(mContext, R.color.linkColor));
35+
36+
setupCreateAccountPreamble();
37+
}
38+
39+
public void setPreamble(TextView textView) {
40+
textView.setMovementMethod(LinkMovementMethod.getInstance());
41+
textView.setText(mBuilder);
42+
}
43+
44+
private void setupCreateAccountPreamble() {
45+
int preambleType = getPreambleType();
46+
if (preambleType == -1) {
47+
return;
48+
}
49+
50+
String[] preambles =
51+
mContext.getResources().getStringArray(R.array.create_account_preamble);
52+
mBuilder = new SpannableStringBuilder(preambles[preambleType]);
53+
54+
replaceTarget(TOS_TARGET, R.string.terms_of_service, mFlowParameters.termsOfServiceUrl);
55+
replaceTarget(PP_TARGET, R.string.privacy_policy, mFlowParameters.privacyPolicyUrl);
56+
}
57+
58+
private void replaceTarget(String target, @StringRes int replacementRes, String url) {
59+
char[] currentPreambleChars = new char[mBuilder.length()];
60+
mBuilder.getChars(0, mBuilder.length(), currentPreambleChars, 0);
61+
String currentPreamble = String.valueOf(currentPreambleChars);
62+
63+
int targetIndex = currentPreamble.indexOf(target);
64+
if (targetIndex != -1) {
65+
String replacement = mContext.getString(replacementRes);
66+
mBuilder.replace(targetIndex, targetIndex + target.length(), replacement);
67+
68+
int end = targetIndex + replacement.length();
69+
mBuilder.setSpan(mLinkSpan, targetIndex, end, 0);
70+
mBuilder.setSpan(new CustomTabsSpan(url), targetIndex, end, 0);
71+
}
72+
}
73+
74+
/**
75+
* 0 means we have both a TOS and a PP
76+
* <p>1 means we only have a TOS
77+
* <p>2 means we only have a PP
78+
* <p>-1 means we have neither
79+
*/
80+
private int getPreambleType() {
81+
int preambleType;
82+
83+
boolean hasTos = !TextUtils.isEmpty(mFlowParameters.termsOfServiceUrl);
84+
boolean hasPp = !TextUtils.isEmpty(mFlowParameters.privacyPolicyUrl);
85+
86+
if (hasTos && hasPp) {
87+
preambleType = 0;
88+
} else if (hasTos) {
89+
preambleType = 1;
90+
} else if (hasPp) {
91+
preambleType = 2;
92+
} else {
93+
preambleType = -1;
94+
}
95+
96+
return preambleType;
97+
}
98+
99+
private class CustomTabsSpan extends ClickableSpan {
100+
private final String mUrl;
101+
private final CustomTabsIntent mCustomTabsIntent;
102+
103+
public CustomTabsSpan(String url) {
104+
mUrl = url;
105+
106+
// Getting default color
107+
TypedValue typedValue = new TypedValue();
108+
mContext.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
109+
@ColorInt int color = typedValue.data;
110+
111+
mCustomTabsIntent = new CustomTabsIntent.Builder()
112+
.setToolbarColor(color)
113+
.setShowTitle(true)
114+
.build();
115+
}
116+
117+
@Override
118+
public void onClick(View widget) {
119+
mCustomTabsIntent.launchUrl(mContext, Uri.parse(mUrl));
120+
}
121+
}
122+
}

auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
package com.firebase.ui.auth.ui.email;
22

3-
import android.net.Uri;
43
import android.os.Bundle;
5-
import android.support.annotation.ColorInt;
64
import android.support.annotation.NonNull;
75
import android.support.annotation.Nullable;
86
import android.support.annotation.RestrictTo;
9-
import android.support.customtabs.CustomTabsIntent;
107
import android.support.design.widget.TextInputLayout;
11-
import android.support.v4.content.ContextCompat;
12-
import android.text.SpannableString;
13-
import android.text.SpannableStringBuilder;
148
import android.text.TextUtils;
15-
import android.text.style.ClickableSpan;
16-
import android.text.style.ForegroundColorSpan;
17-
import android.util.TypedValue;
189
import android.view.LayoutInflater;
1910
import android.view.View;
2011
import android.view.ViewGroup;
@@ -166,8 +157,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
166157
getActivity().setTitle(R.string.title_register_email);
167158

168159
mSaveSmartLock = mHelper.getSaveSmartLockInstance(getActivity());
169-
setUpTermsOfService();
170-
setUpPrivacyPolicy();
160+
new PreambleHandler(getContext(), mHelper.getFlowParams()).setPreamble(mAgreementText);
171161
}
172162

173163
@Override
@@ -180,72 +170,6 @@ public void onSaveInstanceState(Bundle outState) {
180170
super.onSaveInstanceState(outState);
181171
}
182172

183-
private void setUpTermsOfService() {
184-
if (TextUtils.isEmpty(mHelper.getFlowParams().termsOfServiceUrl)) {
185-
return;
186-
}
187-
188-
ForegroundColorSpan foregroundColorSpan =
189-
new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.linkColor));
190-
191-
String preamble = getString(R.string.create_account_preamble);
192-
String link = getString(R.string.terms_of_service);
193-
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(preamble + link);
194-
int start = preamble.length();
195-
spannableStringBuilder.setSpan(foregroundColorSpan, start, start + link.length(), 0);
196-
197-
mAgreementText.setText(spannableStringBuilder);
198-
mAgreementText.setOnClickListener(new View.OnClickListener() {
199-
@Override
200-
public void onClick(View view) {
201-
// Getting default color
202-
TypedValue typedValue = new TypedValue();
203-
getActivity().getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
204-
@ColorInt int color = typedValue.data;
205-
206-
new CustomTabsIntent.Builder()
207-
.setToolbarColor(color)
208-
.build()
209-
.launchUrl(
210-
getActivity(),
211-
Uri.parse(mHelper.getFlowParams().termsOfServiceUrl));
212-
}
213-
});
214-
}
215-
216-
private void setUpPrivacyPolicy() {
217-
if (TextUtils.isEmpty(mHelper.getFlowParams().privacyPolicyUrl)) {
218-
return;
219-
}
220-
221-
ForegroundColorSpan foregroundColorSpan =
222-
new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.linkColor));
223-
224-
String link = getString(R.string.privacy_policy);
225-
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(link);
226-
int start = mAgreementText.length();
227-
spannableStringBuilder.setSpan(foregroundColorSpan, start, start + link.length(), 0);
228-
229-
mAgreementText.append(" and the ");
230-
mAgreementText.append(spannableStringBuilder);
231-
mAgreementText.setOnClickListener(new View.OnClickListener() {
232-
@Override
233-
public void onClick(View view) {
234-
// Getting default color
235-
TypedValue typedValue = new TypedValue();
236-
getActivity().getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
237-
@ColorInt int color = typedValue.data;
238-
239-
new CustomTabsIntent.Builder()
240-
.setToolbarColor(color)
241-
.build()
242-
.launchUrl(
243-
getActivity(),
244-
Uri.parse(mHelper.getFlowParams().privacyPolicyUrl));
245-
}
246-
});
247-
}
248-
249173
@Override
250174
public void onFocusChange(View view, boolean hasFocus) {
251175
if (hasFocus) return; // Only consider fields losing focus

auth/src/main/res/values/strings.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@
4242
</plurals>
4343
<string name="email_account_creation_error">Email account registration unsuccessful</string>
4444
<string name="error_user_collision">An account already exists with that email address.</string>
45-
<string name="create_account_preamble">"By tapping SAVE you are indicating that you agree to the "</string>
45+
<string-array name="create_account_preamble" formatted="false">
46+
<item>By tapping SAVE you are indicating that you agree to the %TOS% and the %PP%.</item>
47+
<item>By tapping SAVE you are indicating that you agree to the %TOS%.</item>
48+
<item>By tapping SAVE you are indicating that you agree to the %PP%.</item>
49+
</string-array>
4650
<string name="terms_of_service">Terms of Service</string>
4751
<string name="privacy_policy">Privacy Policy</string>
4852

0 commit comments

Comments
 (0)