From fd69cd4c33da23b5ccc443b7977feb3c5c7d4afc Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 9 Nov 2017 13:09:28 -0800 Subject: [PATCH] Add help info at the bottom of the dialog It contains a link to help center Bug: 68030013 Test: RunSettingsRoboTest Change-Id: I79260eff35e604fa97cf21c62f58c02f3bbe5cfb --- res/layout/private_dns_mode_dialog.xml | 77 ++++++++------- res/values/strings.xml | 4 +- .../settings/fingerprint/FingerprintSettings.java | 104 ++++++--------------- .../network/PrivateDnsModeDialogFragment.java | 36 ++++++- src/com/android/settings/utils/AnnotationSpan.java | 85 +++++++++++++++++ .../network/PrivateDnsModeDialogFragmentTest.java | 1 - 6 files changed, 192 insertions(+), 115 deletions(-) create mode 100644 src/com/android/settings/utils/AnnotationSpan.java diff --git a/res/layout/private_dns_mode_dialog.xml b/res/layout/private_dns_mode_dialog.xml index 16152a4e12..652bc63ae3 100644 --- a/res/layout/private_dns_mode_dialog.xml +++ b/res/layout/private_dns_mode_dialog.xml @@ -14,43 +14,56 @@ limitations under the License. --> - + android:orientation="vertical" + android:padding="8dp"> - + - + - - - + + + + + + + - - + android:layout_marginTop="16dp" + android:paddingStart="16dp" + android:textAppearance="?android:attr/textAppearanceSmall"/> + diff --git a/res/values/strings.xml b/res/values/strings.xml index 5c1fd98d64..07f12f17e7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2269,7 +2269,8 @@ Emergency Address Used as your location when you make an emergency call over Wi\u2011Fi - + + Learn more about Private DNS features @@ -6341,6 +6342,7 @@ + Account for content diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java index 5d178d2c39..de7187c4ac 100644 --- a/src/com/android/settings/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/fingerprint/FingerprintSettings.java @@ -25,12 +25,10 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; -import android.os.CancellationSignal; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; @@ -41,12 +39,7 @@ import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceViewHolder; -import android.text.Annotation; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.URLSpan; import android.util.Log; import android.view.View; import android.view.WindowManager; @@ -61,6 +54,7 @@ import com.android.settings.Utils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.utils.AnnotationSpan; import com.android.settingslib.HelpUtils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; @@ -103,6 +97,9 @@ public class FingerprintSettings extends SubSettings { private static final long LOCKOUT_DURATION = 30000; // time we have to wait for fp to reset, ms + public static final String ANNOTATION_URL = "url"; + public static final String ANNOTATION_ADMIN_DETAILS = "admin_details"; + public static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings"; @Override @@ -162,6 +159,20 @@ public class FingerprintSettings extends SubSettings { private FingerprintRemoveSidecar mRemovalSidecar; private HashMap mFingerprintsRenaming; + final AnnotationSpan.LinkInfo mUrlLinkInfo = new AnnotationSpan.LinkInfo( + ANNOTATION_URL, (view) -> { + final Context context = view.getContext(); + Intent intent = HelpUtils.getHelpIntent(context, getString(getHelpResource()), + context.getClass().getName()); + if (intent != null) { + try { + view.startActivityForResult(intent, 0); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity was not found for intent, " + intent.toString()); + } + } + }); + FingerprintAuthenticateSidecar.Listener mAuthenticateListener = new FingerprintAuthenticateSidecar.Listener() { @Override @@ -346,10 +357,15 @@ public class FingerprintSettings extends SubSettings { final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference(); final EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled( activity, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId); - pref.setTitle(LearnMoreSpan.linkify(getText(admin != null - ? R.string.security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled + final AnnotationSpan.LinkInfo adminLinkInfo = new AnnotationSpan.LinkInfo( + ANNOTATION_ADMIN_DETAILS, (view) -> { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(activity, admin); + }); + pref.setTitle(AnnotationSpan.linkify(getText(admin != null + ? R.string + .security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled : R.string.security_settings_fingerprint_enroll_disclaimer), - getString(getHelpResource()), admin)); + mUrlLinkInfo, adminLinkInfo)); } protected void removeFingerprintPreference(int fingerprintId) { @@ -906,74 +922,6 @@ public class FingerprintSettings extends SubSettings { } } - private static class LearnMoreSpan extends URLSpan { - private static final String TAG = "LearnMoreSpan"; - private static final Typeface TYPEFACE_MEDIUM = - Typeface.create("sans-serif-medium", Typeface.NORMAL); - - private static final String ANNOTATION_URL = "url"; - private static final String ANNOTATION_ADMIN_DETAILS = "admin_details"; - - private EnforcedAdmin mEnforcedAdmin = null; - - private LearnMoreSpan(String url) { - super(url); - } - - private LearnMoreSpan(EnforcedAdmin admin) { - super((String) null); - mEnforcedAdmin = admin; - } - - @Override - public void onClick(View widget) { - Context ctx = widget.getContext(); - if (mEnforcedAdmin != null) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(ctx, mEnforcedAdmin); - } else { - Intent intent = HelpUtils.getHelpIntent(ctx, getURL(), ctx.getClass().getName()); - if (intent == null) { - Log.w(LearnMoreSpan.TAG, "Null help intent."); - return; - } - try { - widget.startActivityForResult(intent, 0); - } catch (ActivityNotFoundException e) { - Log.w(FingerprintSettingsFragment.TAG, - "Actvity was not found for intent, " + intent.toString()); - } - } - } - - @Override - public void updateDrawState(TextPaint ds) { - super.updateDrawState(ds); - ds.setUnderlineText(false); - ds.setTypeface(TYPEFACE_MEDIUM); - } - - public static CharSequence linkify(CharSequence rawText, String uri, EnforcedAdmin admin) { - SpannableString msg = new SpannableString(rawText); - Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); - SpannableStringBuilder builder = new SpannableStringBuilder(msg); - for (Annotation annotation : spans) { - final String key = annotation.getValue(); - int start = msg.getSpanStart(annotation); - int end = msg.getSpanEnd(annotation); - LearnMoreSpan link = null; - if (ANNOTATION_URL.equals(key)) { - link = new LearnMoreSpan(uri); - } else if (ANNOTATION_ADMIN_DETAILS.equals(key)) { - link = new LearnMoreSpan(admin); - } - if (link != null) { - builder.setSpan(link, start, end, msg.getSpanFlags(link)); - } - } - return builder; - } - } - /** * @deprecated in favor of new SecuritySettings. */ diff --git a/src/com/android/settings/network/PrivateDnsModeDialogFragment.java b/src/com/android/settings/network/PrivateDnsModeDialogFragment.java index 5704fb914b..8b7ccce38c 100644 --- a/src/com/android/settings/network/PrivateDnsModeDialogFragment.java +++ b/src/com/android/settings/network/PrivateDnsModeDialogFragment.java @@ -22,22 +22,30 @@ import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME import android.app.AlertDialog; import android.app.Dialog; import android.app.FragmentManager; +import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.provider.Settings; import android.support.annotation.VisibleForTesting; import android.text.Editable; import android.text.TextWatcher; +import android.text.method.LinkMovementMethod; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; +import android.widget.TextView; +import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.utils.AnnotationSpan; +import com.android.settingslib.HelpUtils; import java.util.HashMap; import java.util.Map; @@ -48,6 +56,8 @@ import java.util.Map; public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment implements DialogInterface.OnClickListener, RadioGroup.OnCheckedChangeListener, TextWatcher { + public static final String ANNOTATION_URL = "url"; + private static final String TAG = "PrivateDnsModeDialogFragment"; // DNS_MODE -> RadioButton id private static final Map PRIVATE_DNS_MAP; @@ -73,6 +83,21 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp @VisibleForTesting String mMode; + private final AnnotationSpan.LinkInfo mUrlLinkInfo = new AnnotationSpan.LinkInfo( + ANNOTATION_URL, (widget) -> { + final Context context = widget.getContext(); + final Intent intent = HelpUtils.getHelpIntent(context, + getString(R.string.help_uri_private_dns), + context.getClass().getName()); + if (intent != null) { + try { + widget.startActivityForResult(intent, 0); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity was not found for intent, " + intent.toString()); + } + } + }); + public static void show(FragmentManager fragmentManager) { if (fragmentManager.findFragmentByTag(TAG) == null) { final PrivateDnsModeDialogFragment fragment = new PrivateDnsModeDialogFragment(); @@ -112,25 +137,30 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp mRadioGroup.setOnCheckedChangeListener(this); mRadioGroup.check(PRIVATE_DNS_MAP.getOrDefault(mMode, R.id.private_dns_mode_opportunistic)); + final TextView helpTextView = view.findViewById(R.id.private_dns_help_info); + helpTextView.setMovementMethod(LinkMovementMethod.getInstance()); + helpTextView.setText(AnnotationSpan.linkify( + context.getText(R.string.private_dns_help_message), mUrlLinkInfo)); + return view; } @Override public void onClick(DialogInterface dialog, int which) { - //TODO(b/34953048): add metric action if (mMode.equals(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { // Only clickable if hostname is valid, so we could save it safely Settings.Global.putString(getContext().getContentResolver(), HOSTNAME_KEY, mEditText.getText().toString()); } + mMetricsFeatureProvider.action(getContext(), + MetricsProto.MetricsEvent.ACTION_PRIVATE_DNS_MODE, mMode); Settings.Global.putString(getContext().getContentResolver(), MODE_KEY, mMode); } @Override public int getMetricsCategory() { - //TODO(b/68030013): add metric id - return 0; + return MetricsProto.MetricsEvent.DIALOG_PRIVATE_DNS; } @Override diff --git a/src/com/android/settings/utils/AnnotationSpan.java b/src/com/android/settings/utils/AnnotationSpan.java new file mode 100644 index 0000000000..645351df0b --- /dev/null +++ b/src/com/android/settings/utils/AnnotationSpan.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.utils; + +import android.text.Annotation; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.style.URLSpan; +import android.view.View; + +/** + * This class is used to add {@link View.OnClickListener} for the text been wrapped by + * annotation. + */ +public class AnnotationSpan extends URLSpan { + private final View.OnClickListener mClickListener; + + private AnnotationSpan(View.OnClickListener lsn) { + super((String) null); + mClickListener = lsn; + } + + @Override + public void onClick(View widget) { + if (mClickListener != null) { + mClickListener.onClick(widget); + } + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + + public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) { + SpannableString msg = new SpannableString(rawText); + Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); + SpannableStringBuilder builder = new SpannableStringBuilder(msg); + for (Annotation annotation : spans) { + final String key = annotation.getValue(); + int start = msg.getSpanStart(annotation); + int end = msg.getSpanEnd(annotation); + AnnotationSpan link = null; + for (LinkInfo linkInfo : linkInfos) { + if (linkInfo.annotation.equals(key)) { + link = new AnnotationSpan(linkInfo.listener); + break; + } + } + if (link != null) { + builder.setSpan(link, start, end, msg.getSpanFlags(link)); + } + } + return builder; + } + + /** + * Data class to store the annotation and the click action + */ + public static class LinkInfo { + public final String annotation; + public final View.OnClickListener listener; + + public LinkInfo(String annotation, View.OnClickListener listener) { + this.annotation = annotation; + this.listener = listener; + } + } +} diff --git a/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java b/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java index f1d7a73c3e..bba689bcf2 100644 --- a/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java @@ -50,7 +50,6 @@ public class PrivateDnsModeDialogFragmentTest { private PrivateDnsModeDialogFragment mFragment; private Button mSaveButton; - @Before public void setUp() { MockitoAnnotations.initMocks(this); -- 2.11.0