TestUtil.java revision 0f32537e40ee2662d4f0b7b625ee280ca9c02066
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,
400f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono    };
410f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono
42b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    /**
43b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono     * Requests permission for a MTP device and returns the first MTP device that has at least one
44b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono     * storage.
45b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono     */
46b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    static UsbDevice setupMtpDevice(
47b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            TestResultInstrumentation instrumentation,
48b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            UsbManager usbManager,
491d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono            MtpManager manager) {
501d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono        while (true) {
51b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            try {
52ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono                final UsbDevice device = findMtpDevice(usbManager, manager);
53b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                waitForStorages(instrumentation, manager, device.getDeviceId());
54b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                return device;
55b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            } catch (IOException exp) {
561d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono                instrumentation.show(Objects.toString(exp.getMessage()));
571d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono                SystemClock.sleep(1000);
58b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                // When the MTP device is Android, and it changes the USB device type from
59b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                // "Charging" to "MTP", the device ID will be updated. We need to find a device
60b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                // again.
61b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                continue;
62b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            }
63b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono        }
64b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    }
65b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono
66f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono    static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
67f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        database.getMapper().startAddingDocuments(null);
68f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        database.getMapper().putDeviceDocument(new MtpDeviceRecord(
690f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0],
700f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono                OPERATIONS_SUPPORTED, null));
71f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        database.getMapper().stopAddingDocuments(null);
72f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono    }
73f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono
74f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono    static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
75f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        database.getMapper().startAddingDocuments(parentId);
760f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono        database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] {
77f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono                new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
78f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        });
79f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono        database.getMapper().stopAddingDocuments(parentId);
80f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono    }
81f578fa275a535016f5322c88ad7a92e517d04a12Daichi Hirono
82b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    private static UsbDevice findMtpDevice(
83af5ea38b8c51f0878e4070671e240f693f3ad796Daichi Hirono            UsbManager usbManager,
84ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono            MtpManager manager) throws IOException {
85ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
86ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        if (devices.size() == 0) {
87ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono            throw new IOException("Device not found.");
88ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        }
89ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        final UsbDevice device = devices.values().iterator().next();
90ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        // Tries to get ownership of the device in case that another application use it.
91ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        if (usbManager.hasPermission(device)) {
92ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono            final UsbDeviceConnection connection = usbManager.openDevice(device);
93ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono            for (int i = 0; i < device.getInterfaceCount(); i++) {
94ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono                // Since the test runs real environment, we need to call claim interface with
95ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono                // force = true to rob interfaces from other applications.
96ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono                connection.claimInterface(device.getInterface(i), true);
97ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono                connection.releaseInterface(device.getInterface(i));
98b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            }
99ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono            connection.close();
100b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono        }
101ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        manager.openDevice(device.getDeviceId());
102ab03cb1b469940ab672850e0d2de3c78025260d3Daichi Hirono        return device;
103b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    }
104b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono
105b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    private static void waitForStorages(
106b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            TestResultInstrumentation instrumentation,
107b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            MtpManager manager,
1081d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono            int deviceId) throws IOException {
109b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono        while (true) {
11020754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            MtpDeviceRecord device = null;
11120754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
11220754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono                if (deviceCandidate.deviceId == deviceId) {
11320754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono                    device = deviceCandidate;
11420754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono                    break;
11520754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono                }
11620754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            }
11720754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            if (device == null) {
11820754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono                throw new IOException("Device was detached.");
11920754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            }
12020754c5a112e418c11cc88176283db2c4bf2efd6Daichi Hirono            if (device.roots.length == 0) {
121b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                instrumentation.show("Wait for storages.");
1221d4779c29a95114c89ec353a8899c0cc8eee3ba5Daichi Hirono                SystemClock.sleep(1000);
123b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono                continue;
124b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            }
125b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono            return;
126b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono        }
127b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono    }
128b255f58904d7a2aa64ba9f03ed0ede3759fd03c5Daichi Hirono}
129