Loading src/com/android/settings/fingerprint/FingerprintSettings.java +5 −18 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; Loading Loading @@ -99,8 +98,6 @@ public class FingerprintSettings extends SubSettings { 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 public Intent getIntent() { Intent modIntent = new Intent(super.getIntent()); Loading Loading @@ -158,20 +155,6 @@ public class FingerprintSettings extends SubSettings { private FingerprintRemoveSidecar mRemovalSidecar; private HashMap<Integer, String> 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 Loading Loading @@ -360,11 +343,15 @@ public class FingerprintSettings extends SubSettings { ANNOTATION_ADMIN_DETAILS, (view) -> { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(activity, admin); }); final Intent helpIntent = HelpUtils.getHelpIntent( activity, getString(getHelpResource()), activity.getClass().getName()); final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( activity, ANNOTATION_URL, helpIntent); pref.setTitle(AnnotationSpan.linkify(getText(admin != null ? R.string .security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled : R.string.security_settings_fingerprint_enroll_disclaimer), mUrlLinkInfo, adminLinkInfo)); linkInfo, adminLinkInfo)); } protected void removeFingerprintPreference(int fingerprintId) { Loading src/com/android/settings/network/PrivateDnsModeDialogFragment.java +10 −20 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ 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; Loading @@ -33,7 +32,6 @@ 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; Loading @@ -58,7 +56,7 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp public static final String ANNOTATION_URL = "url"; private static final String TAG = "PrivateDnsModeDialogFragment"; private static final String TAG = "PrivateDnsModeDialog"; // DNS_MODE -> RadioButton id private static final Map<String, Integer> PRIVATE_DNS_MAP; Loading @@ -83,21 +81,6 @@ 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(); Loading Loading @@ -139,8 +122,15 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp final TextView helpTextView = view.findViewById(R.id.private_dns_help_info); helpTextView.setMovementMethod(LinkMovementMethod.getInstance()); final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString(R.string.help_uri_private_dns), context.getClass().getName()); final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(context, ANNOTATION_URL, helpIntent); if (linkInfo.isActionable()) { helpTextView.setText(AnnotationSpan.linkify( context.getText(R.string.private_dns_help_message), mUrlLinkInfo)); context.getText(R.string.private_dns_help_message), linkInfo)); } return view; } Loading src/com/android/settings/utils/AnnotationSpan.java +39 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.settings.utils; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.text.Annotation; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.style.URLSpan; import android.util.Log; import android.view.View; /** Loading @@ -28,6 +32,7 @@ import android.view.View; * annotation. */ public class AnnotationSpan extends URLSpan { private final View.OnClickListener mClickListener; private AnnotationSpan(View.OnClickListener lsn) { Loading Loading @@ -58,8 +63,8 @@ public class AnnotationSpan extends URLSpan { int end = msg.getSpanEnd(annotation); AnnotationSpan link = null; for (LinkInfo linkInfo : linkInfos) { if (linkInfo.annotation.equals(key)) { link = new AnnotationSpan(linkInfo.listener); if (linkInfo.mAnnotation.equals(key)) { link = new AnnotationSpan(linkInfo.mListener); break; } } Loading @@ -74,12 +79,40 @@ public class AnnotationSpan extends URLSpan { * Data class to store the annotation and the click action */ public static class LinkInfo { public final String annotation; public final View.OnClickListener listener; private static final String TAG = "AnnotationSpan.LinkInfo"; private final String mAnnotation; private final Boolean mActionable; private final View.OnClickListener mListener; public LinkInfo(String annotation, View.OnClickListener listener) { this.annotation = annotation; this.listener = listener; mAnnotation = annotation; mListener = listener; mActionable = true; // assume actionable } public LinkInfo(Context context, String annotation, Intent intent) { mAnnotation = annotation; if (intent != null) { mActionable = context.getPackageManager() .resolveActivity(intent, 0 /* flags */) != null; } else { mActionable = false; } if (!mActionable) { mListener = null; } else { mListener = view -> { try { view.startActivityForResult(intent, 0); } catch (ActivityNotFoundException e) { Log.w(TAG, "Activity was not found for intent, " + intent); } }; } } public boolean isActionable() { return mActionable; } } } tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -29,14 +29,17 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowHelpUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = ShadowHelpUtils.class) public class PrivateDnsModeDialogFragmentTest { private static final String HOST_NAME = "192.168.1.1"; Loading tests/robotests/src/com/android/settings/utils/AnnotationSpanTest.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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 static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadows.ShadowPackageManager; @RunWith(SettingsRobolectricTestRunner.class) public class AnnotationSpanTest { private Intent mTestIntent; private Context mContext; private ShadowPackageManager mPackageManager; @Before public void setUp() { mContext = RuntimeEnvironment.application; mPackageManager = Shadows.shadowOf(mContext.getPackageManager()); mTestIntent = new Intent("test_action"); } @Test public void newLinkInfo_validIntent_isActionable() { mPackageManager.addResolveInfoForIntent(mTestIntent, new ResolveInfo()); assertThat(new AnnotationSpan.LinkInfo(mContext, "annotation", mTestIntent).isActionable()) .isTrue(); } @Test public void newLinkInfo_invalidIntent_isNotActionable() { assertThat(new AnnotationSpan.LinkInfo(mContext, "annotation", mTestIntent).isActionable()) .isFalse(); } } Loading
src/com/android/settings/fingerprint/FingerprintSettings.java +5 −18 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; Loading Loading @@ -99,8 +98,6 @@ public class FingerprintSettings extends SubSettings { 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 public Intent getIntent() { Intent modIntent = new Intent(super.getIntent()); Loading Loading @@ -158,20 +155,6 @@ public class FingerprintSettings extends SubSettings { private FingerprintRemoveSidecar mRemovalSidecar; private HashMap<Integer, String> 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 Loading Loading @@ -360,11 +343,15 @@ public class FingerprintSettings extends SubSettings { ANNOTATION_ADMIN_DETAILS, (view) -> { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(activity, admin); }); final Intent helpIntent = HelpUtils.getHelpIntent( activity, getString(getHelpResource()), activity.getClass().getName()); final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( activity, ANNOTATION_URL, helpIntent); pref.setTitle(AnnotationSpan.linkify(getText(admin != null ? R.string .security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled : R.string.security_settings_fingerprint_enroll_disclaimer), mUrlLinkInfo, adminLinkInfo)); linkInfo, adminLinkInfo)); } protected void removeFingerprintPreference(int fingerprintId) { Loading
src/com/android/settings/network/PrivateDnsModeDialogFragment.java +10 −20 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ 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; Loading @@ -33,7 +32,6 @@ 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; Loading @@ -58,7 +56,7 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp public static final String ANNOTATION_URL = "url"; private static final String TAG = "PrivateDnsModeDialogFragment"; private static final String TAG = "PrivateDnsModeDialog"; // DNS_MODE -> RadioButton id private static final Map<String, Integer> PRIVATE_DNS_MAP; Loading @@ -83,21 +81,6 @@ 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(); Loading Loading @@ -139,8 +122,15 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp final TextView helpTextView = view.findViewById(R.id.private_dns_help_info); helpTextView.setMovementMethod(LinkMovementMethod.getInstance()); final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString(R.string.help_uri_private_dns), context.getClass().getName()); final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(context, ANNOTATION_URL, helpIntent); if (linkInfo.isActionable()) { helpTextView.setText(AnnotationSpan.linkify( context.getText(R.string.private_dns_help_message), mUrlLinkInfo)); context.getText(R.string.private_dns_help_message), linkInfo)); } return view; } Loading
src/com/android/settings/utils/AnnotationSpan.java +39 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.settings.utils; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.text.Annotation; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.style.URLSpan; import android.util.Log; import android.view.View; /** Loading @@ -28,6 +32,7 @@ import android.view.View; * annotation. */ public class AnnotationSpan extends URLSpan { private final View.OnClickListener mClickListener; private AnnotationSpan(View.OnClickListener lsn) { Loading Loading @@ -58,8 +63,8 @@ public class AnnotationSpan extends URLSpan { int end = msg.getSpanEnd(annotation); AnnotationSpan link = null; for (LinkInfo linkInfo : linkInfos) { if (linkInfo.annotation.equals(key)) { link = new AnnotationSpan(linkInfo.listener); if (linkInfo.mAnnotation.equals(key)) { link = new AnnotationSpan(linkInfo.mListener); break; } } Loading @@ -74,12 +79,40 @@ public class AnnotationSpan extends URLSpan { * Data class to store the annotation and the click action */ public static class LinkInfo { public final String annotation; public final View.OnClickListener listener; private static final String TAG = "AnnotationSpan.LinkInfo"; private final String mAnnotation; private final Boolean mActionable; private final View.OnClickListener mListener; public LinkInfo(String annotation, View.OnClickListener listener) { this.annotation = annotation; this.listener = listener; mAnnotation = annotation; mListener = listener; mActionable = true; // assume actionable } public LinkInfo(Context context, String annotation, Intent intent) { mAnnotation = annotation; if (intent != null) { mActionable = context.getPackageManager() .resolveActivity(intent, 0 /* flags */) != null; } else { mActionable = false; } if (!mActionable) { mListener = null; } else { mListener = view -> { try { view.startActivityForResult(intent, 0); } catch (ActivityNotFoundException e) { Log.w(TAG, "Activity was not found for intent, " + intent); } }; } } public boolean isActionable() { return mActionable; } } }
tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogFragmentTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -29,14 +29,17 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowHelpUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = ShadowHelpUtils.class) public class PrivateDnsModeDialogFragmentTest { private static final String HOST_NAME = "192.168.1.1"; Loading
tests/robotests/src/com/android/settings/utils/AnnotationSpanTest.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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 static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadows.ShadowPackageManager; @RunWith(SettingsRobolectricTestRunner.class) public class AnnotationSpanTest { private Intent mTestIntent; private Context mContext; private ShadowPackageManager mPackageManager; @Before public void setUp() { mContext = RuntimeEnvironment.application; mPackageManager = Shadows.shadowOf(mContext.getPackageManager()); mTestIntent = new Intent("test_action"); } @Test public void newLinkInfo_validIntent_isActionable() { mPackageManager.addResolveInfoForIntent(mTestIntent, new ResolveInfo()); assertThat(new AnnotationSpan.LinkInfo(mContext, "annotation", mTestIntent).isActionable()) .isTrue(); } @Test public void newLinkInfo_invalidIntent_isNotActionable() { assertThat(new AnnotationSpan.LinkInfo(mContext, "annotation", mTestIntent).isActionable()) .isFalse(); } }