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

Commit 67503233 authored by Daichi Hirono's avatar Daichi Hirono Committed by Android (Google) Code Review
Browse files

Merge "Add openDevice and closeDevice methods to MtpDocumentsProvider."

parents b1ca5ed7 d5152429
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
LOCAL_PROGUARD_FLAGS := '-keepclassmembers class * {' \
    ' @com.android.internal.annotations.VisibleForTesting *; }'

include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/tests/Android.mk
+71 −4
Original line number Diff line number Diff line
@@ -16,14 +16,24 @@

package com.android.mtp;

import android.content.ContentResolver;
import android.database.Cursor;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * DocumentsProvider for MTP devices.
 */
public class MtpDocumentsProvider extends DocumentsProvider {
    private static final String TAG = "MtpDocumentsProvider";
    public static final String AUTHORITY = "com.android.mtp.documents";
@@ -40,32 +50,89 @@ public class MtpDocumentsProvider extends DocumentsProvider {
            Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
    };

    private MtpManager mDeviceModel;
    private ContentResolver mResolver;

    @Override
    public boolean onCreate() {
        mDeviceModel = new MtpManager(getContext());
        mResolver = getContext().getContentResolver();
        return true;
    }

    @VisibleForTesting
    void onCreateForTesting(MtpManager deviceModel, ContentResolver resolver) {
        this.mDeviceModel = deviceModel;
        this.mResolver = resolver;
    }

    @Override
    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
        return null;
        throw new FileNotFoundException();
    }

    @Override
    public Cursor queryDocument(String documentId, String[] projection)
            throws FileNotFoundException {
        return null;
        throw new FileNotFoundException();
    }

    @Override
    public Cursor queryChildDocuments(String parentDocumentId,
            String[] projection, String sortOrder)
            throws FileNotFoundException {
        return null;
        throw new FileNotFoundException();
    }

    @Override
    public ParcelFileDescriptor openDocument(String documentId, String mode,
            CancellationSignal signal) throws FileNotFoundException {
        return null;
        throw new FileNotFoundException();
    }

    // TODO: Remove annotation when the method starts to be used.
    @VisibleForTesting
    void openDevice(int deviceId) {
        try {
            mDeviceModel.openDevice(deviceId);
            notifyRootsUpdate();
        } catch (IOException error) {
            Log.d(TAG, "Failed to open the MTP device: " + deviceId);
        }
    }

    // TODO: Remove annotation when the method starts to be used.
    @VisibleForTesting
    void closeDevice(int deviceId) {
        try {
            mDeviceModel.closeDevice(deviceId);
            notifyRootsUpdate();
        } catch (IOException error) {
            Log.d(TAG, "Failed to close the MTP device: " + deviceId);
        }
    }

    // TODO: Remove annotation when the method starts to be used.
    @VisibleForTesting
    void closeAllDevices() {
        boolean closed = false;
        for (int deviceId : mDeviceModel.getOpenedDeviceIds()) {
            try {
                mDeviceModel.closeDevice(deviceId);
                closed = true;
            } catch (IOException d) {
                Log.d(TAG, "Failed to close the MTP device: " + deviceId);
            }
        }
        if (closed) {
            notifyRootsUpdate();
        }
    }

    private void notifyRootsUpdate() {
        mResolver.notifyChange(
                DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY),
                null,
                false);
    }
}
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.mtp;

import android.content.Context;

import java.io.IOException;

/**
 * The model wrapping android.mtp API.
 */
class MtpManager {
    MtpManager(Context context) {
    }

    void openDevice(int deviceId) throws IOException {
        // TODO: Implement this method.
    }

    void closeDevice(int deviceId) throws IOException {
        // TODO: Implement this method.
    }

    int[] getOpenedDeviceIds() {
        // TODO: Implement this method.
        return null;
    }
}
+81 −2
Original line number Diff line number Diff line
@@ -16,13 +16,92 @@

package com.android.mtp;

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;

import java.io.IOException;

@SmallTest
public class MtpDocumentsProviderTest extends AndroidTestCase {
    public void testBasic() {
    public void testOpenAndCloseDevice() throws Exception {
        final ContentResolver resolver = new ContentResolver();
        final MtpDocumentsProvider provider = new MtpDocumentsProvider();
        assertNotNull(provider);
        provider.onCreateForTesting(new MtpManagerMock(getContext()), resolver);

        provider.openDevice(MtpManagerMock.SUCCESS_DEVICE_ID);
        assertEquals(1, resolver.changeCount);
        provider.closeDevice(MtpManagerMock.SUCCESS_DEVICE_ID);
        assertEquals(2, resolver.changeCount);

        provider.openDevice(MtpManagerMock.FAILURE_DEVICE_ID);
        assertEquals(2, resolver.changeCount);
        provider.closeDevice(MtpManagerMock.FAILURE_DEVICE_ID);
        assertEquals(2, resolver.changeCount);
    }

    public void testCloseAllDevices() {
        final ContentResolver resolver = new ContentResolver();
        final MtpDocumentsProvider provider = new MtpDocumentsProvider();
        provider.onCreateForTesting(new MtpManagerMock(getContext()), resolver);

        provider.closeAllDevices();
        assertEquals(0, resolver.changeCount);

        provider.openDevice(MtpManagerMock.SUCCESS_DEVICE_ID);
        assertEquals(1, resolver.changeCount);

        provider.closeAllDevices();
        assertEquals(2, resolver.changeCount);
    }

    private static class MtpManagerMock extends MtpManager {
        final static int SUCCESS_DEVICE_ID = 1;
        final static int FAILURE_DEVICE_ID = 2;

        private boolean opened = false;

        MtpManagerMock(Context context) {
            super(context);
        }

        @Override
        void openDevice(int deviceId) throws IOException {
            if (deviceId == SUCCESS_DEVICE_ID) {
                opened = true;
            } else {
                throw new IOException();
            }
        }

        @Override
        void closeDevice(int deviceId) throws IOException {
            if (opened && deviceId == SUCCESS_DEVICE_ID) {
                opened = false;
            } else {
                throw new IOException();
            }
        }

        @Override
        int[] getOpenedDeviceIds() {
            if (opened) {
                return new int[] { SUCCESS_DEVICE_ID };
            } else {
                return new int[0];
            }
        }
    }

    private static class ContentResolver extends MockContentResolver {
        int changeCount = 0;

        @Override
        public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
            changeCount++;
        }
    }
}