Loading packages/MtpDocumentsProvider/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -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 packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +71 −4 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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); } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java 0 → 100644 +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; } } packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +81 −2 Original line number Diff line number Diff line Loading @@ -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++; } } } Loading
packages/MtpDocumentsProvider/Android.mk +2 −0 Original line number Diff line number Diff line Loading @@ -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
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +71 −4 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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); } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java 0 → 100644 +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; } }
packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +81 −2 Original line number Diff line number Diff line Loading @@ -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++; } } }