Merge "Update USB settings screen" into pi-dev

This commit is contained in:
Jerry Zhang
2018-03-16 22:40:38 +00:00
committed by Android (Google) Code Review
23 changed files with 1510 additions and 747 deletions

View File

@@ -16,6 +16,8 @@
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.support.annotation.VisibleForTesting;
import com.android.settings.R;
@@ -38,9 +40,10 @@ public class ConnectedUsbDeviceUpdater {
@VisibleForTesting
UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
(connected, newMode) -> {
(connected, functions, powerRole, dataRole) -> {
if (connected) {
mUsbPreference.setSummary(getSummary(mUsbBackend.getCurrentMode()));
mUsbPreference.setSummary(getSummary(mUsbBackend.getCurrentFunctions(),
mUsbBackend.getPowerRole()));
mDevicePreferenceCallback.onDeviceAdded(mUsbPreference);
} else {
mDevicePreferenceCallback.onDeviceRemoved(mUsbPreference);
@@ -94,28 +97,32 @@ public class ConnectedUsbDeviceUpdater {
mUsbReceiver.register();
}
public static int getSummary(int mode) {
switch (mode) {
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_NONE:
return R.string.usb_summary_charging_only;
case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_NONE:
return R.string.usb_summary_power_only;
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MTP:
return R.string.usb_summary_file_transfers;
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_PTP:
return R.string.usb_summary_photo_transfers;
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MIDI:
return R.string.usb_summary_MIDI;
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_TETHER:
return R.string.usb_summary_tether;
case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_MTP:
return R.string.usb_summary_file_transfers_power;
case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_PTP:
return R.string.usb_summary_photo_transfers_power;
case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_MIDI:
return R.string.usb_summary_MIDI_power;
case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_TETHER:
return R.string.usb_summary_tether_power;
public static int getSummary(long functions, int power) {
switch (power) {
case UsbPort.POWER_ROLE_SINK:
if (functions == UsbManager.FUNCTION_MTP) {
return R.string.usb_summary_file_transfers;
} else if (functions == UsbManager.FUNCTION_RNDIS) {
return R.string.usb_summary_tether;
} else if (functions == UsbManager.FUNCTION_PTP) {
return R.string.usb_summary_photo_transfers;
} else if (functions == UsbManager.FUNCTION_MIDI) {
return R.string.usb_summary_MIDI;
} else {
return R.string.usb_summary_charging_only;
}
case UsbPort.POWER_ROLE_SOURCE:
if (functions == UsbManager.FUNCTION_MTP) {
return R.string.usb_summary_file_transfers_power;
} else if (functions == UsbManager.FUNCTION_RNDIS) {
return R.string.usb_summary_tether_power;
} else if (functions == UsbManager.FUNCTION_PTP) {
return R.string.usb_summary_photo_transfers_power;
} else if (functions == UsbManager.FUNCTION_MIDI) {
return R.string.usb_summary_MIDI_power;
} else {
return R.string.usb_summary_power_only;
}
default:
return R.string.usb_summary_charging_only;
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.settings.connecteddevice.usb;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.usb.UsbManager;
@@ -27,18 +28,13 @@ import android.support.annotation.VisibleForTesting;
import com.android.settings.wrapper.UsbManagerWrapper;
import com.android.settings.wrapper.UserManagerWrapper;
/**
* Provides access to underlying system USB functionality.
*/
public class UsbBackend {
public static final int MODE_POWER_MASK = 0x01;
public static final int MODE_POWER_SINK = 0x00;
public static final int MODE_POWER_SOURCE = 0x01;
public static final int MODE_DATA_MASK = 0x0f << 1;
public static final int MODE_DATA_NONE = 0;
public static final int MODE_DATA_MTP = 0x01 << 1;
public static final int MODE_DATA_PTP = 0x01 << 2;
public static final int MODE_DATA_MIDI = 0x01 << 3;
public static final int MODE_DATA_TETHER = 0x01 << 4;
static final int PD_ROLE_SWAP_TIMEOUT_MS = 3000;
static final int NONPD_ROLE_SWAP_TIMEOUT_MS = 15000;
private final boolean mFileTransferRestricted;
private final boolean mFileTransferRestrictedBySystem;
@@ -48,12 +44,12 @@ public class UsbBackend {
private final boolean mTetheringSupported;
private UsbManager mUsbManager;
@VisibleForTesting
UsbManagerWrapper mUsbManagerWrapper;
private UsbPort mPort;
private UsbPortStatus mPortStatus;
private UsbManagerWrapper mUsbManagerWrapper;
private Context mContext;
@Nullable
private UsbPort mPort;
@Nullable
private UsbPortStatus mPortStatus;
public UsbBackend(Context context) {
this(context, new UserManagerWrapper(UserManager.get(context)), null);
@@ -62,7 +58,6 @@ public class UsbBackend {
@VisibleForTesting
public UsbBackend(Context context, UserManagerWrapper userManagerWrapper,
UsbManagerWrapper usbManagerWrapper) {
mContext = context;
mUsbManager = context.getSystemService(UsbManager.class);
mUsbManagerWrapper = usbManagerWrapper;
@@ -77,9 +72,129 @@ public class UsbBackend {
mMidiSupported = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
ConnectivityManager cm =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mTetheringSupported = cm.isTetheringSupported();
updatePorts();
}
public long getCurrentFunctions() {
return mUsbManagerWrapper.getCurrentFunctions();
}
public void setCurrentFunctions(long functions) {
mUsbManager.setCurrentFunctions(functions);
}
public long getDefaultUsbFunctions() {
return mUsbManager.getScreenUnlockedFunctions();
}
public void setDefaultUsbFunctions(long functions) {
mUsbManager.setScreenUnlockedFunctions(functions);
}
public boolean areFunctionsSupported(long functions) {
if ((!mMidiSupported && (functions & UsbManager.FUNCTION_MIDI) != 0)
|| (!mTetheringSupported && (functions & UsbManager.FUNCTION_RNDIS) != 0)) {
return false;
}
return !(areFunctionDisallowed(functions) || areFunctionsDisallowedBySystem(functions));
}
public int getPowerRole() {
updatePorts();
return mPortStatus == null ? UsbPort.POWER_ROLE_NONE : mPortStatus.getCurrentPowerRole();
}
public int getDataRole() {
updatePorts();
return mPortStatus == null ? UsbPort.DATA_ROLE_NONE : mPortStatus.getCurrentDataRole();
}
public void setPowerRole(int role) {
int newDataRole = getDataRole();
if (!areAllRolesSupported()) {
switch (role) {
case UsbPort.POWER_ROLE_SINK:
newDataRole = UsbPort.DATA_ROLE_DEVICE;
break;
case UsbPort.POWER_ROLE_SOURCE:
newDataRole = UsbPort.DATA_ROLE_HOST;
break;
default:
newDataRole = UsbPort.DATA_ROLE_NONE;
}
}
if (mPort != null) {
mUsbManager.setPortRoles(mPort, role, newDataRole);
}
}
public void setDataRole(int role) {
int newPowerRole = getPowerRole();
if (!areAllRolesSupported()) {
switch (role) {
case UsbPort.DATA_ROLE_DEVICE:
newPowerRole = UsbPort.POWER_ROLE_SINK;
break;
case UsbPort.DATA_ROLE_HOST:
newPowerRole = UsbPort.POWER_ROLE_SOURCE;
break;
default:
newPowerRole = UsbPort.POWER_ROLE_NONE;
}
}
if (mPort != null) {
mUsbManager.setPortRoles(mPort, newPowerRole, role);
}
}
public boolean areAllRolesSupported() {
return mPort != null && mPortStatus != null
&& mPortStatus
.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE)
&& mPortStatus
.isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST)
&& mPortStatus
.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE)
&& mPortStatus
.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
}
public static String usbFunctionsToString(long functions) {
// TODO replace with UsbManager.usbFunctionsToString once supported by Roboelectric
return Long.toBinaryString(functions);
}
public static long usbFunctionsFromString(String functions) {
// TODO replace with UsbManager.usbFunctionsFromString once supported by Roboelectric
return Long.parseLong(functions, 2);
}
public static String dataRoleToString(int role) {
return Integer.toString(role);
}
public static int dataRoleFromString(String role) {
return Integer.parseInt(role);
}
private boolean areFunctionDisallowed(long functions) {
return (mFileTransferRestricted && ((functions & UsbManager.FUNCTION_MTP) != 0
|| (functions & UsbManager.FUNCTION_PTP) != 0))
|| (mTetheringRestricted && ((functions & UsbManager.FUNCTION_RNDIS) != 0));
}
private boolean areFunctionsDisallowedBySystem(long functions) {
return (mFileTransferRestrictedBySystem && ((functions & UsbManager.FUNCTION_MTP) != 0
|| (functions & UsbManager.FUNCTION_PTP) != 0))
|| (mTetheringRestrictedBySystem && ((functions & UsbManager.FUNCTION_RNDIS) != 0));
}
private void updatePorts() {
mPort = null;
mPortStatus = null;
UsbPort[] ports = mUsbManager.getPorts();
if (ports == null) {
return;
@@ -96,120 +211,4 @@ public class UsbBackend {
}
}
}
public int getCurrentMode() {
if (mPort != null) {
int power = mPortStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
&& mPortStatus.isConnected()
? MODE_POWER_SOURCE : MODE_POWER_SINK;
return power | getUsbDataMode();
}
return MODE_POWER_SINK | getUsbDataMode();
}
public int getUsbDataMode() {
return usbFunctionToMode(mUsbManagerWrapper.getCurrentFunctions());
}
public void setDefaultUsbMode(int mode) {
mUsbManager.setScreenUnlockedFunctions(modeToUsbFunction(mode & MODE_DATA_MASK));
}
public int getDefaultUsbMode() {
return usbFunctionToMode(mUsbManager.getScreenUnlockedFunctions());
}
public void setMode(int mode) {
if (mPort != null) {
int powerRole = modeToPower(mode);
// If we aren't using any data modes and we support host mode, then go to host mode
// so maybe? the other device can provide data if it wants, otherwise go into device
// mode because we have no choice.
int dataRole = (mode & MODE_DATA_MASK) == MODE_DATA_NONE
&& mPortStatus.isRoleCombinationSupported(powerRole, UsbPort.DATA_ROLE_HOST)
? UsbPort.DATA_ROLE_HOST : UsbPort.DATA_ROLE_DEVICE;
mUsbManager.setPortRoles(mPort, powerRole, dataRole);
}
setUsbFunction(mode & MODE_DATA_MASK);
}
public boolean isModeDisallowed(int mode) {
if (mFileTransferRestricted && ((mode & MODE_DATA_MASK) == MODE_DATA_MTP
|| (mode & MODE_DATA_MASK) == MODE_DATA_PTP)) {
return true;
} else if (mTetheringRestricted && ((mode & MODE_DATA_MASK) == MODE_DATA_TETHER)) {
return true;
}
return false;
}
public boolean isModeDisallowedBySystem(int mode) {
if (mFileTransferRestrictedBySystem && ((mode & MODE_DATA_MASK) == MODE_DATA_MTP
|| (mode & MODE_DATA_MASK) == MODE_DATA_PTP)) {
return true;
} else if (mTetheringRestrictedBySystem && ((mode & MODE_DATA_MASK) == MODE_DATA_TETHER)) {
return true;
}
return false;
}
public boolean isModeSupported(int mode) {
if (!mMidiSupported && (mode & MODE_DATA_MASK) == MODE_DATA_MIDI) {
return false;
}
if (!mTetheringSupported && (mode & MODE_DATA_MASK) == MODE_DATA_TETHER) {
return false;
}
if (mPort != null) {
int power = modeToPower(mode);
if ((mode & MODE_DATA_MASK) != 0) {
// We have a port and data, need to be in device mode.
return mPortStatus.isRoleCombinationSupported(power,
UsbPort.DATA_ROLE_DEVICE);
} else {
// No data needed, we can do this power mode in either device or host.
return mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_DEVICE)
|| mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_HOST);
}
}
// No port, support sink modes only.
return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
}
private static int usbFunctionToMode(long functions) {
if (functions == UsbManager.FUNCTION_MTP) {
return MODE_DATA_MTP;
} else if (functions == UsbManager.FUNCTION_PTP) {
return MODE_DATA_PTP;
} else if (functions == UsbManager.FUNCTION_MIDI) {
return MODE_DATA_MIDI;
} else if (functions == UsbManager.FUNCTION_RNDIS) {
return MODE_DATA_TETHER;
}
return MODE_DATA_NONE;
}
private static long modeToUsbFunction(int mode) {
switch (mode) {
case MODE_DATA_MTP:
return UsbManager.FUNCTION_MTP;
case MODE_DATA_PTP:
return UsbManager.FUNCTION_PTP;
case MODE_DATA_MIDI:
return UsbManager.FUNCTION_MIDI;
case MODE_DATA_TETHER:
return UsbManager.FUNCTION_RNDIS;
default:
return UsbManager.FUNCTION_NONE;
}
}
private static int modeToPower(int mode) {
return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
}
private void setUsbFunction(int mode) {
mUsbManager.setCurrentFunctions(modeToUsbFunction(mode));
}
}

View File

@@ -15,8 +15,6 @@
*/
package com.android.settings.connecteddevice.usb;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -37,15 +35,22 @@ public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements
private Context mContext;
private UsbConnectionListener mUsbConnectionListener;
private boolean mListeningToUsbEvents;
private int mMode;
private boolean mConnected;
private UsbBackend mUsbBackend;
private boolean mConnected;
private long mFunctions;
private int mDataRole;
private int mPowerRole;
public UsbConnectionBroadcastReceiver(Context context,
UsbConnectionListener usbConnectionListener, UsbBackend backend) {
mContext = context;
mUsbConnectionListener = usbConnectionListener;
mUsbBackend = backend;
mFunctions = UsbManager.FUNCTION_NONE;
mDataRole = UsbPort.DATA_ROLE_NONE;
mPowerRole = UsbPort.POWER_ROLE_NONE;
}
@Override
@@ -54,42 +59,41 @@ public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements
mConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED)
|| intent.getExtras().getBoolean(UsbManager.USB_HOST_CONNECTED);
if (mConnected) {
mMode &= UsbBackend.MODE_POWER_MASK;
long functions = UsbManager.FUNCTION_NONE;
if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MTP)
&& intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) {
mMode |= UsbBackend.MODE_DATA_MTP;
functions |= UsbManager.FUNCTION_MTP;
}
if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_PTP)
&& intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) {
mMode |= UsbBackend.MODE_DATA_PTP;
functions |= UsbManager.FUNCTION_PTP;
}
if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MIDI)) {
mMode |= UsbBackend.MODE_DATA_MIDI;
functions |= UsbManager.FUNCTION_MIDI;
}
if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_RNDIS)) {
mMode |= UsbBackend.MODE_DATA_TETHER;
functions |= UsbManager.FUNCTION_RNDIS;
}
mFunctions = functions;
mDataRole = mUsbBackend.getDataRole();
mPowerRole = mUsbBackend.getPowerRole();
}
} else if (UsbManager.ACTION_USB_PORT_CHANGED.equals(intent.getAction())) {
mMode &= UsbBackend.MODE_DATA_MASK;
UsbPortStatus portStatus = intent.getExtras()
.getParcelable(UsbManager.EXTRA_PORT_STATUS);
if (portStatus != null) {
mConnected = portStatus.isConnected();
if (mConnected) {
mMode |= portStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
? UsbBackend.MODE_POWER_SOURCE : UsbBackend.MODE_POWER_SINK;
}
mDataRole = portStatus.getCurrentDataRole();
mPowerRole = portStatus.getCurrentPowerRole();
}
}
if (mUsbConnectionListener != null) {
mUsbConnectionListener.onUsbConnectionChanged(mConnected, mMode);
mUsbConnectionListener.onUsbConnectionChanged(mConnected, mFunctions, mPowerRole,
mDataRole);
}
}
public void register() {
if (!mListeningToUsbEvents) {
mMode = mUsbBackend.getCurrentMode();
mConnected = false;
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UsbManager.ACTION_USB_STATE);
@@ -124,6 +128,6 @@ public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements
* Interface definition for a callback to be invoked when usb connection is changed.
*/
interface UsbConnectionListener {
void onUsbConnectionChanged(boolean connected, int newMode);
void onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole);
}
}

