/* * 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(); } }