17949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton/* 27949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * Copyright (C) 2010 The Android Open Source Project 37949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * 47949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 57949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * you may not use this file except in compliance with the License. 67949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * You may obtain a copy of the License at 77949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * 87949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 97949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * 107949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * Unless required by applicable law or agreed to in writing, software 117949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 127949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * See the License for the specific language governing permissions and 147949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * limitations under the License. 157949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton */ 167949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 177949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonpackage com.android.apps.tag.record; 187949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 197949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport com.android.apps.tag.R; 20fc8fc43fded621674d99952dcdf95c8a4ded5391Nick Kralevichimport com.google.common.annotations.VisibleForTesting; 217949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport com.google.common.base.Preconditions; 227949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport com.google.common.collect.BiMap; 237949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport com.google.common.collect.ImmutableBiMap; 247949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport com.google.common.primitives.Bytes; 257949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 26f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamotoimport android.Manifest; 277949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.app.Activity; 283f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamiltonimport android.content.ActivityNotFoundException; 297949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.content.Context; 307949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.content.Intent; 31871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.content.pm.PackageManager; 32871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.content.pm.ResolveInfo; 337949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.net.Uri; 347949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.nfc.NdefRecord; 35871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.os.Parcel; 36871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.os.Parcelable; 37c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoiimport android.support.v4.app.ActivityCompat; 387949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.telephony.PhoneNumberUtils; 3958fbc09c19d87b6463bb68f74eefc43af1c13dbfJeff Hamiltonimport android.text.TextUtils; 403f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamiltonimport android.util.Log; 417949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.view.LayoutInflater; 427949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.view.View; 437949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.view.View.OnClickListener; 447949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport android.view.ViewGroup; 45871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.widget.ImageView; 46871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport android.widget.TextView; 47c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoiimport android.widget.Toast; 487949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 49f34e4d5ec99fd7883bbfcdc0f644d9d6e4df6c97Jeff Hamiltonimport java.nio.charset.Charset; 507949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamiltonimport java.util.Arrays; 51871419825f5318836faa4926824d03a2ad8912e6Ben Komaloimport java.util.List; 52a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parksimport java.util.Locale; 537949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 547949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton/** 557949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * A parsed record containing a Uri. 567949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton */ 5740d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parkspublic class UriRecord extends ParsedNdefRecord implements OnClickListener { 583f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton private static final String TAG = "UriRecord"; 593f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton 60871419825f5318836faa4926824d03a2ad8912e6Ben Komalo public static final String RECORD_TYPE = "UriRecord"; 61c6acde24bc12c39c8d952b3ac20639c27c15d504Jeff Hamilton 627949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton private final Uri mUri; 637949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 64871419825f5318836faa4926824d03a2ad8912e6Ben Komalo private UriRecord(Uri uri) { 657949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton this.mUri = Preconditions.checkNotNull(uri); 667949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 677949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 687949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public Intent getIntentForUri() { 697949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton String scheme = mUri.getScheme(); 707949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton if ("tel".equals(scheme)) { 717949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return new Intent(Intent.ACTION_CALL, mUri); 727949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } else if ("sms".equals(scheme) || "smsto".equals(scheme)) { 737949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return new Intent(Intent.ACTION_SENDTO, mUri); 747949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } else { 757949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return new Intent(Intent.ACTION_VIEW, mUri); 767949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 777949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 787949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 797949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public String getPrettyUriString(Context context) { 807949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton String scheme = mUri.getScheme(); 817949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton boolean tel = "tel".equals(scheme); 82c6acde24bc12c39c8d952b3ac20639c27c15d504Jeff Hamilton boolean sms = "sms".equals(scheme) || "smsto".equals(scheme); 837949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton if (tel || sms) { 847949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton String ssp = mUri.getSchemeSpecificPart(); 857949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton int offset = ssp.indexOf('?'); 867949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton if (offset >= 0) { 877949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton ssp = ssp.substring(0, offset); 887949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 897949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton if (tel) { 907949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return context.getString(R.string.action_call, PhoneNumberUtils.formatNumber(ssp)); 917949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } else { 927949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return context.getString(R.string.action_text, PhoneNumberUtils.formatNumber(ssp)); 937949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 947949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } else { 957949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return mUri.toString(); 967949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 977949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 987949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 997949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton @Override 10040d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent, int offset) { 1013da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton return RecordUtils.getViewsForIntent(activity, inflater, parent, this, getIntentForUri(), 1023da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton getPrettyUriString(activity)); 1037949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 1047949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 1057949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton @Override 106a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks public String getSnippet(Context context, Locale locale) { 107a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks return getPrettyUriString(context); 108a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks } 109a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks 110a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks @Override 1117949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public void onClick(View view) { 1123da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton RecordUtils.ClickInfo info = (RecordUtils.ClickInfo) view.getTag(); 113f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto if (requestPermissionIfNeeded(info.activity, info.intent)) { 114f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto return; 115f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto } 1163f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton try { 1173f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton info.activity.startActivity(info.intent); 1183f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton info.activity.finish(); 1193f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton } catch (ActivityNotFoundException e) { 1203f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton // The activity wansn't found for some reason. Don't crash, but don't do anything. 1213f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton Log.e(TAG, "Failed to launch activity for intent " + info.intent, e); 1223f68a15cb124e5d37fbf81c57537722b5f29e9afJeff Hamilton } 1237949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 1247949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 125fc8fc43fded621674d99952dcdf95c8a4ded5391Nick Kralevich @VisibleForTesting 1267949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public Uri getUri() { 1277949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton return mUri; 1287949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 1297949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 1307949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton /** 131c6acde24bc12c39c8d952b3ac20639c27c15d504Jeff Hamilton * Convert {@link android.nfc.NdefRecord} into a {@link android.net.Uri}. This will handle 132871419825f5318836faa4926824d03a2ad8912e6Ben Komalo * both TNF_WELL_KNOWN / RTD_URI and TNF_ABSOLUTE_URI. 1337949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * 1347949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * @throws IllegalArgumentException if the NdefRecord is not a 1357949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton * record containing a URI. 1367949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton */ 1377949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public static UriRecord parse(NdefRecord record) { 138116871653662979554a7326991ba4fd599ac44ffNick Pelly Uri uri = record.toUri(); 139116871653662979554a7326991ba4fd599ac44ffNick Pelly if (uri == null) throw new IllegalArgumentException("not a uri"); 14040d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks return new UriRecord(uri); 1417949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 1427949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton 1437949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton public static boolean isUri(NdefRecord record) { 144116871653662979554a7326991ba4fd599ac44ffNick Pelly return record.toUri() != null; 1457949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton } 146871419825f5318836faa4926824d03a2ad8912e6Ben Komalo 1470c2e44c08ba39fe69b28830137726fa99de017d9Nick Kralevich /** 1480c2e44c08ba39fe69b28830137726fa99de017d9Nick Kralevich * Convert a {@link Uri} to an {@link NdefRecord} 1490c2e44c08ba39fe69b28830137726fa99de017d9Nick Kralevich */ 1500c2e44c08ba39fe69b28830137726fa99de017d9Nick Kralevich public static NdefRecord newUriRecord(Uri uri) { 151116871653662979554a7326991ba4fd599ac44ffNick Pelly return NdefRecord.createUri(uri); 1520c2e44c08ba39fe69b28830137726fa99de017d9Nick Kralevich } 153f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto 154f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto private boolean requestPermissionIfNeeded(Activity activity, Intent intent) { 155f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto boolean needRequestPermission = false; 156f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto if (Intent.ACTION_CALL.equals(intent.getAction())) { 157f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto if (activity.checkSelfPermission(Manifest.permission.CALL_PHONE) 158f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto != PackageManager.PERMISSION_GRANTED) { 159c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoi /* In case the user selected "Do not ask" for permission again. 160c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoi * Display a message on how to change the permission selection. */ 161c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoi if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CALL_PHONE)) 162c4367c0239d4a543a285df92f8841544781d4362Ruchi Kandoi Toast.makeText(activity.getApplicationContext(), R.string.call_phone_permission_denied, Toast.LENGTH_SHORT).show(); 163f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto needRequestPermission = true; 164f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto activity.requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, 1); 165f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto } 166f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto } 167f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto return needRequestPermission; 168f7cc37621baaeb37e79837d6df22e4f3496792d0Hiroki Yamamoto } 1697949534630e1b14cf73a6ad3c0606ec5be2c480cJeff Hamilton} 170