Project: platform_packages_apps_calendar
/*
 * Copyright (C) 2007 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
 
package com.android.calendar; 
 
import com.android.calendar.AsyncQueryService.Operation; 
import com.android.calendar.AsyncQueryServiceHelper.OperationInfo; 
 
import android.content.ComponentName; 
import android.content.ContentProvider; 
import android.content.ContentProviderOperation; 
import android.content.ContentProviderResult; 
import android.content.ContentResolver; 
import android.content.ContentValues; 
import android.content.Context; 
import android.content.Intent; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Handler; 
import android.os.HandlerThread; 
import android.os.Message; 
import android.test.ServiceTestCase; 
import android.test.mock.MockContentResolver; 
import android.test.mock.MockContext; 
import android.test.mock.MockCursor; 
import android.test.suitebuilder.annotation.LargeTest; 
import android.test.suitebuilder.annotation.SmallTest; 
import android.test.suitebuilder.annotation.Smoke; 
import android.util.Log; 
 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.concurrent.Semaphore; 
import java.util.concurrent.TimeUnit; 
 
/**
 * Unit tests for {@link android.text.format.DateUtils#formatDateRange}. 
 */
 
public class AsyncQueryServiceTest extends ServiceTestCase<AsyncQueryServiceHelper> { 
    private static final String TAG = "AsyncQueryServiceTest"
 
    private static final String AUTHORITY_URI = "content://AsyncQueryAuthority/"
 
    private static final String AUTHORITY = "AsyncQueryAuthority"
 
    private static final int MIN_DELAY = 50
 
    private static final int BASE_TEST_WAIT_TIME = MIN_DELAY * 5
 
    private static int mId = 0
 
    private static final String[] TEST_PROJECTION = new String[] { 
            "col1""col2""col3" 
    }; 
 
    private static final String TEST_SELECTION = "selection"
 
    private static final String[] TEST_SELECTION_ARGS = new String[] { 
            "arg1""arg2""arg3" 
    }; 
 
    public AsyncQueryServiceTest() { 
        super(AsyncQueryServiceHelper.class); 
    } 
 
    @Override 
    protected void setUp() throws Exception { 
        super.setUp(); 
    } 
 
    @Smoke 
    @SmallTest 
    public void testQuery() throws Exception { 
        int index = 0
        final OperationInfo[] work = new OperationInfo[1]; 
        work[index] = new OperationInfo(); 
        work[index].op = Operation.EVENT_ARG_QUERY; 
 
        work[index].token = ++mId; 
        work[index].cookie = ++mId; 
        work[index].uri = Uri.parse(AUTHORITY_URI + "blah"); 
        work[index].projection = TEST_PROJECTION; 
        work[index].selection = TEST_SELECTION; 
        work[index].selectionArgs = TEST_SELECTION_ARGS; 
        work[index].orderBy = "order"
 
        work[index].delayMillis = 0
        work[index].result = new TestCursor(); 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work); 
        aqs.startQuery(work[index].token, work[index].cookie, work[index].uri, 
                work[index].projection, work[index].selection, work[index].selectionArgs, 
                work[index].orderBy); 
 
