Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e68a6936 authored by Marco Nelissen's avatar Marco Nelissen Committed by Android (Google) Code Review
Browse files

Merge "Refactor FileInserter in MediaScanner and adding unit tests for the newly added class."

parents 47154025 8e2ed8d5
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 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 android.media;

import android.content.ContentValues;
import android.content.IContentProvider;
import android.net.Uri;
import android.os.RemoteException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * A MediaScanner helper class which enables us to do lazy insertion on the
 * given provider. This class manages buffers internally and flushes when they
 * are full. Note that you should call flushAll() after using this class.
 * {@hide}
 */
public class MediaInserter {
    private HashMap<Uri, List<ContentValues>> mRowMap =
            new HashMap<Uri, List<ContentValues>>();

    private IContentProvider mProvider;
    private int mBufferSizePerUri;

    public MediaInserter(IContentProvider provider, int bufferSizePerUri) {
        mProvider = provider;
        mBufferSizePerUri = bufferSizePerUri;
    }

    public void insert(Uri tableUri, ContentValues values) throws RemoteException {
        List<ContentValues> list = mRowMap.get(tableUri);
        if (list == null) {
            list = new ArrayList<ContentValues>();
            mRowMap.put(tableUri, list);
        }
        list.add(new ContentValues(values));
        if (list.size() >= mBufferSizePerUri) {
            flush(tableUri);
        }
    }

    public void flushAll() throws RemoteException {
        for (Uri tableUri : mRowMap.keySet()){
            flush(tableUri);
        }
        mRowMap.clear();
    }

    private void flush(Uri tableUri) throws RemoteException {
        List<ContentValues> list = mRowMap.get(tableUri);
        if (!list.isEmpty()) {
            ContentValues[] valuesArray = new ContentValues[list.size()];
            valuesArray = list.toArray(valuesArray);
            mProvider.bulkInsert(tableUri, valuesArray);
            list.clear();
        }
    }
}
+7 −55
Original line number Diff line number Diff line
@@ -377,43 +377,7 @@ public class MediaScanner
        }
    }

    private class FileInserter {

        private final Uri mUri;
        private final ContentValues[] mValues;
        private int mIndex;

        public FileInserter(Uri uri, int count) {
            mUri = uri;
            mValues = new ContentValues[count];
        }

        public Uri insert(ContentValues values) {
            if (mIndex == mValues.length) {
                flush();
            }
            mValues[mIndex++] = values;
            // URI not needed when doing bulk inserts
            return null;
        }

        public void flush() {
            while (mIndex < mValues.length) {
                mValues[mIndex++] = null;
            }
            try {
                mMediaProvider.bulkInsert(mUri, mValues);
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException in FileInserter.flush()", e);
            }
            mIndex = 0;
        }
    }

    private FileInserter mAudioInserter;
    private FileInserter mVideoInserter;
    private FileInserter mImageInserter;
    private FileInserter mFileInserter;
    private MediaInserter mMediaInserter;

    // hashes file path to FileCacheEntry.
    // path should be lower case if mCaseInsensitivePaths is true
@@ -880,17 +844,14 @@ public class MediaScanner
            }

            Uri tableUri = mFilesUri;
            FileInserter inserter = mFileInserter;
            MediaInserter inserter = mMediaInserter;
            if (!mNoMedia) {
                if (MediaFile.isVideoFileType(mFileType)) {
                    tableUri = mVideoUri;
                    inserter = mVideoInserter;
                } else if (MediaFile.isImageFileType(mFileType)) {
                    tableUri = mImagesUri;
                    inserter = mImageInserter;
                } else if (MediaFile.isAudioFileType(mFileType)) {
                    tableUri = mAudioUri;
                    inserter = mAudioInserter;
                }
            }
            Uri result = null;
