2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.android.settings.deviceinfo;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.IntentFilter;
21 import android.content.pm.PackageManager;
22 import android.hardware.usb.UsbManager;
23 import android.hardware.usb.UsbPort;
24 import android.hardware.usb.UsbPortStatus;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.support.annotation.VisibleForTesting;
29 public class UsbBackend {
31 public static final int MODE_POWER_MASK = 0x01;
32 public static final int MODE_POWER_SINK = 0x00;
33 public static final int MODE_POWER_SOURCE = 0x01;
35 public static final int MODE_DATA_MASK = 0x03 << 1;
36 public static final int MODE_DATA_NONE = 0x00 << 1;
37 public static final int MODE_DATA_MTP = 0x01 << 1;
38 public static final int MODE_DATA_PTP = 0x02 << 1;
39 public static final int MODE_DATA_MIDI = 0x03 << 1;
41 private final boolean mRestricted;
42 private final boolean mRestrictedBySystem;
43 private final boolean mMidi;
45 private UsbManager mUsbManager;
46 private UsbPort mPort;
47 private UsbPortStatus mPortStatus;
49 private Context mContext;
51 public UsbBackend(Context context) {
52 this(context, new UserRestrictionUtil(context));
56 public UsbBackend(Context context, UserRestrictionUtil userRestrictionUtil) {
58 mUsbManager = context.getSystemService(UsbManager.class);
60 mRestricted = userRestrictionUtil.isUsbFileTransferRestricted();
61 mRestrictedBySystem = userRestrictionUtil.isUsbFileTransferRestrictedBySystem();
62 mMidi = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
64 UsbPort[] ports = mUsbManager.getPorts();
68 // For now look for a connected port, in the future we should identify port in the
69 // notification and pick based on that.
70 final int N = ports.length;
71 for (int i = 0; i < N; i++) {
72 UsbPortStatus status = mUsbManager.getPortStatus(ports[i]);
73 if (status.isConnected()) {
81 public int getCurrentMode() {
83 int power = mPortStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
84 ? MODE_POWER_SOURCE : MODE_POWER_SINK;
85 return power | getUsbDataMode();
87 return MODE_POWER_SINK | getUsbDataMode();
90 public int getUsbDataMode() {
91 if (!isUsbDataUnlocked()) {
92 return MODE_DATA_NONE;
93 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MTP)) {
95 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP)) {
97 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MIDI)) {
98 return MODE_DATA_MIDI;
100 return MODE_DATA_NONE; // ...
103 private boolean isUsbDataUnlocked() {
104 Intent intent = mContext.registerReceiver(null,
105 new IntentFilter(UsbManager.ACTION_USB_STATE));
106 return intent == null ?
107 false : intent.getBooleanExtra(UsbManager.USB_DATA_UNLOCKED, false);
110 private void setUsbFunction(int mode) {
113 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);
116 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
119 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MIDI, true);
122 mUsbManager.setCurrentFunction(null, false);
127 public void setMode(int mode) {
129 int powerRole = modeToPower(mode);
130 // If we aren't using any data modes and we support host mode, then go to host mode
131 // so maybe? the other device can provide data if it wants, otherwise go into device
132 // mode because we have no choice.
133 int dataRole = (mode & MODE_DATA_MASK) == MODE_DATA_NONE
134 && mPortStatus.isRoleCombinationSupported(powerRole, UsbPort.DATA_ROLE_HOST)
135 ? UsbPort.DATA_ROLE_HOST : UsbPort.DATA_ROLE_DEVICE;
136 mUsbManager.setPortRoles(mPort, powerRole, dataRole);
138 setUsbFunction(mode & MODE_DATA_MASK);
141 private int modeToPower(int mode) {
142 return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
143 ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
146 public boolean isModeDisallowed(int mode) {
147 if (mRestricted && (mode & MODE_DATA_MASK) != MODE_DATA_NONE
148 && (mode & MODE_DATA_MASK) != MODE_DATA_MIDI) {
149 // No USB data modes are supported.
155 public boolean isModeDisallowedBySystem(int mode) {
156 if (mRestrictedBySystem && (mode & MODE_DATA_MASK) != MODE_DATA_NONE
157 && (mode & MODE_DATA_MASK) != MODE_DATA_MIDI) {
158 // No USB data modes are supported.
164 public boolean isModeSupported(int mode) {
165 if (!mMidi && (mode & MODE_DATA_MASK) == MODE_DATA_MIDI) {
170 int power = modeToPower(mode);
171 if ((mode & MODE_DATA_MASK) != 0) {
172 // We have a port and data, need to be in device mode.
173 return mPortStatus.isRoleCombinationSupported(power,
174 UsbPort.DATA_ROLE_DEVICE);
176 // No data needed, we can do this power mode in either device or host.
177 return mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_DEVICE)
178 || mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_HOST);
181 // No port, support sink modes only.
182 return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
185 // Wrapper class to enable testing with UserManager APIs
186 public static class UserRestrictionUtil {
187 private UserManager mUserManager;
189 public UserRestrictionUtil(Context context) {
190 mUserManager = UserManager.get(context);
193 public boolean isUsbFileTransferRestricted() {
194 return mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
197 public boolean isUsbFileTransferRestrictedBySystem() {
198 return mUserManager.hasBaseUserRestriction(
199 UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));