1/* 2 * Copyright (C) 2009 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 com.android.internal.telephony.CallerInfo; 20import com.android.internal.telephony.Connection; 21 22import android.content.ContentProvider; 23import android.content.ContentUris; 24import android.content.ContentValues; 25import android.content.Context; 26import android.content.ContextWrapper; 27import android.content.Intent; 28import android.content.pm.PackageManager; 29import android.database.Cursor; 30import android.net.Uri; 31import android.provider.CallLog; 32import android.provider.CallLog.Calls; 33import android.provider.ContactsContract; 34import android.provider.ContactsContract.CommonDataKinds.Phone; 35import android.provider.VoicemailContract.Voicemails; 36import android.test.suitebuilder.annotation.MediumTest; 37 38import java.util.Arrays; 39import java.util.List; 40 41/** 42 * Unit tests for {@link CallLogProvider}. 43 * 44 * Run the test like this: 45 * <code> 46 * adb shell am instrument -e class com.android.providers.contacts.CallLogProviderTest -w \ 47 * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 48 * </code> 49 */ 50@MediumTest 51public class CallLogProviderTest extends BaseContactsProvider2Test { 52 private static final String READ_WRITE_ALL_PERMISSION = 53 "com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL"; 54 private static final String ADD_VOICEMAIL_PERMISSION = 55 "com.android.voicemail.permission.ADD_VOICEMAIL"; 56 57 /** Fields specific to voicemail provider that should not be exposed by call_log*/ 58 private static final String[] VOICEMAIL_PROVIDER_SPECIFIC_COLUMNS = new String[] { 59 Voicemails._DATA, 60 Voicemails.HAS_CONTENT, 61 Voicemails.MIME_TYPE, 62 Voicemails.SOURCE_PACKAGE, 63 Voicemails.SOURCE_DATA, 64 Voicemails.STATE}; 65 /** Total number of columns exposed by call_log provider. */ 66 private static final int NUM_CALLLOG_FIELDS = 18; 67 68 @Override 69 protected Class<? extends ContentProvider> getProviderClass() { 70 return SynchronousContactsProvider2.class; 71 } 72 73 @Override 74 protected String getAuthority() { 75 return ContactsContract.AUTHORITY; 76 } 77 78 @Override 79 protected void setUp() throws Exception { 80 super.setUp(); 81 addProvider(TestCallLogProvider.class, CallLog.AUTHORITY); 82 } 83 84 @Override 85 protected void tearDown() throws Exception { 86 setUpWithVoicemailPermissions(); 87 mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); 88 super.tearDown(); 89 } 90 91 public void testInsert_RegularCallRecord() { 92 ContentValues values = getDefaultCallValues(); 93 Uri uri = mResolver.insert(Calls.CONTENT_URI, values); 94 values.put(Calls.COUNTRY_ISO, "us"); 95 assertStoredValues(uri, values); 96 assertSelection(uri, values, Calls._ID, ContentUris.parseId(uri)); 97 } 98 99 private void setUpWithVoicemailPermissions() { 100 mActor.addPermissions(ADD_VOICEMAIL_PERMISSION); 101 mActor.addPermissions(READ_WRITE_ALL_PERMISSION); 102 } 103 104 private void setUpWithNoVoicemailPermissions() { 105 mActor.removePermissions(ADD_VOICEMAIL_PERMISSION); 106 mActor.removePermissions(READ_WRITE_ALL_PERMISSION); 107 } 108 109 public void testInsert_VoicemailCallRecord() { 110 setUpWithVoicemailPermissions(); 111 final ContentValues values = getDefaultCallValues(); 112 values.put(Calls.TYPE, Calls.VOICEMAIL_TYPE); 113 values.put(Calls.VOICEMAIL_URI, "content://foo/voicemail/2"); 114 115 // Should fail with the base content uri without the voicemail param. 116 EvenMoreAsserts.assertThrows(IllegalArgumentException.class, new Runnable() { 117 @Override 118 public void run() { 119 mResolver.insert(Calls.CONTENT_URI, values); 120 } 121 }); 122 123 // Now grant voicemail permission - should succeed. 124 Uri uri = mResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, values); 125 assertStoredValues(uri, values); 126 assertSelection(uri, values, Calls._ID, ContentUris.parseId(uri)); 127 } 128 129 public void testUpdate() { 130 Uri uri = insertCallRecord(); 131 ContentValues values = new ContentValues(); 132 values.put(Calls.TYPE, Calls.OUTGOING_TYPE); 133 values.put(Calls.NUMBER, "1-800-263-7643"); 134 values.put(Calls.DATE, 2000); 135 values.put(Calls.DURATION, 40); 136 values.put(Calls.CACHED_NAME, "1-800-GOOG-411"); 137 values.put(Calls.CACHED_NUMBER_TYPE, Phone.TYPE_CUSTOM); 138 values.put(Calls.CACHED_NUMBER_LABEL, "Directory"); 139 140 int count = mResolver.update(uri, values, null, null); 141 assertEquals(1, count); 142 assertStoredValues(uri, values); 143 } 144 145 public void testDelete() { 146 Uri uri = insertCallRecord(); 147 try { 148 mResolver.delete(uri, null, null); 149 fail(); 150 } catch (UnsupportedOperationException ex) { 151 // Expected 152 } 153 154 int count = mResolver.delete(Calls.CONTENT_URI, Calls._ID + "=" 155 + ContentUris.parseId(uri), null); 156 assertEquals(1, count); 157 assertEquals(0, getCount(uri, null, null)); 158 } 159 160 public void testCallLogFilter() { 161 ContentValues values = getDefaultCallValues(); 162 mResolver.insert(Calls.CONTENT_URI, values); 163 164 Uri filterUri = Uri.withAppendedPath(Calls.CONTENT_FILTER_URI, "1-800-4664-411"); 165 Cursor c = mResolver.query(filterUri, null, null, null, null); 166 assertEquals(1, c.getCount()); 167 c.moveToFirst(); 168 assertCursorValues(c, values); 169 c.close(); 170 171 filterUri = Uri.withAppendedPath(Calls.CONTENT_FILTER_URI, "1-888-4664-411"); 172 c = mResolver.query(filterUri, null, null, null, null); 173 assertEquals(0, c.getCount()); 174 c.close(); 175 } 176 177 public void testAddCall() { 178 CallerInfo ci = new CallerInfo(); 179 ci.name = "1-800-GOOG-411"; 180 ci.numberType = Phone.TYPE_CUSTOM; 181 ci.numberLabel = "Directory"; 182 Uri uri = Calls.addCall(ci, getMockContext(), "1-800-263-7643", 183 Connection.PRESENTATION_ALLOWED, Calls.OUTGOING_TYPE, 2000, 40); 184 185 ContentValues values = new ContentValues(); 186 values.put(Calls.TYPE, Calls.OUTGOING_TYPE); 187 values.put(Calls.NUMBER, "1-800-263-7643"); 188 values.put(Calls.DATE, 2000); 189 values.put(Calls.DURATION, 40); 190 values.put(Calls.CACHED_NAME, "1-800-GOOG-411"); 191 values.put(Calls.CACHED_NUMBER_TYPE, Phone.TYPE_CUSTOM); 192 values.put(Calls.CACHED_NUMBER_LABEL, "Directory"); 193 values.put(Calls.COUNTRY_ISO, "us"); 194 values.put(Calls.GEOCODED_LOCATION, "usa"); 195 assertStoredValues(uri, values); 196 } 197 198 // Test to check that the calls and voicemail uris returns expected results. 199 public void testDifferentContentUris() { 200 setUpWithVoicemailPermissions(); 201 // Insert one voicemaail and two regular call record. 202 insertVoicemailRecord(); 203 insertCallRecord(); 204 insertCallRecord(); 205 206 // With the default uri, only 2 call entries should be returned. 207 // With the voicemail uri all 3 should be returned. 208 assertEquals(2, getCount(Calls.CONTENT_URI, null, null)); 209 assertEquals(3, getCount(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null)); 210 } 211 212 // Test to check that none of the voicemail provider specific fields are 213 // insertable through call_log provider. 214 public void testCannotAccessVoicemailSpecificFields_Insert() { 215 for (String voicemailColumn : VOICEMAIL_PROVIDER_SPECIFIC_COLUMNS) { 216 final ContentValues values = getDefaultCallValues(); 217 values.put(voicemailColumn, "foo"); 218 EvenMoreAsserts.assertThrows("Column: " + voicemailColumn, 219 IllegalArgumentException.class, new Runnable() { 220 @Override 221 public void run() { 222 mResolver.insert(Calls.CONTENT_URI, values); 223 } 224 }); 225 } 226 } 227 228 // Test to check that none of the voicemail provider specific fields are 229 // exposed through call_log provider query. 230 public void testCannotAccessVoicemailSpecificFields_Query() { 231 // Query. 232 Cursor cursor = mResolver.query(Calls.CONTENT_URI, null, null, null, null); 233 List<String> columnNames = Arrays.asList(cursor.getColumnNames()); 234 assertEquals(NUM_CALLLOG_FIELDS, columnNames.size()); 235 // None of the voicemail provider specific columns should be present. 236 for (String voicemailColumn : VOICEMAIL_PROVIDER_SPECIFIC_COLUMNS) { 237 assertFalse("Unexpected column: '" + voicemailColumn + "' returned.", 238 columnNames.contains(voicemailColumn)); 239 } 240 } 241 242 // Test to check that none of the voicemail provider specific fields are 243 // updatable through call_log provider. 244 public void testCannotAccessVoicemailSpecificFields_Update() { 245 for (String voicemailColumn : VOICEMAIL_PROVIDER_SPECIFIC_COLUMNS) { 246 final Uri insertedUri = insertCallRecord(); 247 final ContentValues values = new ContentValues(); 248 values.put(voicemailColumn, "foo"); 249 EvenMoreAsserts.assertThrows("Column: " + voicemailColumn, 250 IllegalArgumentException.class, new Runnable() { 251 @Override 252 public void run() { 253 mResolver.update(insertedUri, values, null, null); 254 } 255 }); 256 } 257 } 258 259 public void testVoicemailPermissions_Insert() { 260 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 261 @Override 262 public void run() { 263 mResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultVoicemailValues()); 264 } 265 }); 266 // Should now succeed with permissions granted. 267 setUpWithVoicemailPermissions(); 268 mResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultVoicemailValues()); 269 } 270 271 public void testVoicemailPermissions_Update() { 272 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 273 @Override 274 public void run() { 275 mResolver.update(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultVoicemailValues(), 276 null, null); 277 } 278 }); 279 // Should now succeed with permissions granted. 280 setUpWithVoicemailPermissions(); 281 mResolver.update(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultCallValues(), null, null); 282 } 283 284 public void testVoicemailPermissions_Query() { 285 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 286 @Override 287 public void run() { 288 mResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null); 289 } 290 }); 291 // Should now succeed with permissions granted. 292 setUpWithVoicemailPermissions(); 293 mResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null); 294 } 295 296 public void testVoicemailPermissions_Delete() { 297 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 298 @Override 299 public void run() { 300 mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); 301 } 302 }); 303 // Should now succeed with permissions granted. 304 setUpWithVoicemailPermissions(); 305 mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); 306 } 307 308 private ContentValues getDefaultValues(int callType) { 309 ContentValues values = new ContentValues(); 310 values.put(Calls.TYPE, callType); 311 values.put(Calls.NUMBER, "1-800-4664-411"); 312 values.put(Calls.DATE, 1000); 313 values.put(Calls.DURATION, 30); 314 values.put(Calls.NEW, 1); 315 return values; 316 } 317 318 private ContentValues getDefaultCallValues() { 319 return getDefaultValues(Calls.INCOMING_TYPE); 320 } 321 322 private ContentValues getDefaultVoicemailValues() { 323 return getDefaultValues(Calls.VOICEMAIL_TYPE); 324 } 325 326 private Uri insertCallRecord() { 327 return mResolver.insert(Calls.CONTENT_URI, getDefaultCallValues()); 328 } 329 330 private Uri insertVoicemailRecord() { 331 return mResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultVoicemailValues()); 332 } 333 334 public static class TestCallLogProvider extends CallLogProvider { 335 private static ContactsDatabaseHelper mDbHelper; 336 337 @Override 338 protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 339 if (mDbHelper == null) { 340 mDbHelper = new ContactsDatabaseHelper(context); 341 } 342 return mDbHelper; 343 } 344 345 @Override 346 protected CallLogInsertionHelper createCallLogInsertionHelper(Context context) { 347 return new CallLogInsertionHelper() { 348 @Override 349 public String getGeocodedLocationFor(String number, String countryIso) { 350 return "usa"; 351 } 352 353 @Override 354 public void addComputedValues(ContentValues values) { 355 values.put(Calls.COUNTRY_ISO, "us"); 356 values.put(Calls.GEOCODED_LOCATION, "usa"); 357 } 358 }; 359 } 360 361 @Override 362 protected Context context() { 363 return new ContextWrapper(super.context()) { 364 @Override 365 public PackageManager getPackageManager() { 366 return new MockPackageManager("com.test.package1", "com.test.package2"); 367 } 368 369 @Override 370 public void sendBroadcast(Intent intent, String receiverPermission) { 371 // Do nothing for now. 372 } 373 }; 374 } 375 } 376} 377