diff options
22 files changed, 444 insertions, 1508 deletions
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java index 34f6d7de0cc9..adbe9d015626 100644 --- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java +++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java @@ -18,7 +18,6 @@ package com.android.commands.svc; import android.content.Context; import android.hardware.usb.IUsbManager; -import android.hardware.usb.UsbManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -39,9 +38,6 @@ public class UsbCommand extends Svc.Command { + "\n" + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n" + " Set the current usb function and optionally the data lock state.\n\n" - + " svc usb setScreenUnlockedFunctions [function]\n" - + " Sets the functions which, if the device was charging," - + " become current on screen unlock.\n" + " svc usb getFunction\n" + " Gets the list of currently enabled functions\n"; } @@ -66,16 +62,6 @@ public class UsbCommand extends Svc.Command { } else if ("getFunction".equals(args[1])) { System.err.println(SystemProperties.get("sys.usb.config")); return; - } else if ("setScreenUnlockedFunctions".equals(args[1])) { - IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( - Context.USB_SERVICE)); - try { - usbMgr.setScreenUnlockedFunctions((args.length >= 3 ? args[2] : - UsbManager.USB_FUNCTION_NONE)); - } catch (RemoteException e) { - System.err.println("Error communicating with UsbManager: " + e); - } - return; } } System.err.println(longHelp()); diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index f2160e192623..c8d983933fc6 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -268,11 +268,4 @@ public abstract class ActivityManagerInternal { * @param token The IApplicationToken for the activity */ public abstract void setFocusedActivity(IBinder token); - - public interface ScreenObserver { - public void onAwakeStateChanged(boolean isAwake); - public void onKeyguardStateChanged(boolean isShowing); - } - - public abstract void registerScreenObserver(ScreenObserver observer); } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 4e8c45dc2c46..025d46d12567 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -96,11 +96,6 @@ interface IUsbManager */ void setCurrentFunction(String function, boolean usbDataUnlocked); - /* Sets the screen unlocked USB function(s), which will be set automatically - * when the screen is unlocked. - */ - void setScreenUnlockedFunctions(String function); - /* Allow USB debugging from the attached host. If alwaysAllow is true, add the * the public key to list of host keys that the user has approved. */ diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 48e8d342db65..d73d3d8b04cf 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -590,32 +590,6 @@ public class UsbManager { } /** - * Sets the screen unlocked functions, which are persisted and set as the current functions - * whenever the screen is unlocked. - * <p> - * The allowed values are: {@link #USB_FUNCTION_NONE}, - * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP}, - * or {@link #USB_FUNCTION_RNDIS}. - * {@link #USB_FUNCTION_NONE} has the effect of switching off this feature, so functions - * no longer change on screen unlock. - * </p><p> - * Note: When the screen is on, this method will apply given functions as current functions, - * which is asynchronous and may fail silently without applying the requested changes. - * </p> - * - * @param function function to set as default - * - * {@hide} - */ - public void setScreenUnlockedFunctions(String function) { - try { - mService.setScreenUnlockedFunctions(function); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Returns a list of physical USB ports on the device. * <p> * This list is guaranteed to contain all dual-role USB Type C ports but it might diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 19f0c90e32bc..01546b0001ef 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,6 +21,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.BitUtils; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6c7455d35397..91e2f7d4ddd0 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3866,7 +3866,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private void onTouchDown(MotionEvent ev) { mHasPerformedLongPress = false; mActivePointerId = ev.getPointerId(0); - hideSelector(); if (mTouchMode == TOUCH_MODE_OVERFLING) { // Stopped the fling. It is a scroll. @@ -5227,21 +5226,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } mRecycler.fullyDetachScrapViews(); - boolean selectorOnScreen = false; if (!inTouchMode && mSelectedPosition != INVALID_POSITION) { final int childIndex = mSelectedPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { positionSelector(mSelectedPosition, getChildAt(childIndex)); - selectorOnScreen = true; } } else if (mSelectorPosition != INVALID_POSITION) { final int childIndex = mSelectorPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { - positionSelector(mSelectorPosition, getChildAt(childIndex)); - selectorOnScreen = true; + positionSelector(INVALID_POSITION, getChildAt(childIndex)); } - } - if (!selectorOnScreen) { + } else { mSelectorRect.setEmpty(); } diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 324f923674eb..6af41a51f0dd 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -256,7 +256,7 @@ public class MenuPopupHelper implements MenuHelper { final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; if (hgrav == Gravity.RIGHT) { - xOffset -= mAnchorView.getWidth(); + xOffset += mAnchorView.getWidth(); } popup.setHorizontalOffset(xOffset); diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index 445379b1d9f4..d9ca5be0502e 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -263,6 +263,7 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes); subPopup.setPresenterCallback(mPresenterCallback); subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu)); + subPopup.setGravity(mDropDownGravity); // Pass responsibility for handling onDismiss to the submenu. subPopup.setOnDismissListener(mOnDismissListener); @@ -272,17 +273,8 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mMenu.close(false /* closeAllMenus */); // Show the new sub-menu popup at the same location as this popup. - int horizontalOffset = mPopup.getHorizontalOffset(); + final int horizontalOffset = mPopup.getHorizontalOffset(); final int verticalOffset = mPopup.getVerticalOffset(); - - // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT, - // So, again to display sub-menu popup in same xOffset, add the Anchor width. - final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, - mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; - if (hgrav == Gravity.RIGHT) { - horizontalOffset += mAnchorView.getWidth(); - } - if (subPopup.tryShow(horizontalOffset, verticalOffset)) { if (mPresenterCallback != null) { mPresenterCallback.onOpenSubMenu(subMenu); diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index c0a8acda628e..ab9912a438d4 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1041,13 +1041,6 @@ </intent-filter> </activity> - <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> - </intent-filter> - </activity> - <activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml deleted file mode 100644 index 3b9e2bdb3130..000000000000 --- a/core/tests/coretests/res/layout/context_menu.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 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. -*/ ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <LinearLayout - android:id="@+id/context_menu_target_ltr" - android:orientation="horizontal" - android:layoutDirection="ltr" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="50px" - android:layout_marginEnd="50px"> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="LTR"/> - </LinearLayout> - - <LinearLayout - android:id="@+id/context_menu_target_rtl" - android:orientation="horizontal" - android:layoutDirection="rtl" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="50px" - android:layout_marginEnd="50px"> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="RTL"/> - </LinearLayout> - -</LinearLayout> diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java deleted file mode 100644 index 468b9b2a4864..000000000000 --- a/core/tests/coretests/src/android/util/PollingCheck.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2017 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 android.util; - -import org.junit.Assert; - -/** - * Utility used for testing that allows to poll for a certain condition to happen within a timeout. - * - * Code copied from com.android.compatibility.common.util.PollingCheck - */ -public abstract class PollingCheck { - - private static final long DEFAULT_TIMEOUT = 3000; - private static final long TIME_SLICE = 50; - private final long mTimeout; - - /** - * The condition that the PollingCheck should use to proceed successfully. - */ - public interface PollingCheckCondition { - - /** - * @return Whether the polling condition has been met. - */ - boolean canProceed(); - } - - public PollingCheck(long timeout) { - mTimeout = timeout; - } - - protected abstract boolean check(); - - /** - * Start running the polling check. - */ - public void run() { - if (check()) { - return; - } - - long timeout = mTimeout; - while (timeout > 0) { - try { - Thread.sleep(TIME_SLICE); - } catch (InterruptedException e) { - Assert.fail("unexpected InterruptedException"); - } - - if (check()) { - return; - } - - timeout -= TIME_SLICE; - } - - Assert.fail("unexpected timeout"); - } - - /** - * Instantiate and start polling for a given condition with a default 3000ms timeout. - * - * @param condition The condition to check for success. - */ - public static void waitFor(final PollingCheckCondition condition) { - new PollingCheck(DEFAULT_TIMEOUT) { - @Override - protected boolean check() { - return condition.canProceed(); - } - }.run(); - } - - /** - * Instantiate and start polling for a given condition. - * - * @param timeout Time out in ms - * @param condition The condition to check for success. - */ - public static void waitFor(long timeout, final PollingCheckCondition condition) { - new PollingCheck(timeout) { - @Override - protected boolean check() { - return condition.canProceed(); - } - }.run(); - } -} - diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java deleted file mode 100644 index 830b3d549773..000000000000 --- a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java +++ /dev/null @@ -1,54 +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 android.view.menu; - -import android.app.Activity; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View; - -import com.android.frameworks.coretests.R; - -public class ContextMenuActivity extends Activity { - - static final String LABEL_ITEM = "Item"; - static final String LABEL_SUBMENU = "Submenu"; - static final String LABEL_SUBITEM = "Subitem"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.context_menu); - registerForContextMenu(getTargetLtr()); - registerForContextMenu(getTargetRtl()); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - menu.add(LABEL_ITEM); - menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM); - } - - View getTargetLtr() { - return findViewById(R.id.context_menu_target_ltr); - } - - View getTargetRtl() { - return findViewById(R.id.context_menu_target_rtl); - } -} diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java deleted file mode 100644 index 59d4e55d8d45..000000000000 --- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java +++ /dev/null @@ -1,93 +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 android.view.menu; - -import android.content.Context; -import android.graphics.Point; -import android.support.test.filters.MediumTest; -import android.test.ActivityInstrumentationTestCase; -import android.util.PollingCheck; -import android.view.Display; -import android.view.View; -import android.view.WindowManager; -import android.widget.espresso.ContextMenuUtils; - -@MediumTest -public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> { - - public ContextMenuTest() { - super("com.android.frameworks.coretests", ContextMenuActivity.class); - } - - public void testContextMenuPositionLtr() throws InterruptedException { - testMenuPosition(getActivity().getTargetLtr()); - } - - public void testContextMenuPositionRtl() throws InterruptedException { - testMenuPosition(getActivity().getTargetRtl()); - } - - private void testMenuPosition(View target) throws InterruptedException { - final int minScreenDimension = getMinScreenDimension(); - if (minScreenDimension < 320) { - // Assume there is insufficient room for the context menu to be aligned properly. - return; - } - - int offsetX = target.getWidth() / 2; - int offsetY = target.getHeight() / 2; - - getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY)); - - PollingCheck.waitFor( - () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU)); - - ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); - - ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU); - - PollingCheck.waitFor( - () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM)); - - if (minScreenDimension < getCascadingMenuTreshold()) { - // A non-cascading submenu should be displayed at the same location as its parent. - // Not testing cascading submenu position, as it is positioned differently. - ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); - } - } - - /** - * Returns the minimum of the default display's width and height. - */ - private int getMinScreenDimension() { - final WindowManager windowManager = (WindowManager) getActivity().getSystemService( - Context.WINDOW_SERVICE); - final Display display = windowManager.getDefaultDisplay(); - final Point displaySize = new Point(); - display.getRealSize(displaySize); - return Math.min(displaySize.x, displaySize.y); - } - - /** - * Returns the minimum display size where cascading submenus are supported. - */ - private int getCascadingMenuTreshold() { - // Use the same dimension resource as in MenuPopupHelper.createPopup(). - return getActivity().getResources().getDimensionPixelSize( - com.android.internal.R.dimen.cascading_menus_min_smallest_width); - } -} diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java index 487a881082e7..c8218aa490f2 100644 --- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java +++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java @@ -17,32 +17,25 @@ package android.widget.espresso; import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; import static android.support.test.espresso.matcher.ViewMatchers.hasFocus; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; import static android.support.test.espresso.matcher.ViewMatchers.isEnabled; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.not; +import com.android.internal.view.menu.ListMenuItemView; + import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.matcher.ViewMatchers; -import android.view.View; import android.widget.MenuPopupWindow.MenuDropDownListView; -import com.android.internal.view.menu.ListMenuItemView; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - /** * Espresso utility methods for the context menu. */ @@ -89,15 +82,10 @@ public final class ContextMenuUtils { private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel, boolean enabled) { onContextMenu().check(matches( - hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled)))); - } - - private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) { - return allOf( - isAssignableFrom(ListMenuItemView.class), - hasDescendant(withText(itemLabel)), - enabled ? isEnabled() : not(isEnabled()), - isDisplayingAtLeast(90)); + hasDescendant(allOf( + isAssignableFrom(ListMenuItemView.class), + enabled ? isEnabled() : not(isEnabled()), + hasDescendant(withText(itemLabel)))))); } /** @@ -119,70 +107,4 @@ public final class ContextMenuUtils { public static void assertContextMenuContainsItemDisabled(String itemLabel) { asssertContextMenuContainsItemWithEnabledState(itemLabel, false); } - - /** - * Asserts that the context menu window is aligned to a given view with a given offset. - * - * @param anchor Anchor view. - * @param offsetX x offset - * @param offsetY y offset. - * @throws AssertionError if the assertion fails - */ - public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) { - int [] expectedLocation = new int[2]; - anchor.getLocationOnScreen(expectedLocation); - expectedLocation[0] += offsetX; - expectedLocation[1] += offsetY; - - final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - - onContextMenu().check(matches(new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("root view "); - description.appendText(rtl ? "right" : "left"); - description.appendText("="); - description.appendText(Integer.toString(offsetX)); - description.appendText(", top="); - description.appendText(Integer.toString(offsetY)); - } - - @Override - public boolean matchesSafely(View view) { - View rootView = view.getRootView(); - int [] actualLocation = new int[2]; - rootView.getLocationOnScreen(actualLocation); - if (rtl) { - actualLocation[0] += rootView.getWidth(); - } - return expectedLocation[0] == actualLocation[0] - && expectedLocation[1] == actualLocation[1]; - } - })); - } - - /** - * Check is the menu item is clickable (i.e. visible and enabled). - * - * @param itemLabel Label of the item. - * @return True if the menu item is clickable. - */ - public static boolean isMenuItemClickable(String itemLabel) { - try { - onContextMenu().check(matches( - hasDescendant(getVisibleMenuItemMatcher(itemLabel, true)))); - return true; - } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) { - return false; - } - } - - /** - * Click on a menu item with the specified label - * @param itemLabel Label of the item. - */ - public static void clickMenuItem(String itemLabel) { - onView(getVisibleMenuItemMatcher(itemLabel, true)) - .inRoot(withDecorView(hasFocus())).perform(click()); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index 13617f127b3e..533771a31d0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -265,9 +265,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC mStatusBarIconController.getTransitionsController().dump(fd, pw, args); pw.println(); pw.println(" NavigationBarTransitionsController:"); - if (mNavigationBarController != null) { - mNavigationBarController.dump(fd, pw, args); - } + mNavigationBarController.dump(fd, pw, args); pw.println(); } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index e467903cec18..b08b26d77b76 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -49,6 +49,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.qs.tiles.DndTile; @@ -339,15 +340,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private boolean shouldShowUI(int flags) { updateStatusBar(); - // if status bar isn't null, check if phone is in AOD, else check flags - // since we could be using a different status bar - return mStatusBar != null ? - mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP - && mStatusBar.getWakefulnessState() != - WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP + return mStatusBar != null + && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP + && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP && mStatusBar.isDeviceInteractive() - && (flags & AudioManager.FLAG_SHOW_UI) != 0 - : (flags & AudioManager.FLAG_SHOW_UI) != 0; + && (flags & AudioManager.FLAG_SHOW_UI) != 0; } boolean onVolumeChangedW(int stream, int flags) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7da3adb684a2..df64abce0ac4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -201,7 +201,6 @@ import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -1563,8 +1562,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final List<ScreenObserver> mScreenObservers = new ArrayList<>(); - final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1706,8 +1703,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; - static final int DISPATCH_SCREEN_AWAKE_MSG = 71; - static final int DISPATCH_SCREEN_KEYGUARD_MSG = 72; static final int START_USER_SWITCH_FG_MSG = 712; static final int NOTIFY_VR_KEYGUARD_MSG = 74; @@ -2434,17 +2429,11 @@ public class ActivityManagerService extends IActivityManager.Stub } } } break; - case DISPATCH_SCREEN_AWAKE_MSG: { - final boolean isAwake = msg.arg1 != 0; - for (int i = mScreenObservers.size() - 1; i >= 0; i--) { - mScreenObservers.get(i).onAwakeStateChanged(isAwake); - } + case NOTIFY_VR_SLEEPING_MSG: { + notifyVrManagerOfSleepState(msg.arg1 != 0); } break; - case DISPATCH_SCREEN_KEYGUARD_MSG: { - final boolean isShowing = msg.arg1 != 0; - for (int i = mScreenObservers.size() - 1; i >= 0; i--) { - mScreenObservers.get(i).onKeyguardStateChanged(isShowing); - } + case NOTIFY_VR_KEYGUARD_MSG: { + notifyVrManagerOfKeyguardState(msg.arg1 != 0); } break; case HANDLE_TRUST_STORAGE_UPDATE_MSG: { synchronized (ActivityManagerService.this) { @@ -3343,6 +3332,32 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); } + private void sendNotifyVrManagerOfSleepState(boolean isSleeping) { + mHandler.sendMessage( + mHandler.obtainMessage(NOTIFY_VR_SLEEPING_MSG, isSleeping ? 1 : 0, 0)); + } + + private void notifyVrManagerOfSleepState(boolean isSleeping) { + final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); + if (vrService == null) { + return; + } + vrService.onSleepStateChanged(isSleeping); + } + + private void sendNotifyVrManagerOfKeyguardState(boolean isShowing) { + mHandler.sendMessage( + mHandler.obtainMessage(NOTIFY_VR_KEYGUARD_MSG, isShowing ? 1 : 0, 0)); + } + + private void notifyVrManagerOfKeyguardState(boolean isShowing) { + final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); + if (vrService == null) { + return; + } + vrService.onKeyguardStateChanged(isShowing); + } + final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; @@ -12488,8 +12503,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (wasAwake != isAwake) { // Also update state in a special way for running foreground services UI. mServices.updateScreenStateLocked(isAwake); - mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0) - .sendToTarget(); + sendNotifyVrManagerOfSleepState(!isAwake); } } } @@ -12642,9 +12656,7 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(ident); } } - - mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, showing ? 1 : 0, 0) - .sendToTarget(); + sendNotifyVrManagerOfKeyguardState(showing); } @Override @@ -24312,11 +24324,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } } - - @Override - public void registerScreenObserver(ScreenObserver observer) { - mScreenObservers.add(observer); - } } /** diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java index 35b6ad3079a5..7b1e12e24072 100644 --- a/services/core/java/com/android/server/vr/VrManagerInternal.java +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -59,6 +59,13 @@ public abstract class VrManagerInternal { int userId, int processId, @NonNull ComponentName calling); /** + * Set whether the system has acquired a sleep token. + * + * @param isAsleep is {@code true} if the device is asleep, or {@code false} otherwise. + */ + public abstract void onSleepStateChanged(boolean isAsleep); + + /** * Set whether the display used for VR output is on. * * @param isScreenOn is {@code true} if the display is on and can receive commands, @@ -67,6 +74,13 @@ public abstract class VrManagerInternal { public abstract void onScreenStateChanged(boolean isScreenOn); /** + * Set whether the keyguard is currently active/showing. + * + * @param isShowing is {@code true} if the keyguard is active/showing. + */ + public abstract void onKeyguardStateChanged(boolean isShowing); + + /** * Return NO_ERROR if the given package is installed on the device and enabled as a * VrListenerService for the given current user, or a negative error code indicating a failure. * diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 56cacf4e6aa1..b0fd248b2b39 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -19,7 +19,6 @@ import static android.view.Display.INVALID_DISPLAY; import android.Manifest; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.INotificationManager; @@ -105,8 +104,7 @@ import java.util.Objects; * * @hide */ -public class VrManagerService extends SystemService - implements EnabledComponentChangeListener, ScreenObserver { +public class VrManagerService extends SystemService implements EnabledComponentChangeListener{ public static final String TAG = "VrManagerService"; static final boolean DBG = false; @@ -233,17 +231,15 @@ public class VrManagerService extends SystemService } } - private void setScreenOn(boolean isScreenOn) { - setSystemState(FLAG_SCREEN_ON, isScreenOn); + private void setSleepState(boolean isAsleep) { + setSystemState(FLAG_AWAKE, !isAsleep); } - @Override - public void onAwakeStateChanged(boolean isAwake) { - setSystemState(FLAG_AWAKE, isAwake); + private void setScreenOn(boolean isScreenOn) { + setSystemState(FLAG_SCREEN_ON, isScreenOn); } - @Override - public void onKeyguardStateChanged(boolean isShowing) { + private void setKeyguardShowing(boolean isShowing) { setSystemState(FLAG_KEYGUARD_UNLOCKED, !isShowing); } @@ -679,11 +675,21 @@ public class VrManagerService extends SystemService } @Override + public void onSleepStateChanged(boolean isAsleep) { + VrManagerService.this.setSleepState(isAsleep); + } + + @Override public void onScreenStateChanged(boolean isScreenOn) { VrManagerService.this.setScreenOn(isScreenOn); } @Override + public void onKeyguardStateChanged(boolean isShowing) { + VrManagerService.this.setKeyguardShowing(isShowing); + } + + @Override public boolean isCurrentVrListener(String packageName, int userId) { return VrManagerService.this.isCurrentVrListener(packageName, userId); } @@ -734,9 +740,6 @@ public class VrManagerService extends SystemService @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { - LocalServices.getService(ActivityManagerInternal.class) - .registerScreenObserver(this); - mNotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); synchronized (mLock) { diff --git a/services/usb/Android.bp b/services/usb/Android.bp index feb7b76ae119..0cd9ac306dfb 100644 --- a/services/usb/Android.bp +++ b/services/usb/Android.bp @@ -10,6 +10,5 @@ java_library_static { static_libs: [ "android.hardware.usb-V1.0-java", "android.hardware.usb-V1.1-java", - "android.hardware.usb.gadget-V1.0-java", ], } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index e3e5e3e1b10b..1b057f9b9681 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -16,9 +16,6 @@ package com.android.server.usb; -import android.app.ActivityManager; -import android.app.ActivityManagerInternal; -import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -29,7 +26,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; @@ -41,21 +37,12 @@ import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; -import android.hardware.usb.gadget.V1_0.GadgetFunction; -import android.hardware.usb.gadget.V1_0.IUsbGadget; -import android.hardware.usb.gadget.V1_0.IUsbGadgetCallback; -import android.hardware.usb.gadget.V1_0.Status; -import android.hidl.manager.V1_0.IServiceManager; -import android.hidl.manager.V1_0.IServiceNotification; import android.os.BatteryManager; -import android.os.Environment; import android.os.FileUtils; import android.os.Handler; -import android.os.HwBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; -import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; @@ -73,7 +60,6 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.SomeArgs; import com.android.internal.util.IndentingPrintWriter; import com.android.server.FgThread; -import com.android.server.LocalServices; import java.io.File; import java.io.FileNotFoundException; @@ -83,24 +69,32 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Set; -import java.util.StringJoiner; /** * UsbDeviceManager manages USB state in device mode. */ -public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver { +public class UsbDeviceManager { private static final String TAG = "UsbDeviceManager"; private static final boolean DEBUG = false; /** - * The SharedPreference setting per user that stores the screen unlocked functions between - * sessions. + * The persistent property which stores whether adb is enabled or not. + * May also contain vendor-specific default functions for testing purposes. */ - private static final String UNLOCKED_CONFIG_PREF = "usb-screen-unlocked-config-%d"; + private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; + + /** + * The non-persistent property which stores the current USB settings. + */ + private static final String USB_CONFIG_PROPERTY = "sys.usb.config"; + + /** + * The non-persistent property which stores the current USB actual state. + */ + private static final String USB_STATE_PROPERTY = "sys.usb.state"; /** * ro.bootmode value when phone boots into usual Android. @@ -134,12 +128,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private static final int MSG_UPDATE_CHARGING_STATE = 9; private static final int MSG_UPDATE_HOST_STATE = 10; private static final int MSG_LOCALE_CHANGED = 11; - private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12; - private static final int MSG_UPDATE_SCREEN_LOCK = 13; - private static final int MSG_SET_CHARGING_FUNCTIONS = 14; - private static final int MSG_SET_FUNCTIONS_TIMEOUT = 15; - private static final int MSG_GET_CURRENT_USB_FUNCTIONS = 16; - private static final int MSG_FUNCTION_SWITCH_TIMEOUT = 17; private static final int AUDIO_MODE_SOURCE = 1; @@ -155,9 +143,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private static final String BOOT_MODE_PROPERTY = "ro.bootmode"; private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv"; + private UsbHandler mHandler; private boolean mBootCompleted; - private boolean mSystemReady; private final Object mLock = new Object(); @@ -173,6 +161,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private boolean mMidiEnabled; private int mMidiCard; private int mMidiDevice; + private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap; private String[] mAccessoryStrings; private UsbDebuggingManager mDebuggingManager; private final UsbAlsaManager mUsbAlsaManager; @@ -180,7 +169,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private Intent mBroadcastedIntent; private boolean mPendingBootBroadcast; private static Set<Integer> sBlackListedInterfaces; - private SharedPreferences mSettings; static { sBlackListedInterfaces = new HashSet<>(); @@ -229,31 +217,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } }; - @Override - public void onKeyguardStateChanged(boolean isShowing) { - int userHandle = ActivityManager.getCurrentUser(); - boolean secure = mContext.getSystemService(KeyguardManager.class) - .isDeviceSecure(userHandle); - boolean unlocking = mContext.getSystemService(UserManager.class) - .isUserUnlockingOrUnlocked(userHandle); - if (DEBUG) { - Slog.v(TAG, "onKeyguardStateChanged: isShowing:" + isShowing + " secure:" + secure - + " unlocking:" + unlocking + " user:" + userHandle); - } - // We are unlocked when the keyguard is down or non-secure, and user storage is unlocked. - mHandler.sendMessage(MSG_UPDATE_SCREEN_LOCK, (isShowing && secure) || !unlocking); - } - - @Override - public void onAwakeStateChanged(boolean isAwake) { - // ignore - } - - /** Called when a user is unlocked. */ - public void onUnlockUser(int userHandle) { - onKeyguardStateChanged(false); - } - public UsbDeviceManager(Context context, UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) { mContext = context; @@ -264,27 +227,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); initRndisAddress(); - boolean halNotPresent = false; - try { - IUsbGadget.getService(true); - } catch (RemoteException e) { - Slog.e(TAG, "USB GADGET HAL present but exception thrown", e); - } catch (NoSuchElementException e) { - halNotPresent = true; - Slog.i(TAG, "USB GADGET HAL not present in the device", e); - } + readOemUsbOverrideConfig(); - if (halNotPresent) { - /** - * Initialze the legacy UsbHandler - */ - mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext); - } else { - /** - * Initialize HAL based UsbHandler - */ - mHandler = new UsbHandlerHal(FgThread.get().getLooper()); - } + mHandler = new UsbHandler(FgThread.get().getLooper()); if (nativeIsStartRequested()) { if (DEBUG) Slog.d(TAG, "accessory attached at boot"); @@ -358,8 +303,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver public void systemReady() { if (DEBUG) Slog.d(TAG, "systemReady"); - LocalServices.getService(ActivityManagerInternal.class).registerScreenObserver(this); - mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -382,6 +325,15 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver massStorageSupported = primary != null && primary.allowMassStorage(); mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean( com.android.internal.R.bool.config_usbChargingMessage); + + // make sure the ADB_ENABLED setting value matches the current state + try { + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); + } catch (SecurityException e) { + // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed. + Slog.d(TAG, "ADB_ENABLED is restricted."); + } mHandler.sendEmptyMessage(MSG_SYSTEM_READY); } @@ -455,15 +407,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } - private SharedPreferences getPinnedSharedPrefs(Context context) { - final File prefsFile = new File(new File( - Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL, - context.getUserId(), context.getPackageName()), "shared_prefs"), - UsbDeviceManager.class.getSimpleName() + ".xml"); - return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); - } - - private abstract class UsbHandler extends Handler { + private final class UsbHandler extends Handler { // current USB state private boolean mConnected; @@ -471,53 +415,73 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private boolean mSourcePower; private boolean mSinkPower; private boolean mConfigured; - protected boolean mUsbDataUnlocked; + private boolean mUsbDataUnlocked; private boolean mAudioAccessoryConnected; private boolean mAudioAccessorySupported; - protected String mCurrentFunctions; - protected boolean mCurrentFunctionsApplied; + private String mCurrentFunctions; + private boolean mCurrentFunctionsApplied; private UsbAccessory mCurrentAccessory; private int mUsbNotificationId; private boolean mAdbNotificationShown; - private int mCurrentUser; + private int mCurrentUser = UserHandle.USER_NULL; private boolean mUsbCharging; + private String mCurrentOemFunctions; private boolean mHideUsbNotification; private boolean mSupportsAllCombinations; - private String mScreenUnlockedFunctions = UsbManager.USB_FUNCTION_NONE; - private boolean mScreenLocked; - protected boolean mCurrentUsbFunctionsRequested; - protected boolean mCurrentUsbFunctionsReceived; - - /** - * The persistent property which stores whether adb is enabled or not. - * May also contain vendor-specific default functions for testing purposes. - */ - protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; public UsbHandler(Looper looper) { super(looper); + try { + // Restore default functions. - mCurrentUser = ActivityManager.getCurrentUser(); - mScreenLocked = true; - - /* - * Use the normal bootmode persistent prop to maintain state of adb across - * all boot modes. - */ - mAdbEnabled = UsbManager.containsFunction( - SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY), - UsbManager.USB_FUNCTION_ADB); - - /* - * Previous versions can set persist config to mtp/ptp but it does not - * get reset on OTA. Reset the property here instead. - */ - String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY); - if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) { - SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, - UsbManager.removeFunction(UsbManager.removeFunction(persisted, - UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP)); + mCurrentOemFunctions = SystemProperties.get(UsbDeviceManager.getPersistProp(false), + UsbManager.USB_FUNCTION_NONE); + if (isNormalBoot()) { + mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, + UsbManager.USB_FUNCTION_NONE); + mCurrentFunctionsApplied = mCurrentFunctions.equals( + SystemProperties.get(USB_STATE_PROPERTY)); + } else { + mCurrentFunctions = SystemProperties.get(getPersistProp(true), + UsbManager.USB_FUNCTION_NONE); + mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY, + UsbManager.USB_FUNCTION_NONE).equals( + SystemProperties.get(USB_STATE_PROPERTY)); + } + + /* + * Use the normal bootmode persistent prop to maintain state of adb across + * all boot modes. + */ + mAdbEnabled = UsbManager.containsFunction( + SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY), + UsbManager.USB_FUNCTION_ADB); + + /* + * Previous versions can set persist config to mtp/ptp but it does not + * get reset on OTA. Reset the property here instead. + */ + String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY); + if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP) + || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) { + SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, + UsbManager.removeFunction(UsbManager.removeFunction(persisted, + UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP)); + } + + String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); + updateState(state); + + // register observer to listen for settings changes + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), + false, new AdbSettingsObserver()); + + // Watch for USB configuration changes + mUEventObserver.startObserving(USB_STATE_MATCH); + mUEventObserver.startObserving(ACCESSORY_START_MATCH); + } catch (Exception e) { + Slog.e(TAG, "Error initializing UsbHandler", e); } } @@ -543,21 +507,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver sendMessage(m); } - public void sendMessage(int what, boolean arg1, boolean arg2) { - removeMessages(what); - Message m = Message.obtain(this, what); - m.arg1 = (arg1 ? 1 : 0); - m.arg2 = (arg2 ? 1 : 0); - sendMessage(m); - } - - public void sendMessageDelayed(int what, boolean arg, long delayMillis) { - removeMessages(what); - Message m = Message.obtain(this, what); - m.arg1 = (arg ? 1 : 0); - sendMessageDelayed(m, delayMillis); - } - public void updateState(String state) { int connected, configured; @@ -575,7 +524,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return; } removeMessages(MSG_UPDATE_STATE); - if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT); Message msg = Message.obtain(this, MSG_UPDATE_STATE); msg.arg1 = connected; msg.arg2 = configured; @@ -598,6 +546,28 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver sendMessageDelayed(msg, UPDATE_DELAY); } + private boolean waitForState(String state) { + // wait for the transition to complete. + // give up after 1 second. + String value = null; + for (int i = 0; i < 20; i++) { + // State transition is done when sys.usb.state is set to the new configuration + value = SystemProperties.get(USB_STATE_PROPERTY); + if (state.equals(value)) return true; + SystemClock.sleep(50); + } + Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value); + return false; + } + + private void setUsbConfig(String config) { + if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); + // set the new configuration + // we always set it due to b/23631400, where adbd was getting killed + // and not restarted due to property timeouts on some devices + SystemProperties.set(USB_CONFIG_PROPERTY, config); + } + private void setAdbEnabled(boolean enable) { if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); if (enable != mAdbEnabled) { @@ -624,7 +594,114 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected String applyAdbFunction(String functions) { + /** + * Evaluates USB function policies and applies the change accordingly. + */ + private void setEnabledFunctions(String functions, boolean forceRestart, + boolean usbDataUnlocked) { + if (DEBUG) { + Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " + + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked); + } + + if (usbDataUnlocked != mUsbDataUnlocked) { + mUsbDataUnlocked = usbDataUnlocked; + updateUsbNotification(false); + forceRestart = true; + } + + // Try to set the enabled functions. + final String oldFunctions = mCurrentFunctions; + final boolean oldFunctionsApplied = mCurrentFunctionsApplied; + if (trySetEnabledFunctions(functions, forceRestart)) { + return; + } + + // Didn't work. Try to revert changes. + // We always reapply the policy in case certain constraints changed such as + // user restrictions independently of any other new functions we were + // trying to activate. + if (oldFunctionsApplied && !oldFunctions.equals(functions)) { + Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); + if (trySetEnabledFunctions(oldFunctions, false)) { + return; + } + } + + // Still didn't work. Try to restore the default functions. + Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); + if (trySetEnabledFunctions(null, false)) { + return; + } + + // Now we're desperate. Ignore the default functions. + // Try to get ADB working if enabled. + Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled)."); + if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) { + return; + } + + // Ouch. + Slog.e(TAG, "Unable to set any USB functions!"); + } + + private boolean isNormalBoot() { + String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"); + } + + private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { + if (functions == null || applyAdbFunction(functions) + .equals(UsbManager.USB_FUNCTION_NONE)) { + functions = getDefaultFunctions(); + } + functions = applyAdbFunction(functions); + + String oemFunctions = applyOemOverrideFunction(functions); + + if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) { + SystemProperties.set(getPersistProp(true), functions); + } + + if ((!functions.equals(oemFunctions) && + !mCurrentOemFunctions.equals(oemFunctions)) + || !mCurrentFunctions.equals(functions) + || !mCurrentFunctionsApplied + || forceRestart) { + Slog.i(TAG, "Setting USB config to " + functions); + mCurrentFunctions = functions; + mCurrentOemFunctions = oemFunctions; + mCurrentFunctionsApplied = false; + + // Kick the USB stack to close existing connections. + setUsbConfig(UsbManager.USB_FUNCTION_NONE); + + if (!waitForState(UsbManager.USB_FUNCTION_NONE)) { + Slog.e(TAG, "Failed to kick USB config"); + return false; + } + + // Set the new USB configuration. + setUsbConfig(oemFunctions); + + if (mBootCompleted + && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP) + || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { + // Start up dependent services. + updateUsbStateBroadcastIfNeeded(true); + } + + if (!waitForState(oemFunctions)) { + Slog.e(TAG, "Failed to switch USB config to " + functions); + return false; + } + + mCurrentFunctionsApplied = true; + } + return true; + } + + private String applyAdbFunction(String functions) { // Do not pass null pointer to the UsbManager. // There isnt a check there. if (functions == null) { @@ -706,7 +783,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return false; } - protected void updateUsbStateBroadcastIfNeeded(boolean configChanged) { + private void updateUsbStateBroadcastIfNeeded(boolean configChanged) { // send a sticky broadcast containing current USB state Intent intent = new Intent(UsbManager.ACTION_USB_STATE); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING @@ -799,14 +876,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mMidiEnabled && mConfigured, mMidiCard, mMidiDevice); } - private void setScreenUnlockedFunctions() { - setEnabledFunctions(mScreenUnlockedFunctions, false, - UsbManager.containsFunction(mScreenUnlockedFunctions, - UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(mScreenUnlockedFunctions, - UsbManager.USB_FUNCTION_PTP)); - } - @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -824,16 +893,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver updateCurrentAccessory(); } if (mBootCompleted) { - if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT) - && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) { + if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) { // restore defaults when USB is disconnected - if (!mScreenLocked - && !UsbManager.USB_FUNCTION_NONE.equals( - mScreenUnlockedFunctions)) { - setScreenUnlockedFunctions(); - } else { - setEnabledFunctions(null, !mAdbEnabled, false); - } + setEnabledFunctions(null, !mAdbEnabled, false); } updateUsbFunctions(); } else { @@ -916,47 +978,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver String functions = (String) msg.obj; setEnabledFunctions(functions, false, msg.arg1 == 1); break; - case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS: - mScreenUnlockedFunctions = (String) msg.obj; - SharedPreferences.Editor editor = mSettings.edit(); - editor.putString(String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, - mCurrentUser), mScreenUnlockedFunctions); - editor.commit(); - if (!mScreenLocked && !UsbManager.USB_FUNCTION_NONE.equals( - mScreenUnlockedFunctions)) { - // If the screen is unlocked, also set current functions. - setScreenUnlockedFunctions(); - } - break; - case MSG_UPDATE_SCREEN_LOCK: - if (msg.arg1 == 1 == mScreenLocked) { - break; - } - mScreenLocked = msg.arg1 == 1; - if (mSettings == null && !mScreenLocked) { - // Shared preferences aren't accessible until the user has been unlocked. - mSettings = getPinnedSharedPrefs(mContext); - mScreenUnlockedFunctions = mSettings.getString( - String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), - UsbManager.USB_FUNCTION_NONE); - } - if (!mBootCompleted) { - break; - } - if (mScreenLocked) { - if (!mConnected) { - setEnabledFunctions(null, false, false); - } - } else { - if (!UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions) - && (UsbManager.USB_FUNCTION_ADB.equals(mCurrentFunctions) - || (UsbManager.USB_FUNCTION_MTP.equals(mCurrentFunctions) - && !mUsbDataUnlocked))) { - // Set the screen unlocked functions if current function is charging. - setScreenUnlockedFunctions(); - } - } - break; case MSG_UPDATE_USER_RESTRICTIONS: // Restart the USB stack if USB transfer is enabled but no longer allowed. final boolean forceRestart = mUsbDataUnlocked @@ -966,8 +987,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart); break; case MSG_SYSTEM_READY: - mSystemReady = true; - finishBoot(); + updateUsbNotification(false); + updateAdbNotification(false); + updateUsbFunctions(); break; case MSG_LOCALE_CHANGED: updateAdbNotification(true); @@ -975,19 +997,30 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver break; case MSG_BOOT_COMPLETED: mBootCompleted = true; - finishBoot(); + if (mPendingBootBroadcast) { + updateUsbStateBroadcastIfNeeded(false); + mPendingBootBroadcast = false; + } + setEnabledFunctions(null, false, false); + if (mCurrentAccessory != null) { + getCurrentSettings().accessoryAttached(mCurrentAccessory); + } + if (mDebuggingManager != null) { + mDebuggingManager.setAdbEnabled(mAdbEnabled); + } break; case MSG_USER_SWITCHED: { if (mCurrentUser != msg.arg1) { - if (DEBUG) { - Slog.v(TAG, "Current user switched to " + msg.arg1); + // Restart the USB stack and re-apply user restrictions for MTP or PTP. + if (mUsbDataUnlocked + && isUsbDataTransferActive() + && mCurrentUser != UserHandle.USER_NULL) { + Slog.v(TAG, "Current user switched to " + msg.arg1 + + "; resetting USB host stack for MTP or PTP"); + // avoid leaking sensitive data from previous user + setEnabledFunctions(null, true, false); } mCurrentUser = msg.arg1; - mScreenLocked = true; - mScreenUnlockedFunctions = mSettings.getString( - String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), - UsbManager.USB_FUNCTION_NONE); - setEnabledFunctions(null, false, false); } break; } @@ -1005,41 +1038,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected void finishBoot() { - if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) { - if (mPendingBootBroadcast) { - updateUsbStateBroadcastIfNeeded(false); - mPendingBootBroadcast = false; - } - if (!mScreenLocked - && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) { - setScreenUnlockedFunctions(); - } else { - setEnabledFunctions(null, false, false); - } - if (mCurrentAccessory != null) { - getCurrentSettings().accessoryAttached(mCurrentAccessory); - } - if (mDebuggingManager != null) { - mDebuggingManager.setAdbEnabled(mAdbEnabled); - } - - // make sure the ADB_ENABLED setting value matches the current state - try { - Settings.Global.putInt(mContentResolver, - Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); - } catch (SecurityException e) { - // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't - // be changed. - Slog.d(TAG, "ADB_ENABLED is restricted."); - } - - updateUsbNotification(false); - updateAdbNotification(false); - updateUsbFunctions(); - } - } - private boolean isUsbDataTransferActive() { return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP) || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP); @@ -1049,7 +1047,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return mCurrentAccessory; } - protected void updateUsbNotification(boolean force) { + private void updateUsbNotification(boolean force) { if (mNotificationManager == null || !mUseUsbNotification || ("0".equals(SystemProperties.get("persist.charging.notify")))) { return; @@ -1074,12 +1072,20 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver titleRes = com.android.internal.R.string.usb_unsupported_audio_accessory_title; id = SystemMessage.NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED; } else if (mConnected) { - if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MTP) && mUsbDataUnlocked) { + if (!mUsbDataUnlocked) { + if (mSourcePower) { + titleRes = com.android.internal.R.string.usb_supplying_notification_title; + id = SystemMessage.NOTE_USB_SUPPLYING; + } else { + titleRes = com.android.internal.R.string.usb_charging_notification_title; + id = SystemMessage.NOTE_USB_CHARGING; + } + } else if (UsbManager.containsFunction(mCurrentFunctions, + UsbManager.USB_FUNCTION_MTP)) { titleRes = com.android.internal.R.string.usb_mtp_notification_title; id = SystemMessage.NOTE_USB_MTP; } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_PTP) && mUsbDataUnlocked) { + UsbManager.USB_FUNCTION_PTP)) { titleRes = com.android.internal.R.string.usb_ptp_notification_title; id = SystemMessage.NOTE_USB_PTP; } else if (UsbManager.containsFunction(mCurrentFunctions, @@ -1149,18 +1155,18 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } Notification.Builder builder = new Notification.Builder(mContext, channel) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) - .setWhen(0) - .setOngoing(true) - .setTicker(title) - .setDefaults(0) // please be quiet - .setColor(mContext.getColor( - com.android.internal.R.color - .system_notification_accent_color)) - .setContentTitle(title) - .setContentText(message) - .setContentIntent(pi) - .setVisibility(Notification.VISIBILITY_PUBLIC); + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setWhen(0) + .setOngoing(true) + .setTicker(title) + .setDefaults(0) // please be quiet + .setColor(mContext.getColor( + com.android.internal.R.color + .system_notification_accent_color)) + .setContentTitle(title) + .setContentText(message) + .setContentIntent(pi) + .setVisibility(Notification.VISIBILITY_PUBLIC); if (titleRes == com.android.internal.R.string @@ -1178,7 +1184,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected void updateAdbNotification(boolean force) { + private void updateAdbNotification(boolean force) { if (mNotificationManager == null) return; final int id = SystemMessage.NOTE_ADB_ACTIVE; final int titleRes = com.android.internal.R.string.adb_active_notification_title; @@ -1230,26 +1236,23 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected String getChargingFunctions() { + private String getDefaultFunctions() { + String func = SystemProperties.get(getPersistProp(true), + UsbManager.USB_FUNCTION_NONE); // if ADB is enabled, reset functions to ADB // else enable MTP as usual. - if (mAdbEnabled) { + if (UsbManager.containsFunction(func, UsbManager.USB_FUNCTION_ADB)) { return UsbManager.USB_FUNCTION_ADB; } else { return UsbManager.USB_FUNCTION_MTP; } } - public boolean isFunctionEnabled(String function) { - return UsbManager.containsFunction(mCurrentFunctions, function); - } - public void dump(IndentingPrintWriter pw) { pw.println("USB Device State:"); pw.println(" mCurrentFunctions: " + mCurrentFunctions); + pw.println(" mCurrentOemFunctions: " + mCurrentOemFunctions); pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); - pw.println(" mScreenUnlockedFunctions: " + mScreenUnlockedFunctions); - pw.println(" mScreenLocked: " + mScreenLocked); pw.println(" mConnected: " + mConnected); pw.println(" mConfigured: " + mConfigured); pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); @@ -1260,7 +1263,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver pw.println(" mUsbCharging: " + mUsbCharging); pw.println(" mHideUsbNotification: " + mHideUsbNotification); pw.println(" mAudioAccessoryConnected: " + mAudioAccessoryConnected); - pw.println(" mAdbEnabled: " + mAdbEnabled); try { pw.println(" Kernel state: " @@ -1271,675 +1273,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver pw.println("IOException: " + e); } } - - /** - * Evaluates USB function policies and applies the change accordingly. - */ - protected abstract void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked); - - } - - private final class UsbHandlerLegacy extends UsbHandler { - /** - * The non-persistent property which stores the current USB settings. - */ - private static final String USB_CONFIG_PROPERTY = "sys.usb.config"; - - /** - * The non-persistent property which stores the current USB actual state. - */ - private static final String USB_STATE_PROPERTY = "sys.usb.state"; - - private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap; - private String mCurrentOemFunctions; - - UsbHandlerLegacy(Looper looper, Context context) { - super(looper); - try { - readOemUsbOverrideConfig(context); - // Restore default functions. - mCurrentOemFunctions = SystemProperties.get(getPersistProp(false), - UsbManager.USB_FUNCTION_NONE); - if (isNormalBoot()) { - mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, - UsbManager.USB_FUNCTION_NONE); - mCurrentFunctionsApplied = mCurrentFunctions.equals( - SystemProperties.get(USB_STATE_PROPERTY)); - } else { - mCurrentFunctions = SystemProperties.get(getPersistProp(true), - UsbManager.USB_FUNCTION_NONE); - mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY, - UsbManager.USB_FUNCTION_NONE).equals( - SystemProperties.get(USB_STATE_PROPERTY)); - } - mCurrentUsbFunctionsReceived = true; - - String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); - updateState(state); - - // register observer to listen for settings changes - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); - - // Watch for USB configuration changes - mUEventObserver.startObserving(USB_STATE_MATCH); - mUEventObserver.startObserving(ACCESSORY_START_MATCH); - } catch (Exception e) { - Slog.e(TAG, "Error initializing UsbHandler", e); - } - } - - private void readOemUsbOverrideConfig(Context context) { - String[] configList = mContext.getResources().getStringArray( - com.android.internal.R.array.config_oemUsbModeOverride); - - if (configList != null) { - for (String config : configList) { - String[] items = config.split(":"); - if (items.length == 3 || items.length == 4) { - if (mOemModeMap == null) { - mOemModeMap = new HashMap<>(); - } - HashMap<String, Pair<String, String>> overrideMap = - mOemModeMap.get(items[0]); - if (overrideMap == null) { - overrideMap = new HashMap<>(); - mOemModeMap.put(items[0], overrideMap); - } - - // Favoring the first combination if duplicate exists - if (!overrideMap.containsKey(items[1])) { - if (items.length == 3) { - overrideMap.put(items[1], new Pair<>(items[2], "")); - } else { - overrideMap.put(items[1], new Pair<>(items[2], items[3])); - } - } - } - } - } - } - - private String applyOemOverrideFunction(String usbFunctions) { - if ((usbFunctions == null) || (mOemModeMap == null)) { - return usbFunctions; - } - - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); - Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode); - - Map<String, Pair<String, String>> overridesMap = - mOemModeMap.get(bootMode); - // Check to ensure that the oem is not overriding in the normal - // boot mode - if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT) - || bootMode.equals("unknown"))) { - Pair<String, String> overrideFunctions = - overridesMap.get(usbFunctions); - if (overrideFunctions != null) { - Slog.d(TAG, "OEM USB override: " + usbFunctions - + " ==> " + overrideFunctions.first - + " persist across reboot " - + overrideFunctions.second); - if (!overrideFunctions.second.equals("")) { - String newFunction; - if (mAdbEnabled) { - newFunction = UsbManager.addFunction(overrideFunctions.second, - UsbManager.USB_FUNCTION_ADB); - } else { - newFunction = overrideFunctions.second; - } - Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: " - + getPersistProp(false)); - SystemProperties.set(getPersistProp(false), - newFunction); - } - return overrideFunctions.first; - } else if (mAdbEnabled) { - String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE, - UsbManager.USB_FUNCTION_ADB); - SystemProperties.set(getPersistProp(false), - newFunction); - } else { - SystemProperties.set(getPersistProp(false), - UsbManager.USB_FUNCTION_NONE); - } - } - // return passed in functions as is. - return usbFunctions; - } - - private boolean waitForState(String state) { - // wait for the transition to complete. - // give up after 1 second. - String value = null; - for (int i = 0; i < 20; i++) { - // State transition is done when sys.usb.state is set to the new configuration - value = SystemProperties.get(USB_STATE_PROPERTY); - if (state.equals(value)) return true; - SystemClock.sleep(50); - } - Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value); - return false; - } - - private void setUsbConfig(String config) { - if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); - /** - * set the new configuration - * we always set it due to b/23631400, where adbd was getting killed - * and not restarted due to property timeouts on some devices - */ - SystemProperties.set(USB_CONFIG_PROPERTY, config); - } - - @Override - protected void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked) { - if (DEBUG) { - Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " - + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked); - } - - if (usbDataUnlocked != mUsbDataUnlocked) { - mUsbDataUnlocked = usbDataUnlocked; - updateUsbNotification(false); - forceRestart = true; - } - - /** - * Try to set the enabled functions. - */ - final String oldFunctions = mCurrentFunctions; - final boolean oldFunctionsApplied = mCurrentFunctionsApplied; - if (trySetEnabledFunctions(functions, forceRestart)) { - return; - } - - /** - * Didn't work. Try to revert changes. - * We always reapply the policy in case certain constraints changed such as - * user restrictions independently of any other new functions we were - * trying to activate. - */ - if (oldFunctionsApplied && !oldFunctions.equals(functions)) { - Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); - if (trySetEnabledFunctions(oldFunctions, false)) { - return; - } - } - - /** - * Still didn't work. Try to restore the default functions. - */ - Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); - if (trySetEnabledFunctions(null, false)) { - return; - } - - /** - * Now we're desperate. Ignore the default functions. - * Try to get ADB working if enabled. - */ - Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled)."); - if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) { - return; - } - - /** - * Ouch. - */ - Slog.e(TAG, "Unable to set any USB functions!"); - } - - private boolean isNormalBoot() { - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); - return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"); - } - - private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { - if (functions == null || applyAdbFunction(functions) - .equals(UsbManager.USB_FUNCTION_NONE)) { - functions = getChargingFunctions(); - } - functions = applyAdbFunction(functions); - - String oemFunctions = applyOemOverrideFunction(functions); - - if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) { - SystemProperties.set(getPersistProp(true), functions); - } - - if ((!functions.equals(oemFunctions) - && !mCurrentOemFunctions.equals(oemFunctions)) - || !mCurrentFunctions.equals(functions) - || !mCurrentFunctionsApplied - || forceRestart) { - Slog.i(TAG, "Setting USB config to " + functions); - mCurrentFunctions = functions; - mCurrentOemFunctions = oemFunctions; - mCurrentFunctionsApplied = false; - - /** - * Kick the USB stack to close existing connections. - */ - setUsbConfig(UsbManager.USB_FUNCTION_NONE); - - if (!waitForState(UsbManager.USB_FUNCTION_NONE)) { - Slog.e(TAG, "Failed to kick USB config"); - return false; - } - - /** - * Set the new USB configuration. - */ - setUsbConfig(oemFunctions); - - if (mBootCompleted - && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { - /** - * Start up dependent services. - */ - updateUsbStateBroadcastIfNeeded(true); - } - - if (!waitForState(oemFunctions)) { - Slog.e(TAG, "Failed to switch USB config to " + functions); - return false; - } - - mCurrentFunctionsApplied = true; - } - return true; - } - - private String getPersistProp(boolean functions) { - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); - String persistProp = USB_PERSISTENT_CONFIG_PROPERTY; - if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) { - if (functions) { - persistProp = "persist.sys.usb." + bootMode + ".func"; - } else { - persistProp = "persist.sys.usb." + bootMode + ".config"; - } - } - return persistProp; - } - } - - private final class UsbHandlerHal extends UsbHandler { - - /** - * Proxy object for the usb gadget hal daemon. - */ - @GuardedBy("mGadgetProxyLock") - private IUsbGadget mGadgetProxy; - - private final Object mGadgetProxyLock = new Object(); - - /** - * Cookie sent for usb gadget hal death notification. - */ - private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000; - - /** - * Keeps track of the latest setCurrentUsbFunctions request number. - */ - private int mCurrentRequest = 0; - - /** - * The maximum time for which the UsbDeviceManager would wait once - * setCurrentUsbFunctions is called. - */ - private static final int SET_FUNCTIONS_TIMEOUT_MS = 3000; - - /** - * Conseration leeway to make sure that the hal callback arrives before - * SET_FUNCTIONS_TIMEOUT_MS expires. If the callback does not arrive - * within SET_FUNCTIONS_TIMEOUT_MS, UsbDeviceManager retries enabling - * default functions. - */ - private static final int SET_FUNCTIONS_LEEWAY_MS = 500; - - /** - * While switching functions, a disconnect is excpect as the usb gadget - * us torn down and brought back up. Wait for SET_FUNCTIONS_TIMEOUT_MS + - * ENUMERATION_TIME_OUT_MS before switching back to default fumctions when - * switching functions. - */ - private static final int ENUMERATION_TIME_OUT_MS = 2000; - - /** - * Command to start native service. - */ - protected static final String CTL_START = "ctl.start"; - - /** - * Command to start native service. - */ - protected static final String CTL_STOP = "ctl.stop"; - - /** - * Adb natvie daemon - */ - protected static final String ADBD = "adbd"; - - - UsbHandlerHal(Looper looper) { - super(looper); - try { - ServiceNotification serviceNotification = new ServiceNotification(); - - boolean ret = IServiceManager.getService() - .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget", - "", serviceNotification); - if (!ret) { - Slog.e(TAG, "Failed to register usb gadget service start notification"); - return; - } - - synchronized (mGadgetProxyLock) { - mGadgetProxy = IUsbGadget.getService(true); - mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(), - USB_GADGET_HAL_DEATH_COOKIE); - mCurrentFunctions = UsbManager.USB_FUNCTION_NONE; - mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback()); - mCurrentUsbFunctionsRequested = true; - } - String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); - updateState(state); - - /** - * Register observer to listen for settings changes. - */ - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); - - /** - * Watch for USB configuration changes. - */ - mUEventObserver.startObserving(USB_STATE_MATCH); - mUEventObserver.startObserving(ACCESSORY_START_MATCH); - } catch (NoSuchElementException e) { - Slog.e(TAG, "Usb gadget hal not found", e); - } catch (RemoteException e) { - Slog.e(TAG, "Usb Gadget hal not responding", e); - } catch (Exception e) { - Slog.e(TAG, "Error initializing UsbHandler", e); - } - } - - - final class UsbGadgetDeathRecipient implements HwBinder.DeathRecipient { - @Override - public void serviceDied(long cookie) { - if (cookie == USB_GADGET_HAL_DEATH_COOKIE) { - Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie); - synchronized (mGadgetProxyLock) { - mGadgetProxy = null; - } - } - } - } - - final class ServiceNotification extends IServiceNotification.Stub { - @Override - public void onRegistration(String fqName, String name, boolean preexisting) { - Slog.i(TAG, "Usb gadget hal service started " + fqName + " " + name); - synchronized (mGadgetProxyLock) { - try { - mGadgetProxy = IUsbGadget.getService(); - mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(), - USB_GADGET_HAL_DEATH_COOKIE); - if (!mCurrentFunctionsApplied) { - setCurrentFunctions(mCurrentFunctions, mUsbDataUnlocked); - } - } catch (NoSuchElementException e) { - Slog.e(TAG, "Usb gadget hal not found", e); - } catch (RemoteException e) { - Slog.e(TAG, "Usb Gadget hal not responding", e); - } - } - } - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SET_CHARGING_FUNCTIONS: - setEnabledFunctions(null, false, mUsbDataUnlocked); - break; - case MSG_SET_FUNCTIONS_TIMEOUT: - Slog.e(TAG, "Set functions timed out! no reply from usb hal"); - if (msg.arg1 != 1) { - setEnabledFunctions(null, false, mUsbDataUnlocked); - } - break; - case MSG_GET_CURRENT_USB_FUNCTIONS: - Slog.e(TAG, "prcessing MSG_GET_CURRENT_USB_FUNCTIONS"); - mCurrentUsbFunctionsReceived = true; - - if (mCurrentUsbFunctionsRequested) { - Slog.e(TAG, "updating mCurrentFunctions"); - mCurrentFunctions = functionListToString((Long) msg.obj); - Slog.e(TAG, - "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1); - mCurrentFunctionsApplied = msg.arg1 == 1; - } - finishBoot(); - break; - case MSG_FUNCTION_SWITCH_TIMEOUT: - /** - * Dont force to default when the configuration is already set to default. - */ - if (msg.arg1 != 1) { - setEnabledFunctions(null, !mAdbEnabled, false); - } - break; - default: - super.handleMessage(msg); - } - } - - private class UsbGadgetCallback extends IUsbGadgetCallback.Stub { - int mRequest; - long mFunctions; - boolean mChargingFunctions; - - UsbGadgetCallback() { - } - - UsbGadgetCallback(int request, long functions, - boolean chargingFunctions) { - mRequest = request; - mFunctions = functions; - mChargingFunctions = chargingFunctions; - } - - @Override - public void setCurrentUsbFunctionsCb(long functions, - int status) { - /** - * Callback called for a previous setCurrenUsbFunction - */ - if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT) - || (mFunctions != functions)) { - return; - } - - removeMessages(MSG_SET_FUNCTIONS_TIMEOUT); - Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status); - if (status == Status.SUCCESS) { - mCurrentFunctionsApplied = true; - } else if (!mChargingFunctions) { - Slog.e(TAG, "Setting default fuctions"); - sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS); - } - } - - @Override - public void getCurrentUsbFunctionsCb(long functions, - int status) { - sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions, - status == Status.FUNCTIONS_APPLIED); - } - } - - private long stringToFunctionList(String config) { - long functionsMask = 0; - String[] functions = config.split(","); - for (int i = 0; i < functions.length; i++) { - switch (functions[i]) { - case "none": - functionsMask |= GadgetFunction.NONE; - break; - case "adb": - functionsMask |= GadgetFunction.ADB; - break; - case "mtp": - functionsMask |= GadgetFunction.MTP; - break; - case "ptp": - functionsMask |= GadgetFunction.PTP; - break; - case "midi": - functionsMask |= GadgetFunction.MIDI; - break; - case "accessory": - functionsMask |= GadgetFunction.ACCESSORY; - break; - case "rndis": - functionsMask |= GadgetFunction.RNDIS; - break; - } - } - return functionsMask; - } - - private String functionListToString(Long functionList) { - StringJoiner functions = new StringJoiner(","); - if (functionList == GadgetFunction.NONE) { - functions.add("none"); - return functions.toString(); - } - if ((functionList & GadgetFunction.ADB) != 0) { - functions.add("adb"); - } - if ((functionList & GadgetFunction.MTP) != 0) { - functions.add("mtp"); - } - if ((functionList & GadgetFunction.PTP) != 0) { - functions.add("ptp"); - } - if ((functionList & GadgetFunction.MIDI) != 0) { - functions.add("midi"); - } - if ((functionList & GadgetFunction.ACCESSORY) != 0) { - functions.add("accessory"); - } - if ((functionList & GadgetFunction.RNDIS) != 0) { - functions.add("rndis"); - } - /** - * Remove the trailing comma. - */ - return functions.toString(); - } - - - private void setUsbConfig(String config, boolean chargingFunctions) { - Long functions = stringToFunctionList(config); - if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest); - /** - * Cancel any ongoing requests, if present. - */ - removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT); - removeMessages(MSG_SET_FUNCTIONS_TIMEOUT); - removeMessages(MSG_SET_CHARGING_FUNCTIONS); - - synchronized (mGadgetProxyLock) { - if (mGadgetProxy == null) { - Slog.e(TAG, "setUsbConfig mGadgetProxy is null"); - return; - } - try { - if ((functions & GadgetFunction.ADB) != 0) { - /** - * Start adbd if ADB function is included in the configuration. - */ - SystemProperties.set(CTL_START, ADBD); - } else { - /** - * Stop adbd otherwise. - */ - SystemProperties.set(CTL_STOP, ADBD); - } - UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest, - functions, chargingFunctions); - mGadgetProxy.setCurrentUsbFunctions(functions, usbGadgetCallback, - SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS); - sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions, - SET_FUNCTIONS_TIMEOUT_MS); - sendMessageDelayed(MSG_FUNCTION_SWITCH_TIMEOUT, chargingFunctions, - SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS); - if (DEBUG) Slog.d(TAG, "timeout message queued"); - } catch (RemoteException e) { - Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e); - } - } - } - - @Override - protected void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked) { - if (DEBUG) { - Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " - + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked); - } - - if (usbDataUnlocked != mUsbDataUnlocked) { - mUsbDataUnlocked = usbDataUnlocked; - updateUsbNotification(false); - forceRestart = true; - } - - trySetEnabledFunctions(functions, forceRestart); - } - - private void trySetEnabledFunctions(String functions, boolean forceRestart) { - boolean chargingFunctions = false; - - if (functions == null || applyAdbFunction(functions) - .equals(UsbManager.USB_FUNCTION_NONE)) { - functions = getChargingFunctions(); - chargingFunctions = true; - } - functions = applyAdbFunction(functions); - - if (!mCurrentFunctions.equals(functions) - || !mCurrentFunctionsApplied - || forceRestart) { - Slog.i(TAG, "Setting USB config to " + functions); - mCurrentFunctions = functions; - mCurrentFunctionsApplied = false; - // set the flag to false as that would be stale value - mCurrentUsbFunctionsRequested = false; - - // Set the new USB configuration. - setUsbConfig(mCurrentFunctions, chargingFunctions); - - if (mBootCompleted - && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { - // Start up dependent services. - updateUsbStateBroadcastIfNeeded(true); - } - } - } } /* returns the currently attached USB accessory */ @@ -1947,11 +1280,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return mHandler.getCurrentAccessory(); } - /** - * opens the currently attached USB accessory. - * - * @param accessory accessory to be openened. - */ + /* opens the currently attached USB accessory */ public ParcelFileDescriptor openAccessory(UsbAccessory accessory, UsbUserSettingsManager settings) { UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); @@ -1968,41 +1297,113 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return nativeOpenAccessory(); } - /** - * Checks whether the function is present in the USB configuration. - * - * @param function function to be checked. - */ public boolean isFunctionEnabled(String function) { - return mHandler.isFunctionEnabled(function); + return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function); } - /** - * Adds function to the current USB configuration. - * - * @param functions name of the USB function, or null to restore the default function. - * @param usbDataUnlocked whether user data is accessible. - */ public void setCurrentFunctions(String functions, boolean usbDataUnlocked) { if (DEBUG) { - Slog.d(TAG, "setCurrentFunctions(" + functions + ", " - + usbDataUnlocked + ")"); + Slog.d(TAG, "setCurrentFunctions(" + functions + ", " + + usbDataUnlocked + ")"); } mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked); } - /** - * Sets the functions which are set when the screen is unlocked. - * - * @param functions Functions to set. - */ - public void setScreenUnlockedFunctions(String functions) { - if (DEBUG) { - Slog.d(TAG, "setScreenUnlockedFunctions(" + functions + ")"); + private void readOemUsbOverrideConfig() { + String[] configList = mContext.getResources().getStringArray( + com.android.internal.R.array.config_oemUsbModeOverride); + + if (configList != null) { + for (String config : configList) { + String[] items = config.split(":"); + if (items.length == 3 || items.length == 4) { + if (mOemModeMap == null) { + mOemModeMap = new HashMap<>(); + } + HashMap<String, Pair<String, String>> overrideMap + = mOemModeMap.get(items[0]); + if (overrideMap == null) { + overrideMap = new HashMap<>(); + mOemModeMap.put(items[0], overrideMap); + } + + // Favoring the first combination if duplicate exists + if (!overrideMap.containsKey(items[1])) { + if (items.length == 3) { + overrideMap.put(items[1], new Pair<>(items[2], "")); + } else { + overrideMap.put(items[1], new Pair<>(items[2], items[3])); + } + } + } + } } - mHandler.sendMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, functions); } + private String applyOemOverrideFunction(String usbFunctions) { + if ((usbFunctions == null) || (mOemModeMap == null)) { + return usbFunctions; + } + + String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode); + + Map<String, Pair<String, String>> overridesMap = + mOemModeMap.get(bootMode); + // Check to ensure that the oem is not overriding in the normal + // boot mode + if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT) || + bootMode.equals("unknown"))) { + Pair<String, String> overrideFunctions = + overridesMap.get(usbFunctions); + if (overrideFunctions != null) { + Slog.d(TAG, "OEM USB override: " + usbFunctions + + " ==> " + overrideFunctions.first + + " persist across reboot " + + overrideFunctions.second); + if (!overrideFunctions.second.equals("")) { + String newFunction; + if (mAdbEnabled) { + newFunction = UsbManager.addFunction(overrideFunctions.second, + UsbManager.USB_FUNCTION_ADB); + } else { + newFunction = overrideFunctions.second; + } + Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: " + + UsbDeviceManager.getPersistProp(false)); + SystemProperties.set(UsbDeviceManager.getPersistProp(false), + newFunction); + } + return overrideFunctions.first; + } else if (mAdbEnabled) { + String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE, + UsbManager.USB_FUNCTION_ADB); + SystemProperties.set(UsbDeviceManager.getPersistProp(false), + newFunction); + } else { + SystemProperties.set(UsbDeviceManager.getPersistProp(false), + UsbManager.USB_FUNCTION_NONE); + } + } + // return passed in functions as is. + return usbFunctions; + } + + public static String getPersistProp(boolean functions) { + String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + String persistProp = USB_PERSISTENT_CONFIG_PROPERTY; + if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) { + if (functions) { + persistProp = "persist.sys.usb." + bootMode + ".func"; + } else { + persistProp = "persist.sys.usb." + bootMode + ".config"; + } + } + + return persistProp; + } + + public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { if (mDebuggingManager != null) { mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index 039597cf473a..e4fcea77fa44 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -87,11 +87,6 @@ public class UsbService extends IUsbManager.Stub { public void onStopUser(int userHandle) { mUsbService.onStopUser(UserHandle.of(userHandle)); } - - @Override - public void onUnlockUser(int userHandle) { - mUsbService.onUnlockUser(userHandle); - } } private static final String TAG = "UsbService"; @@ -210,13 +205,6 @@ public class UsbService extends IUsbManager.Stub { } } - /** Called when a user is unlocked. */ - public void onUnlockUser(int user) { - if (mDeviceManager != null) { - mDeviceManager.onUnlockUser(user); - } - } - /* Returns a list of all currently attached USB devices (host mdoe) */ @Override public void getDeviceList(Bundle devices) { @@ -401,23 +389,6 @@ public class UsbService extends IUsbManager.Stub { } } - @Override - public void setScreenUnlockedFunctions(String function) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - - if (!isSupportedCurrentFunction(function)) { - Slog.w(TAG, "Caller of setScreenUnlockedFunctions() requested unsupported USB function:" - + function); - function = UsbManager.USB_FUNCTION_NONE; - } - - if (mDeviceManager != null) { - mDeviceManager.setScreenUnlockedFunctions(function); - } else { - throw new IllegalStateException("USB device mode not supported"); - } - } - private static boolean isSupportedCurrentFunction(String function) { if (function == null) return true; |