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.deviceinfo; 17 18 import android.content.Context; 19 import android.content.Intent; 20 import android.content.IntentFilter; 21 import android.hardware.usb.UsbManager; 22 import android.hardware.usb.UsbPort; 23 import android.hardware.usb.UsbPortStatus; 24 import android.os.UserManager; 25 26 public class UsbBackend { 27 28 private static final int MODE_POWER_MASK = 0x01; 29 public static final int MODE_POWER_SINK = 0x00; 30 public static final int MODE_POWER_SOURCE = 0x01; 31 32 private static final int MODE_DATA_MASK = 0x03 << 1; 33 public static final int MODE_DATA_NONE = 0x00 << 1; 34 public static final int MODE_DATA_MTP = 0x01 << 1; 35 public static final int MODE_DATA_PTP = 0x02 << 1; 36 public static final int MODE_DATA_MIDI = 0x03 << 1; 37 38 private final boolean mRestricted; 39 40 private UserManager mUserManager; 41 private UsbManager mUsbManager; 42 private UsbPort mPort; 43 private UsbPortStatus mPortStatus; 44 45 private boolean mIsUnlocked; 46 UsbBackend(Context context)47 public UsbBackend(Context context) { 48 Intent intent = context.registerReceiver(null, 49 new IntentFilter(UsbManager.ACTION_USB_STATE)); 50 mIsUnlocked = intent.getBooleanExtra(UsbManager.USB_DATA_UNLOCKED, false); 51 52 mUserManager = UserManager.get(context); 53 mUsbManager = context.getSystemService(UsbManager.class); 54 55 mRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER); 56 UsbPort[] ports = mUsbManager.getPorts(); 57 // For now look for a connected port, in the future we should identify port in the 58 // notification and pick based on that. 59 final int N = ports.length; 60 for (int i = 0; i < N; i++) { 61 UsbPortStatus status = mUsbManager.getPortStatus(ports[i]); 62 if (status.isConnected()) { 63 mPort = ports[i]; 64 mPortStatus = status; 65 break; 66 } 67 } 68 } 69 getCurrentMode()70 public int getCurrentMode() { 71 if (mPort != null) { 72 int power = mPortStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE 73 ? MODE_POWER_SOURCE : MODE_POWER_SINK; 74 return power | getUsbDataMode(); 75 } 76 return MODE_POWER_SINK | getUsbDataMode(); 77 } 78 getUsbDataMode()79 public int getUsbDataMode() { 80 if (!mIsUnlocked) { 81 return MODE_DATA_NONE; 82 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MTP)) { 83 return MODE_DATA_MTP; 84 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP)) { 85 return MODE_DATA_PTP; 86 } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MIDI)) { 87 return MODE_DATA_MIDI; 88 } 89 return MODE_DATA_NONE; // ... 90 } 91 setUsbFunction(int mode)92 private void setUsbFunction(int mode) { 93 switch (mode) { 94 case MODE_DATA_MTP: 95 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP); 96 mUsbManager.setUsbDataUnlocked(true); 97 break; 98 case MODE_DATA_PTP: 99 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP); 100 mUsbManager.setUsbDataUnlocked(true); 101 break; 102 case MODE_DATA_MIDI: 103 mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MIDI); 104 mUsbManager.setUsbDataUnlocked(true); 105 break; 106 default: 107 mUsbManager.setCurrentFunction(null); 108 mUsbManager.setUsbDataUnlocked(false); 109 break; 110 } 111 } 112 setMode(int mode)113 public void setMode(int mode) { 114 if (mPort != null) { 115 int powerRole = modeToPower(mode); 116 // If we aren't using any data modes and we support host mode, then go to host mode 117 // so maybe? the other device can provide data if it wants, otherwise go into device 118 // mode because we have no choice. 119 int dataRole = (mode & MODE_DATA_MASK) == MODE_DATA_NONE 120 && mPortStatus.isRoleCombinationSupported(powerRole, UsbPort.DATA_ROLE_HOST) 121 ? UsbPort.DATA_ROLE_HOST : UsbPort.DATA_ROLE_DEVICE; 122 mUsbManager.setPortRoles(mPort, powerRole, dataRole); 123 } 124 setUsbFunction(mode & MODE_DATA_MASK); 125 } 126 modeToPower(int mode)127 private int modeToPower(int mode) { 128 return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE 129 ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK; 130 } 131 isModeSupported(int mode)132 public boolean isModeSupported(int mode) { 133 if (mRestricted && (mode & MODE_DATA_MASK) != MODE_DATA_NONE 134 && (mode & MODE_DATA_MASK) != MODE_DATA_MIDI) { 135 // No USB data modes are supported. 136 return false; 137 } 138 if (mPort != null) { 139 int power = modeToPower(mode); 140 if ((mode & MODE_DATA_MASK) != 0) { 141 // We have a port and data, need to be in device mode. 142 return mPortStatus.isRoleCombinationSupported(power, 143 UsbPort.DATA_ROLE_DEVICE); 144 } else { 145 // No data needed, we can do this power mode in either device or host. 146 return mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_DEVICE) 147 || mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_HOST); 148 } 149 } 150 // No port, support sink modes only. 151 return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE; 152 } 153 }