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

Commit 7c3dca52 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4388640 from 7c06618a to pi-release

Change-Id: I07911489c8559df899fd3e3534adfaec7f1e98fe
parents c654d16d 7c06618a
Loading
Loading
Loading
Loading
+110 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.documentsui.inspector;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.LocaleList;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextSelection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Checks if a TextView has a latitude and longitude. If so shows the default maps app to open
 * those coordinates.
 *
 * Example - textView.setTextClassifier(new GpsCoordinatesTextClassifier(context, intent));
 */
final class GpsCoordinatesTextClassifier implements TextClassifier {

    // Checks for latitude and longitude points, latitude ranges -90.0 to 90.0 and longitude
    // ranges -180.0 to 180.0 Valid entries can be of the format "0,0", "0, 0" and "0.0, 0.0"
    // in the mentioned range.
    private static final String geoPattern
        = "-?(90(\\.0*)?|[1-8]?[0-9](\\.[0-9]*)?), *-?(180("
        + "\\.0*)?|([1][0-7][0-9]|[0-9]?[0-9])(\\.[0-9]*)?)";
    private static final Pattern sGeoPattern = Pattern.compile(geoPattern);

    private final TextClassifier mSystemClassifier;
    private final PackageManager mPackageManager;

    public GpsCoordinatesTextClassifier(PackageManager pm, TextClassifier classifier) {
        assert pm != null;
        assert classifier != null;
        mPackageManager = pm;
        mSystemClassifier = classifier;
    }

    public static GpsCoordinatesTextClassifier create(Context context) {
        return new GpsCoordinatesTextClassifier(
                context.getPackageManager(),
                context.getSystemService(TextClassificationManager.class).getTextClassifier());
    }

    // TODO: add support for local specific formatting
    @Override
    public TextClassification classifyText(
            CharSequence text, int start, int end, LocaleList localeList) {

        CharSequence sequence = text.subSequence(start, end);
        if (isGeoSequence(sequence)) {

            Intent intent = new Intent(Intent.ACTION_VIEW)
                .setData(Uri.parse(String.format("geo:0,0?q=%s", sequence)));

            final ResolveInfo info = mPackageManager.resolveActivity(intent, 0);
            if (info != null) {

                return new TextClassification.Builder()
                        .setText(sequence.toString())
                        .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
                        .setIcon(info.loadIcon(mPackageManager))
                        .setLabel(info.loadLabel(mPackageManager).toString())
                        .setIntent(intent)
                        .build();
            }
        }

        // return default if text was not latitude, longitude or we couldn't find an application
        // to handle the geo intent.
        return mSystemClassifier.classifyText(text, start, end, localeList);
    }

    @Override
    public TextSelection suggestSelection(
        CharSequence context, int start, int end, LocaleList localeList) {

        // Show map action menu popup when entire TextView is selected.
        final int[] boundaries = {0, context.length()};

        if (boundaries != null) {
            return new TextSelection.Builder(boundaries[0], boundaries[1])
                .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
                .build();
        }
        return mSystemClassifier.suggestSelection(context, start, end, localeList);
    }

    private static boolean isGeoSequence(CharSequence text) {
        return sGeoPattern.matcher(text).matches();
    }
}
+8 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.view.View;
import android.view.textclassifier.TextClassifier;
import android.widget.LinearLayout;
import android.widget.TextView;

