VoicemailContentProvider.java revision 9cf06e7bcb0be759f1c930412fd2e41eba4f5f03
152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee/*
252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * Copyright (C) 2011 The Android Open Source Project
352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee *
452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * Licensed under the Apache License, Version 2.0 (the "License");
552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * you may not use this file except in compliance with the License.
652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * You may obtain a copy of the License at
752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee *
852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee *      http://www.apache.org/licenses/LICENSE-2.0
952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee *
1052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * Unless required by applicable law or agreed to in writing, software
1152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * distributed under the License is distributed on an "AS IS" BASIS,
1252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * See the License for the specific language governing permissions and
1452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee * limitations under the License
1552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee */
1652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeepackage com.android.providers.contacts;
1752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
189cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport static android.provider.VoicemailContract.SOURCE_PACKAGE_FIELD;
199cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.concatenateClauses;
2052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
2152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
22975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjeeimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeeimport com.android.providers.contacts.util.SelectionBuilder;
24975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjeeimport com.android.providers.contacts.util.TypedUriMatcherImpl;
25975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee
2606f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjeeimport android.content.ComponentName;
2752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.ContentProvider;
2852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.ContentResolver;
2952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.ContentValues;
3052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.Context;
3152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.Intent;
3206f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjeeimport android.content.pm.ActivityInfo;
3342e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjeeimport android.content.pm.ResolveInfo;
3452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.database.Cursor;
3552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.net.Uri;
3652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.os.Binder;
3752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.os.ParcelFileDescriptor;
389cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport android.provider.BaseColumns;
3952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.provider.VoicemailContract;
4052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.provider.VoicemailContract.Voicemails;
4152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
4252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport java.io.FileNotFoundException;
43975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjeeimport java.util.ArrayList;
4452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport java.util.List;
4552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
4652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee/**
479cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * An implementation of the Voicemail content provider. This class in the entry point for both
489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * voicemail content ('calls') table and 'voicemail_status' table. This class performs all common
499cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * permission checks and then delegates database level operations to respective table delegate
509cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * objects.
5152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee */
524b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeepublic class VoicemailContentProvider extends ContentProvider
534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        implements VoicemailTable.DelegateHelper {
5452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    private static final String TAG = "VoicemailContentProvider";
5552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
5652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    private ContentResolver mContentResolver;
57aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private VoicemailPermissions mVoicemailPermissions;
584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private VoicemailTable.Delegate mVoicemailContentTable;
599cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private VoicemailTable.Delegate mVoicemailStatusTable;
6052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
6152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
6252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    public boolean onCreate() {
6352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        Context context = context();
6452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        mContentResolver = context.getContentResolver();
65aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        mVoicemailPermissions = new VoicemailPermissions(context);
669cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        mVoicemailContentTable = new VoicemailContentTable(Tables.CALLS, context,
679cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                getDatabaseHelper(context), this);
689cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        mVoicemailStatusTable = new VoicemailStatusTable(Tables.VOICEMAIL_STATUS, context,
694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getDatabaseHelper(context), this);
7052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return true;
7152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
7252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
731975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee    /*package for testing*/ ContactsDatabaseHelper getDatabaseHelper(Context context) {
741975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee        return ContactsDatabaseHelper.getInstance(context);
751975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee    }
761975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee
7752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /*package for testing*/ Context context() {
7852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return getContext();
7952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
8052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
8152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
8252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    public String getType(Uri uri) {
8352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        UriData uriData = null;
8452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        try {
854b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            uriData = UriData.createUriData(uri);
8652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        } catch (IllegalArgumentException ignored) {
8752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // Special case: for illegal URIs, we return null rather than thrown an exception.
8852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
8952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
909cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).getType(uriData);
9152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
9252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
9352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
944b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int bulkInsert(Uri uri, ContentValues[] valuesArray) {
959cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri, valuesArray);
969cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).bulkInsert(uriData, valuesArray);
9752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
9852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
9952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
1004b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Uri insert(Uri uri, ContentValues values) {
1019cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri, values);
1029cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).insert(uriData, values);
10352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
10452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
10552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
1064b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
1074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String sortOrder) {
1084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri);
1094b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        selectionBuilder.addClause(getPackageRestrictionClause());
1119cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).query(uriData, projection, selectionBuilder.build(),
1124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                selectionArgs, sortOrder);
11352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
11452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1179cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri, values);
1184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        selectionBuilder.addClause(getPackageRestrictionClause());
1209cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).update(uriData, values, selectionBuilder.build(),
1214b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                selectionArgs);
12252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
12352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int delete(Uri uri, String selection, String[] selectionArgs) {
1264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri);
1274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        selectionBuilder.addClause(getPackageRestrictionClause());
1299cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).delete(uriData, selectionBuilder.build(), selectionArgs);
13052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
13152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
1344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri);
1354b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // openFileHelper() relies on "_data" column to be populated with the file path.
1369cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).openFile(uriData, mode);
1379cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
1389cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
1399cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /** Returns the correct table delegate object that can handle this URI. */
1409cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private VoicemailTable.Delegate getTableDelegate(UriData uriData) {
1419cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        switch (uriData.getUriType()) {
1429cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case STATUS:
1439cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case STATUS_ID:
1449cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                return mVoicemailStatusTable;
1459cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case VOICEMAILS:
1469cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case VOICEMAILS_ID:
1479cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                return mVoicemailContentTable;
1489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case NO_MATCH:
1499cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new IllegalStateException("Invalid uri type for uri: " + uriData.getUri());
1509cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            default:
1519cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new IllegalStateException("Impossible, all cases are covered.");
1529cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
15352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
15452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
15552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
1564b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * Decorates a URI by providing methods to get various properties from the URI.
15752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
1584b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public static class UriData {
1594b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final Uri mUri;
1604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final String mId;
1614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final String mSourcePackage;
1629cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        private final VoicemailUriType mUriType;
16352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1649cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public UriData(Uri uri, VoicemailUriType uriType, String id, String sourcePackage) {
1659cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            mUriType = uriType;
1664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mUri = uri;
1674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mId = id;
1684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mSourcePackage = sourcePackage;
16952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
17052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the original URI to which this {@link UriData} corresponds. */
1724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final Uri getUri() {
1734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mUri;
17452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
17552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1764b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Tells us if our URI has an individual voicemail id. */
1774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final boolean hasId() {
1784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mId != null;
17952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
18052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1814b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the ID for the voicemail. */
1824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final String getId() {
1834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mId;
18452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
18552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1864b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Tells us if our URI has a source package string. */
1874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final boolean hasSourcePackage() {
1884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mSourcePackage != null;
18952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
19052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1914b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the source package. */
1924b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final String getSourcePackage() {
1934b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mSourcePackage;
19452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
19552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1969cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        /** Gets the Voicemail URI type. */
1979cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public final VoicemailUriType getUriType() {
1989cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return mUriType;
1999cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2009cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2019cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        /** Builds a where clause from the URI data. */
2029cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public final String getWhereClause() {
2039cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return concatenateClauses(
2049cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    (hasId() ? getEqualityClause(BaseColumns._ID, getId()) : null),
2059cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    (hasSourcePackage() ? getEqualityClause(SOURCE_PACKAGE_FIELD,
2069cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                            getSourcePackage()) : null));
2079cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2089cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2094b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Create a {@link UriData} corresponding to a given uri. */
2104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public static UriData createUriData(Uri uri) {
2114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String sourcePackage = uri.getQueryParameter(
2124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    VoicemailContract.PARAM_KEY_SOURCE_PACKAGE);
2134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            List<String> segments = uri.getPathSegments();
2149cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            VoicemailUriType uriType = createUriMatcher().match(uri);
2159cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            switch (uriType) {
2164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case VOICEMAILS:
2179cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                case STATUS:
2189cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    return new UriData(uri, uriType, null, sourcePackage);
2194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case VOICEMAILS_ID:
2209cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                case STATUS_ID:
2219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    return new UriData(uri, uriType, segments.get(1), sourcePackage);
2224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case NO_MATCH:
2234b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    throw new IllegalArgumentException("Invalid URI: " + uri);
2244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                default:
2254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    throw new IllegalStateException("Impossible, all cases are covered");
2264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            }
2274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2289cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2299cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        private static TypedUriMatcherImpl<VoicemailUriType> createUriMatcher() {
2309cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return new TypedUriMatcherImpl<VoicemailUriType>(
2319cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    VoicemailContract.AUTHORITY, VoicemailUriType.values());
2329cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
23352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
23452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
2354b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2364b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    // VoicemailTable.DelegateHelper interface.
2374b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public void notifyChange(Uri notificationUri, String... intentActions) {
23852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // Notify the observers.
23952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        mContentResolver.notifyChange(notificationUri, null, true);
24042e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjee        String callingPackage = getCallingPackage();
24152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // Fire notification intents.
24252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        for (String intentAction : intentActions) {
24352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // TODO: We can possibly be more intelligent here and send targeted intents based on
24452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // what voicemail permission the package has. If possible, here is what we would like to
24552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // do for a given broadcast intent -
24652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // 1) Send it to all packages that have READ_WRITE_ALL_VOICEMAIL permission.
24752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // 2) Send it to only the owner package that has just READ_WRITE_OWN_VOICEMAIL, if not
24852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // already sent in (1).
24906f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjee            for (ComponentName component :
25006f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjee                    getBroadcastReceiverComponents(intentAction, notificationUri)) {
25142e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjee                Intent intent = new Intent(intentAction, notificationUri);
25206f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjee                intent.setComponent(component);
25342e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjee                intent.putExtra(VoicemailContract.EXTRA_SELF_CHANGE,
25406f995b614e0ebe59ff75f170e20ca96c9b17f0cDebashish Chatterjee                        callingPackage.equals(component.getPackageName()));
25542e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjee                context().sendBroadcast(intent, Manifest.permission.READ_WRITE_OWN_VOICEMAIL);
25642e8dddb940a502e97151a08f16b87aed7b30de5Debashish Chatterjee            }
25752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
25852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
25952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
2604b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2614b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    // VoicemailTable.DelegateHelper interface.
2624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public void checkAndAddSourcePackageIntoValues(UriData uriData, ContentValues values) {
2634b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // If content values don't contain the provider, calculate the right provider to use.
2649cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (!values.containsKey(SOURCE_PACKAGE_FIELD)) {
2654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String provider = uriData.hasSourcePackage() ?
2664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getSourcePackage() : getCallingPackage();
2679cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            values.put(SOURCE_PACKAGE_FIELD, provider);
2684b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2694b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // You must have access to the provider given in values.
2704b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        if (!mVoicemailPermissions.callerHasFullAccess()) {
2714b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            checkPackagesMatch(getCallingPackage(),
2724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD),
2734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getUri());
274975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee        }
275975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee    }
276975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee
2779cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /**
2789cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * Checks that the source_package field is same in uriData and ContentValues, if it happens
2799cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * to be set in both.
2809cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     */
2819cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private void checkSourcePackageSameIfSet(UriData uriData, ContentValues values) {
2829cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (uriData.hasSourcePackage() && values.containsKey(SOURCE_PACKAGE_FIELD)) {
2839cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            if (!uriData.getSourcePackage().equals(values.get(SOURCE_PACKAGE_FIELD))) {
2849cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new SecurityException(
2859cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        "source_package in URI was " + uriData.getSourcePackage() +
2869cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        " but doesn't match source_package in ContentValues which was "
2879cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        + values.get(SOURCE_PACKAGE_FIELD));
2889cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            }
2899cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2909cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
2919cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2929cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    @Override
2939cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /** Implementation of  {@link VoicemailTable.DelegateHelper#openDataFile(UriData, String)} */
2949cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    public ParcelFileDescriptor openDataFile(UriData uriData, String mode)
2959cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            throws FileNotFoundException {
2969cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return openFileHelper(uriData.getUri(), mode);
29752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
29852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
29952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
3004b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * Performs necessary voicemail permission checks common to all operations and returns
3014b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * the structured representation, {@link UriData}, of the supplied uri.
30252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
3034b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private UriData checkPermissionsAndCreateUriData(Uri uri) {
3044b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        mVoicemailPermissions.checkCallerHasOwnVoicemailAccess();
3054b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        UriData uriData = UriData.createUriData(uri);
3064b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        checkPackagePermission(uriData);
3074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return uriData;
3084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
30952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
3104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /**
3119cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * Same as {@link #checkPackagePermission(UriData)}. In addition does permission check
3129cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * on the ContentValues.
3139cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     */
3149cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private UriData checkPermissionsAndCreateUriData(Uri uri, ContentValues... valuesArray) {
3159cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        UriData uriData = checkPermissionsAndCreateUriData(uri);
3169cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        for (ContentValues values : valuesArray) {
3179cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            checkSourcePackageSameIfSet(uriData, values);
3189cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
3199cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return uriData;
3209cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
3219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
3229cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /**
3239cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * Checks that the callingPackage is same as voicemailSourcePackage. Throws {@link
3244b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * SecurityException} if they don't match.
3254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     */
3269cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private final void checkPackagesMatch(String callingPackage, String voicemailSourcePackage,
3274b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            Uri uri) {
3289cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (!voicemailSourcePackage.equals(callingPackage)) {
3294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String errorMsg = String.format("Permission denied for URI: %s\n. " +
3309cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    "Package %s cannot perform this operation for %s. Requires %s permission.",
3319cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    uri, callingPackage, voicemailSourcePackage,
3324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    Manifest.permission.READ_WRITE_ALL_VOICEMAIL);
3334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new SecurityException(errorMsg);
33452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
33552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
33652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
33752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
33852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * Checks that either the caller has READ_WRITE_ALL_VOICEMAIL permission, or has the
33952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * READ_WRITE_OWN_VOICEMAIL permission and is using a URI that matches
3409cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * /voicemail/?source_package=[source-package] where [source-package] is the same as the calling
34152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * package.
34252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     *
34352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * @throws SecurityException if the check fails.
34452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
34552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    private void checkPackagePermission(UriData uriData) {
346aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (!mVoicemailPermissions.callerHasFullAccess()) {
34752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            if (!uriData.hasSourcePackage()) {
3489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                // You cannot have a match if this is not a provider URI.
34952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                throw new SecurityException(String.format(
35052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                        "Provider %s does not have %s permission." +
3514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                                "\nPlease set query parameter '%s' in the URI.\nURI: %s",
35252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                        getCallingPackage(), Manifest.permission.READ_WRITE_ALL_VOICEMAIL,
3534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                        VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, uriData.getUri()));
35452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
35552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            checkPackagesMatch(getCallingPackage(), uriData.getSourcePackage(), uriData.getUri());
35652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
35752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
35852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
35952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
36052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * Gets the name of the calling package.
36152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * <p>
36252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * It's possible (though unlikely) for there to be more than one calling package (requires that
36352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * your manifest say you want to share process ids) in which case we will return an arbitrary
36452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * package name. It's also possible (though very unlikely) for us to be unable to work out what
36552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * your calling package is, in which case we will return null.
36652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
36752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /* package for test */String getCallingPackage() {
36852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        int caller = Binder.getCallingUid();
36952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (caller == 0) {
37052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
37152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
37252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        String[] callerPackages = context().getPackageManager().getPackagesForUid(caller);
37352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (callerPackages == null || callerPackages.length == 0) {
37452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
37552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
37652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (callerPackages.length == 1) {
37752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return callerPackages[0];
37852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
37952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // If we have more than one caller package, which is very unlikely, let's return the one
38052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // with the highest permissions. If more than one has the same permission, we don't care
38152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // which one we return.
38252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        String bestSoFar = callerPackages[0];
38352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        for (String callerPackage : callerPackages) {
384aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            if (mVoicemailPermissions.packageHasFullAccess(callerPackage)) {
38552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                // Full always wins, we can return early.
38652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                return callerPackage;
38752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
388aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            if (mVoicemailPermissions.packageHasOwnVoicemailAccess(callerPackage)) {
38952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                bestSoFar = callerPackage;
39052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
39152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
39252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return bestSoFar;
39352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
39452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
39552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
39652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * Creates a clause to restrict the selection to the calling provider or null if the caller has
39752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * access to all data.
39852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
39952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    private String getPackageRestrictionClause() {
400aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (mVoicemailPermissions.callerHasFullAccess()) {
40152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
40252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
40352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return getEqualityClause(Voicemails.SOURCE_PACKAGE, getCallingPackage());
40452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
40552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
4064b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /** Determines the components that can possibly receive the specified intent. */
4074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    protected List<ComponentName> getBroadcastReceiverComponents(String intentAction, Uri uri) {
4084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        Intent intent = new Intent(intentAction, uri);
4094b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        List<ComponentName> receiverComponents = new ArrayList<ComponentName>();
4104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // For broadcast receivers ResolveInfo.activityInfo is the one that is populated.
4114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        for (ResolveInfo resolveInfo :
4124b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                context().getPackageManager().queryBroadcastReceivers(intent, 0)) {
4134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            ActivityInfo activityInfo = resolveInfo.activityInfo;
4144b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            receiverComponents.add(new ComponentName(activityInfo.packageName, activityInfo.name));
4154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
4164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return receiverComponents;
41752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
41852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee}
419