Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 609ece77 authored by Jerry Zhang's avatar Jerry Zhang Committed by Android (Google) Code Review
Browse files

Merge "Add UsbDefaultFragment and tests"

parents deb1e570 50247172
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -8096,6 +8096,10 @@
         for this device should be used for. These options are less commonly used.
         Choices are usb_use_tethering, usb_use_photo_transfers, usb_use_MIDI, and usb_use_power_only.-->
    <string name="usb_use_also">Also use USB for</string>
    <!-- The label that leads to the Default USB configuration window. -->
    <string name="usb_default_label">Default USB Configuration</string>
    <!-- Description at the footer of the default USB configuration window that describes how the setting works. -->
    <string name="usb_default_info">When another device is connected and your phone is unlocked, these settings will be applied. Only connect to trusted devices.</string>
    <!-- Settings item title for USB preference [CHAR LIMIT=35] -->
    <string name="usb_pref">USB</string>
+5 −6
Original line number Diff line number Diff line
@@ -235,12 +235,11 @@
            android:title="@string/tethering_hardware_offload"
            android:summary="@string/tethering_hardware_offload_summary" />

        <ListPreference
            android:key="select_usb_configuration"
            android:title="@string/select_usb_configuration_title"
            android:dialogTitle="@string/select_usb_configuration_dialog_title"
            android:entries="@array/usb_configuration_titles"
            android:entryValues="@array/usb_configuration_values" />
        <Preference
            android:key="default_usb_configuration"
            android:fragment="com.android.settings.connecteddevice.usb.UsbDefaultFragment"
            android:icon="@drawable/ic_usb"
            android:title="@string/usb_default_label"/>

        <SwitchPreference
            android:key="bluetooth_show_devices_without_names"
+21 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  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.
  -->
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="@string/usb_pref"
    android:key="usb_default_fragment">
</PreferenceScreen>
+50 −82
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.net.ConnectivityManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;

import com.android.settings.wrapper.UsbManagerWrapper;
import com.android.settings.wrapper.UserManagerWrapper;

public class UsbBackend {

