• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.settings.connecteddevice.usb;
17 
18 import android.annotation.Nullable;
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.hardware.usb.UsbManager;
22 import android.hardware.usb.UsbPort;
23 import android.hardware.usb.UsbPortStatus;
24 import android.net.ConnectivityManager;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.support.annotation.VisibleForTesting;
28 
29 /**
30  * Provides access to underlying system USB functionality.
31  */
32 public class UsbBackend {
33 
34     static final int PD_ROLE_SWAP_TIMEOUT_MS = 3000;
35     static final int NONPD_ROLE_SWAP_TIMEOUT_MS = 15000;
36 
37     private final boolean mFileTransferRestricted;
38     private final boolean mFileTransferRestrictedBySystem;
39     private final boolean mTetheringRestricted;
40     private final boolean mTetheringRestrictedBySystem;
41     private final boolean mMidiSupported;
42     private final boolean mTetheringSupported;
43 
44     private UsbManager mUsbManager;
45 
46     @Nullable
47     private UsbPort mPort;
48     @Nullable
49     private UsbPortStatus mPortStatus;
50 
UsbBackend(Context context)51     public UsbBackend(Context context) {
52         this(context, (UserManager) context.getSystemService(Context.USER_SERVICE));
53     }
54 
55     @VisibleForTesting
UsbBackend(Context context, UserManager userManager)56     public UsbBackend(Context context, UserManager userManager) {
57         mUsbManager = context.getSystemService(UsbManager.class);
58 
59         mFileTransferRestricted = isUsbFileTransferRestricted(userManager);
60         mFileTransferRestrictedBySystem = isUsbFileTransferRestrictedBySystem(userManager);
61         mTetheringRestricted = isUsbTetheringRestricted(userManager);
62         mTetheringRestrictedBySystem = isUsbTetheringRestrictedBySystem(userManager);
63 
64         mMidiSupported = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
65         ConnectivityManager cm =
66                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
67         mTetheringSupported = cm.isTetheringSupported();
68 
69         updatePorts();
70     }
71 
getCurrentFunctions()72     public long getCurrentFunctions() {
73         return mUsbManager.getCurrentFunctions();
74     }
75 
setCurrentFunctions(long functions)76     public void setCurrentFunctions(long functions) {
77         mUsbManager.setCurrentFunctions(functions);
78     }
79 
getDefaultUsbFunctions()80     public long getDefaultUsbFunctions() {
81         return mUsbManager.getScreenUnlockedFunctions();
82     }
83 
setDefaultUsbFunctions(long functions)84     public void setDefaultUsbFunctions(long functions) {
85         mUsbManager.setScreenUnlockedFunctions(functions);
86     }
87 
areFunctionsSupported(long functions)88     public boolean areFunctionsSupported(long functions) {
89         if ((!mMidiSupported && (functions & UsbManager.FUNCTION_MIDI) != 0)
90                 || (!mTetheringSupported && (functions & UsbManager.FUNCTION_RNDIS) != 0)) {
91             return false;
92         }
93         return !(areFunctionDisallowed(functions) || areFunctionsDisallowedBySystem(functions));
94     }
95 
getPowerRole()96     public int getPowerRole() {
97         updatePorts();
98         return mPortStatus == null ? UsbPort.POWER_ROLE_NONE : mPortStatus.getCurrentPowerRole();
99     }
100 
getDataRole()101     public int getDataRole() {
102         updatePorts();
103         return mPortStatus == null ? UsbPort.DATA_ROLE_NONE : mPortStatus.getCurrentDataRole();
104     }
105 
setPowerRole(int role)106     public void setPowerRole(int role) {
107         int newDataRole = getDataRole();
108         if (!areAllRolesSupported()) {
109             switch (role) {
110                 case UsbPort.POWER_ROLE_SINK:
111                     newDataRole = UsbPort.DATA_ROLE_DEVICE;
112                     break;
113                 case UsbPort.POWER_ROLE_SOURCE:
114                     newDataRole = UsbPort.DATA_ROLE_HOST;
115                     break;
116                 default:
117                     newDataRole = UsbPort.DATA_ROLE_NONE;
118             }
119         }
120         if (mPort != null) {
121             mUsbManager.setPortRoles(mPort, role, newDataRole);
122         }
123     }
124 
setDataRole(int role)125     public void setDataRole(int role) {
126         int newPowerRole = getPowerRole();
127         if (!areAllRolesSupported()) {
128             switch (role) {
129                 case UsbPort.DATA_ROLE_DEVICE:
130                     newPowerRole = UsbPort.POWER_ROLE_SINK;
131                     break;
132                 case UsbPort.DATA_ROLE_HOST:
133                     newPowerRole = UsbPort.POWER_ROLE_SOURCE;
134                     break;
135                 default:
136                     newPowerRole = UsbPort.POWER_ROLE_NONE;
137             }
138         }
139         if (mPort != null) {
140             mUsbManager.setPortRoles(mPort, newPowerRole, role);
141         }
142     }
143 
areAllRolesSupported()144     public boolean areAllRolesSupported() {
145         return mPort != null && mPortStatus != null
146                 && mPortStatus
147                 .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE)
148                 && mPortStatus
149                 .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST)
150                 && mPortStatus
151                 .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE)
152                 && mPortStatus
153                 .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
154     }
155 
usbFunctionsToString(long functions)156     public static String usbFunctionsToString(long functions) {
157         // TODO replace with UsbManager.usbFunctionsToString once supported by Roboelectric
158         return Long.toBinaryString(functions);
159     }
160 
usbFunctionsFromString(String functions)161     public static long usbFunctionsFromString(String functions) {
162         // TODO replace with UsbManager.usbFunctionsFromString once supported by Roboelectric
163         return Long.parseLong(functions, 2);
164     }
165 
dataRoleToString(int role)166     public static String dataRoleToString(int role) {
167         return Integer.toString(role);
168     }
169 
dataRoleFromString(String role)170     public static int dataRoleFromString(String role) {
171         return Integer.parseInt(role);
172     }
173 
isUsbFileTransferRestricted(UserManager userManager)174     private static boolean isUsbFileTransferRestricted(UserManager userManager) {
175         return userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
176     }
177 
isUsbTetheringRestricted(UserManager userManager)178     private static boolean isUsbTetheringRestricted(UserManager userManager) {
179         return userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
180     }
181 
isUsbFileTransferRestrictedBySystem(UserManager userManager)182     private static boolean isUsbFileTransferRestrictedBySystem(UserManager userManager) {
183         return userManager.hasBaseUserRestriction(
184                 UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
185     }
186 
isUsbTetheringRestrictedBySystem(UserManager userManager)187     private static boolean isUsbTetheringRestrictedBySystem(UserManager userManager) {
188         return userManager.hasBaseUserRestriction(
189                 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(UserHandle.myUserId()));
190     }
191 
areFunctionDisallowed(long functions)192     private boolean areFunctionDisallowed(long functions) {
193         return (mFileTransferRestricted && ((functions & UsbManager.FUNCTION_MTP) != 0
194                 || (functions & UsbManager.FUNCTION_PTP) != 0))
195                 || (mTetheringRestricted && ((functions & UsbManager.FUNCTION_RNDIS) != 0));
196     }
197 
areFunctionsDisallowedBySystem(long functions)198     private boolean areFunctionsDisallowedBySystem(long functions) {
199         return (mFileTransferRestrictedBySystem && ((functions & UsbManager.FUNCTION_MTP) != 0
200                 || (functions & UsbManager.FUNCTION_PTP) != 0))
201                 || (mTetheringRestrictedBySystem && ((functions & UsbManager.FUNCTION_RNDIS) != 0));
202     }
203 
updatePorts()204     private void updatePorts() {
205         mPort = null;
206         mPortStatus = null;
207         UsbPort[] ports = mUsbManager.getPorts();
208         if (ports == null) {
209             return;
210         }
211         // For now look for a connected port, in the future we should identify port in the
212         // notification and pick based on that.
213         final int N = ports.length;
214         for (int i = 0; i < N; i++) {
215             UsbPortStatus status = mUsbManager.getPortStatus(ports[i]);
216             if (status.isConnected()) {
217                 mPort = ports[i];
218                 mPortStatus = status;
219                 break;
220             }
221         }
222     }
223 }
224