View File

@@ -18,7 +18,6 @@ package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,14 +40,6 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment {
@VisibleForTesting
UsbBackend mUsbBackend;
private static final String[] FUNCTIONS_LIST = {
UsbManager.USB_FUNCTION_NONE,
UsbManager.USB_FUNCTION_MTP,
UsbManager.USB_FUNCTION_RNDIS,
UsbManager.USB_FUNCTION_MIDI,
UsbManager.USB_FUNCTION_PTP
};
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -76,33 +67,13 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment {
@Override
protected List<? extends CandidateInfo> getCandidates() {
List<CandidateInfo> ret = Lists.newArrayList();
for (final String option : FUNCTIONS_LIST) {
int newMode = 0;
final String title;
final Context context = getContext();
if (option.equals(UsbManager.USB_FUNCTION_MTP)) {
newMode = UsbBackend.MODE_DATA_MTP;
title = context.getString(R.string.usb_use_file_transfers);
} else if (option.equals(UsbManager.USB_FUNCTION_PTP)) {
newMode = UsbBackend.MODE_DATA_PTP;
title = context.getString(R.string.usb_use_photo_transfers);
} else if (option.equals(UsbManager.USB_FUNCTION_MIDI)) {
newMode = UsbBackend.MODE_DATA_MIDI;
title = context.getString(R.string.usb_use_MIDI);
} else if (option.equals(UsbManager.USB_FUNCTION_RNDIS)) {
newMode = UsbBackend.MODE_DATA_TETHER;
title = context.getString(R.string.usb_use_tethering);
} else if (option.equals(UsbManager.USB_FUNCTION_NONE)) {
newMode = UsbBackend.MODE_DATA_NONE;
title = context.getString(R.string.usb_use_charging_only);
} else {
title = "";
}
for (final long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) {
final String title = getContext().getString(
UsbDetailsFunctionsController.FUNCTIONS_MAP.get(option));
final String key = UsbBackend.usbFunctionsToString(option);
// Only show supported and allowed options
if (mUsbBackend.isModeSupported(newMode)
&& !mUsbBackend.isModeDisallowedBySystem(newMode)
&& !mUsbBackend.isModeDisallowed(newMode)) {
// Only show supported functions
if (mUsbBackend.areFunctionsSupported(option)) {
ret.add(new CandidateInfo(true /* enabled */) {
@Override
public CharSequence loadLabel() {
@@ -116,7 +87,7 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment {
@Override
public String getKey() {
return option;
return key;
}
});
}
@@ -126,34 +97,14 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment {
@Override
protected String getDefaultKey() {
switch (mUsbBackend.getDefaultUsbMode()) {
case UsbBackend.MODE_DATA_MTP:
return UsbManager.USB_FUNCTION_MTP;
case UsbBackend.MODE_DATA_PTP:
return UsbManager.USB_FUNCTION_PTP;
case UsbBackend.MODE_DATA_TETHER:
return UsbManager.USB_FUNCTION_RNDIS;
case UsbBackend.MODE_DATA_MIDI:
return UsbManager.USB_FUNCTION_MIDI;
default:
return UsbManager.USB_FUNCTION_NONE;
}
return UsbBackend.usbFunctionsToString(mUsbBackend.getDefaultUsbFunctions());
}
@Override
protected boolean setDefaultKey(String key) {
int thisMode = UsbBackend.MODE_DATA_NONE;
if (key.equals(UsbManager.USB_FUNCTION_MTP)) {
thisMode = UsbBackend.MODE_DATA_MTP;
} else if (key.equals(UsbManager.USB_FUNCTION_PTP)) {
thisMode = UsbBackend.MODE_DATA_PTP;
} else if (key.equals(UsbManager.USB_FUNCTION_RNDIS)) {
thisMode = UsbBackend.MODE_DATA_TETHER;
} else if (key.equals(UsbManager.USB_FUNCTION_MIDI)) {
thisMode = UsbBackend.MODE_DATA_MIDI;
}
long functions = UsbBackend.usbFunctionsFromString(key);
if (!Utils.isMonkeyRunning()) {
mUsbBackend.setDefaultUsbMode(thisMode);
mUsbBackend.setDefaultUsbFunctions(functions);
}
return true;
}

View File

@@ -17,9 +17,10 @@
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.os.Handler;
import android.support.annotation.UiThread;
import android.support.v14.preference.PreferenceFragment;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -30,14 +31,18 @@ public abstract class UsbDetailsController extends AbstractPreferenceController
implements PreferenceControllerMixin {
protected final Context mContext;
protected final PreferenceFragment mFragment;
protected final UsbDetailsFragment mFragment;
protected final UsbBackend mUsbBackend;
public UsbDetailsController(Context context, PreferenceFragment fragment, UsbBackend backend) {
@VisibleForTesting
Handler mHandler;
public UsbDetailsController(Context context, UsbDetailsFragment fragment, UsbBackend backend) {
super(context);
mContext = context;
mFragment = fragment;
mUsbBackend = backend;
mHandler = new Handler(context.getMainLooper());
}
@Override
@@ -46,9 +51,13 @@ public abstract class UsbDetailsController extends AbstractPreferenceController
}
/**
* This method is called when the USB mode has changed and the controller needs to update.
* @param newMode the new mode, made up of OR'd values from UsbBackend
* Called when the USB state has changed, so that this component can be refreshed.
*
* @param connected Whether USB is connected
* @param functions A mask of the currently enabled functions
* @param powerRole The current power role
* @param dataRole The current data role
*/
@UiThread
protected abstract void refresh(int newMode);
protected abstract void refresh(boolean connected, long functions, int powerRole, int dataRole);
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.hardware.usb.UsbPort;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.widget.RadioButtonPreference;
/**
* This class controls the radio buttons for switching between
* USB device and host mode.
*/
public class UsbDetailsDataRoleController extends UsbDetailsController
implements RadioButtonPreference.OnClickListener {
private PreferenceCategory mPreferenceCategory;
private RadioButtonPreference mDevicePref;
private RadioButtonPreference mHostPref;
private RadioButtonPreference mNextRolePref;
private final Runnable mFailureCallback = () -> {
if (mNextRolePref != null) {
mNextRolePref.setSummary(R.string.usb_switching_failed);
mNextRolePref = null;
}
};
public UsbDetailsDataRoleController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
mHostPref = makeRadioPreference(UsbBackend.dataRoleToString(UsbPort.DATA_ROLE_HOST),
R.string.usb_control_host);
mDevicePref = makeRadioPreference(UsbBackend.dataRoleToString(UsbPort.DATA_ROLE_DEVICE),
R.string.usb_control_device);
}
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
if (dataRole == UsbPort.DATA_ROLE_DEVICE) {
mDevicePref.setChecked(true);
mHostPref.setChecked(false);
mPreferenceCategory.setEnabled(true);
} else if (dataRole == UsbPort.DATA_ROLE_HOST) {
mDevicePref.setChecked(false);
mHostPref.setChecked(true);
mPreferenceCategory.setEnabled(true);
} else if (!connected || dataRole == UsbPort.DATA_ROLE_NONE){
mPreferenceCategory.setEnabled(false);
if (mNextRolePref == null) {
// Disconnected with no operation pending, so clear subtexts
mHostPref.setSummary("");
mDevicePref.setSummary("");
}
}
if (mNextRolePref != null && dataRole != UsbPort.DATA_ROLE_NONE) {
if (UsbBackend.dataRoleFromString(mNextRolePref.getKey()) == dataRole) {
// Clear switching text if switch succeeded
mNextRolePref.setSummary("");
} else {
// Set failure text if switch failed
mNextRolePref.setSummary(R.string.usb_switching_failed);
}
mNextRolePref = null;
mHandler.removeCallbacks(mFailureCallback);
}
}
@Override
public void onRadioButtonClicked(RadioButtonPreference preference) {
int role = UsbBackend.dataRoleFromString(preference.getKey());
if (role != mUsbBackend.getDataRole() && mNextRolePref == null
&& !Utils.isMonkeyRunning()) {
mUsbBackend.setDataRole(role);
mNextRolePref = preference;
preference.setSummary(R.string.usb_switching);
mHandler.postDelayed(mFailureCallback,
mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS
: UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS);
}
}
@Override
public boolean isAvailable() {
return !Utils.isMonkeyRunning();
}
@Override
public String getPreferenceKey() {
return "usb_details_data_role";
}
private RadioButtonPreference makeRadioPreference(String key, int titleId) {
RadioButtonPreference pref = new RadioButtonPreference(mPreferenceCategory.getContext());
pref.setKey(key);
pref.setTitle(titleId);
pref.setOnClickListener(this);
mPreferenceCategory.addPreference(pref);
return pref;
}
}

View File

@@ -17,14 +17,12 @@
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
@@ -48,13 +46,9 @@ public class UsbDetailsFragment extends DashboardFragment {
UsbConnectionBroadcastReceiver mUsbReceiver;
private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
(connected, newMode) -> {
if (!connected) {
this.finish();
} else {
for (UsbDetailsController controller : mControllers) {
controller.refresh(newMode);
}
(connected, functions, powerRole, dataRole) -> {
for (UsbDetailsController controller : mControllers) {
controller.refresh(connected, functions, powerRole, dataRole);
}
};
@@ -78,6 +72,10 @@ public class UsbDetailsFragment extends DashboardFragment {
super.onCreatePreferences(savedInstanceState, rootKey);
}
public boolean isConnected() {
return mUsbReceiver.isConnected();
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
mUsbBackend = new UsbBackend(context);
@@ -86,21 +84,16 @@ public class UsbDetailsFragment extends DashboardFragment {
mUsbBackend);
this.getLifecycle().addObserver(mUsbReceiver);
List<AbstractPreferenceController> ret = new ArrayList<>();
ret.addAll(mControllers);
return ret;
return new ArrayList<>(mControllers);
}
private static List<UsbDetailsController> createControllerList(Context context,
UsbBackend usbBackend, DashboardFragment fragment) {
UsbBackend usbBackend, UsbDetailsFragment fragment) {
List<UsbDetailsController> ret = new ArrayList<>();
ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));
ret.add(new UsbDetailsProfilesController(context, fragment,
usbBackend, Lists.newArrayList(UsbManager.USB_FUNCTION_MTP), "usb_main_options"));
ret.add(new UsbDetailsProfilesController(context, fragment,
usbBackend, Lists.newArrayList(UsbDetailsProfilesController.KEY_POWER,
UsbManager.USB_FUNCTION_RNDIS, UsbManager.USB_FUNCTION_MIDI,
UsbManager.USB_FUNCTION_PTP), "usb_secondary_options"));
ret.add(new UsbDetailsDataRoleController(context, fragment, usbBackend));
ret.add(new UsbDetailsFunctionsController(context, fragment, usbBackend));
ret.add(new UsbDetailsPowerRoleController(context, fragment, usbBackend));
return ret;
}
@@ -112,7 +105,9 @@ public class UsbDetailsFragment extends DashboardFragment {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
return new ArrayList<>();
SearchIndexableResource res = new SearchIndexableResource(context);
res.xmlResId = R.xml.usb_details_fragment;
return Lists.newArrayList(res);
}
@Override
@@ -123,9 +118,8 @@ public class UsbDetailsFragment extends DashboardFragment {
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
List<AbstractPreferenceController> ret = new ArrayList<>();
ret.addAll(createControllerList(context, new UsbBackend(context), null));
return ret;
return new ArrayList<>(
createControllerList(context, new UsbBackend(context), null));
}
};
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.widget.RadioButtonPreference;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* This class controls the radio buttons for choosing between different USB functions.
*/
public class UsbDetailsFunctionsController extends UsbDetailsController
implements RadioButtonPreference.OnClickListener {
static final Map<Long, Integer> FUNCTIONS_MAP = new LinkedHashMap<>();
static {
FUNCTIONS_MAP.put(UsbManager.FUNCTION_MTP, R.string.usb_use_file_transfers);
FUNCTIONS_MAP.put(UsbManager.FUNCTION_RNDIS, R.string.usb_use_tethering);
FUNCTIONS_MAP.put(UsbManager.FUNCTION_MIDI, R.string.usb_use_MIDI);
FUNCTIONS_MAP.put(UsbManager.FUNCTION_PTP, R.string.usb_use_photo_transfers);
FUNCTIONS_MAP.put(UsbManager.FUNCTION_NONE, R.string.usb_use_charging_only);
}
private PreferenceCategory mProfilesContainer;
public UsbDetailsFunctionsController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mProfilesContainer = (PreferenceCategory) screen.findPreference(getPreferenceKey());
}
/**
* Gets a switch preference for the particular option, creating it if needed.
*/
private RadioButtonPreference getProfilePreference(String key, int titleId) {
RadioButtonPreference pref = (RadioButtonPreference) mProfilesContainer.findPreference(key);
if (pref == null) {
pref = new RadioButtonPreference(mProfilesContainer.getContext());
pref.setKey(key);
pref.setTitle(titleId);
pref.setOnClickListener(this);
mProfilesContainer.addPreference(pref);
}
return pref;
}
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
if (!connected || dataRole != UsbPort.DATA_ROLE_DEVICE) {
mProfilesContainer.setEnabled(false);
} else {
// Functions are only available in device mode
mProfilesContainer.setEnabled(true);
}
RadioButtonPreference pref;
for (long option : FUNCTIONS_MAP.keySet()) {
int title = FUNCTIONS_MAP.get(option);
pref = getProfilePreference(UsbBackend.usbFunctionsToString(option), title);
// Only show supported options
if (mUsbBackend.areFunctionsSupported(option)) {
pref.setChecked(functions == option);
} else {
mProfilesContainer.removePreference(pref);
}
}
}
@Override
public void onRadioButtonClicked(RadioButtonPreference preference) {
long function = UsbBackend.usbFunctionsFromString(preference.getKey());
if (function != mUsbBackend.getCurrentFunctions() && !Utils.isMonkeyRunning()) {
mUsbBackend.setCurrentFunctions(function);
}
}
@Override
public boolean isAvailable() {
return !Utils.isMonkeyRunning();
}
@Override
public String getPreferenceKey() {
return "usb_details_functions";
}
}

View File

@@ -17,7 +17,6 @@
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
@@ -25,14 +24,14 @@ import com.android.settings.applications.LayoutPreference;
import com.android.settings.widget.EntityHeaderController;
/**
* This class adds a header with device name and current function.
* This class adds a header with device name.
*/
public class UsbDetailsHeaderController extends UsbDetailsController {
private static final String KEY_DEVICE_HEADER = "usb_device_header";
private EntityHeaderController mHeaderController;
public UsbDetailsHeaderController(Context context, PreferenceFragment fragment,
public UsbDetailsHeaderController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
}
@@ -44,16 +43,13 @@ public class UsbDetailsHeaderController extends UsbDetailsController {
(LayoutPreference) screen.findPreference(KEY_DEVICE_HEADER);
mHeaderController = EntityHeaderController.newInstance(mFragment.getActivity(), mFragment,
headerPreference.findViewById(R.id.entity_header));
screen.addPreference(headerPreference);
}
@Override
protected void refresh(int newMode) {
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
mHeaderController.setLabel(mContext.getString(R.string.usb_pref));
mHeaderController.setIcon(mContext.getDrawable(R.drawable.ic_usb));
mHeaderController.setSummary(
mContext.getString(ConnectedUsbDeviceUpdater.getSummary(newMode)));
mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.connecteddevice.usb;
import android.content.Context;
import android.hardware.usb.UsbPort;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
/**
* This class controls the switch for changing USB power direction.
*/
public class UsbDetailsPowerRoleController extends UsbDetailsController
implements OnPreferenceClickListener {
private PreferenceCategory mPreferenceCategory;
private SwitchPreference mSwitchPreference;
private int mNextPowerRole;
private final Runnable mFailureCallback = () -> {
if (mNextPowerRole != UsbPort.POWER_ROLE_NONE) {
mSwitchPreference.setSummary(R.string.usb_switching_failed);
mNextPowerRole = UsbPort.POWER_ROLE_NONE;
}
};
public UsbDetailsPowerRoleController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
mNextPowerRole = UsbPort.POWER_ROLE_NONE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
mSwitchPreference = new SwitchPreference(mPreferenceCategory.getContext());
mSwitchPreference.setTitle(R.string.usb_use_power_only);
mSwitchPreference.setOnPreferenceClickListener(this);
mPreferenceCategory.addPreference(mSwitchPreference);
}
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
// Hide this option if this is not a PD compatible connection
if (connected && !mUsbBackend.areAllRolesSupported()) {
mFragment.getPreferenceScreen().removePreference(mPreferenceCategory);
} else if (connected && mUsbBackend.areAllRolesSupported()){
mFragment.getPreferenceScreen().addPreference(mPreferenceCategory);
}
if (powerRole == UsbPort.POWER_ROLE_SOURCE) {
mSwitchPreference.setChecked(true);
mPreferenceCategory.setEnabled(true);
} else if (powerRole == UsbPort.POWER_ROLE_SINK) {
mSwitchPreference.setChecked(false);
mPreferenceCategory.setEnabled(true);
} else if (!connected || powerRole == UsbPort.POWER_ROLE_NONE){
mPreferenceCategory.setEnabled(false);
if (mNextPowerRole == UsbPort.POWER_ROLE_NONE) {
mSwitchPreference.setSummary("");
}
}
if (mNextPowerRole != UsbPort.POWER_ROLE_NONE && powerRole != UsbPort.POWER_ROLE_NONE) {
if (mNextPowerRole == powerRole) {
// Clear switching text if switch succeeded
mSwitchPreference.setSummary("");
} else {
// Set failure text if switch failed
mSwitchPreference.setSummary(R.string.usb_switching_failed);
}
mNextPowerRole = UsbPort.POWER_ROLE_NONE;
mHandler.removeCallbacks(mFailureCallback);
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
int newRole = mSwitchPreference.isChecked() ? UsbPort.POWER_ROLE_SOURCE
: UsbPort.POWER_ROLE_SINK;
if (mUsbBackend.getPowerRole() != newRole && mNextPowerRole == UsbPort.POWER_ROLE_NONE
&& !Utils.isMonkeyRunning()) {
mUsbBackend.setPowerRole(newRole);
mNextPowerRole = newRole;
mSwitchPreference.setSummary(R.string.usb_switching);
mHandler.postDelayed(mFailureCallback,
mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS
: UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS);
}
// We don't know that the action succeeded until called back in refresh()
mSwitchPreference.setChecked(!mSwitchPreference.isChecked());
return true;
}
@Override
public boolean isAvailable() {
return !Utils.isMonkeyRunning();
}
@Override
public String getPreferenceKey() {
return "usb_details_power_role";
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.connecteddevice.usb;
import com.android.settings.R;
import com.android.settings.Utils;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.support.v14.preference.PreferenceFragment;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import java.util.List;
/**
* This class adds switches for toggling individual USB options, such as "transfer files",
* "supply power", "usb tethering", etc.
*/
public class UsbDetailsProfilesController extends UsbDetailsController
implements Preference.OnPreferenceClickListener {
static final String KEY_POWER = "power";
private PreferenceCategory mProfilesContainer;
private List<String> mOptions;
private String mKey;
public UsbDetailsProfilesController(Context context, PreferenceFragment fragment,
UsbBackend backend, List<String> options, String key) {
super(context, fragment, backend);
mOptions = options;
mKey = key;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mProfilesContainer = (PreferenceCategory) screen.findPreference(getPreferenceKey());
}
/**
* Gets a switch preference for the particular option, creating it if needed.
*/
private SwitchPreference getProfilePreference(String key, int titleId) {
SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(key);
if (pref == null) {
pref = new SwitchPreference(mProfilesContainer.getContext());
pref.setKey(key);
pref.setTitle(titleId);
pref.setOnPreferenceClickListener(this);
mProfilesContainer.addPreference(pref);
}
return pref;
}
@Override
protected void refresh(int mode) {
SwitchPreference pref;
for (String option : mOptions) {
int newMode;
int summary = -1;
int title;
if (option.equals(UsbManager.USB_FUNCTION_MTP)) {
newMode = UsbBackend.MODE_DATA_MTP;
title = R.string.usb_use_file_transfers;
} else if (option.equals(KEY_POWER)) {
newMode = UsbBackend.MODE_POWER_SOURCE;
title = R.string.usb_use_power_only;
summary = R.string.usb_use_power_only_desc;
} else if (option.equals(UsbManager.USB_FUNCTION_PTP)) {
newMode = UsbBackend.MODE_DATA_PTP;
title = R.string.usb_use_photo_transfers;
} else if (option.equals(UsbManager.USB_FUNCTION_MIDI)) {
newMode = UsbBackend.MODE_DATA_MIDI;
title = R.string.usb_use_MIDI;
} else if (option.equals(UsbManager.USB_FUNCTION_RNDIS)) {
newMode = UsbBackend.MODE_DATA_TETHER;
title = R.string.usb_use_tethering;
} else {
continue;
}
pref = getProfilePreference(option, title);
// Only show supported and allowed options
if (mUsbBackend.isModeSupported(newMode)
&& !mUsbBackend.isModeDisallowedBySystem(newMode)
&& !mUsbBackend.isModeDisallowed(newMode)) {
if (summary != -1) {
pref.setSummary(summary);
}
pref.setChecked((mode & newMode) != 0);
} else {
mProfilesContainer.removePreference(pref);
}
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
SwitchPreference profilePref = (SwitchPreference) preference;
String key = profilePref.getKey();
int mode = mUsbBackend.getCurrentMode();
int thisMode = 0;
if (key.equals(KEY_POWER)) {
thisMode = UsbBackend.MODE_POWER_SOURCE;
} else if (key.equals(UsbManager.USB_FUNCTION_MTP)) {
thisMode = UsbBackend.MODE_DATA_MTP;
} else if (key.equals(UsbManager.USB_FUNCTION_PTP)) {
thisMode = UsbBackend.MODE_DATA_PTP;
} else if (key.equals(UsbManager.USB_FUNCTION_RNDIS)) {
thisMode = UsbBackend.MODE_DATA_TETHER;
} else if (key.equals(UsbManager.USB_FUNCTION_MIDI)) {
thisMode = UsbBackend.MODE_DATA_MIDI;
}
if (profilePref.isChecked()) {
if (!key.equals(KEY_POWER)) {
// Only one non power mode can currently be set at once.
mode &= UsbBackend.MODE_POWER_MASK;
}
mode |= thisMode;
} else {
mode &= ~thisMode;
}
if (!Utils.isMonkeyRunning()) {
mUsbBackend.setMode(mode);
}
return false;
}
@Override
public boolean isAvailable() {
return !Utils.isMonkeyRunning();
}
@Override
public String getPreferenceKey() {
return mKey;
}
}

View File

@@ -27,8 +27,4 @@ public class UsbManagerWrapper {
public long getCurrentFunctions() {
return mUsbManager.getCurrentFunctions();
}
public long usbFunctionsFromString(String str) {
return UsbManager.usbFunctionsFromString(str);
}
}