1b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono/* 2b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * Copyright (C) 2015 The Android Open Source Project 3b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * 4b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 5b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * you may not use this file except in compliance with the License. 6b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * You may obtain a copy of the License at 7b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * 8b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 9b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * 10b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * Unless required by applicable law or agreed to in writing, software 11b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 12b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * See the License for the specific language governing permissions and 14b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * limitations under the License. 15b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono */ 16b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 17b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironopackage com.android.mtp; 18b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 19b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironoimport android.hardware.usb.UsbDevice; 20b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironoimport android.hardware.usb.UsbDeviceConnection; 21b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironoimport android.hardware.usb.UsbManager; 220f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hironoimport android.mtp.MtpConstants; 231d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hironoimport android.os.SystemClock; 24b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 25f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hironoimport java.io.FileNotFoundException; 26b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironoimport java.io.IOException; 27b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hironoimport java.util.HashMap; 281d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hironoimport java.util.Objects; 291d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono 30b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono/** 31b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * Static utility methods for testing. 32b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono */ 3399b58052f85c18272e63047b471edfd8089c09d3Daichi Hironofinal class TestUtil { 34b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono private TestUtil() {} 35b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 360f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono static final int[] OPERATIONS_SUPPORTED = new int[] { 370f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono MtpConstants.OPERATION_GET_PARTIAL_OBJECT, 380f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono MtpConstants.OPERATION_SEND_OBJECT, 390f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono MtpConstants.OPERATION_SEND_OBJECT_INFO, 4061ba923ca0cb5c928a16729d0aa67b6bf4b2f027Daichi Hirono MtpConstants.OPERATION_DELETE_OBJECT, 4164111e08d905525c7f4fe27e69953eb71bd62511Daichi Hirono MtpConstants.OPERATION_GET_OBJECT_PROP_DESC, 4264111e08d905525c7f4fe27e69953eb71bd62511Daichi Hirono MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE 430f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono }; 440f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono 45b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono /** 46b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * Requests permission for a MTP device and returns the first MTP device that has at least one 47b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono * storage. 48b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono */ 49b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono static UsbDevice setupMtpDevice( 50b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono TestResultInstrumentation instrumentation, 51b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono UsbManager usbManager, 521d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono MtpManager manager) { 531d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono while (true) { 54b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono try { 55ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono final UsbDevice device = findMtpDevice(usbManager, manager); 56b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono waitForStorages(instrumentation, manager, device.getDeviceId()); 57b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono return device; 58b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } catch (IOException exp) { 591d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono instrumentation.show(Objects.toString(exp.getMessage())); 601d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono SystemClock.sleep(1000); 61b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono // When the MTP device is Android, and it changes the USB device type from 62b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono // "Charging" to "MTP", the device ID will be updated. We need to find a device 63b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono // again. 64b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono continue; 65b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 66b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 67b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 68b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 69f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono static void addTestDevice(MtpDatabase database) throws FileNotFoundException { 70f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono database.getMapper().startAddingDocuments(null); 71f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono database.getMapper().putDeviceDocument(new MtpDeviceRecord( 720f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], 730f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono OPERATIONS_SUPPORTED, null)); 74f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono database.getMapper().stopAddingDocuments(null); 75f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono } 76f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono 77f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException { 78f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono database.getMapper().startAddingDocuments(parentId); 790f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] { 80f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono new MtpRoot(0, 100, "Storage", 1024, 1024, ""), 81f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono }); 82f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono database.getMapper().stopAddingDocuments(parentId); 83f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono } 84f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono 85b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono private static UsbDevice findMtpDevice( 86af5ea38b8c51f0878e4070671e240f693f3ad796Daichi Hirono UsbManager usbManager, 87ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono MtpManager manager) throws IOException { 88ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono final HashMap<String,UsbDevice> devices = usbManager.getDeviceList(); 89ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono if (devices.size() == 0) { 90ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono throw new IOException("Device not found."); 91ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono } 92ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono final UsbDevice device = devices.values().iterator().next(); 93ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono // Tries to get ownership of the device in case that another application use it. 94ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono if (usbManager.hasPermission(device)) { 95ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono final UsbDeviceConnection connection = usbManager.openDevice(device); 96ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono for (int i = 0; i < device.getInterfaceCount(); i++) { 97ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono // Since the test runs real environment, we need to call claim interface with 98ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono // force = true to rob interfaces from other applications. 99ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono connection.claimInterface(device.getInterface(i), true); 100ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono connection.releaseInterface(device.getInterface(i)); 101b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 102ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono connection.close(); 103b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 104ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono manager.openDevice(device.getDeviceId()); 105ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono return device; 106b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 107b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono 108b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono private static void waitForStorages( 109b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono TestResultInstrumentation instrumentation, 110b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono MtpManager manager, 1111d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono int deviceId) throws IOException { 112b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono while (true) { 11320754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono MtpDeviceRecord device = null; 11420754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) { 11520754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono if (deviceCandidate.deviceId == deviceId) { 11620754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono device = deviceCandidate; 11720754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono break; 11820754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono } 11920754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono } 12020754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono if (device == null) { 12120754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono throw new IOException("Device was detached."); 12220754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono } 12320754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono if (device.roots.length == 0) { 124b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono instrumentation.show("Wait for storages."); 1251d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono SystemClock.sleep(1000); 126b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono continue; 127b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 128b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono return; 129b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 130b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono } 131b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono} 132