1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16package com.android.providers.contacts; 17 18import android.content.ContentValues; 19import android.content.Context; 20import android.content.Intent; 21import android.content.res.AssetFileDescriptor; 22import android.database.Cursor; 23import android.database.sqlite.SQLiteDatabase; 24import android.net.Uri; 25import android.os.CancellationSignal; 26import android.provider.ContactsContract.Intents; 27 28import java.io.FileNotFoundException; 29import java.util.Locale; 30 31/** 32 * Simple content provider to handle directing profile-specific calls against a separate 33 * database from the rest of contacts. 34 */ 35public class ProfileProvider extends AbstractContactsProvider { 36 private static final String READ_PERMISSION = "android.permission.READ_PROFILE"; 37 private static final String WRITE_PERMISSION = "android.permission.WRITE_PROFILE"; 38 39 // The Contacts provider handles most of the logic - this provider is only invoked when the 40 // URI belongs to a profile action, setting up the proper database. 41 private final ContactsProvider2 mDelegate; 42 43 public ProfileProvider(ContactsProvider2 delegate) { 44 mDelegate = delegate; 45 } 46 47 /** 48 * Performs a permission check on the read profile permission. Checks the delegate contacts 49 * provider to see whether this is an authorized one-time-use URI. 50 * @param uri The URI being accessed. 51 */ 52 public void enforceReadPermission(Uri uri) { 53 if (!mDelegate.isValidPreAuthorizedUri(uri)) { 54 mDelegate.getContext().enforceCallingOrSelfPermission(READ_PERMISSION, null); 55 } 56 } 57 58 /** 59 * Performs a permission check on the write profile permission. 60 */ 61 public void enforceWritePermission() { 62 mDelegate.getContext().enforceCallingOrSelfPermission(WRITE_PERMISSION, null); 63 } 64 65 @Override 66 protected ProfileDatabaseHelper getDatabaseHelper(Context context) { 67 return ProfileDatabaseHelper.getInstance(context); 68 } 69 70 @Override 71 protected ThreadLocal<ContactsTransaction> getTransactionHolder() { 72 return mDelegate.getTransactionHolder(); 73 } 74 75 @Override 76 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 77 String sortOrder) { 78 return query(uri, projection, selection, selectionArgs, sortOrder, null); 79 } 80 81 @Override 82 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 83 String sortOrder, CancellationSignal cancellationSignal) { 84 enforceReadPermission(uri); 85 return mDelegate.queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, 86 cancellationSignal); 87 } 88 89 @Override 90 protected Uri insertInTransaction(Uri uri, ContentValues values) { 91 enforceWritePermission(); 92 useProfileDbForTransaction(); 93 return mDelegate.insertInTransaction(uri, values); 94 } 95 96 @Override 97 protected int updateInTransaction(Uri uri, ContentValues values, String selection, 98 String[] selectionArgs) { 99 enforceWritePermission(); 100 useProfileDbForTransaction(); 101 return mDelegate.updateInTransaction(uri, values, selection, selectionArgs); 102 } 103 104 @Override 105 protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 106 enforceWritePermission(); 107 useProfileDbForTransaction(); 108 return mDelegate.deleteInTransaction(uri, selection, selectionArgs); 109 } 110 111 @Override 112 public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 113 if (mode != null && mode.contains("w")) { 114 enforceWritePermission(); 115 } else { 116 enforceReadPermission(uri); 117 } 118 return mDelegate.openAssetFileLocal(uri, mode); 119 } 120 121 private void useProfileDbForTransaction() { 122 ContactsTransaction transaction = getCurrentTransaction(); 123 SQLiteDatabase db = getDatabaseHelper().getWritableDatabase(); 124 transaction.startTransactionForDb(db, ContactsProvider2.PROFILE_DB_TAG, this); 125 } 126 127 @Override 128 protected void notifyChange() { 129 mDelegate.notifyChange(); 130 } 131 132 protected void notifyChange(boolean syncToNetwork) { 133 mDelegate.notifyChange(syncToNetwork); 134 } 135 136 protected Locale getLocale() { 137 return mDelegate.getLocale(); 138 } 139 140 @Override 141 public void onBegin() { 142 mDelegate.onBeginTransactionInternal(true); 143 } 144 145 @Override 146 public void onCommit() { 147 mDelegate.onCommitTransactionInternal(true); 148 sendProfileChangedBroadcast(); 149 } 150 151 @Override 152 public void onRollback() { 153 mDelegate.onRollbackTransactionInternal(true); 154 } 155 156 @Override 157 protected boolean yield(ContactsTransaction transaction) { 158 return mDelegate.yield(transaction); 159 } 160 161 @Override 162 public String getType(Uri uri) { 163 return mDelegate.getType(uri); 164 } 165 166 /** Use only for debug logging */ 167 @Override 168 public String toString() { 169 return "ProfileProvider"; 170 } 171 172 private void sendProfileChangedBroadcast() { 173 final Intent intent = new Intent(Intents.ACTION_PROFILE_CHANGED); 174 getContext().sendBroadcast(intent, READ_PERMISSION); 175 } 176} 177