15bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono/* 25bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * Copyright (C) 2015 The Android Open Source Project 35bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * 45bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 55bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * you may not use this file except in compliance with the License. 65bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * You may obtain a copy of the License at 75bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * 85bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 95bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * 105bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * Unless required by applicable law or agreed to in writing, software 115bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 125bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * See the License for the specific language governing permissions and 145bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono * limitations under the License. 155bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono */ 165bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono 175bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironopackage com.android.mtp; 185bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono 195bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironoimport android.content.Context; 205bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironoimport android.hardware.usb.UsbDevice; 215bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironoimport android.hardware.usb.UsbManager; 222a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hironoimport android.mtp.MtpConstants; 232a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hironoimport android.mtp.MtpEvent; 24d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hironoimport android.mtp.MtpObjectInfo; 250b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hironoimport android.os.CancellationSignal; 260b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hironoimport android.os.OperationCanceledException; 27d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hironoimport android.os.ParcelFileDescriptor; 281d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hironoimport android.os.SystemClock; 295bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironoimport android.test.InstrumentationTestCase; 305bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono 310b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hironoimport java.io.IOException; 321d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hironoimport java.util.Arrays; 3399b58052f85c18272e63047b471edfd8089c09d3Daichi Hironoimport java.util.concurrent.Callable; 3499b58052f85c18272e63047b471edfd8089c09d3Daichi Hironoimport java.util.concurrent.FutureTask; 3599b58052f85c18272e63047b471edfd8089c09d3Daichi Hironoimport java.util.concurrent.TimeUnit; 365bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono 370b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono@RealDeviceTest 385bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hironopublic class MtpManagerTest extends InstrumentationTestCase { 390b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono private static final int TIMEOUT_MS = 1000; 400b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono UsbManager mUsbManager; 410b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono MtpManager mManager; 420b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono UsbDevice mUsbDevice; 430b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono 440b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono @Override 450b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono public void setUp() throws Exception { 460b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono mUsbManager = getContext().getSystemService(UsbManager.class); 47b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono mManager = new MtpManager(getContext()); 48b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono mUsbDevice = TestUtil.setupMtpDevice(getInstrumentation(), mUsbManager, mManager); 490b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono } 500b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono 510b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono @Override 520b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono public void tearDown() throws IOException { 530b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono mManager.closeDevice(mUsbDevice.getDeviceId()); 540b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono } 550b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono 56b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono @Override 57b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono public TestResultInstrumentation getInstrumentation() { 58b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono return (TestResultInstrumentation) super.getInstrumentation(); 59b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 60b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 610b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono public void testCancelEvent() throws Exception { 620b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono final CancellationSignal signal = new CancellationSignal(); 6399b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono final FutureTask<Boolean> future = new FutureTask<Boolean>( 6499b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono new Callable<Boolean>() { 6599b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono @Override 6699b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono public Boolean call() throws IOException { 6799b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono try { 684c4061210e52b7b1786ecb26a2dd7f8c1298e752Daichi Hirono while (true) { 694c4061210e52b7b1786ecb26a2dd7f8c1298e752Daichi Hirono mManager.readEvent(mUsbDevice.getDeviceId(), signal); 704c4061210e52b7b1786ecb26a2dd7f8c1298e752Daichi Hirono } 7199b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono } catch (OperationCanceledException exception) { 7299b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono return true; 7399b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono } 7499b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono } 7599b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono }); 7699b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono final Thread thread = new Thread(future); 770b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono thread.start(); 781d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono SystemClock.sleep(TIMEOUT_MS); 790b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono signal.cancel(); 8099b58052f85c18272e63047b471edfd8089c09d3Daichi Hirono assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 810b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono } 820b494663a4cb177fc6f05988c9bda2ef6277333dDaichi Hirono 831d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono public void testOperationsSupported() { 841d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono final MtpDeviceRecord[] records = mManager.getDevices(); 851d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono assertEquals(1, records.length); 861d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono assertNotNull(records[0].operationsSupported); 871d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono getInstrumentation().show(Arrays.toString(records[0].operationsSupported)); 881d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono } 891d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono 90148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono public void testEventsSupported() { 91148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono final MtpDeviceRecord[] records = mManager.getDevices(); 92148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono assertEquals(1, records.length); 93148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono assertNotNull(records[0].eventsSupported); 94148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono getInstrumentation().show(Arrays.toString(records[0].eventsSupported)); 95148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono } 96148954a657941ea95ef17da5b3ce40b9145f8755Daichi Hirono 97637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono public void testDeviceKey() { 98637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono final MtpDeviceRecord[] records = mManager.getDevices(); 99637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono assertEquals(1, records.length); 100637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono assertNotNull(records[0].deviceKey); 101637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono getInstrumentation().show("deviceKey: " + records[0].deviceKey); 102637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono } 103637a2010f4a0c0484b13c4cb87aa2858bdf079b2Daichi Hirono 1042a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono public void testEventObjectAdded() throws Exception { 1052a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono while (true) { 1062a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono getInstrumentation().show("Please take a photo by using connected MTP device."); 1072a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono final CancellationSignal signal = new CancellationSignal(); 1082a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono MtpEvent event = mManager.readEvent(mUsbDevice.getDeviceId(), signal); 10986c1a9bf6081d23c82f05f7293aded3266f61368Daichi Hirono if (event.getEventCode() != MtpEvent.EVENT_OBJECT_ADDED) { 1102a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono continue; 1112a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono } 1122a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono assertTrue(event.getObjectHandle() != 0); 1132a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono break; 1142a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono } 1152a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono } 1162a9a43369b4717bcf6b372f6798f72e80e938e30Daichi Hirono 117d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono public void testCreateDocumentAndGetPartialObject() throws Exception { 118d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono int storageId = 0; 119d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono for (final MtpDeviceRecord record : mManager.getDevices()) { 120d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono if (record.deviceId == mUsbDevice.getDeviceId()) { 121d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono storageId = record.roots[0].mStorageId; 122d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono break; 123d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 124d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 125d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono assertTrue("Valid storage not found.", storageId != 0); 1263a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono 127d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono final String testFileName = "MtpManagerTest_testFile.txt"; 128d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono for (final int handle : mManager.getObjectHandles( 129d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono mUsbDevice.getDeviceId(), storageId, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN)) { 130d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono if (mManager.getObjectInfo(mUsbDevice.getDeviceId(), handle) 131d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono .getName().equals(testFileName)) { 132d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono mManager.deleteDocument(mUsbDevice.getDeviceId(), handle); 133d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono break; 134d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 135d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 1363a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono 1373a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 138d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono final byte[] expectedBytes = "Hello Android!".getBytes("ascii"); 1393a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono try (final ParcelFileDescriptor.AutoCloseOutputStream stream = 1403a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono new ParcelFileDescriptor.AutoCloseOutputStream(fds[1])) { 141d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono stream.write(expectedBytes); 142d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 1433a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono final int objectHandle = mManager.createDocument( 1443a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono mUsbDevice.getDeviceId(), 1453a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono new MtpObjectInfo.Builder() 1463a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono .setStorageId(storageId) 1473a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono .setName(testFileName) 1483a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono .setCompressedSize(expectedBytes.length) 1493a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono .setFormat(MtpConstants.FORMAT_TEXT) 1503a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono .build(), 1513a6212ae558c945d6f24ace8fd38ab043a7697d1Daichi Hirono fds[0]); 152d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono final byte[] bytes = new byte[100]; 153d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono assertEquals(5, mManager.getPartialObject( 154d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono mUsbDevice.getDeviceId(), objectHandle, 0, 5, bytes)); 155d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono assertEquals("Hello", new String(bytes, 0, 5, "ascii")); 156d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono assertEquals(8, mManager.getPartialObject( 157d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono mUsbDevice.getDeviceId(), objectHandle, 6, 100, bytes)); 158d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono assertEquals("Android!", new String(bytes, 0, 8, "ascii")); 159d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono } 160d426ed27857a444c5328613769e4c9b1e7a24c81Daichi Hirono 1615bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono private Context getContext() { 1625bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono return getInstrumentation().getContext(); 1635bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono } 1645bc41d18544d983d913bd42e067bc8b7db0378cdDaichi Hirono} 165