    public static final int MODE_POWER_MASK  = 0x01;
@@ -47,31 +49,31 @@ public class UsbBackend {

    private UsbManager mUsbManager;
    @VisibleForTesting
    UsbManagerPassThrough mUsbManagerPassThrough;
    UsbManagerWrapper mUsbManagerWrapper;
    private UsbPort mPort;
    private UsbPortStatus mPortStatus;

    private Context mContext;

    public UsbBackend(Context context) {
        this(context, new UserRestrictionUtil(context), null);
        this(context, new UserManagerWrapper(UserManager.get(context)), null);
    }

    @VisibleForTesting
    public UsbBackend(Context context, UserRestrictionUtil userRestrictionUtil,
            UsbManagerPassThrough usbManagerPassThrough) {
    public UsbBackend(Context context, UserManagerWrapper userManagerWrapper,
            UsbManagerWrapper usbManagerWrapper) {
        mContext = context;
        mUsbManager = context.getSystemService(UsbManager.class);

        mUsbManagerPassThrough = usbManagerPassThrough;
        if (mUsbManagerPassThrough == null) {
            mUsbManagerPassThrough = new UsbManagerPassThrough(mUsbManager);
        mUsbManagerWrapper = usbManagerWrapper;
        if (mUsbManagerWrapper == null) {
            mUsbManagerWrapper = new UsbManagerWrapper(mUsbManager);
        }

        mFileTransferRestricted = userRestrictionUtil.isUsbFileTransferRestricted();
        mFileTransferRestrictedBySystem = userRestrictionUtil.isUsbFileTransferRestrictedBySystem();
        mTetheringRestricted = userRestrictionUtil.isUsbTetheringRestricted();
        mTetheringRestrictedBySystem = userRestrictionUtil.isUsbTetheringRestrictedBySystem();
        mFileTransferRestricted = userManagerWrapper.isUsbFileTransferRestricted();
        mFileTransferRestrictedBySystem = userManagerWrapper.isUsbFileTransferRestrictedBySystem();
        mTetheringRestricted = userManagerWrapper.isUsbTetheringRestricted();
        mTetheringRestrictedBySystem = userManagerWrapper.isUsbTetheringRestrictedBySystem();

        mMidiSupported = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
        ConnectivityManager cm =
@@ -106,37 +108,15 @@ public class UsbBackend {
    }

    public int getUsbDataMode() {
        long functions = mUsbManagerPassThrough.getCurrentFunctions();
        if (functions == UsbManager.FUNCTION_MTP) {
            return MODE_DATA_MTP;
        } else if (functions == UsbManager.FUNCTION_PTP) {
            return MODE_DATA_PTP;
        } else if (functions == UsbManager.FUNCTION_MIDI) {
            return MODE_DATA_MIDI;
        } else if (functions == UsbManager.FUNCTION_RNDIS) {
            return MODE_DATA_TETHER;
        }
        return MODE_DATA_NONE;
        return usbFunctionToMode(mUsbManagerWrapper.getCurrentFunctions());
    }

    private void setUsbFunction(int mode) {
        switch (mode) {
            case MODE_DATA_MTP:
                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_MTP);
                break;
            case MODE_DATA_PTP:
                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_PTP);
                break;
            case MODE_DATA_MIDI:
                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_MIDI);
                break;
            case MODE_DATA_TETHER:
                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
                break;
            default:
                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_NONE);
                break;
    public void setDefaultUsbMode(int mode) {
        mUsbManager.setScreenUnlockedFunctions(modeToUsbFunction(mode & MODE_DATA_MASK));
    }

    public int getDefaultUsbMode() {
        return usbFunctionToMode(mUsbManager.getScreenUnlockedFunctions());
    }

    public void setMode(int mode) {
@@ -153,11 +133,6 @@ public class UsbBackend {
        setUsbFunction(mode & MODE_DATA_MASK);
    }

    private int modeToPower(int mode) {
        return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
                    ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
    }

    public boolean isModeDisallowed(int mode) {
        if (mFileTransferRestricted && ((mode & MODE_DATA_MASK) == MODE_DATA_MTP
                || (mode & MODE_DATA_MASK) == MODE_DATA_PTP)) {
@@ -201,47 +176,40 @@ public class UsbBackend {
        return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
    }

    // Wrapper class to enable testing with UserManager APIs
    public static class UserRestrictionUtil {
        private UserManager mUserManager;

        public UserRestrictionUtil(Context context) {
            mUserManager = UserManager.get(context);
        }

        public boolean isUsbFileTransferRestricted() {
            return mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
        }

        public boolean isUsbTetheringRestricted() {
            return mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
    private static int usbFunctionToMode(long functions) {
        if (functions == UsbManager.FUNCTION_MTP) {
            return MODE_DATA_MTP;
        } else if (functions == UsbManager.FUNCTION_PTP) {
            return MODE_DATA_PTP;
        } else if (functions == UsbManager.FUNCTION_MIDI) {
            return MODE_DATA_MIDI;
        } else if (functions == UsbManager.FUNCTION_RNDIS) {
            return MODE_DATA_TETHER;
        }

        public boolean isUsbFileTransferRestrictedBySystem() {
            return mUserManager.hasBaseUserRestriction(
                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
        return MODE_DATA_NONE;
    }

        public boolean isUsbTetheringRestrictedBySystem() {
            return mUserManager.hasBaseUserRestriction(
                UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(UserHandle.myUserId()));
        }
    private static long modeToUsbFunction(int mode) {
        switch (mode) {
            case MODE_DATA_MTP:
                return UsbManager.FUNCTION_MTP;
            case MODE_DATA_PTP:
                return UsbManager.FUNCTION_PTP;
            case MODE_DATA_MIDI:
                return UsbManager.FUNCTION_MIDI;
            case MODE_DATA_TETHER:
                return UsbManager.FUNCTION_RNDIS;
            default:
                return UsbManager.FUNCTION_NONE;
        }

    // Temporary pass-through to allow roboelectric to use getCurrentFunctions()
    public static class UsbManagerPassThrough {
        private UsbManager mUsbManager;

        public UsbManagerPassThrough(UsbManager manager) {
            mUsbManager = manager;
    }

        public long getCurrentFunctions() {
            return mUsbManager.getCurrentFunctions();
    private static int modeToPower(int mode) {
        return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
                ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
    }

        public long usbFunctionsFromString(String str) {
            return UsbManager.usbFunctionsFromString(str);
        }
    private void setUsbFunction(int mode) {
        mUsbManager.setCurrentFunctions(modeToUsbFunction(mode));
    }
}
+159 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.connecteddevice.usb;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.hardware.usb.UsbManager;
import android.os.Bundle;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.FooterPreferenceMixin;

import com.google.android.collect.Lists;

import java.util.List;

/**
 * Provides options for selecting the default USB mode.
 */
public class UsbDefaultFragment extends RadioButtonPickerFragment {
    @VisibleForTesting
    UsbBackend mUsbBackend;

    private static final String[] FUNCTIONS_LIST = {
            UsbManager.USB_FUNCTION_NONE,
            UsbManager.USB_FUNCTION_MTP,
            UsbManager.USB_FUNCTION_RNDIS,
            UsbManager.USB_FUNCTION_MIDI,
            UsbManager.USB_FUNCTION_PTP
    };

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mUsbBackend = new UsbBackend(context);
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        super.onCreatePreferences(savedInstanceState, rootKey);
        FooterPreferenceMixin footer = new FooterPreferenceMixin(this, this.getLifecycle());
        FooterPreference pref = footer.createFooterPreference();
        pref.setTitle(R.string.usb_default_info);
    }

    @Override
    public int getMetricsCategory() {
        return MetricsProto.MetricsEvent.USB_DEFAULT;
    }

    @Override
    protected int getPreferenceScreenResId() {
        return R.xml.usb_default_fragment;
    }

    @Override
    protected List<? extends CandidateInfo> getCandidates() {
        List<CandidateInfo> ret = Lists.newArrayList();
        for (final String option : FUNCTIONS_LIST) {
            int newMode = 0;
            final String title;
            final Context context = getContext();
            if (option.equals(UsbManager.USB_FUNCTION_MTP)) {
                newMode = UsbBackend.MODE_DATA_MTP;
                title = context.getString(R.string.usb_use_file_transfers);
            } else if (option.equals(UsbManager.USB_FUNCTION_PTP)) {
                newMode = UsbBackend.MODE_DATA_PTP;
                title = context.getString(R.string.usb_use_photo_transfers);
            } else if (option.equals(UsbManager.USB_FUNCTION_MIDI)) {
                newMode = UsbBackend.MODE_DATA_MIDI;
                title = context.getString(R.string.usb_use_MIDI);
            } else if (option.equals(UsbManager.USB_FUNCTION_RNDIS)) {
                newMode = UsbBackend.MODE_DATA_TETHER;
                title = context.getString(R.string.usb_use_tethering);
            } else if (option.equals(UsbManager.USB_FUNCTION_NONE)) {
                newMode = UsbBackend.MODE_DATA_NONE;
                title = context.getString(R.string.usb_use_charging_only);
            } else {
                title = "";
            }

            // Only show supported and allowed options
            if (mUsbBackend.isModeSupported(newMode)
                    && !mUsbBackend.isModeDisallowedBySystem(newMode)
                    && !mUsbBackend.isModeDisallowed(newMode)) {
                ret.add(new CandidateInfo(true /* enabled */) {
                    @Override
                    public CharSequence loadLabel() {
                        return title;
                    }

                    @Override
                    public Drawable loadIcon() {
                        return null;
                    }

                    @Override
                    public String getKey() {
                        return option;
                    }
                });
            }
        }
        return ret;
    }

    @Override
    protected String getDefaultKey() {
        switch (mUsbBackend.getDefaultUsbMode()) {
            case UsbBackend.MODE_DATA_MTP:
                return UsbManager.USB_FUNCTION_MTP;
            case UsbBackend.MODE_DATA_PTP:
                return UsbManager.USB_FUNCTION_PTP;
            case UsbBackend.MODE_DATA_TETHER:
                return UsbManager.USB_FUNCTION_RNDIS;
            case UsbBackend.MODE_DATA_MIDI:
                return UsbManager.USB_FUNCTION_MIDI;
            default:
                return UsbManager.USB_FUNCTION_NONE;
        }
    }

    @Override
    protected boolean setDefaultKey(String key) {
        int thisMode = UsbBackend.MODE_DATA_NONE;
        if (key.equals(UsbManager.USB_FUNCTION_MTP)) {
            thisMode = UsbBackend.MODE_DATA_MTP;
        } else if (key.equals(UsbManager.USB_FUNCTION_PTP)) {
            thisMode = UsbBackend.MODE_DATA_PTP;
        } else if (key.equals(UsbManager.USB_FUNCTION_RNDIS)) {
            thisMode = UsbBackend.MODE_DATA_TETHER;
        } else if (key.equals(UsbManager.USB_FUNCTION_MIDI)) {
            thisMode = UsbBackend.MODE_DATA_MIDI;
        }
        if (!Utils.isMonkeyRunning()) {
            mUsbBackend.setDefaultUsbMode(thisMode);
        }
        return true;
    }
}
 No newline at end of file
Loading