Hide spannable link if it's not actionable
Created a new constructor that detects if intent is actionable and set a flag in LinkInfo. In fragments, first check if linkInfo is actionable, if not, don't do anything with it. Change-Id: Ibda12ecac2545d696acc7c197fc315e423b984aa Fixes: 74726487 Test: make RunSettingsRoboTests -j
This commit is contained in:
@@ -21,7 +21,6 @@ import android.app.Activity;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -99,8 +98,6 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
public static final String ANNOTATION_URL = "url";
|
public static final String ANNOTATION_URL = "url";
|
||||||
public static final String ANNOTATION_ADMIN_DETAILS = "admin_details";
|
public static final String ANNOTATION_ADMIN_DETAILS = "admin_details";
|
||||||
|
|
||||||
public static final String KEY_FINGERPRINT_SETTINGS = "fingerprint_settings";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Intent getIntent() {
|
public Intent getIntent() {
|
||||||
Intent modIntent = new Intent(super.getIntent());
|
Intent modIntent = new Intent(super.getIntent());
|
||||||
@@ -158,20 +155,6 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
private FingerprintRemoveSidecar mRemovalSidecar;
|
private FingerprintRemoveSidecar mRemovalSidecar;
|
||||||
private HashMap<Integer, String> mFingerprintsRenaming;
|
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 =
|
FingerprintAuthenticateSidecar.Listener mAuthenticateListener =
|
||||||
new FingerprintAuthenticateSidecar.Listener() {
|
new FingerprintAuthenticateSidecar.Listener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -360,11 +343,15 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
ANNOTATION_ADMIN_DETAILS, (view) -> {
|
ANNOTATION_ADMIN_DETAILS, (view) -> {
|
||||||
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(activity, admin);
|
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
|
pref.setTitle(AnnotationSpan.linkify(getText(admin != null
|
||||||
? R.string
|
? R.string
|
||||||
.security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled
|
.security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled
|
||||||
: R.string.security_settings_fingerprint_enroll_disclaimer),
|
: R.string.security_settings_fingerprint_enroll_disclaimer),
|
||||||
mUrlLinkInfo, adminLinkInfo));
|
linkInfo, adminLinkInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeFingerprintPreference(int fingerprintId) {
|
protected void removeFingerprintPreference(int fingerprintId) {
|
||||||
|
@@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.FragmentManager;
|
import android.app.FragmentManager;
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -33,7 +32,6 @@ import android.support.annotation.VisibleForTesting;
|
|||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@@ -58,7 +56,7 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp
|
|||||||
|
|
||||||
public static final String ANNOTATION_URL = "url";
|
public static final String ANNOTATION_URL = "url";
|
||||||
|
|
||||||
private static final String TAG = "PrivateDnsModeDialogFragment";
|
private static final String TAG = "PrivateDnsModeDialog";
|
||||||
// DNS_MODE -> RadioButton id
|
// DNS_MODE -> RadioButton id
|
||||||
private static final Map<String, Integer> PRIVATE_DNS_MAP;
|
private static final Map<String, Integer> PRIVATE_DNS_MAP;
|
||||||
|
|
||||||
@@ -83,21 +81,6 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
String mMode;
|
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) {
|
public static void show(FragmentManager fragmentManager) {
|
||||||
if (fragmentManager.findFragmentByTag(TAG) == null) {
|
if (fragmentManager.findFragmentByTag(TAG) == null) {
|
||||||
final PrivateDnsModeDialogFragment fragment = new PrivateDnsModeDialogFragment();
|
final PrivateDnsModeDialogFragment fragment = new PrivateDnsModeDialogFragment();
|
||||||
@@ -139,8 +122,15 @@ public class PrivateDnsModeDialogFragment extends InstrumentedDialogFragment imp
|
|||||||
|
|
||||||
final TextView helpTextView = view.findViewById(R.id.private_dns_help_info);
|
final TextView helpTextView = view.findViewById(R.id.private_dns_help_info);
|
||||||
helpTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
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(
|
helpTextView.setText(AnnotationSpan.linkify(
|
||||||
context.getText(R.string.private_dns_help_message), mUrlLinkInfo));
|
context.getText(R.string.private_dns_help_message), linkInfo));
|
||||||
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,15 @@
|
|||||||
|
|
||||||
package com.android.settings.utils;
|
package com.android.settings.utils;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.text.Annotation;
|
import android.text.Annotation;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +32,7 @@ import android.view.View;
|
|||||||
* annotation.
|
* annotation.
|
||||||
*/
|
*/
|
||||||
public class AnnotationSpan extends URLSpan {
|
public class AnnotationSpan extends URLSpan {
|
||||||
|
|
||||||
private final View.OnClickListener mClickListener;
|
private final View.OnClickListener mClickListener;
|
||||||
|
|
||||||
private AnnotationSpan(View.OnClickListener lsn) {
|
private AnnotationSpan(View.OnClickListener lsn) {
|
||||||
@@ -58,8 +63,8 @@ public class AnnotationSpan extends URLSpan {
|
|||||||
int end = msg.getSpanEnd(annotation);
|
int end = msg.getSpanEnd(annotation);
|
||||||
AnnotationSpan link = null;
|
AnnotationSpan link = null;
|
||||||
for (LinkInfo linkInfo : linkInfos) {
|
for (LinkInfo linkInfo : linkInfos) {
|
||||||
if (linkInfo.annotation.equals(key)) {
|
if (linkInfo.mAnnotation.equals(key)) {
|
||||||
link = new AnnotationSpan(linkInfo.listener);
|
link = new AnnotationSpan(linkInfo.mListener);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,12 +79,40 @@ public class AnnotationSpan extends URLSpan {
|
|||||||
* Data class to store the annotation and the click action
|
* Data class to store the annotation and the click action
|
||||||
*/
|
*/
|
||||||
public static class LinkInfo {
|
public static class LinkInfo {
|
||||||
public final String annotation;
|
private static final String TAG = "AnnotationSpan.LinkInfo";
|
||||||
public final View.OnClickListener listener;
|
private final String mAnnotation;
|
||||||
|
private final Boolean mActionable;
|
||||||
|
private final View.OnClickListener mListener;
|
||||||
|
|
||||||
public LinkInfo(String annotation, View.OnClickListener listener) {
|
public LinkInfo(String annotation, View.OnClickListener listener) {
|
||||||
this.annotation = annotation;
|
mAnnotation = annotation;
|
||||||
this.listener = listener;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,14 +29,17 @@ import android.widget.Button;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowHelpUtils;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(shadows = ShadowHelpUtils.class)
|
||||||
public class PrivateDnsModeDialogFragmentTest {
|
public class PrivateDnsModeDialogFragmentTest {
|
||||||
|
|
||||||
private static final String HOST_NAME = "192.168.1.1";
|
private static final String HOST_NAME = "192.168.1.1";
|
||||||
|
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user