@@ -37,6 +38,7 @@ public class KeyValueRow extends LinearLayout {

    private final Resources mRes;
    private @Nullable ColorStateList mDefaultTextColor;
    private @Nullable TextClassifier mClassifier;

    public KeyValueRow(Context context) {
        this(context, null);
@@ -48,10 +50,13 @@ public class KeyValueRow extends LinearLayout {

    public KeyValueRow(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mRes = context.getResources();
    }

    public void setTextClassifier(TextClassifier classifier) {
        mClassifier = classifier;
    }

    /**
     * Sets the raw value of the key. Only localized values
     * should be passed.
@@ -67,6 +72,7 @@ public class KeyValueRow extends LinearLayout {
    public void setValue(CharSequence value) {
        TextView text = ((TextView) findViewById(R.id.table_row_value));
        text.setText(value);
        text.setTextClassifier(mClassifier);
        text.setOnLongClickListener((View view) -> {

            CharSequence textValue = text.getText();
+6 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.textclassifier.TextClassifier;
import android.widget.LinearLayout;
import android.widget.TextView;

@@ -40,7 +41,8 @@ public class TableView extends LinearLayout implements TableDisplay {

    private final Map<CharSequence, KeyValueRow> mRows = new HashMap<>();
    private final Resources mRes;
    private Map<CharSequence, TextView> mTitles = new HashMap<>();
    private final Map<CharSequence, TextView> mTitles = new HashMap<>();
    private final TextClassifier mClassifier;

    public TableView(Context context) {
        this(context, null);
@@ -54,6 +56,7 @@ public class TableView extends LinearLayout implements TableDisplay {
        super(context, attrs, defStyleAttr);
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mRes = context.getResources();
        mClassifier = GpsCoordinatesTextClassifier.create(context);
    }

    void setTitle(@StringRes int title, boolean showDivider) {
@@ -79,6 +82,7 @@ public class TableView extends LinearLayout implements TableDisplay {
    protected KeyValueRow createKeyValueRow(ViewGroup parent) {
        KeyValueRow row = (KeyValueRow) mInflater.inflate(R.layout.table_key_value_row, null);
        parent.addView(row);
        row.setTextClassifier(mClassifier);
        return row;
    }

@@ -106,6 +110,7 @@ public class TableView extends LinearLayout implements TableDisplay {
        }

        row.setValue(value);
        row.setTextClassifier(mClassifier);
        return row;
    }

+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.documentsui.inspector;

import static junit.framework.Assert.assertEquals;

import android.content.pm.PackageManager;
import android.os.LocaleList;
import android.support.test.InstrumentationRegistry;

import android.content.Context;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import com.android.documentsui.testing.TestPackageManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Test class for testing recognizing geo coordinates.
 */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class GpsCoordinatesTextClassifierTest {

    private GpsCoordinatesTextClassifier mClassifier;

    @Before
    public void setUp() throws Exception {
        PackageManager pm = TestPackageManager.create();
        Context context = InstrumentationRegistry.getTargetContext();

        TextClassifier defaultClassifier =
                context.getSystemService(TextClassificationManager.class).getTextClassifier();
        mClassifier = new GpsCoordinatesTextClassifier(pm, defaultClassifier);
    }

    @Test
    public void testBasicPatterns() throws Exception {
        assertClassifiedGeo("0,0", true);
        assertClassifiedGeo("0, 0", true);
        assertClassifiedGeo("0.0,0.0", true);
        assertClassifiedGeo("0.0, 0.0", true);
        assertClassifiedGeo("90,180", true);
        assertClassifiedGeo("90, 180", true);
        assertClassifiedGeo("90.0000,180.0000", true);
        assertClassifiedGeo("90.000, 180.000000000000000", true);
        assertClassifiedGeo("-77.5646564,133.656554654", true);
        assertClassifiedGeo("33, -179.324234242423", true);
        assertClassifiedGeo("44.4545454,70.0", true);
        assertClassifiedGeo("60.0, 60.0", true);
        assertClassifiedGeo("-33.33,-180", true);
        assertClassifiedGeo("-88.888888, -33.3333", true);
        assertClassifiedGeo("90.0, 180.000000", true);
        assertClassifiedGeo("-90.00000, -180.0", true);
    }

    @Test
    public void testInvalidPatterns() throws Exception {
        assertClassifiedGeo("0", false);
        assertClassifiedGeo("Geo Intent", false);
        assertClassifiedGeo("GeoIntent", false);
        assertClassifiedGeo("A.B, C.D", false);
        assertClassifiedGeo("5000, 5000", false);
        assertClassifiedGeo("500, 500", false);
        assertClassifiedGeo("90.165464, 180.1", false);
        assertClassifiedGeo("-90.1, -180.156754", false);
    }

    private void assertClassifiedGeo(CharSequence text, boolean expectClassified) {
        boolean wasClassified;
        TextClassification test = mClassifier.classifyText(
                text,
                0,
                text.length(),
                new LocaleList());
        try {
            wasClassified = "geo".equals(test.getIntent().getData().getScheme());
        } catch (NullPointerException intentNotSet) {
            wasClassified = false;
        }
        assertEquals(wasClassified, expectClassified);
    }
}