Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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 android.content.cts;
     18 
     19 import com.android.cts.content.R;
     20 
     21 
     22 import android.accounts.Account;
     23 import android.content.ContentProviderClient;
     24 import android.content.ContentResolver;
     25 import android.content.ContentValues;
     26 import android.content.Context;
     27 import android.content.res.AssetFileDescriptor;
     28 import android.cts.util.PollingCheck;
     29 import android.database.ContentObserver;
     30 import android.database.Cursor;
     31 import android.database.sqlite.SQLiteQueryBuilder;
     32 import android.net.Uri;
     33 import android.os.Bundle;
     34 import android.os.CancellationSignal;
     35 import android.os.OperationCanceledException;
     36 import android.os.ParcelFileDescriptor;
     37 import android.os.RemoteException;
     38 import android.test.AndroidTestCase;
     39 import android.util.Log;
     40 
     41 import java.io.FileInputStream;
     42 import java.io.FileNotFoundException;
     43 import java.io.IOException;
     44 import java.io.InputStream;
     45 import java.io.InputStreamReader;
     46 import java.io.OutputStream;
     47 
     48 public class ContentResolverTest extends AndroidTestCase {
     49     private final static String COLUMN_ID_NAME = "_id";
     50     private final static String COLUMN_KEY_NAME = "key";
     51     private final static String COLUMN_VALUE_NAME = "value";
     52 
     53     private static final String AUTHORITY = "ctstest";
     54     private static final Uri TABLE1_URI = Uri.parse("content://" + AUTHORITY + "/testtable1/");
     55     private static final Uri TABLE1_CROSS_URI =
     56             Uri.parse("content://" + AUTHORITY + "/testtable1/cross");
     57     private static final Uri TABLE2_URI = Uri.parse("content://" + AUTHORITY + "/testtable2/");
     58     private static final Uri SELF_URI = Uri.parse("content://" + AUTHORITY + "/self/");
     59     private static final Uri CRASH_URI = Uri.parse("content://" + AUTHORITY + "/crash/");
     60 
     61     private static final String REMOTE_AUTHORITY = "remotectstest";
     62     private static final Uri REMOTE_TABLE1_URI = Uri.parse("content://"
     63                 + REMOTE_AUTHORITY + "/testtable1/");
     64     private static final Uri REMOTE_SELF_URI = Uri.parse("content://"
     65                 + REMOTE_AUTHORITY + "/self/");
     66     private static final Uri REMOTE_CRASH_URI = Uri.parse("content://"
     67             + REMOTE_AUTHORITY + "/crash/");
     68 
     69     private static final Account ACCOUNT = new Account("cts", "cts");
     70 
     71     private static final String KEY1 = "key1";
     72     private static final String KEY2 = "key2";
     73     private static final String KEY3 = "key3";
     74     private static final int VALUE1 = 1;
     75     private static final int VALUE2 = 2;
     76     private static final int VALUE3 = 3;
     77 
     78     private static final String TEST_PACKAGE_NAME = "com.android.cts.content";
     79 
     80     private Context mContext;
     81     private ContentResolver mContentResolver;
     82     private Cursor mCursor;
     83 
     84     @Override
     85     protected void setUp() throws Exception {
     86         super.setUp();
     87 
     88         mContext = getContext();
     89         mContentResolver = mContext.getContentResolver();
     90 
     91         android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0);
     92 
     93         // add three rows to database when every test case start.
     94         ContentValues values = new ContentValues();
     95 
     96         values.put(COLUMN_KEY_NAME, KEY1);
     97         values.put(COLUMN_VALUE_NAME, VALUE1);
     98         mContentResolver.insert(TABLE1_URI, values);
     99         mContentResolver.insert(REMOTE_TABLE1_URI, values);
    100 
    101         values.put(COLUMN_KEY_NAME, KEY2);
    102         values.put(COLUMN_VALUE_NAME, VALUE2);
    103         mContentResolver.insert(TABLE1_URI, values);
    104         mContentResolver.insert(REMOTE_TABLE1_URI, values);
    105 
    106         values.put(COLUMN_KEY_NAME, KEY3);
    107         values.put(COLUMN_VALUE_NAME, VALUE3);
    108         mContentResolver.insert(TABLE1_URI, values);
    109         mContentResolver.insert(REMOTE_TABLE1_URI, values);
    110     }
    111 
    112     @Override
    113     protected void tearDown() throws Exception {
    114         mContentResolver.delete(TABLE1_URI, null, null);
    115         if ( null != mCursor && !mCursor.isClosed() ) {
    116             mCursor.close();
    117         }
    118         mContentResolver.delete(REMOTE_TABLE1_URI, null, null);
    119         if ( null != mCursor && !mCursor.isClosed() ) {
    120             mCursor.close();
    121         }
    122         super.tearDown();
    123     }
    124 
    125     public void testConstructor() {
    126         assertNotNull(mContentResolver);
    127     }
    128 
    129     public void testCrashOnLaunch() {
    130         // This test is going to make sure that the platform deals correctly
    131         // with a content provider process going away while a client is waiting
    132         // for it to come up.
    133         // First, we need to make sure our provider process is gone.  Goodbye!
    134         ContentProviderClient client = mContentResolver.acquireContentProviderClient(
    135                 REMOTE_AUTHORITY);
    136         // We are going to do something wrong here...  release the client first,
    137         // so the act of killing it doesn't kill our own process.
    138         client.release();
    139         try {
    140             client.delete(REMOTE_SELF_URI, null, null);
    141         } catch (RemoteException e) {
    142         }
    143         // Now make sure the thing is actually gone.
    144         boolean gone = true;
    145         try {
    146             client.getType(REMOTE_TABLE1_URI);
    147             gone = false;
    148         } catch (RemoteException e) {
    149         }
    150         if (!gone) {
    151             fail("Content provider process is not gone!");
    152         }
    153         try {
    154             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1);
    155             String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    156             assertEquals(android.provider.Settings.System.getInt(mContentResolver,
    157                 "__cts_crash_on_launch", 0), 0);
    158             assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    159         } finally {
    160             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0);
    161         }
    162     }
    163 
    164     public void testUnstableToStableRefs() {
    165         // Get an unstable refrence on the remote content provider.
    166         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
    167                 REMOTE_AUTHORITY);
    168         // Verify we can access it.
    169         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    170         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    171 
    172         // Get a stable reference on the remote content provider.
    173         ContentProviderClient sClient = mContentResolver.acquireContentProviderClient(
    174                 REMOTE_AUTHORITY);
    175         // Verify we can still access it.
    176         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    177         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    178 
    179         // Release unstable reference.
    180         uClient.release();
    181         // Verify we can still access it.
    182         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    183         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    184 
    185         // Release stable reference, removing last ref.
    186         sClient.release();
    187         // Kill it.  Note that a bug at this point where it causes our own
    188         // process to be killed will result in the entire test failing.
    189         try {
    190             Log.i("ContentResolverTest",
    191                     "Killing remote client -- if test process goes away, that is why!");
    192             uClient.delete(REMOTE_SELF_URI, null, null);
    193         } catch (RemoteException e) {
    194         }
    195         // Make sure the remote client is actually gone.
    196         boolean gone = true;
    197         try {
    198             sClient.getType(REMOTE_TABLE1_URI);
    199             gone = false;
    200         } catch (RemoteException e) {
    201         }
    202         if (!gone) {
    203             fail("Content provider process is not gone!");
    204         }
    205     }
    206 
    207     public void testStableToUnstableRefs() {
    208         // Get a stable reference on the remote content provider.
    209         ContentProviderClient sClient = mContentResolver.acquireContentProviderClient(
    210                 REMOTE_AUTHORITY);
    211         // Verify we can still access it.
    212         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    213         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    214 
    215         // Get an unstable refrence on the remote content provider.
    216         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
    217                 REMOTE_AUTHORITY);
    218         // Verify we can access it.
    219         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    220         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    221 
    222         // Release stable reference, leaving only an unstable ref.
    223         sClient.release();
    224 
    225         // Kill it.  Note that a bug at this point where it causes our own
    226         // process to be killed will result in the entire test failing.
    227         try {
    228             Log.i("ContentResolverTest",
    229                     "Killing remote client -- if test process goes away, that is why!");
    230             uClient.delete(REMOTE_SELF_URI, null, null);
    231         } catch (RemoteException e) {
    232         }
    233         // Make sure the remote client is actually gone.
    234         boolean gone = true;
    235         try {
    236             uClient.getType(REMOTE_TABLE1_URI);
    237             gone = false;
    238         } catch (RemoteException e) {
    239         }
    240         if (!gone) {
    241             fail("Content provider process is not gone!");
    242         }
    243 
    244         // Release unstable reference.
    245         uClient.release();
    246     }
    247 
    248     public void testGetType() {
    249         String type1 = mContentResolver.getType(TABLE1_URI);
    250         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    251 
    252         String type2 = mContentResolver.getType(TABLE2_URI);
    253         assertTrue(type2.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    254 
    255         Uri invalidUri = Uri.parse("abc");
    256         assertNull(mContentResolver.getType(invalidUri));
    257 
    258         try {
    259             mContentResolver.getType(null);
    260             fail("did not throw NullPointerException when Uri is null.");
    261         } catch (NullPointerException e) {
    262             //expected.
    263         }
    264     }
    265 
    266     public void testUnstableGetType() {
    267         // Get an unstable refrence on the remote content provider.
    268         ContentProviderClient client = mContentResolver.acquireUnstableContentProviderClient(
    269                 REMOTE_AUTHORITY);
    270         // Verify we can access it.
    271         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    272         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    273 
    274         // Kill it.  Note that a bug at this point where it causes our own
    275         // process to be killed will result in the entire test failing.
    276         try {
    277             Log.i("ContentResolverTest",
    278                     "Killing remote client -- if test process goes away, that is why!");
    279             client.delete(REMOTE_SELF_URI, null, null);
    280         } catch (RemoteException e) {
    281         }
    282         // Make sure the remote client is actually gone.
    283         boolean gone = true;
    284         try {
    285             client.getType(REMOTE_TABLE1_URI);
    286             gone = false;
    287         } catch (RemoteException e) {
    288         }
    289         if (!gone) {
    290             fail("Content provider process is not gone!");
    291         }
    292 
    293         // Now the remote client is gone, can we recover?
    294         // Release our old reference.
    295         client.release();
    296         // Get a new reference.
    297         client = mContentResolver.acquireUnstableContentProviderClient(REMOTE_AUTHORITY);
    298         // Verify we can access it.
    299         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
    300         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
    301     }
    302 
    303     public void testQuery() {
    304         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    305 
    306         assertNotNull(mCursor);
    307         assertEquals(3, mCursor.getCount());
    308         assertEquals(3, mCursor.getColumnCount());
    309 
    310         mCursor.moveToLast();
    311         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    312         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    313         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    314 
    315         mCursor.moveToPrevious();
    316         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    317         assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    318         assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    319         mCursor.close();
    320 
    321         String selection = COLUMN_ID_NAME + "=1";
    322         mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null);
    323         assertNotNull(mCursor);
    324         assertEquals(1, mCursor.getCount());
    325         assertEquals(3, mCursor.getColumnCount());
    326 
    327         mCursor.moveToFirst();
    328         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    329         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    330         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    331         mCursor.close();
    332 
    333         selection = COLUMN_KEY_NAME + "=\"" + KEY3 + "\"";
    334         mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null);
    335         assertNotNull(mCursor);
    336         assertEquals(1, mCursor.getCount());
    337         assertEquals(3, mCursor.getColumnCount());
    338 
    339         mCursor.moveToFirst();
    340         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    341         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    342         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    343         mCursor.close();
    344 
    345         try {
    346             mContentResolver.query(null, null, null, null, null);
    347             fail("did not throw NullPointerException when uri is null.");
    348         } catch (NullPointerException e) {
    349             //expected.
    350         }
    351     }
    352 
    353     public void testCrashingQuery() {
    354         try {
    355             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1);
    356             mCursor = mContentResolver.query(REMOTE_CRASH_URI, null, null, null, null);
    357             assertEquals(android.provider.Settings.System.getInt(mContentResolver,
    358                 "__cts_crash_on_launch", 0), 0);
    359         } finally {
    360             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0);
    361         }
    362 
    363         assertNotNull(mCursor);
    364         assertEquals(3, mCursor.getCount());
    365         assertEquals(3, mCursor.getColumnCount());
    366 
    367         mCursor.moveToLast();
    368         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    369         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    370         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    371 
    372         mCursor.moveToPrevious();
    373         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    374         assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    375         assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    376         mCursor.close();
    377     }
    378 
    379     public void testCancelableQuery_WhenNotCanceled_ReturnsResultSet() {
    380         CancellationSignal cancellationSignal = new CancellationSignal();
    381 
    382         Cursor cursor = mContentResolver.query(TABLE1_URI, null, null, null, null,
    383                 cancellationSignal);
    384         assertEquals(3, cursor.getCount());
    385         cursor.close();
    386     }
    387 
    388     public void testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately() {
    389         CancellationSignal cancellationSignal = new CancellationSignal();
    390         cancellationSignal.cancel();
    391 
    392         try {
    393             mContentResolver.query(TABLE1_URI, null, null, null, null, cancellationSignal);
    394             fail("Expected OperationCanceledException");
    395         } catch (OperationCanceledException ex) {
    396             // expected
    397         }
    398     }
    399 
    400     public void testCancelableQuery_WhenCanceledDuringLongRunningQuery_CancelsQueryAndThrows() {
    401         // Populate a table with a bunch of integers.
    402         mContentResolver.delete(TABLE1_URI, null, null);
    403         ContentValues values = new ContentValues();
    404         for (int i = 0; i < 100; i++) {
    405             values.put(COLUMN_KEY_NAME, i);
    406             values.put(COLUMN_VALUE_NAME, i);
    407             mContentResolver.insert(TABLE1_URI, values);
    408         }
    409 
    410         for (int i = 0; i < 5; i++) {
    411             final CancellationSignal cancellationSignal = new CancellationSignal();
    412             Thread cancellationThread = new Thread() {
    413                 @Override
    414                 public void run() {
    415                     try {
    416                         Thread.sleep(300);
    417                     } catch (InterruptedException ex) {
    418                     }
    419                     cancellationSignal.cancel();
    420                 }
    421             };
    422             try {
    423                 // Build an unsatisfiable 5-way cross-product query over 100 values but
    424                 // produces no output.  This should force SQLite to loop for a long time
    425                 // as it tests 10^10 combinations.
    426                 cancellationThread.start();
    427 
    428                 final long startTime = System.nanoTime();
    429                 try {
    430                     mContentResolver.query(TABLE1_CROSS_URI, null,
    431                             "a.value + b.value + c.value + d.value + e.value > 1000000",
    432                             null, null, cancellationSignal);
    433                     fail("Expected OperationCanceledException");
    434                 } catch (OperationCanceledException ex) {
    435                     // expected
    436                 }
    437 
    438                 // We want to confirm that the query really was running and then got
    439                 // canceled midway.
    440                 final long waitTime = System.nanoTime() - startTime;
    441                 if (waitTime > 150 * 1000000L && waitTime < 600 * 1000000L) {
    442                     return; // success!
    443                 }
    444             } finally {
    445                 try {
    446                     cancellationThread.join();
    447                 } catch (InterruptedException e) {
    448                 }
    449             }
    450         }
    451 
    452         // Occasionally we might miss the timing deadline due to factors in the
    453         // environment, but if after several trials we still couldn't demonstrate
    454         // that the query was canceled, then the test must be broken.
    455         fail("Could not prove that the query actually canceled midway during execution.");
    456     }
    457 
    458     public void testOpenInputStream() throws IOException {
    459         final Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
    460                 "://" + TEST_PACKAGE_NAME + "/" + R.drawable.pass);
    461 
    462         InputStream is = mContentResolver.openInputStream(uri);
    463         assertNotNull(is);
    464         is.close();
    465 
    466         final Uri invalidUri = Uri.parse("abc");
    467         try {
    468             mContentResolver.openInputStream(invalidUri);
    469             fail("did not throw FileNotFoundException when uri is invalid.");
    470         } catch (FileNotFoundException e) {
    471             //expected.
    472         }
    473     }
    474 
    475     public void testOpenOutputStream() throws IOException {
    476         Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" +
    477                 getContext().getCacheDir().getAbsolutePath() +
    478                 "/temp.jpg");
    479         OutputStream os = mContentResolver.openOutputStream(uri);
    480         assertNotNull(os);
    481         os.close();
    482 
    483         os = mContentResolver.openOutputStream(uri, "wa");
    484         assertNotNull(os);
    485         os.close();
    486 
    487         uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
    488                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
    489         try {
    490             mContentResolver.openOutputStream(uri);
    491             fail("did not throw FileNotFoundException when scheme is not accepted.");
    492         } catch (FileNotFoundException e) {
    493             //expected.
    494         }
    495 
    496         try {
    497             mContentResolver.openOutputStream(uri, "w");
    498             fail("did not throw FileNotFoundException when scheme is not accepted.");
    499         } catch (FileNotFoundException e) {
    500             //expected.
    501         }
    502 
    503         Uri invalidUri = Uri.parse("abc");
    504         try {
    505             mContentResolver.openOutputStream(invalidUri);
    506             fail("did not throw FileNotFoundException when uri is invalid.");
    507         } catch (FileNotFoundException e) {
    508             //expected.
    509         }
    510 
    511         try {
    512             mContentResolver.openOutputStream(invalidUri, "w");
    513             fail("did not throw FileNotFoundException when uri is invalid.");
    514         } catch (FileNotFoundException e) {
    515             //expected.
    516         }
    517     }
    518 
    519     public void testOpenAssetFileDescriptor() throws IOException {
    520         Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
    521                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
    522 
    523         AssetFileDescriptor afd = mContentResolver.openAssetFileDescriptor(uri, "r");
    524         assertNotNull(afd);
    525         afd.close();
    526 
    527         try {
    528             mContentResolver.openAssetFileDescriptor(uri, "d");
    529             fail("did not throw FileNotFoundException when mode is unknown.");
    530         } catch (FileNotFoundException e) {
    531             //expected.
    532         }
    533 
    534         Uri invalidUri = Uri.parse("abc");
    535         try {
    536             mContentResolver.openAssetFileDescriptor(invalidUri, "r");
    537             fail("did not throw FileNotFoundException when uri is invalid.");
    538         } catch (FileNotFoundException e) {
    539             //expected.
    540         }
    541     }
    542 
    543     private String consumeAssetFileDescriptor(AssetFileDescriptor afd)
    544             throws IOException {
    545         FileInputStream stream = null;
    546         try {
    547             stream = afd.createInputStream();
    548             InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
    549 
    550             // Got it...  copy the stream into a local string and return it.
    551             StringBuilder builder = new StringBuilder(128);
    552             char[] buffer = new char[8192];
    553             int len;
    554             while ((len=reader.read(buffer)) > 0) {
    555                 builder.append(buffer, 0, len);
    556             }
    557             return builder.toString();
    558 
    559         } finally {
    560             if (stream != null) {
    561                 try {
    562                     stream.close();
    563                 } catch (IOException e) {
    564                 }
    565             }
    566         }
    567 
    568     }
    569 
    570     public void testCrashingOpenAssetFileDescriptor() throws IOException {
    571         AssetFileDescriptor afd = null;
    572         try {
    573             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1);
    574             afd = mContentResolver.openAssetFileDescriptor(REMOTE_CRASH_URI, "rw");
    575             assertEquals(android.provider.Settings.System.getInt(mContentResolver,
    576                     "__cts_crash_on_launch", 0), 0);
    577             assertNotNull(afd);
    578             String str = consumeAssetFileDescriptor(afd);
    579             afd = null;
    580             assertEquals(str, "This is the openAssetFile test data!");
    581         } finally {
    582             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0);
    583             if (afd != null) {
    584                 afd.close();
    585             }
    586         }
    587 
    588         // Make sure a content provider crash at this point won't hurt us.
    589         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
    590                 REMOTE_AUTHORITY);
    591         // Kill it.  Note that a bug at this point where it causes our own
    592         // process to be killed will result in the entire test failing.
    593         try {
    594             Log.i("ContentResolverTest",
    595                     "Killing remote client -- if test process goes away, that is why!");
    596             uClient.delete(REMOTE_SELF_URI, null, null);
    597         } catch (RemoteException e) {
    598         }
    599         uClient.release();
    600     }
    601 
    602     public void testCrashingOpenTypedAssetFileDescriptor() throws IOException {
    603         AssetFileDescriptor afd = null;
    604         try {
    605             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1);
    606             afd = mContentResolver.openTypedAssetFileDescriptor(
    607                     REMOTE_CRASH_URI, "text/plain", null);
    608             assertEquals(android.provider.Settings.System.getInt(mContentResolver,
    609                     "__cts_crash_on_launch", 0), 0);
    610             assertNotNull(afd);
    611             String str = consumeAssetFileDescriptor(afd);
    612             afd = null;
    613             assertEquals(str, "This is the openTypedAssetFile test data!");
    614         } finally {
    615             android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0);
    616             if (afd != null) {
    617                 afd.close();
    618             }
    619         }
    620 
    621         // Make sure a content provider crash at this point won't hurt us.
    622         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
    623                 REMOTE_AUTHORITY);
    624         // Kill it.  Note that a bug at this point where it causes our own
    625         // process to be killed will result in the entire test failing.
    626         try {
    627             Log.i("ContentResolverTest",
    628                     "Killing remote client -- if test process goes away, that is why!");
    629             uClient.delete(REMOTE_SELF_URI, null, null);
    630         } catch (RemoteException e) {
    631         }
    632         uClient.release();
    633     }
    634 
    635     public void testOpenFileDescriptor() throws IOException {
    636         Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" +
    637                 getContext().getCacheDir().getAbsolutePath() +
    638                 "/temp.jpg");
    639         ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(uri, "w");
    640         assertNotNull(pfd);
    641         pfd.close();
    642 
    643         try {
    644             mContentResolver.openFileDescriptor(uri, "d");
    645             fail("did not throw IllegalArgumentException when mode is unknown.");
    646         } catch (IllegalArgumentException e) {
    647             //expected.
    648         }
    649 
    650         Uri invalidUri = Uri.parse("abc");
    651         try {
    652             mContentResolver.openFileDescriptor(invalidUri, "w");
    653             fail("did not throw FileNotFoundException when uri is invalid.");
    654         } catch (FileNotFoundException e) {
    655             //expected.
    656         }
    657 
    658         uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
    659                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
    660         try {
    661             mContentResolver.openFileDescriptor(uri, "w");
    662             fail("did not throw FileNotFoundException when scheme is not accepted.");
    663         } catch (FileNotFoundException e) {
    664             //expected.
    665         }
    666     }
    667 
    668     public void testInsert() {
    669         String key4 = "key4";
    670         String key5 = "key5";
    671         int value4 = 4;
    672         int value5 = 5;
    673         String key4Selection = COLUMN_KEY_NAME + "=\"" + key4 + "\"";
    674 
    675         mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null);
    676         assertEquals(0, mCursor.getCount());
    677         mCursor.close();
    678 
    679         ContentValues values = new ContentValues();
    680         values.put(COLUMN_KEY_NAME, key4);
    681         values.put(COLUMN_VALUE_NAME, value4);
    682         Uri uri = mContentResolver.insert(TABLE1_URI, values);
    683         assertNotNull(uri);
    684 
    685         mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null);
    686         assertNotNull(mCursor);
    687         assertEquals(1, mCursor.getCount());
    688 
    689         mCursor.moveToFirst();
    690         assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    691         assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    692         assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    693         mCursor.close();
    694 
    695         values.put(COLUMN_KEY_NAME, key5);
    696         values.put(COLUMN_VALUE_NAME, value5);
    697         uri = mContentResolver.insert(TABLE1_URI, values);
    698         assertNotNull(uri);
    699 
    700         // check returned uri
    701         mCursor = mContentResolver.query(uri, null, null, null, null);
    702         assertNotNull(mCursor);
    703         assertEquals(1, mCursor.getCount());
    704 
    705         mCursor.moveToLast();
    706         assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    707         assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    708         assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    709         mCursor.close();
    710 
    711         try {
    712             mContentResolver.insert(null, values);
    713             fail("did not throw NullPointerException when uri is null.");
    714         } catch (NullPointerException e) {
    715             //expected.
    716         }
    717     }
    718 
    719     public void testBulkInsert() {
    720         String key4 = "key4";
    721         String key5 = "key5";
    722         int value4 = 4;
    723         int value5 = 5;
    724 
    725         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    726         assertNotNull(mCursor);
    727         assertEquals(3, mCursor.getCount());
    728         mCursor.close();
    729 
    730         ContentValues[] cvs = new ContentValues[2];
    731         cvs[0] = new ContentValues();
    732         cvs[0].put(COLUMN_KEY_NAME, key4);
    733         cvs[0].put(COLUMN_VALUE_NAME, value4);
    734 
    735         cvs[1] = new ContentValues();
    736         cvs[1].put(COLUMN_KEY_NAME, key5);
    737         cvs[1].put(COLUMN_VALUE_NAME, value5);
    738 
    739         assertEquals(2, mContentResolver.bulkInsert(TABLE1_URI, cvs));
    740         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    741         assertNotNull(mCursor);
    742         assertEquals(5, mCursor.getCount());
    743 
    744         mCursor.moveToLast();
    745         assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    746         assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    747         assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    748 
    749         mCursor.moveToPrevious();
    750         assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    751         assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    752         assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    753         mCursor.close();
    754 
    755         try {
    756             mContentResolver.bulkInsert(null, cvs);
    757             fail("did not throw NullPointerException when uri is null.");
    758         } catch (NullPointerException e) {
    759             //expected.
    760         }
    761     }
    762 
    763     public void testDelete() {
    764         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    765         assertNotNull(mCursor);
    766         assertEquals(3, mCursor.getCount());
    767         mCursor.close();
    768 
    769         assertEquals(3, mContentResolver.delete(TABLE1_URI, null, null));
    770         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    771         assertNotNull(mCursor);
    772         assertEquals(0, mCursor.getCount());
    773         mCursor.close();
    774 
    775         // add three rows to database.
    776         ContentValues values = new ContentValues();
    777         values.put(COLUMN_KEY_NAME, KEY1);
    778         values.put(COLUMN_VALUE_NAME, VALUE1);
    779         mContentResolver.insert(TABLE1_URI, values);
    780 
    781         values.put(COLUMN_KEY_NAME, KEY2);
    782         values.put(COLUMN_VALUE_NAME, VALUE2);
    783         mContentResolver.insert(TABLE1_URI, values);
    784 
    785         values.put(COLUMN_KEY_NAME, KEY3);
    786         values.put(COLUMN_VALUE_NAME, VALUE3);
    787         mContentResolver.insert(TABLE1_URI, values);
    788 
    789         // test delete row using selection
    790         String selection = COLUMN_ID_NAME + "=2";
    791         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
    792 
    793         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    794         assertNotNull(mCursor);
    795         assertEquals(2, mCursor.getCount());
    796 
    797         mCursor.moveToFirst();
    798         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    799         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    800         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    801 
    802         mCursor.moveToNext();
    803         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    804         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    805         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    806         mCursor.close();
    807 
    808         selection = COLUMN_VALUE_NAME + "=3";
    809         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
    810 
    811         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    812         assertNotNull(mCursor);
    813         assertEquals(1, mCursor.getCount());
    814 
    815         mCursor.moveToFirst();
    816         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    817         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    818         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    819         mCursor.close();
    820 
    821         selection = COLUMN_KEY_NAME + "=\"" + KEY1 + "\"";
    822         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
    823 
    824         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    825         assertNotNull(mCursor);
    826         assertEquals(0, mCursor.getCount());
    827         mCursor.close();
    828 
    829         try {
    830             mContentResolver.delete(null, null, null);
    831             fail("did not throw NullPointerException when uri is null.");
    832         } catch (NullPointerException e) {
    833             //expected.
    834         }
    835     }
    836 
    837     public void testUpdate() {
    838         ContentValues values = new ContentValues();
    839         String key10 = "key10";
    840         String key20 = "key20";
    841         int value10 = 10;
    842         int value20 = 20;
    843 
    844         values.put(COLUMN_KEY_NAME, key10);
    845         values.put(COLUMN_VALUE_NAME, value10);
    846 
    847         // test update all the rows.
    848         assertEquals(3, mContentResolver.update(TABLE1_URI, values, null, null));
    849         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    850         assertNotNull(mCursor);
    851         assertEquals(3, mCursor.getCount());
    852 
    853         mCursor.moveToFirst();
    854         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    855         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    856         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    857 
    858         mCursor.moveToNext();
    859         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    860         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    861         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    862 
    863         mCursor.moveToLast();
    864         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    865         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    866         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    867         mCursor.close();
    868 
    869         // test update one row using selection.
    870         String selection = COLUMN_ID_NAME + "=1";
    871         values.put(COLUMN_KEY_NAME, key20);
    872         values.put(COLUMN_VALUE_NAME, value20);
    873 
    874         assertEquals(1, mContentResolver.update(TABLE1_URI, values, selection, null));
    875         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
    876         assertNotNull(mCursor);
    877         assertEquals(3, mCursor.getCount());
    878 
    879         mCursor.moveToFirst();
    880         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    881         assertEquals(key20, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    882         assertEquals(value20, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    883 
    884         mCursor.moveToNext();
    885         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    886         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    887         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    888 
    889         mCursor.moveToLast();
    890         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
    891         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
    892         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
    893         mCursor.close();
    894 
    895         try {
    896             mContentResolver.update(null, values, null, null);
    897             fail("did not throw NullPointerException when uri is null.");
    898         } catch (NullPointerException e) {
    899             //expected.
    900         }
    901 
    902         // javadoc says it will throw NullPointerException when values are null,
    903         // but actually, it throws IllegalArgumentException here.
    904         try {
    905             mContentResolver.update(TABLE1_URI, null, null, null);
    906             fail("did not throw IllegalArgumentException when values are null.");
    907         } catch (IllegalArgumentException e) {
    908             //expected.
    909         }
    910     }
    911 
    912     public void testRegisterContentObserver() {
    913         final MockContentObserver mco = new MockContentObserver();
    914 
    915         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
    916         assertFalse(mco.hadOnChanged());
    917 
    918         ContentValues values = new ContentValues();
    919         values.put(COLUMN_KEY_NAME, "key10");
    920         values.put(COLUMN_VALUE_NAME, 10);
    921         mContentResolver.update(TABLE1_URI, values, null, null);
    922         new PollingCheck() {
    923             @Override
    924             protected boolean check() {
    925                 return mco.hadOnChanged();
    926             }
    927         }.run();
    928 
    929         mco.reset();
    930         mContentResolver.unregisterContentObserver(mco);
    931         assertFalse(mco.hadOnChanged());
    932         mContentResolver.update(TABLE1_URI, values, null, null);
    933 
    934         assertFalse(mco.hadOnChanged());
    935 
    936         try {
    937             mContentResolver.registerContentObserver(null, false, mco);
    938             fail("did not throw NullPointerException or IllegalArgumentException when uri is null.");
    939         } catch (NullPointerException e) {
    940             //expected.
    941         } catch (IllegalArgumentException e) {
    942             // also expected
    943         }
    944 
    945         try {
    946             mContentResolver.registerContentObserver(TABLE1_URI, false, null);
    947             fail("did not throw NullPointerException when register null content observer.");
    948         } catch (NullPointerException e) {
    949             //expected.
    950         }
    951 
    952         try {
    953             mContentResolver.unregisterContentObserver(null);
    954             fail("did not throw NullPointerException when unregister null content observer.");
    955         } catch (NullPointerException e) {
    956             //expected.
    957         }
    958     }
    959 
    960     public void testNotifyChange1() {
    961         final MockContentObserver mco = new MockContentObserver();
    962 
    963         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
    964         assertFalse(mco.hadOnChanged());
    965 
    966         mContentResolver.notifyChange(TABLE1_URI, mco);
    967         new PollingCheck() {
    968             @Override
    969             protected boolean check() {
    970                 return mco.hadOnChanged();
    971             }
    972         }.run();
    973 
    974         mContentResolver.unregisterContentObserver(mco);
    975     }
    976 
    977     public void testNotifyChange2() {
    978         final MockContentObserver mco = new MockContentObserver();
    979 
    980         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
    981         assertFalse(mco.hadOnChanged());
    982 
    983         mContentResolver.notifyChange(TABLE1_URI, mco, false);
    984         new PollingCheck() {
    985             @Override
    986             protected boolean check() {
    987                 return mco.hadOnChanged();
    988             }
    989         }.run();
    990 
    991         mContentResolver.unregisterContentObserver(mco);
    992     }
    993 
    994     public void testStartCancelSync() {
    995         Bundle extras = new Bundle();
    996 
    997         extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    998 
    999         ContentResolver.requestSync(ACCOUNT, AUTHORITY, extras);
   1000         //FIXME: how to get the result to assert.
   1001 
   1002         ContentResolver.cancelSync(ACCOUNT, AUTHORITY);
   1003         //FIXME: how to assert.
   1004     }
   1005 
   1006     public void testStartSyncFailure() {
   1007         try {
   1008             ContentResolver.requestSync(null, null, null);
   1009             fail("did not throw IllegalArgumentException when extras is null.");
   1010         } catch (IllegalArgumentException e) {
   1011             //expected.
   1012         }
   1013     }
   1014 
   1015     public void testValidateSyncExtrasBundle() {
   1016         Bundle extras = new Bundle();
   1017         extras.putInt("Integer", 20);
   1018         extras.putLong("Long", 10l);
   1019         extras.putBoolean("Boolean", true);
   1020         extras.putFloat("Float", 5.5f);
   1021         extras.putDouble("Double", 2.5);
   1022         extras.putString("String", "cts");
   1023         extras.putCharSequence("CharSequence", null);
   1024 
   1025         ContentResolver.validateSyncExtrasBundle(extras);
   1026 
   1027         extras.putChar("Char", 'a'); // type Char is invalid
   1028         try {
   1029             ContentResolver.validateSyncExtrasBundle(extras);
   1030             fail("did not throw IllegalArgumentException when extras is invalide.");
   1031         } catch (IllegalArgumentException e) {
   1032             //expected.
   1033         }
   1034     }
   1035 
   1036     private class MockContentObserver extends ContentObserver {
   1037         private boolean mHadOnChanged = false;
   1038 
   1039         public MockContentObserver() {
   1040             super(null);
   1041         }
   1042 
   1043         @Override
   1044         public boolean deliverSelfNotifications() {
   1045             return true;
   1046         }
   1047 
   1048         @Override
   1049         public synchronized void onChange(boolean selfChange) {
   1050             super.onChange(selfChange);
   1051             mHadOnChanged = true;
   1052         }
   1053 
   1054         public synchronized boolean hadOnChanged() {
   1055             return mHadOnChanged;
   1056         }
   1057 
   1058         public synchronized void reset() {
   1059             mHadOnChanged = false;
   1060         }
   1061     }
   1062 }
   1063