1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mtp;
18
19import android.content.Context;
20import android.hardware.usb.UsbDevice;
21import android.hardware.usb.UsbManager;
22import android.mtp.MtpConstants;
23import android.mtp.MtpEvent;
24import android.mtp.MtpObjectInfo;
25import android.os.CancellationSignal;
26import android.os.OperationCanceledException;
27import android.os.ParcelFileDescriptor;
28import android.os.SystemClock;
29import android.test.InstrumentationTestCase;
30
31import java.io.IOException;
32import java.util.Arrays;
33import java.util.concurrent.Callable;
34import java.util.concurrent.FutureTask;
35import java.util.concurrent.TimeUnit;
36
37@RealDeviceTest
38public class MtpManagerTest extends InstrumentationTestCase {
39    private static final int TIMEOUT_MS = 1000;
40    UsbManager mUsbManager;
41    MtpManager mManager;
42    UsbDevice mUsbDevice;
43
44    @Override
45    public void setUp() throws Exception {
46        mUsbManager = getContext().getSystemService(UsbManager.class);
47        mManager = new MtpManager(getContext());
48        mUsbDevice = TestUtil.setupMtpDevice(getInstrumentation(), mUsbManager, mManager);
49    }
50
51    @Override
52    public void tearDown() throws IOException {
53        mManager.closeDevice(mUsbDevice.getDeviceId());
54    }
55
56    @Override
57    public TestResultInstrumentation getInstrumentation() {
58        return (TestResultInstrumentation) super.getInstrumentation();
59    }
60
61    public void testCancelEvent() throws Exception {
62        final CancellationSignal signal = new CancellationSignal();
63        final FutureTask<Boolean> future = new FutureTask<Boolean>(
64                new Callable<Boolean>() {
65                    @Override
66                    public Boolean call() throws IOException {
67                        try {
68                            while (true) {
69                                mManager.readEvent(mUsbDevice.getDeviceId(), signal);
70                            }
71                        } catch (OperationCanceledException exception) {
72                            return true;
73                        }
74                    }
75                });
76        final Thread thread = new Thread(future);
77        thread.start();
78        SystemClock.sleep(TIMEOUT_MS);
79        signal.cancel();
80        assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
81    }
82
83    public void testOperationsSupported() {
84        final MtpDeviceRecord[] records = mManager.getDevices();
85        assertEquals(1, records.length);
86        assertNotNull(records[0].operationsSupported);
87        getInstrumentation().show(Arrays.toString(records[0].operationsSupported));
88    }
89
90    public void testEventsSupported() {
91        final MtpDeviceRecord[] records = mManager.getDevices();
92        assertEquals(1, records.length);
93        assertNotNull(records[0].eventsSupported);
94        getInstrumentation().show(Arrays.toString(records[0].eventsSupported));
95    }
96
97    public void testDeviceKey() {
98        final MtpDeviceRecord[] records = mManager.getDevices();
99        assertEquals(1, records.length);
100        assertNotNull(records[0].deviceKey);
101        getInstrumentation().show("deviceKey: " + records[0].deviceKey);
102    }
103
104    public void testEventObjectAdded() throws Exception {
105        while (true) {
106            getInstrumentation().show("Please take a photo by using connected MTP device.");
107            final CancellationSignal signal = new CancellationSignal();
108            MtpEvent event = mManager.readEvent(mUsbDevice.getDeviceId(), signal);
109            if (event.getEventCode() != MtpEvent.EVENT_OBJECT_ADDED) {
110                continue;
111            }
112            assertTrue(event.getObjectHandle() != 0);
113            break;
114        }
115    }
116
117    public void testCreateDocumentAndGetPartialObject() throws Exception {
118        int storageId = 0;
119        for (final MtpDeviceRecord record : mManager.getDevices()) {
120            if (record.deviceId == mUsbDevice.getDeviceId()) {
121                storageId = record.roots[0].mStorageId;
122                break;
123            }
124        }
125        assertTrue("Valid storage not found.", storageId != 0);
126
127        final String testFileName = "MtpManagerTest_testFile.txt";
128        for (final int handle : mManager.getObjectHandles(
129                mUsbDevice.getDeviceId(), storageId, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN)) {
130            if (mManager.getObjectInfo(mUsbDevice.getDeviceId(), handle)
131                    .getName().equals(testFileName)) {
132                mManager.deleteDocument(mUsbDevice.getDeviceId(), handle);
133                break;
134            }
135        }
136
137        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
138        final byte[] expectedBytes = "Hello Android!".getBytes("ascii");
139        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
140                new ParcelFileDescriptor.AutoCloseOutputStream(fds[1])) {
141            stream.write(expectedBytes);
142        }
143        final int objectHandle = mManager.createDocument(
144                mUsbDevice.getDeviceId(),
145                new MtpObjectInfo.Builder()
146                        .setStorageId(storageId)
147                        .setName(testFileName)
148                        .setCompressedSize(expectedBytes.length)
149                        .setFormat(MtpConstants.FORMAT_TEXT)
150                        .build(),
151                fds[0]);
152        final byte[] bytes = new byte[100];
153        assertEquals(5, mManager.getPartialObject(
154                mUsbDevice.getDeviceId(), objectHandle, 0, 5, bytes));
155        assertEquals("Hello", new String(bytes, 0, 5, "ascii"));
156        assertEquals(8, mManager.getPartialObject(
157                mUsbDevice.getDeviceId(), objectHandle, 6, 100, bytes));
158        assertEquals("Android!", new String(bytes, 0, 8, "ascii"));
159    }
160
161    private Context getContext() {
162        return getInstrumentation().getContext();
163    }
164}
165