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 
17 package com.android.mtp;
18 
19 import android.hardware.usb.UsbDevice;
20 import android.hardware.usb.UsbDeviceConnection;
21 import android.hardware.usb.UsbManager;
22 import android.mtp.MtpConstants;
23 import android.os.SystemClock;
24 
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.util.HashMap;
28 import java.util.Objects;
29 
30 /**
31  * Static utility methods for testing.
32  */
33 final class TestUtil {
TestUtil()34     private TestUtil() {}
35 
36     static final int[] OPERATIONS_SUPPORTED = new int[] {
37             MtpConstants.OPERATION_GET_PARTIAL_OBJECT,
38             MtpConstants.OPERATION_SEND_OBJECT,
39             MtpConstants.OPERATION_SEND_OBJECT_INFO,
40             MtpConstants.OPERATION_DELETE_OBJECT,
41             MtpConstants.OPERATION_GET_OBJECT_PROP_DESC,
42             MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE
43     };
44 
45     /**
46      * Requests permission for a MTP device and returns the first MTP device that has at least one
47      * storage.
48      */
setupMtpDevice( TestResultInstrumentation instrumentation, UsbManager usbManager, MtpManager manager)49     static UsbDevice setupMtpDevice(
50             TestResultInstrumentation instrumentation,
51             UsbManager usbManager,
52             MtpManager manager) {
53         while (true) {
54             try {
55                 final UsbDevice device = findMtpDevice(usbManager, manager);
56                 waitForStorages(instrumentation, manager, device.getDeviceId());
57                 return device;
58             } catch (IOException exp) {
59                 instrumentation.show(Objects.toString(exp.getMessage()));
60                 SystemClock.sleep(1000);
61                 // When the MTP device is Android, and it changes the USB device type from
62                 // "Charging" to "MTP", the device ID will be updated. We need to find a device
63                 // again.
64                 continue;
65             }
66         }
67     }
68 
addTestDevice(MtpDatabase database)69     static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
70         database.getMapper().startAddingDocuments(null);
71         database.getMapper().putDeviceDocument(new MtpDeviceRecord(
72                 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0],
73                 OPERATIONS_SUPPORTED, null));
74         database.getMapper().stopAddingDocuments(null);
75     }
76 
addTestStorage(MtpDatabase database, String parentId)77     static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
78         database.getMapper().startAddingDocuments(parentId);
79         database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] {
80                 new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
81         });
82         database.getMapper().stopAddingDocuments(parentId);
83     }
84 
findMtpDevice( UsbManager usbManager, MtpManager manager)85     private static UsbDevice findMtpDevice(
86             UsbManager usbManager,
87             MtpManager manager) throws IOException {
88         final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
89         if (devices.size() == 0) {
90             throw new IOException("Device not found.");
91         }
92         final UsbDevice device = devices.values().iterator().next();
93         // Tries to get ownership of the device in case that another application use it.
94         if (usbManager.hasPermission(device)) {
95             final UsbDeviceConnection connection = usbManager.openDevice(device);
96             for (int i = 0; i < device.getInterfaceCount(); i++) {
97                 // Since the test runs real environment, we need to call claim interface with
98                 // force = true to rob interfaces from other applications.
99                 connection.claimInterface(device.getInterface(i), true);
100                 connection.releaseInterface(device.getInterface(i));
101             }
102             connection.close();
103         }
104         manager.openDevice(device.getDeviceId());
105         return device;
106     }
107 
waitForStorages( TestResultInstrumentation instrumentation, MtpManager manager, int deviceId)108     private static void waitForStorages(
109             TestResultInstrumentation instrumentation,
110             MtpManager manager,
111             int deviceId) throws IOException {
112         while (true) {
113             MtpDeviceRecord device = null;
114             for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
115                 if (deviceCandidate.deviceId == deviceId) {
116                     device = deviceCandidate;
117                     break;
118                 }
119             }
120             if (device == null) {
121                 throw new IOException("Device was detached.");
122             }
123             if (device.roots.length == 0) {
124                 instrumentation.show("Wait for storages.");
125                 SystemClock.sleep(1000);
126                 continue;
127             }
128             return;
129         }
130     }
131 }
132