Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ee2a88f authored by Fan Zhang's avatar Fan Zhang
Browse files

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
parent b5241a11
Loading
Loading
Loading
Loading
+5 −18
Original line number Diff line number Diff line
@@ -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;
@@ -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());
@@ -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
@@ -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) {
+10 −20
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;

@@ -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();
@@ -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;
    }
+39 −6
Original line number Diff line number Diff line
@@ -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;

/**
@@ -28,6 +32,7 @@ import android.view.View;
 * annotation.
 */
public class AnnotationSpan extends URLSpan {

    private final View.OnClickListener mClickListener;

    private AnnotationSpan(View.OnClickListener lsn) {
@@ -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;
                }
            }
@@ -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;
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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";
+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();
    }
}