@@ -913,7 +874,7 @@ public class MediaScanner
                if (inserter == null || entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
                    result = mMediaProvider.insert(tableUri, values);
                } else {
                    result = inserter.insert(values);
                    inserter.insert(tableUri, values);
                }

                if (result != null) {
@@ -1212,11 +1173,8 @@ public class MediaScanner
            long prescan = System.currentTimeMillis();

            if (ENABLE_BULK_INSERTS) {
                // create FileInserters for bulk inserts
                mAudioInserter = new FileInserter(mAudioUri, 500);
                mVideoInserter = new FileInserter(mVideoUri, 500);
                mImageInserter = new FileInserter(mImagesUri, 500);
                mFileInserter = new FileInserter(mFilesUri, 500);
                // create MediaInserter for bulk inserts
                mMediaInserter = new MediaInserter(mMediaProvider, 500);
            }

            for (int i = 0; i < directories.length; i++) {
@@ -1225,14 +1183,8 @@ public class MediaScanner

            if (ENABLE_BULK_INSERTS) {
                // flush remaining inserts
                mAudioInserter.flush();
                mVideoInserter.flush();
                mImageInserter.flush();
                mFileInserter.flush();
                mAudioInserter = null;
                mVideoInserter = null;
                mImageInserter = null;
                mFileInserter = null;
                mMediaInserter.flushAll();
                mMediaInserter = null;
            }

            long scan = System.currentTimeMillis();
+2 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_JAVA_LIBRARIES := android.test.runner

LOCAL_STATIC_JAVA_LIBRARIES := easymocklib

LOCAL_PACKAGE_NAME := mediaframeworktest

include $(BUILD_PACKAGE)
+5 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
        addMediaMetadataRetrieverStateUnitTests(suite);
        addMediaRecorderStateUnitTests(suite);
        addMediaPlayerStateUnitTests(suite);
        addMediaScannerUnitTests(suite);
        return suite;
    }

@@ -89,4 +90,8 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
        suite.addTestSuite(MediaPlayerSetVolumeStateUnitTest.class);
        suite.addTestSuite(MediaPlayerMetadataParserTest.class);
    }

    private void addMediaScannerUnitTests(TestSuite suite) {
        suite.addTestSuite(MediaInserterTest.class);
    }
}
+246 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 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.mediaframeworktest.unit;

import android.content.ContentValues;
import android.content.IContentProvider;
import android.media.MediaInserter;
import android.net.Uri;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Files;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import dalvik.annotation.TestTargetClass;

import org.easymock.EasyMock;
import org.easymock.IArgumentMatcher;

@TestTargetClass(MediaInserter.class)
public class MediaInserterTest extends InstrumentationTestCase {

    private MediaInserter mMediaInserter;
    private static final int TEST_BUFFER_SIZE = 10;
    private IContentProvider mMockProvider;

    private int mFilesCounter;
    private int mAudioCounter;
    private int mVideoCounter;
    private int mImagesCounter;

    private static final String sVolumeName = "external";
    private static final Uri sAudioUri = Audio.Media.getContentUri(sVolumeName);
    private static final Uri sVideoUri = Video.Media.getContentUri(sVolumeName);
    private static final Uri sImagesUri = Images.Media.getContentUri(sVolumeName);
    private static final Uri sFilesUri = Files.getContentUri(sVolumeName);

    private static class MediaUriMatcher implements IArgumentMatcher {
        private Uri mUri;

        private MediaUriMatcher(Uri uri) {
            mUri = uri;
        }

        @Override
        public boolean matches(Object argument) {
            if (!(argument instanceof Uri)) {
                return false;
            }

            Uri actualUri = (Uri) argument;
            if (actualUri == mUri) return true;
            return false;
        }

        @Override
        public void appendTo(StringBuffer buffer) {
            buffer.append("expected a TableUri '").append(mUri).append("'");
        }

        private static Uri expectMediaUri(Uri in) {
            EasyMock.reportMatcher(new MediaUriMatcher(in));
            return null;
        }
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mMockProvider = EasyMock.createMock(IContentProvider.class);
        mMediaInserter = new MediaInserter(mMockProvider, TEST_BUFFER_SIZE);
        mFilesCounter = 0;
        mAudioCounter = 0;
        mVideoCounter = 0;
        mImagesCounter = 0;
    }

