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