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