1 /* 2 * Copyright (C) 2017 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 17 package com.android.dialer.preferredsim.impl; 18 19 import android.Manifest.permission; 20 import android.content.ContentProvider; 21 import android.content.ContentValues; 22 import android.content.pm.PackageManager; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.support.annotation.NonNull; 26 import android.support.annotation.Nullable; 27 import android.text.TextUtils; 28 import com.android.dialer.preferredsim.PreferredSimFallbackContract; 29 import com.android.dialer.preferredsim.PreferredSimFallbackContract.PreferredSim; 30 31 /** 32 * Content provider for preferred SIM columns that is only available in ContactsProvider after P. 33 * Only supports {@link PreferredSimFallbackContract#CONTENT_URI} without id. Insert and delete not 34 * supported because there are no current use case. 35 * 36 * @see PreferredSimFallbackContract 37 */ 38 public class PreferredSimFallbackProvider extends ContentProvider { 39 40 private static final String UPDATE_ID_SELECTION = PreferredSim.DATA_ID + " = ?"; 41 42 private PreferredSimDatabaseHelper databaseHelper; 43 44 @Override onCreate()45 public boolean onCreate() { 46 databaseHelper = new PreferredSimDatabaseHelper(getContext()); 47 return true; 48 } 49 50 @Nullable 51 @Override query( @onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)52 public Cursor query( 53 @NonNull Uri uri, 54 @Nullable String[] projection, 55 @Nullable String selection, 56 @Nullable String[] selectionArgs, 57 @Nullable String sortOrder) { 58 checkReadContactsPermission(); 59 return databaseHelper 60 .getReadableDatabase() 61 .query( 62 PreferredSimDatabaseHelper.TABLE, 63 projection, 64 selection, 65 selectionArgs, 66 null, 67 null, 68 sortOrder); 69 } 70 71 @Nullable 72 @Override getType(@onNull Uri uri)73 public String getType(@NonNull Uri uri) { 74 return null; 75 } 76 77 @Nullable 78 @Override insert(@onNull Uri uri, @Nullable ContentValues values)79 public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { 80 throw new IllegalArgumentException("Unsupported operation"); 81 } 82 83 /** 84 * A row should only be deleted through {@link android.provider.ContactsContract.Data}. Since 85 * {@link android.provider.ContactsContract.Data#_ID} is AUTOINCREMENT and could not be reused, 86 * rows in this database will simply be orphaned and not cleaned up. To unset preference, update 87 * {@link PreferredSim#PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME} and {@link 88 * PreferredSim#PREFERRED_PHONE_ACCOUNT_ID} to {@code null}. Delete is only allowed from dialer so 89 * simulator can wipe all preference. 90 */ 91 @Override delete( @onNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs)92 public int delete( 93 @NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { 94 checkWriteContactsPermission(); 95 96 if (PreferredSimFallbackContract.CONTENT_URI.equals(uri) 97 && selection == null 98 && selectionArgs == null) { 99 return databaseHelper 100 .getWritableDatabase() 101 .delete(PreferredSimDatabaseHelper.TABLE, null, null); 102 } 103 104 if (!TextUtils.equals(getContext().getPackageName(), getCallingPackage())) { 105 throw new IllegalArgumentException("Unsupported operation"); 106 } 107 108 return databaseHelper 109 .getWritableDatabase() 110 .delete(PreferredSimDatabaseHelper.TABLE, selection, selectionArgs); 111 } 112 113 /** 114 * Data will be inserted if {@link PreferredSim#DATA_ID} does not already exist in the database. 115 * During update the whole row will be replaced. 116 * 117 * @param uri must be {@link PreferredSimFallbackContract#CONTENT_URI} 118 * @param values must contains exactly the keys {@link 119 * PreferredSim#PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME} {@link 120 * PreferredSim#PREFERRED_PHONE_ACCOUNT_ID}. The value may be {@code null} 121 * @param selection must equals "data_id = ?" 122 * @param selectionArgs must contains exactly the {@link PreferredSim#DATA_ID} 123 */ 124 @Override update( @onNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs)125 public int update( 126 @NonNull Uri uri, 127 @Nullable ContentValues values, 128 @Nullable String selection, 129 @Nullable String[] selectionArgs) { 130 checkWriteContactsPermission(); 131 if (values == null) { 132 return 0; 133 } 134 if (!UPDATE_ID_SELECTION.equals(selection) 135 || selectionArgs == null 136 || selectionArgs.length != 1) { 137 throw new IllegalArgumentException("Unsupported operation"); 138 } 139 values.put(PreferredSim.DATA_ID, selectionArgs[0]); 140 if (databaseHelper.getWritableDatabase().replace(PreferredSimDatabaseHelper.TABLE, null, values) 141 == -1) { 142 throw new IllegalStateException("update failed"); 143 } 144 getContext().getContentResolver().notifyChange(PreferredSimFallbackContract.CONTENT_URI, null); 145 return 1; 146 } 147 checkReadContactsPermission()148 private void checkReadContactsPermission() { 149 if (getContext().checkCallingOrSelfPermission(permission.READ_CONTACTS) 150 == PackageManager.PERMISSION_DENIED) { 151 throw new SecurityException("READ_CONTACTS required"); 152 } 153 } 154 checkWriteContactsPermission()155 private void checkWriteContactsPermission() { 156 if (getContext().checkCallingOrSelfPermission(permission.WRITE_CONTACTS) 157 == PackageManager.PERMISSION_DENIED) { 158 throw new SecurityException("WRITE_CONTACTS required"); 159 } 160 } 161 } 162