        Log.d(TAG, "testQuery Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testQuery Done <<<<<<<<<<<<<<"); 
    } 
 
    @SmallTest 
    public void testInsert() throws Exception { 
        int index = 0
        final OperationInfo[] work = new OperationInfo[1]; 
        work[index] = new OperationInfo(); 
        work[index].op = Operation.EVENT_ARG_INSERT; 
 
        work[index].token = ++mId; 
        work[index].cookie = ++mId; 
        work[index].uri = Uri.parse(AUTHORITY_URI + "blah"); 
        work[index].values = new ContentValues(); 
        work[index].values.put("key", ++mId); 
 
        work[index].delayMillis = 0
        work[index].result = Uri.parse(AUTHORITY_URI + "Result=" + ++mId); 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work); 
        aqs.startInsert(work[index].token, work[index].cookie, work[index].uri, work[index].values, 
                work[index].delayMillis); 
 
        Log.d(TAG, "testInsert Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testInsert Done <<<<<<<<<<<<<<"); 
    } 
 
    @SmallTest 
    public void testUpdate() throws Exception { 
        int index = 0
        final OperationInfo[] work = new OperationInfo[1]; 
        work[index] = new OperationInfo(); 
        work[index].op = Operation.EVENT_ARG_UPDATE; 
 
        work[index].token = ++mId; 
        work[index].cookie = ++mId; 
        work[index].uri = Uri.parse(AUTHORITY_URI + ++mId); 
        work[index].values = new ContentValues(); 
        work[index].values.put("key", ++mId); 
        work[index].selection = TEST_SELECTION; 
        work[index].selectionArgs = TEST_SELECTION_ARGS; 
 
        work[index].delayMillis = 0
        work[index].result = ++mId; 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work); 
        aqs.startUpdate(work[index].token, work[index].cookie, work[index].uri, work[index].values, 
                work[index].selection, work[index].selectionArgs, work[index].delayMillis); 
 
        Log.d(TAG, "testUpdate Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testUpdate Done <<<<<<<<<<<<<<"); 
    } 
 
    @SmallTest 
    public void testDelete() throws Exception { 
        int index = 0
        final OperationInfo[] work = new OperationInfo[1]; 
        work[index] = new OperationInfo(); 
        work[index].op = Operation.EVENT_ARG_DELETE; 
 
        work[index].token = ++mId; 
        work[index].cookie = ++mId; 
        work[index].uri = Uri.parse(AUTHORITY_URI + "blah"); 
        work[index].selection = TEST_SELECTION; 
        work[index].selectionArgs = TEST_SELECTION_ARGS; 
 
        work[index].delayMillis = 0
        work[index].result = ++mId; 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work); 
        aqs.startDelete(work[index].token, 
                work[index].cookie, 
                work[index].uri, 
                work[index].selection, 
                work[index].selectionArgs, 
                work[index].delayMillis); 
 
        Log.d(TAG, "testDelete Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testDelete Done <<<<<<<<<<<<<<"); 
    } 
 
    @SmallTest 
    public void testBatch() throws Exception { 
        int index = 0
        final OperationInfo[] work = new OperationInfo[1]; 
        work[index] = new OperationInfo(); 
        work[index].op = Operation.EVENT_ARG_BATCH; 
 
        work[index].token = ++mId; 
        work[index].cookie = ++mId; 
        work[index].authority = AUTHORITY; 
        work[index].cpo = new ArrayList<ContentProviderOperation>(); 
        work[index].cpo.add(ContentProviderOperation.newInsert(Uri.parse(AUTHORITY_URI + ++mId)) 
                .build()); 
 
        work[index].delayMillis = 0
        ContentProviderResult[] resultArray = new ContentProviderResult[1]; 
        resultArray[0] = new ContentProviderResult(++mId); 
        work[index].result = resultArray; 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work); 
        aqs.startBatch(work[index].token, 
                work[index].cookie, 
                work[index].authority, 
                work[index].cpo, 
                work[index].delayMillis); 
 
        Log.d(TAG, "testBatch Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testBatch Done <<<<<<<<<<<<<<"); 
    } 
 
    @LargeTest 
    public void testDelay() throws Exception { 
        // Tests the ordering of the workqueue 
        int index = 0
        OperationInfo[] work = new OperationInfo[5]; 
        work[index++] = generateWork(MIN_DELAY * 2); 
        work[index++] = generateWork(0); 
        work[index++] = generateWork(MIN_DELAY * 1); 
        work[index++] = generateWork(0); 
        work[index++] = generateWork(MIN_DELAY * 3); 
 
        OperationInfo[] sorted = generateSortedWork(work, work.length); 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(sorted), sorted); 
        startWork(aqs, work); 
 
        Log.d(TAG, "testDelay Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", work.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testDelay Done <<<<<<<<<<<<<<"); 
    } 
 
    @LargeTest 
    public void testCancel_simpleCancelLastTest() throws Exception { 
        int index = 0
        OperationInfo[] work = new OperationInfo[5]; 
        work[index++] = generateWork(MIN_DELAY * 2); 
        work[index++] = generateWork(0); 
        work[index++] = generateWork(MIN_DELAY); 
        work[index++] = generateWork(0); 
        work[index] = generateWork(MIN_DELAY * 3); 
 
        // Not part of the expected as it will be canceled 
        OperationInfo toBeCancelled1 = work[index]; 
        OperationInfo[] expected = generateSortedWork(work, work.length - 1); 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected); 
        startWork(aqs, work); 
        Operation lastOne = aqs.getLastCancelableOperation(); 
        // Log.d(TAG, "lastOne = " + lastOne.toString()); 
        // Log.d(TAG, "toBeCancelled1 = " + toBeCancelled1.toString()); 
        assertTrue("1) delay=3 is not last", toBeCancelled1.equivalent(lastOne)); 
        assertEquals("Can't cancel delay 3"1, aqs.cancelOperation(lastOne.token)); 
 
        Log.d(TAG, "testCancel_simpleCancelLastTest Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", expected.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testCancel_simpleCancelLastTest Done <<<<<<<<<<<<<<"); 
    } 
 
    @LargeTest 
    public void testCancel_cancelSecondToLast() throws Exception { 
        int index = 0
        OperationInfo[] work = new OperationInfo[5]; 
        work[index++] = generateWork(MIN_DELAY * 2); 
        work[index++] = generateWork(0); 
        work[index++] = generateWork(MIN_DELAY); 
        work[index++] = generateWork(0); 
        work[index] = generateWork(MIN_DELAY * 3); 
 
        // Not part of the expected as it will be canceled 
        OperationInfo toBeCancelled1 = work[index]; 
        OperationInfo[] expected = new OperationInfo[4]; 
        expected[0] = work[1]; // delay = 0 
        expected[1] = work[3]; // delay = 0 
        expected[2] = work[2]; // delay = MIN_DELAY 
        expected[3] = work[4]; // delay = MIN_DELAY * 3 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected); 
        startWork(aqs, work); 
 
        Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3 
        assertTrue("2) delay=3 is not last", toBeCancelled1.equivalent(lastOne)); 
        assertEquals("Can't cancel delay 2"1, aqs.cancelOperation(work[0].token)); 
        assertEquals("Delay 2 should be gone"0, aqs.cancelOperation(work[0].token)); 
 
        Log.d(TAG, "testCancel_cancelSecondToLast Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", expected.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testCancel_cancelSecondToLast Done <<<<<<<<<<<<<<"); 
    } 
 
    @LargeTest 
    public void testCancel_multipleCancels() throws Exception { 
        int index = 0
        OperationInfo[] work = new OperationInfo[5]; 
        work[index++] = generateWork(MIN_DELAY * 2); 
        work[index++] = generateWork(0); 
        work[index++] = generateWork(MIN_DELAY); 
        work[index++] = generateWork(0); 
        work[index] = generateWork(MIN_DELAY * 3); 
 
        // Not part of the expected as it will be canceled 
        OperationInfo[] expected = new OperationInfo[3]; 
        expected[0] = work[1]; // delay = 0 
        expected[1] = work[3]; // delay = 0 
        expected[2] = work[2]; // delay = MIN_DELAY 
 
        TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected); 
        startWork(aqs, work); 
 
        Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3 
        assertTrue("3) delay=3 is not last", work[4].equivalent(lastOne)); 
        assertEquals("Can't cancel delay 2"1, aqs.cancelOperation(work[0].token)); 
        assertEquals("Delay 2 should be gone"0, aqs.cancelOperation(work[0].token)); 
        assertEquals("Can't cancel delay 3"1, aqs.cancelOperation(work[4].token)); 
        assertEquals("Delay 3 should be gone"0, aqs.cancelOperation(work[4].token)); 
 
        Log.d(TAG, "testCancel_multipleCancels Waiting >>>>>>>>>>>"); 
        assertEquals("Not all operations were executed.", expected.length, aqs 
                .waitForCompletion(BASE_TEST_WAIT_TIME)); 
        Log.d(TAG, "testCancel_multipleCancels Done <<<<<<<<<<<<<<"); 
    } 
 
    private OperationInfo generateWork(long delayMillis) { 
        OperationInfo work = new OperationInfo(); 
        work.op = Operation.EVENT_ARG_DELETE; 
 
        work.token = ++mId; 
        work.cookie = 100 + work.token; 
        work.uri = Uri.parse(AUTHORITY_URI + "blah"); 
        work.selection = TEST_SELECTION; 
        work.selectionArgs = TEST_SELECTION_ARGS; 
 
        work.delayMillis = delayMillis; 
        work.result = 1000 + work.token; 
        return work; 
    } 
 
    private void startWork(TestAsyncQueryService aqs, OperationInfo[] work) { 
        for (OperationInfo w : work) { 
            if (w != null) { 
                aqs.startDelete(w.token, w.cookie, w.uri, w.selection, w.selectionArgs, 
                        w.delayMillis); 
            } 
        } 
    } 
 
    OperationInfo[] generateSortedWork(OperationInfo[] work, int length) { 
        OperationInfo[] sorted = new OperationInfo[length]; 
        System.arraycopy(work, 0, sorted, 0, length); 
 
        // Set the scheduled time so they get sorted properly 
        for (OperationInfo w : sorted) { 
            if (w != null) { 
                w.calculateScheduledTime(); 
            } 
        } 
 
        // Stable sort by scheduled time 
        Arrays.sort(sorted); 
 
        Log.d(TAG, "Unsorted work: " + work.length); 
        for (OperationInfo w : work) { 
            if (w != null) { 
                Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis); 
            } 
        } 
        Log.d(TAG, "Sorted work: " + sorted.length); 
        for (OperationInfo w : sorted) { 
            if (w != null) { 
                Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis); 
            } 
        } 
 
        return sorted; 
    } 
 
    private Context buildTestContext(final OperationInfo[] work) { 
        MockContext context = new MockContext() { 
            MockContentResolver mResolver; 
 
            @Override 
            public ContentResolver getContentResolver() { 
                if (mResolver == null) { 
                    ContentProvider provider = new TestProvider(work); 
                    mResolver = new MockContentResolver(); 
                    mResolver.addProvider(AUTHORITY, provider); 
                } 
                return mResolver; 
            } 
 
            @Override 
            public String getPackageName() { 
                return AsyncQueryServiceTest.class.getPackage().getName(); 
            } 
 
            @Override 
            public ComponentName startService(Intent service) { 
                AsyncQueryServiceTest.this.startService(service); 
                return service.getComponent(); 
            } 
        }; 
 
        return context; 
    } 
 
    private final class TestCursor extends MockCursor { 
        int mUnique = ++mId; 
 
        @Override 
        public int getCount() { 
            return mUnique; 
        } 
    } 
 
    /**
     * TestAsyncQueryService takes the expected results in the constructor. They 
     * are used to verify the data passed to the callbacks. 
     */
 
    class TestAsyncQueryService extends AsyncQueryService { 
        int mIndex = 0
 
        private OperationInfo[] mWork; 
 
        private Semaphore mCountingSemaphore; 
 
        public TestAsyncQueryService(Context context, OperationInfo[] work) { 
            super(context); 
            mCountingSemaphore = new Semaphore(0); 
 
            // run in a separate thread but call the same code 
            HandlerThread thread = new HandlerThread("TestAsyncQueryService"); 
            thread.start(); 
            super.setTestHandler(new Handler(thread.getLooper()) { 
                @Override 
                public void handleMessage(Message msg) { 
                    TestAsyncQueryService.this.handleMessage(msg); 
                } 
            }); 
 
            mWork = work; 
        } 
 
        @Override 
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 
            Log.d(TAG, "onQueryComplete tid=" + Thread.currentThread().getId()); 
            Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex); 
 
            assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_QUERY); 
            assertEquals(mWork[mIndex].token, token); 
            /*
             * Even though our TestProvider returned mWork[mIndex].result, it is 
             * wrapped with new'ed CursorWrapperInner and there's no equal() in 
             * CursorWrapperInner. assertEquals the two cursor will always fail. 
             * So just compare the count which will be unique in our TestCursor; 
             */
 
            assertEquals(((Cursor) mWork[mIndex].result).getCount(), cursor.getCount()); 
 
            mIndex++; 
            mCountingSemaphore.release(); 
        } 
 
        @Override 
        protected void onInsertComplete(int token, Object cookie, Uri uri) { 
            Log.d(TAG, "onInsertComplete tid=" + Thread.currentThread().getId()); 
            Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex); 
 
            assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_INSERT); 
            assertEquals(mWork[mIndex].token, token); 
            assertEquals(mWork[mIndex].result, uri); 
 
            mIndex++; 
            mCountingSemaphore.release(); 
        } 
 
        @Override 
        protected void onUpdateComplete(int token, Object cookie, int result) { 
            Log.d(TAG, "onUpdateComplete tid=" + Thread.currentThread().getId()); 
            Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex); 
 
            assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_UPDATE); 
            assertEquals(mWork[mIndex].token, token); 
            assertEquals(mWork[mIndex].result, result); 
 
            mIndex++; 
            mCountingSemaphore.release(); 
        } 
 
        @Override 
        protected void onDeleteComplete(int token, Object cookie, int result) { 
            Log.d(TAG, "onDeleteComplete tid=" + Thread.currentThread().getId()); 
            Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex); 
 
            assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_DELETE); 
            assertEquals(mWork[mIndex].token, token); 
            assertEquals(mWork[mIndex].result, result); 
 
            mIndex++; 
            mCountingSemaphore.release(); 
        } 
 
        @Override 
        protected void onBatchComplete(int token, Object cookie, ContentProviderResult[] results) { 
            Log.d(TAG, "onBatchComplete tid=" + Thread.currentThread().getId()); 
            Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex); 
 
            assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_BATCH); 
            assertEquals(mWork[mIndex].token, token); 
 
            ContentProviderResult[] expected = (ContentProviderResult[]) mWork[mIndex].result; 
            assertEquals(expected.length, results.length); 
            for (int i = 0; i < expected.length; ++i) { 
                assertEquals(expected[i].count, results[i].count); 
                assertEquals(expected[i].uri, results[i].uri); 
            } 
 
            mIndex++; 
            mCountingSemaphore.release(); 
        } 
 
        public int waitForCompletion(long timeoutMills) { 
            Log.d(TAG, "waitForCompletion tid=" + Thread.currentThread().getId()); 
            int count = 0
            try { 
                while (count < mWork.length) { 
                    if (!mCountingSemaphore.tryAcquire(timeoutMills, TimeUnit.MILLISECONDS)) { 
                        break
                    } 
                    count++; 
                } 
            } catch (InterruptedException e) { 
            } 
            return count; 
        } 
    } 
 
    /**
     * This gets called by AsyncQueryServiceHelper to read or write the data. It 
     * also verifies the data against the data passed in the constructor 
     */
 
    class TestProvider extends ContentProvider { 
        OperationInfo[] mWork; 
 
        int index = 0
 
        public TestProvider(OperationInfo[] work) { 
            mWork = work; 
        } 
 
        @Override 
        public final Cursor query(Uri uri, String[] projection, String selection, 
                String[] selectionArgs, String orderBy) { 
            Log.d(TAG, "Provider query index=" + index); 
            assertEquals(mWork[index].op, Operation.EVENT_ARG_QUERY); 
            assertEquals(mWork[index].uri, uri); 
            assertEquals(mWork[index].projection, projection); 
            assertEquals(mWork[index].selection, selection); 
            assertEquals(mWork[index].selectionArgs, selectionArgs); 
            assertEquals(mWork[index].orderBy, orderBy); 
            return (Cursor) mWork[index++].result; 
        } 
 
        @Override 
        public Uri insert(Uri uri, ContentValues values) { 
            Log.d(TAG, "Provider insert index=" + index); 
            assertEquals(mWork[index].op, Operation.EVENT_ARG_INSERT); 
            assertEquals(mWork[index].uri, uri); 
            assertEquals(mWork[index].values, values); 
            return (Uri) mWork[index++].result; 
        } 
 
        @Override 
        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
            Log.d(TAG, "Provider update index=" + index); 
            assertEquals(mWork[index].op, Operation.EVENT_ARG_UPDATE); 
            assertEquals(mWork[index].uri, uri); 
            assertEquals(mWork[index].values, values); 
            assertEquals(mWork[index].selection, selection); 
            assertEquals(mWork[index].selectionArgs, selectionArgs); 
            return (Integer) mWork[index++].result; 
        } 
 
        @Override 
        public int delete(Uri uri, String selection, String[] selectionArgs) { 
            Log.d(TAG, "Provider delete index=" + index); 
            assertEquals(mWork[index].op, Operation.EVENT_ARG_DELETE); 
            assertEquals(mWork[index].uri, uri); 
            assertEquals(mWork[index].selection, selection); 
            assertEquals(mWork[index].selectionArgs, selectionArgs); 
            return (Integer) mWork[index++].result; 
        } 
 
        @Override 
        public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) { 
            Log.d(TAG, "Provider applyBatch index=" + index); 
            assertEquals(mWork[index].op, Operation.EVENT_ARG_BATCH); 
            assertEquals(mWork[index].cpo, operations); 
            return (ContentProviderResult[]) mWork[index++].result; 
        } 
 
        @Override 
        public String getType(Uri uri) { 
            return null
        } 
 
        @Override 
        public boolean onCreate() { 
            return false
        } 
    } 
}