1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.connecteddevice.usb; 18 19 import static android.net.ConnectivityManager.TETHERING_USB; 20 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.graphics.drawable.Drawable; 24 import android.hardware.usb.UsbManager; 25 import android.net.ConnectivityManager; 26 import android.os.Bundle; 27 28 import androidx.annotation.VisibleForTesting; 29 import androidx.preference.PreferenceScreen; 30 31 import com.android.settings.R; 32 import com.android.settings.Utils; 33 import com.android.settings.widget.RadioButtonPickerFragment; 34 import com.android.settingslib.widget.CandidateInfo; 35 import com.android.settingslib.widget.FooterPreference; 36 import com.android.settingslib.widget.RadioButtonPreference; 37 38 import com.google.android.collect.Lists; 39 40 import java.util.List; 41 42 /** 43 * Provides options for selecting the default USB mode. 44 */ 45 public class UsbDefaultFragment extends RadioButtonPickerFragment { 46 @VisibleForTesting 47 UsbBackend mUsbBackend; 48 @VisibleForTesting 49 ConnectivityManager mConnectivityManager; 50 @VisibleForTesting 51 OnStartTetheringCallback mOnStartTetheringCallback = new OnStartTetheringCallback(); 52 @VisibleForTesting 53 long mPreviousFunctions; 54 @VisibleForTesting 55 long mCurrentFunctions; 56 @VisibleForTesting 57 boolean mIsStartTethering = false; 58 59 private UsbConnectionBroadcastReceiver mUsbReceiver; 60 61 @VisibleForTesting 62 UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener = 63 (connected, functions, powerRole, dataRole) -> { 64 if (mIsStartTethering) { 65 mCurrentFunctions = functions; 66 refresh(functions); 67 } 68 }; 69 70 @Override onAttach(Context context)71 public void onAttach(Context context) { 72 super.onAttach(context); 73 mUsbBackend = new UsbBackend(context); 74 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 75 mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener, 76 mUsbBackend); 77 getSettingsLifecycle().addObserver(mUsbReceiver); 78 mCurrentFunctions = mUsbBackend.getDefaultUsbFunctions(); 79 } 80 81 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)82 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 83 super.onCreatePreferences(savedInstanceState, rootKey); 84 getPreferenceScreen().addPreference(new FooterPreference.Builder(getActivity()).setTitle( 85 R.string.usb_default_info).build()); 86 } 87 88 @Override getMetricsCategory()89 public int getMetricsCategory() { 90 return SettingsEnums.USB_DEFAULT; 91 } 92 93 @Override getPreferenceScreenResId()94 protected int getPreferenceScreenResId() { 95 return R.xml.usb_default_fragment; 96 } 97 98 @Override getCandidates()99 protected List<? extends CandidateInfo> getCandidates() { 100 List<CandidateInfo> ret = Lists.newArrayList(); 101 for (final long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) { 102 final String title = getContext().getString( 103 UsbDetailsFunctionsController.FUNCTIONS_MAP.get(option)); 104 final String key = UsbBackend.usbFunctionsToString(option); 105 106 // Only show supported functions 107 if (mUsbBackend.areFunctionsSupported(option)) { 108 ret.add(new CandidateInfo(true /* enabled */) { 109 @Override 110 public CharSequence loadLabel() { 111 return title; 112 } 113 114 @Override 115 public Drawable loadIcon() { 116 return null; 117 } 118 119 @Override 120 public String getKey() { 121 return key; 122 } 123 }); 124 } 125 } 126 return ret; 127 } 128 129 @Override getDefaultKey()130 protected String getDefaultKey() { 131 return UsbBackend.usbFunctionsToString(mUsbBackend.getDefaultUsbFunctions()); 132 } 133 134 @Override setDefaultKey(String key)135 protected boolean setDefaultKey(String key) { 136 long functions = UsbBackend.usbFunctionsFromString(key); 137 mPreviousFunctions = mUsbBackend.getCurrentFunctions(); 138 if (!Utils.isMonkeyRunning()) { 139 if (functions == UsbManager.FUNCTION_RNDIS) { 140 // We need to have entitlement check for usb tethering, so use API in 141 // ConnectivityManager. 142 mIsStartTethering = true; 143 mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */, 144 mOnStartTetheringCallback); 145 } else { 146 mIsStartTethering = false; 147 mCurrentFunctions = functions; 148 mUsbBackend.setDefaultUsbFunctions(functions); 149 } 150 151 } 152 return true; 153 } 154 155 @Override onPause()156 public void onPause() { 157 super.onPause(); 158 mUsbBackend.setDefaultUsbFunctions(mCurrentFunctions); 159 } 160 161 @VisibleForTesting 162 final class OnStartTetheringCallback extends 163 ConnectivityManager.OnStartTetheringCallback { 164 165 @Override onTetheringStarted()166 public void onTetheringStarted() { 167 super.onTetheringStarted(); 168 // Set default usb functions again to make internal data persistent 169 mCurrentFunctions = UsbManager.FUNCTION_RNDIS; 170 mUsbBackend.setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS); 171 } 172 173 @Override onTetheringFailed()174 public void onTetheringFailed() { 175 super.onTetheringFailed(); 176 mUsbBackend.setDefaultUsbFunctions(mPreviousFunctions); 177 updateCandidates(); 178 } 179 } 180 refresh(long functions)181 private void refresh(long functions) { 182 final PreferenceScreen screen = getPreferenceScreen(); 183 for (long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) { 184 final RadioButtonPreference pref = 185 screen.findPreference(UsbBackend.usbFunctionsToString(option)); 186 if (pref != null) { 187 final boolean isSupported = mUsbBackend.areFunctionsSupported(option); 188 pref.setEnabled(isSupported); 189 if (isSupported) { 190 pref.setChecked(functions == option); 191 } 192 } 193 } 194 } 195 }