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 */ 16 17package com.android.providers.contacts; 18 19import static com.android.providers.contacts.util.DbQueryUtils.concatenateClauses; 20 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Context; 24import android.database.Cursor; 25import android.database.sqlite.SQLiteDatabase; 26import android.database.sqlite.SQLiteQueryBuilder; 27import android.net.Uri; 28import android.os.ParcelFileDescriptor; 29import android.provider.VoicemailContract.Status; 30import com.android.common.content.ProjectionMap; 31import com.android.providers.contacts.VoicemailContentProvider.UriData; 32 33/** 34 * Implementation of {@link VoicemailTable.Delegate} for the voicemail status table. 35 * 36 * Public methods of this class are thread-safe as it is used in a content provider, which should 37 * be thread-safe. 38 */ 39public class VoicemailStatusTable implements VoicemailTable.Delegate { 40 41 private static final ProjectionMap sStatusProjectionMap = new ProjectionMap.Builder() 42 .add(Status._ID) 43 .add(Status.PHONE_ACCOUNT_COMPONENT_NAME) 44 .add(Status.PHONE_ACCOUNT_ID) 45 .add(Status.CONFIGURATION_STATE) 46 .add(Status.DATA_CHANNEL_STATE) 47 .add(Status.NOTIFICATION_CHANNEL_STATE) 48 .add(Status.SETTINGS_URI) 49 .add(Status.SOURCE_PACKAGE) 50 .add(Status.VOICEMAIL_ACCESS_URI) 51 .add(Status.QUOTA_OCCUPIED) 52 .add(Status.QUOTA_TOTAL) 53 .add(Status.SOURCE_TYPE) 54 .build(); 55 56 private static final Object DATABASE_LOCK = new Object(); 57 58 private final String mTableName; 59 private final Context mContext; 60 private final CallLogDatabaseHelper mDbHelper; 61 private final VoicemailTable.DelegateHelper mDelegateHelper; 62 63 public VoicemailStatusTable(String tableName, Context context, CallLogDatabaseHelper dbHelper, 64 VoicemailTable.DelegateHelper delegateHelper) { 65 mTableName = tableName; 66 mContext = context; 67 mDbHelper = dbHelper; 68 mDelegateHelper = delegateHelper; 69 } 70 71 @Override 72 public Uri insert(UriData uriData, ContentValues values) { 73 synchronized (DATABASE_LOCK) { 74 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 75 // Try to update before insert. 76 String combinedClause = uriData.getWhereClause(); 77 int rowsChanged = getDatabaseModifier(db) 78 .update(uriData.getUri(), mTableName, values, combinedClause, null); 79 if (rowsChanged != 0) { 80 final String[] selection = new String[] {Status._ID}; 81 Cursor c = db.query(mTableName, selection, combinedClause, null, null, null, null); 82 c.moveToFirst(); 83 int rowId = c.getInt(0); 84 c.close(); 85 return ContentUris.withAppendedId(uriData.getUri(), rowId); 86 } 87 ContentValues copiedValues = new ContentValues(values); 88 mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues); 89 long rowId = getDatabaseModifier(db).insert(mTableName, null, copiedValues); 90 if (rowId > 0) { 91 return ContentUris.withAppendedId(uriData.getUri(), rowId); 92 } else { 93 return null; 94 } 95 } 96 } 97 98 @Override 99 public int delete(UriData uriData, String selection, String[] selectionArgs) { 100 synchronized (DATABASE_LOCK) { 101 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 102 String combinedClause = concatenateClauses(selection, uriData.getWhereClause()); 103 return getDatabaseModifier(db).delete(mTableName, combinedClause, 104 selectionArgs); 105 } 106 } 107 108 @Override 109 public Cursor query(UriData uriData, String[] projection, String selection, 110 String[] selectionArgs, String sortOrder) { 111 synchronized (DATABASE_LOCK) { 112 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 113 qb.setTables(mTableName); 114 qb.setProjectionMap(sStatusProjectionMap); 115 qb.setStrict(true); 116 117 String combinedClause = concatenateClauses(selection, uriData.getWhereClause()); 118 SQLiteDatabase db = mDbHelper.getReadableDatabase(); 119 Cursor c = qb 120 .query(db, projection, combinedClause, selectionArgs, null, null, sortOrder); 121 if (c != null) { 122 c.setNotificationUri(mContext.getContentResolver(), Status.CONTENT_URI); 123 } 124 return c; 125 } 126 } 127 128 @Override 129 public int update(UriData uriData, ContentValues values, String selection, 130 String[] selectionArgs) { 131 synchronized (DATABASE_LOCK) { 132 SQLiteDatabase db = mDbHelper.getWritableDatabase(); 133 String combinedClause = concatenateClauses(selection, uriData.getWhereClause()); 134 return getDatabaseModifier(db) 135 .update(uriData.getUri(), mTableName, values, combinedClause, selectionArgs); 136 } 137 } 138 139 @Override 140 public String getType(UriData uriData) { 141 if (uriData.hasId()) { 142 return Status.ITEM_TYPE; 143 } else { 144 return Status.DIR_TYPE; 145 } 146 } 147 148 @Override 149 public ParcelFileDescriptor openFile(UriData uriData, String mode) { 150 throw new UnsupportedOperationException("File operation is not supported for status table"); 151 } 152 153 private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) { 154 return new DbModifierWithNotification(mTableName, db, mContext); 155 } 156} 157