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
2252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.ContentProvider;
2352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.ContentValues;
2452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.content.Context;
25eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjeeimport android.content.Intent;
26eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjeeimport android.content.pm.PackageManager;
2752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.database.Cursor;
2852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.net.Uri;
2952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.os.Binder;
3052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.os.ParcelFileDescriptor;
319cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjeeimport android.provider.BaseColumns;
3252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.provider.VoicemailContract;
3352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport android.provider.VoicemailContract.Voicemails;
34663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onukiimport android.util.Log;
3552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
3638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
3738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.SelectionBuilder;
3838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.TypedUriMatcherImpl;
3938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.common.annotations.VisibleForTesting;
4038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki
4152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport java.io.FileNotFoundException;
4252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjeeimport java.util.List;
4352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
4452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee/**
459cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * An implementation of the Voicemail content provider. This class in the entry point for both
469cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * voicemail content ('calls') table and 'voicemail_status' table. This class performs all common
479cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * permission checks and then delegates database level operations to respective table delegate
489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee * objects.
4952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee */
504b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjeepublic class VoicemailContentProvider extends ContentProvider
514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        implements VoicemailTable.DelegateHelper {
52aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private VoicemailPermissions mVoicemailPermissions;
534b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    private VoicemailTable.Delegate mVoicemailContentTable;
549cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private VoicemailTable.Delegate mVoicemailStatusTable;
5552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
5652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
5752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    public boolean onCreate() {
58663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
59663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki            Log.d(Constants.PERFORMANCE_TAG, "VoicemailContentProvider.onCreate start");
60663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
6152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        Context context = context();
62aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        mVoicemailPermissions = new VoicemailPermissions(context);
639cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        mVoicemailContentTable = new VoicemailContentTable(Tables.CALLS, context,
64aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda                getDatabaseHelper(context), this, createCallLogInsertionHelper(context));
659cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        mVoicemailStatusTable = new VoicemailStatusTable(Tables.VOICEMAIL_STATUS, context,
664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                getDatabaseHelper(context), this);
67663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
68663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki            Log.d(Constants.PERFORMANCE_TAG, "VoicemailContentProvider.onCreate finish");
69663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
7052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return true;
7152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
7252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
73aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
74aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    /*package*/ CallLogInsertionHelper createCallLogInsertionHelper(Context context) {
75c4144727cd740079f47e74ae5078d1613874f72aMakoto Onuki        return DefaultCallLogInsertionHelper.getInstance(context);
76aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    }
77aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda
78aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
79aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    /*package*/ ContactsDatabaseHelper getDatabaseHelper(Context context) {
801975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee        return ContactsDatabaseHelper.getInstance(context);
811975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee    }
821975b56a3368b4b7684429ffa79e7b9dbc35b475Debashish Chatterjee
83aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
84aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    /*package*/ Context context() {
8552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return getContext();
8652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
8752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
8852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
8952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    public String getType(Uri uri) {
9052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        UriData uriData = null;
9152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        try {
924b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            uriData = UriData.createUriData(uri);
9352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        } catch (IllegalArgumentException ignored) {
9452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            // Special case: for illegal URIs, we return null rather than thrown an exception.
9552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
9652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
979cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).getType(uriData);
9852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
9952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
10052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
1014b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Uri insert(Uri uri, ContentValues values) {
102ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values);
1039cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).insert(uriData, values);
10452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
10552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
10652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    @Override
1074b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
1084b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String sortOrder) {
109ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        UriData uriData = checkPermissionsAndCreateUriDataForRead(uri);
1104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1113ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        selectionBuilder.addClause(getPackageRestrictionClause(true/*isQuery*/));
1129cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).query(uriData, projection, selectionBuilder.build(),
1134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                selectionArgs, sortOrder);
11452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
11552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
118ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values);
1194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1203ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        selectionBuilder.addClause(getPackageRestrictionClause(false/*isQuery*/));
1219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).update(uriData, values, selectionBuilder.build(),
1224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                selectionArgs);
12352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
12452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1264b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public int delete(Uri uri, String selection, String[] selectionArgs) {
127ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri);
1284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
1293ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        selectionBuilder.addClause(getPackageRestrictionClause(false/*isQuery*/));
1309cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).delete(uriData, selectionBuilder.build(), selectionArgs);
13152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
13252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
1344b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
135eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        UriData uriData = null;
136eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        if (mode.equals("r")) {
137ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            uriData = checkPermissionsAndCreateUriDataForRead(uri);
138eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        } else {
139ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            uriData = checkPermissionsAndCreateUriDataForWrite(uri);
140eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
1414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // openFileHelper() relies on "_data" column to be populated with the file path.
1429cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return getTableDelegate(uriData).openFile(uriData, mode);
1439cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
1449cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
1459cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /** Returns the correct table delegate object that can handle this URI. */
1469cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private VoicemailTable.Delegate getTableDelegate(UriData uriData) {
1479cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        switch (uriData.getUriType()) {
1489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case STATUS:
1499cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case STATUS_ID:
1509cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                return mVoicemailStatusTable;
1519cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case VOICEMAILS:
1529cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case VOICEMAILS_ID:
1539cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                return mVoicemailContentTable;
1549cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            case NO_MATCH:
1559cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new IllegalStateException("Invalid uri type for uri: " + uriData.getUri());
1569cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            default:
1579cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new IllegalStateException("Impossible, all cases are covered.");
1589cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
15952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
16052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
16152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
1624b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * Decorates a URI by providing methods to get various properties from the URI.
16352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
1644b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public static class UriData {
1654b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final Uri mUri;
1664b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final String mId;
1674b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        private final String mSourcePackage;
1689cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        private final VoicemailUriType mUriType;
16952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1709cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public UriData(Uri uri, VoicemailUriType uriType, String id, String sourcePackage) {
1719cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            mUriType = uriType;
1724b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mUri = uri;
1734b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mId = id;
1744b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            mSourcePackage = sourcePackage;
17552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
17652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1774b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the original URI to which this {@link UriData} corresponds. */
1784b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final Uri getUri() {
1794b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mUri;
18052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
18152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1824b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Tells us if our URI has an individual voicemail id. */
1834b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final boolean hasId() {
1844b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mId != null;
18552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
18652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1874b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the ID for the voicemail. */
1884b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final String getId() {
1894b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mId;
19052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
19152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1924b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Tells us if our URI has a source package string. */
1934b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final boolean hasSourcePackage() {
1944b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mSourcePackage != null;
19552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
19652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
1974b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Gets the source package. */
1984b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public final String getSourcePackage() {
1994b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            return mSourcePackage;
20052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
20152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
2029cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        /** Gets the Voicemail URI type. */
2039cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public final VoicemailUriType getUriType() {
2049cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return mUriType;
2059cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2069cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2079cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        /** Builds a where clause from the URI data. */
2089cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        public final String getWhereClause() {
2099cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return concatenateClauses(
2109cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    (hasId() ? getEqualityClause(BaseColumns._ID, getId()) : null),
2119cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    (hasSourcePackage() ? getEqualityClause(SOURCE_PACKAGE_FIELD,
2129cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                            getSourcePackage()) : null));
2139cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2149cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2154b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        /** Create a {@link UriData} corresponding to a given uri. */
2164b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        public static UriData createUriData(Uri uri) {
2174b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String sourcePackage = uri.getQueryParameter(
2184b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    VoicemailContract.PARAM_KEY_SOURCE_PACKAGE);
2194b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            List<String> segments = uri.getPathSegments();
2209cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            VoicemailUriType uriType = createUriMatcher().match(uri);
2219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            switch (uriType) {
2224b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case VOICEMAILS:
2239cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                case STATUS:
2249cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    return new UriData(uri, uriType, null, sourcePackage);
2254b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case VOICEMAILS_ID:
2269cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                case STATUS_ID:
2279cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    return new UriData(uri, uriType, segments.get(1), sourcePackage);
2284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                case NO_MATCH:
2294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    throw new IllegalArgumentException("Invalid URI: " + uri);
2304b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                default:
2314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    throw new IllegalStateException("Impossible, all cases are covered");
2324b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            }
2334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
2349cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2359cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        private static TypedUriMatcherImpl<VoicemailUriType> createUriMatcher() {
2369cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            return new TypedUriMatcherImpl<VoicemailUriType>(
2379cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    VoicemailContract.AUTHORITY, VoicemailUriType.values());
2389cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
23952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
24052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
2414b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    @Override
2424b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    // VoicemailTable.DelegateHelper interface.
2434b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    public void checkAndAddSourcePackageIntoValues(UriData uriData, ContentValues values) {
2444b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // If content values don't contain the provider, calculate the right provider to use.
2459cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (!values.containsKey(SOURCE_PACKAGE_FIELD)) {
2464b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String provider = uriData.hasSourcePackage() ?
24766d989c439fbb82a5b40a7efffa2f28208cf11d8Jeff Sharkey                    uriData.getSourcePackage() : getCallingPackage_();
2489cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            values.put(SOURCE_PACKAGE_FIELD, provider);
2494b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        }
250ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee
2514b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        // You must have access to the provider given in values.
2522ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee        if (!mVoicemailPermissions.callerHasWriteAccess()) {
25366d989c439fbb82a5b40a7efffa2f28208cf11d8Jeff Sharkey            checkPackagesMatch(getCallingPackage_(),
2544b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD),
2554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                    uriData.getUri());
256975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee        }
257975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee    }
258975d52af754e6f05089fcd9f7066df05c290c3b7Debashish Chatterjee
2599cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /**
2609cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * Checks that the source_package field is same in uriData and ContentValues, if it happens
2619cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * to be set in both.
2629cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     */
2639cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private void checkSourcePackageSameIfSet(UriData uriData, ContentValues values) {
2649cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (uriData.hasSourcePackage() && values.containsKey(SOURCE_PACKAGE_FIELD)) {
2659cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            if (!uriData.getSourcePackage().equals(values.get(SOURCE_PACKAGE_FIELD))) {
2669cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                throw new SecurityException(
2679cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        "source_package in URI was " + uriData.getSourcePackage() +
2689cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        " but doesn't match source_package in ContentValues which was "
2699cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                        + values.get(SOURCE_PACKAGE_FIELD));
2709cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            }
2719cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
2729cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
2739cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
2749cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    @Override
2759cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /** Implementation of  {@link VoicemailTable.DelegateHelper#openDataFile(UriData, String)} */
2769cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    public ParcelFileDescriptor openDataFile(UriData uriData, String mode)
2779cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            throws FileNotFoundException {
2789cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return openFileHelper(uriData.getUri(), mode);
27952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
28052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
28152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
282ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * Ensures that the caller has the permissions to perform a query/read operation, and
283ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * then returns the structured representation {@link UriData} of the supplied uri.
28452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
285ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    private UriData checkPermissionsAndCreateUriDataForRead(Uri uri) {
286eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        // If the caller has been explicitly granted read permission to this URI then no need to
287eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        // check further.
288eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        if (context().checkCallingUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
289eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                == PackageManager.PERMISSION_GRANTED) {
290eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            return UriData.createUriData(uri);
291eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
2923ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland
2932ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee        if (mVoicemailPermissions.callerHasReadAccess()) {
2943ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland            return UriData.createUriData(uri);
2953ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        }
2963ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland
297ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        return checkPermissionsAndCreateUriData(uri, true);
298eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
299eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
300eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    /**
301eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee     * Performs necessary voicemail permission checks common to all operations and returns
302eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee     * the structured representation, {@link UriData}, of the supplied uri.
303eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee     */
304ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    private UriData checkPermissionsAndCreateUriData(Uri uri, boolean read) {
3054b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        UriData uriData = UriData.createUriData(uri);
306ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        if (!hasReadWritePermission(read)) {
307ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            mVoicemailPermissions.checkCallerHasOwnVoicemailAccess();
308ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            checkPackagePermission(uriData);
309ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        }
3104b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee        return uriData;
3114b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    }
31252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
3134b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee    /**
314ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * Ensures that the caller has the permissions to perform an update/delete operation, and
315ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * then returns the structured representation {@link UriData} of the supplied uri.
316ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * Also does a permission check on the ContentValues.
3179cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     */
318ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    private UriData checkPermissionsAndCreateUriDataForWrite(Uri uri, ContentValues... valuesArray) {
319ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        UriData uriData = checkPermissionsAndCreateUriData(uri, false);
3209cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        for (ContentValues values : valuesArray) {
3219cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee            checkSourcePackageSameIfSet(uriData, values);
3229cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        }
3239cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        return uriData;
3249cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    }
3259cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee
3269cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    /**
3279cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * Checks that the callingPackage is same as voicemailSourcePackage. Throws {@link
3284b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     * SecurityException} if they don't match.
3294b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee     */
3309cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee    private final void checkPackagesMatch(String callingPackage, String voicemailSourcePackage,
3314b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            Uri uri) {
3329cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee        if (!voicemailSourcePackage.equals(callingPackage)) {
3334b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            String errorMsg = String.format("Permission denied for URI: %s\n. " +
3349cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    "Package %s cannot perform this operation for %s. Requires %s permission.",
3359cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                    uri, callingPackage, voicemailSourcePackage,
3362ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee                    android.Manifest.permission.WRITE_VOICEMAIL);
3374b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee            throw new SecurityException(errorMsg);
33852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
33952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
34052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
34152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
342ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * Checks that either the caller has the MANAGE_VOICEMAIL permission,
3433ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland     * or has the ADD_VOICEMAIL permission and is using a URI that matches
3449cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee     * /voicemail/?source_package=[source-package] where [source-package] is the same as the calling
34552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * package.
34652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     *
34752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * @throws SecurityException if the check fails.
34852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
34952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    private void checkPackagePermission(UriData uriData) {
3502ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee        if (!mVoicemailPermissions.callerHasWriteAccess()) {
35152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            if (!uriData.hasSourcePackage()) {
3529cf06e7bcb0be759f1c930412fd2e41eba4f5f03Debashish Chatterjee                // You cannot have a match if this is not a provider URI.
35352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                throw new SecurityException(String.format(
35452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                        "Provider %s does not have %s permission." +
3554b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                                "\nPlease set query parameter '%s' in the URI.\nURI: %s",
3562ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee                        getCallingPackage_(), android.Manifest.permission.WRITE_VOICEMAIL,
3574b571ba0de4fac4ff9d2a4277032b8c6548fdbfaDebashish Chatterjee                        VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, uriData.getUri()));
35852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
35966d989c439fbb82a5b40a7efffa2f28208cf11d8Jeff Sharkey            checkPackagesMatch(getCallingPackage_(), uriData.getSourcePackage(), uriData.getUri());
36052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
36152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
36252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
36352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
36452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * Gets the name of the calling package.
36552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * <p>
36652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * It's possible (though unlikely) for there to be more than one calling package (requires that
36752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * your manifest say you want to share process ids) in which case we will return an arbitrary
36852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * package name. It's also possible (though very unlikely) for us to be unable to work out what
36952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * your calling package is, in which case we will return null.
37052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
37166d989c439fbb82a5b40a7efffa2f28208cf11d8Jeff Sharkey    /* package for test */String getCallingPackage_() {
37252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        int caller = Binder.getCallingUid();
37352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (caller == 0) {
37452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
37552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
37652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        String[] callerPackages = context().getPackageManager().getPackagesForUid(caller);
37752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (callerPackages == null || callerPackages.length == 0) {
37852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
37952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
38052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        if (callerPackages.length == 1) {
38152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return callerPackages[0];
38252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
38352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // If we have more than one caller package, which is very unlikely, let's return the one
38452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // with the highest permissions. If more than one has the same permission, we don't care
38552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        // which one we return.
38652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        String bestSoFar = callerPackages[0];
38752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        for (String callerPackage : callerPackages) {
3882ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee            if (mVoicemailPermissions.packageHasWriteAccess(callerPackage)) {
38952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                // Full always wins, we can return early.
39052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                return callerPackage;
39152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
392aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            if (mVoicemailPermissions.packageHasOwnVoicemailAccess(callerPackage)) {
39352e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee                bestSoFar = callerPackage;
39452e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            }
39552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
39652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        return bestSoFar;
39752e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
39852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee
39952e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    /**
40052e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * Creates a clause to restrict the selection to the calling provider or null if the caller has
40152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     * access to all data.
40252e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee     */
4033ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland    private String getPackageRestrictionClause(boolean isQuery) {
404ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee        if (hasReadWritePermission(isQuery)) {
40552e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee            return null;
40652e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee        }
40766d989c439fbb82a5b40a7efffa2f28208cf11d8Jeff Sharkey        return getEqualityClause(Voicemails.SOURCE_PACKAGE, getCallingPackage_());
40852e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee    }
409ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee
410ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    /**
411ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * Whether or not the calling package has the appropriate read/write permission
412ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     *
413ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * @param read Whether or not this operation is a read
414ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     *
415ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     * @return True if the package has the permission required to perform the read/write operation
416ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee     */
417ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    private boolean hasReadWritePermission(boolean read) {
4182ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee        return read ? mVoicemailPermissions.callerHasReadAccess() :
4192ad39edbd856f3ea1177788aff7e653e593781ebYorke Lee            mVoicemailPermissions.callerHasWriteAccess();
420ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee    }
42152e8d24f8492116f0b49b147576ce13a5f913aa2Debashish Chatterjee}
422