    private ContentValues createFileContent() {
        ContentValues values = new ContentValues();
        values.put("_data", "/mnt/sdcard/file" + ++mFilesCounter);
        return values;
    }

    private ContentValues createAudioContent() {
        ContentValues values = new ContentValues();
        values.put("_data", "/mnt/sdcard/audio" + ++mAudioCounter);
        return values;
    }

    private ContentValues createVideoContent() {
        ContentValues values = new ContentValues();
        values.put("_data", "/mnt/sdcard/video" + ++mVideoCounter);
        return values;
    }

    private ContentValues createImageContent() {
        ContentValues values = new ContentValues();
        values.put("_data", "/mnt/sdcard/image" + ++mImagesCounter);
        return values;
    }

    private ContentValues createContent(Uri uri) {
        if (uri == sFilesUri) return createFileContent();
        else if (uri == sAudioUri) return createAudioContent();
        else if (uri == sVideoUri) return createVideoContent();
        else if (uri == sImagesUri) return createImageContent();
        else throw new IllegalArgumentException("Unknown URL: " + uri.toString());
    }

    private void fillBuffer(Uri uri, int numberOfFiles) throws Exception {
        ContentValues values;
        for (int i = 0; i < numberOfFiles; ++i) {
            values = createContent(uri);
            mMediaInserter.insert(uri, values);
        }
    }

    @SmallTest
    public void testInsertContentsLessThanBufferSize() throws Exception {
        EasyMock.replay(mMockProvider);

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testInsertContentsEqualToBufferSize() throws Exception {
        EasyMock.expect(mMockProvider.bulkInsert(
                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(4);
        EasyMock.replay(mMockProvider);

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE);

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testInsertContentsMoreThanBufferSize() throws Exception {
        EasyMock.expect(mMockProvider.bulkInsert(
                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(4);
        EasyMock.replay(mMockProvider);

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE + 1);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE + 2);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testFlushAllWithEmptyContents() throws Exception {
        EasyMock.replay(mMockProvider);

        mMediaInserter.flushAll();

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testFlushAllWithSomeContents() throws Exception {
        EasyMock.expect(mMockProvider.bulkInsert(
                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(4);
        EasyMock.replay(mMockProvider);

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
        mMediaInserter.flushAll();

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testInsertContentsAfterFlushAll() throws Exception {
        EasyMock.expect(mMockProvider.bulkInsert(
                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(8);
        EasyMock.replay(mMockProvider);

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
        mMediaInserter.flushAll();

        fillBuffer(sFilesUri, TEST_BUFFER_SIZE + 1);
        fillBuffer(sAudioUri, TEST_BUFFER_SIZE + 2);
        fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
        fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);

        EasyMock.verify(mMockProvider);
    }

    @SmallTest
    public void testInsertContentsWithDifferentSizePerContentType() throws Exception {
        EasyMock.expect(mMockProvider.bulkInsert(MediaUriMatcher.expectMediaUri(sFilesUri),
                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(1);
        EasyMock.expect(mMockProvider.bulkInsert(MediaUriMatcher.expectMediaUri(sAudioUri),
                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(2);
        EasyMock.expect(mMockProvider.bulkInsert(MediaUriMatcher.expectMediaUri(sVideoUri),
                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(3);
        EasyMock.expect(mMockProvider.bulkInsert(MediaUriMatcher.expectMediaUri(sImagesUri),
                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
        EasyMock.expectLastCall().times(4);
        EasyMock.replay(mMockProvider);

        for (int i = 0; i < TEST_BUFFER_SIZE; ++i) {
            fillBuffer(sFilesUri, 1);
            fillBuffer(sAudioUri, 2);
            fillBuffer(sVideoUri, 3);
            fillBuffer(sImagesUri, 4);
        }

        EasyMock.verify(mMockProvider);
    }
}