chromium/android_webview/test/shell/src/org/chromium/android_webview/test/TestContentProvider.java

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/** Content provider for testing content URLs. */
package org.chromium.android_webview.test;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.AbstractCursor;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

// Note: if you move this class, make sure you have also updated AndroidManifest.xml
public class TestContentProvider extends ContentProvider {
    private static final String AUTHORITY = "org.chromium.android_webview.test.TestContentProvider";
    private static final String CONTENT_SCHEME = "content://";
    private static final String CONTENT_IMAGE_TYPE = "image/png";
    private static final String CONTENT_IMAGE_TARGET = "image";
    private static final String GET_RESOURCE_REQUEST_COUNT = "get_resource_request_count";
    private static final String RESET_RESOURCE_REQUEST_COUNT = "reset_resource_request_count";
    private static final String TAG = "TestContentProvider";
    private static final int EXPECTED_COLUMN_INDEX = 0;
    private static final Map<String, String> REGISTERED_CONTENT_TYPE =
            new HashMap<String, String>();
    private static final Map<String, byte[]> REGISTERED_RESPONSE = new HashMap<String, byte[]>();
    private final Map<String, Integer> mResourceRequestCount;

    // 1x1 black dot png image.
    private static final byte[] IMAGE = {
        (byte) 0x89,
        0x50,
        0x4e,
        0x47,
        0x0d,
        0x0a,
        0x1a,
        0x0a,
        0x00,
        0x00,
        0x00,
        0x0d,
        0x49,
        0x48,
        0x44,
        0x52,
        0x00,
        0x00,
        0x00,
        0x01,
        0x00,
        0x00,
        0x00,
        0x01,
        0x08,
        0x00,
        0x00,
        0x00,
        0x00,
        0x3a,
        0x7e,
        (byte) 0x9b,
        0x55,
        0x00,
        0x00,
        0x00,
        0x01,
        0x73,
        0x52,
        0x47,
        0x42,
        0x00,
        (byte) 0xae,
        (byte) 0xce,
        0x1c,
        (byte) 0xe9,
        0x00,
        0x00,
        0x00,
        0x0d,
        0x49,
        0x44,
        0x41,
        0x54,
        0x08,
        0x1d,
        0x01,
        0x02,
        0x00,
        (byte) 0xfd,
        (byte) 0xff,
        0x00,
        0x00,
        0x00,
        0x02,
        0x00,
        0x01,
        (byte) 0xcd,
        (byte) 0xe3,
        (byte) 0xd1,
        0x2b,
        0x00,
        0x00,
        0x00,
        0x00,
        0x49,
        0x45,
        0x4e,
        0x44,
        (byte) 0xae,
        0x42,
        0x60,
        (byte) 0x82
    };

    public static String createContentUrl(String target) {
        return CONTENT_SCHEME + AUTHORITY + "/" + target;
    }

    private static Uri createRequestUri(final String target, String resource) {
        return Uri.parse(createContentUrl(target) + "?" + resource);
    }

    public static int getResourceRequestCount(Context context, String resource) {
        Uri uri = createRequestUri(GET_RESOURCE_REQUEST_COUNT, resource);
        final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
        try {
            cursor.moveToFirst();
            return cursor.getInt(EXPECTED_COLUMN_INDEX);
        } finally {
            cursor.close();
        }
    }

    public static void resetResourceRequestCount(Context context, String resource) {
        Uri uri = createRequestUri(RESET_RESOURCE_REQUEST_COUNT, resource);
        // A null cursor is returned for this request.
        context.getContentResolver().query(uri, null, null, null, null);
    }

    public static void register(String target, String contentType, byte[] response) {
        REGISTERED_CONTENT_TYPE.put(target, contentType);
        REGISTERED_RESPONSE.put(target, response);
    }

    public TestContentProvider() {
        super();
        mResourceRequestCount = new HashMap<String, Integer>();
        register(CONTENT_IMAGE_TARGET, CONTENT_IMAGE_TYPE, IMAGE);
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
        String target = uri.getLastPathSegment();
        if (mResourceRequestCount.containsKey(target)) {
            mResourceRequestCount.put(target, mResourceRequestCount.get(target) + 1);
        } else {
            mResourceRequestCount.put(target, 1);
        }
        if (REGISTERED_RESPONSE.containsKey(target)) return createResponse(target);
        // Default to return the registered image content.
        return createResponse(CONTENT_IMAGE_TARGET);
    }

    @Override
    public String getType(Uri uri) {
        String target = uri.getLastPathSegment();
        if (REGISTERED_CONTENT_TYPE.containsKey(target)) return REGISTERED_CONTENT_TYPE.get(target);
        // Default to return the type for the registered image content.
        return CONTENT_IMAGE_TYPE;
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        return 0;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    /** Cursor object for retrieving resource request counters. */
    private static class ProviderStateCursor extends AbstractCursor {
        private final int mResourceRequestCount;

        public ProviderStateCursor(int resourceRequestCount) {
            mResourceRequestCount = resourceRequestCount;
        }

        @Override
        public boolean isNull(int columnIndex) {
            return columnIndex != EXPECTED_COLUMN_INDEX;
        }

        @Override
        public int getCount() {
            return 1;
        }

        @Override
        public int getType(int columnIndex) {
            return columnIndex == EXPECTED_COLUMN_INDEX
                    ? Cursor.FIELD_TYPE_INTEGER
                    : Cursor.FIELD_TYPE_NULL;
        }

        private void unsupported() {
            throw new UnsupportedOperationException();
        }

        @Override
        public double getDouble(int columnIndex) {
            unsupported();
            return 0.0;
        }

        @Override
        public float getFloat(int columnIndex) {
            unsupported();
            return 0.0f;
        }

        @Override
        public int getInt(int columnIndex) {
            return columnIndex == EXPECTED_COLUMN_INDEX ? mResourceRequestCount : -1;
        }

        @Override
        public short getShort(int columnIndex) {
            unsupported();
            return 0;
        }

        @Override
        public long getLong(int columnIndex) {
            return getInt(columnIndex);
        }

        @Override
        public String getString(int columnIndex) {
            unsupported();
            return null;
        }

        @Override
        public String[] getColumnNames() {
            return new String[] {GET_RESOURCE_REQUEST_COUNT};
        }
    }

    @Override
    public Cursor query(
            Uri uri,
            String[] projection,
            String selection,
            String[] selectionArgs,
            String sortOrder) {
        String action = uri.getLastPathSegment();
        String resource = uri.getQuery();
        if (GET_RESOURCE_REQUEST_COUNT.equals(action)) {
            return new ProviderStateCursor(
                    mResourceRequestCount.containsKey(resource)
                            ? mResourceRequestCount.get(resource)
                            : 0);
        } else if (RESET_RESOURCE_REQUEST_COUNT.equals(action)) {
            mResourceRequestCount.put(resource, 0);
        }
        return null;
    }

    private static AssetFileDescriptor createResponse(String target) {
        ParcelFileDescriptor[] pfds = null;
        FileOutputStream fileOut = null;
        try {
            try {
                pfds = ParcelFileDescriptor.createPipe();
                fileOut = new FileOutputStream(pfds[1].getFileDescriptor());
                fileOut.write(REGISTERED_RESPONSE.get(target));
                fileOut.flush();
                return new AssetFileDescriptor(pfds[0], 0, -1);
            } finally {
                if (fileOut != null) fileOut.close();
                if (pfds != null && pfds[1] != null) pfds[1].close();
            }
        } catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        return null;
    }
}