1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.documentsui.inspector; 17 18 import android.content.Context; 19 import android.content.Intent; 20 import android.content.pm.PackageManager; 21 import android.content.pm.ResolveInfo; 22 import android.net.Uri; 23 import android.os.LocaleList; 24 import android.view.textclassifier.TextClassification; 25 import android.view.textclassifier.TextClassificationManager; 26 import android.view.textclassifier.TextClassifier; 27 import android.view.textclassifier.TextSelection; 28 import java.util.regex.Matcher; 29 import java.util.regex.Pattern; 30 31 /** 32 * Checks if a TextView has a latitude and longitude. If so shows the default maps app to open 33 * those coordinates. 34 * 35 * Example - textView.setTextClassifier(new GpsCoordinatesTextClassifier(context, intent)); 36 */ 37 final class GpsCoordinatesTextClassifier implements TextClassifier { 38 39 // Checks for latitude and longitude points, latitude ranges -90.0 to 90.0 and longitude 40 // ranges -180.0 to 180.0 Valid entries can be of the format "0,0", "0, 0" and "0.0, 0.0" 41 // in the mentioned range. 42 private static final String geoPattern 43 = "-?(90(\\.0*)?|[1-8]?[0-9](\\.[0-9]*)?), *-?(180(" 44 + "\\.0*)?|([1][0-7][0-9]|[0-9]?[0-9])(\\.[0-9]*)?)"; 45 private static final Pattern sGeoPattern = Pattern.compile(geoPattern); 46 47 private final TextClassifier mSystemClassifier; 48 private final PackageManager mPackageManager; 49 GpsCoordinatesTextClassifier(PackageManager pm, TextClassifier classifier)50 public GpsCoordinatesTextClassifier(PackageManager pm, TextClassifier classifier) { 51 assert pm != null; 52 assert classifier != null; 53 mPackageManager = pm; 54 mSystemClassifier = classifier; 55 } 56 create(Context context)57 public static GpsCoordinatesTextClassifier create(Context context) { 58 return new GpsCoordinatesTextClassifier( 59 context.getPackageManager(), 60 context.getSystemService(TextClassificationManager.class).getTextClassifier()); 61 } 62 63 // TODO: add support for local specific formatting 64 @Override classifyText( CharSequence text, int start, int end, LocaleList localeList)65 public TextClassification classifyText( 66 CharSequence text, int start, int end, LocaleList localeList) { 67 68 CharSequence sequence = text.subSequence(start, end); 69 if (isGeoSequence(sequence)) { 70 71 Intent intent = new Intent(Intent.ACTION_VIEW) 72 .setData(Uri.parse(String.format("geo:0,0?q=%s", sequence))); 73 74 final ResolveInfo info = mPackageManager.resolveActivity(intent, 0); 75 if (info != null) { 76 77 return new TextClassification.Builder() 78 .setText(sequence.toString()) 79 .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f) 80 .setIcon(info.loadIcon(mPackageManager)) 81 .setLabel(info.loadLabel(mPackageManager).toString()) 82 .setIntent(intent) 83 .build(); 84 } 85 } 86 87 // return default if text was not latitude, longitude or we couldn't find an application 88 // to handle the geo intent. 89 return mSystemClassifier.classifyText(text, start, end, localeList); 90 } 91 92 @Override suggestSelection( CharSequence context, int start, int end, LocaleList localeList)93 public TextSelection suggestSelection( 94 CharSequence context, int start, int end, LocaleList localeList) { 95 96 // Show map action menu popup when entire TextView is selected. 97 final int[] boundaries = {0, context.length()}; 98 99 if (boundaries != null) { 100 return new TextSelection.Builder(boundaries[0], boundaries[1]) 101 .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f) 102 .build(); 103 } 104 return mSystemClassifier.suggestSelection(context, start, end, localeList); 105 } 106 isGeoSequence(CharSequence text)107 private static boolean isGeoSequence(CharSequence text) { 108 return sGeoPattern.matcher(text).matches(); 109 } 110 } 111