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.TetheringManager.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.TetheringManager; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.HandlerExecutor; 29 import android.util.Log; 30 31 import androidx.annotation.VisibleForTesting; 32 import androidx.preference.PreferenceScreen; 33 34 import com.android.settings.R; 35 import com.android.settings.Utils; 36 import com.android.settings.widget.RadioButtonPickerFragment; 37 import com.android.settingslib.widget.CandidateInfo; 38 import com.android.settingslib.widget.FooterPreference; 39 import com.android.settingslib.widget.SelectorWithWidgetPreference; 40 41 import com.google.android.collect.Lists; 42 43 import java.util.List; 44 45 /** 46 * Provides options for selecting the default USB mode. 47 */ 48 public class UsbDefaultFragment extends RadioButtonPickerFragment { 49 50 private static final String TAG = "UsbDefaultFragment"; 51 52 @VisibleForTesting 53 UsbBackend mUsbBackend; 54 @VisibleForTesting 55 TetheringManager mTetheringManager; 56 @VisibleForTesting 57 OnStartTetheringCallback mOnStartTetheringCallback = new OnStartTetheringCallback(); 58 @VisibleForTesting 59 long mPreviousFunctions; 60 @VisibleForTesting 61 long mCurrentFunctions; 62 @VisibleForTesting 63 boolean mIsStartTethering = false; 64 @VisibleForTesting 65 Handler mHandler; 66 67 private UsbConnectionBroadcastReceiver mUsbReceiver; 68 private boolean mIsConnected = false; 69 70 @VisibleForTesting 71 UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener = 72 (connected, functions, powerRole, dataRole, isUsbConfigured) -> { 73 final long defaultFunctions = mUsbBackend.getDefaultUsbFunctions(); 74 Log.d(TAG, "UsbConnectionListener() connected : " + connected + ", functions : " 75 + functions + ", defaultFunctions : " + defaultFunctions 76 + ", mIsStartTethering : " + mIsStartTethering 77 + ", isUsbConfigured : " + isUsbConfigured); 78 if (connected && !mIsConnected && ((defaultFunctions == UsbManager.FUNCTION_RNDIS 79 || defaultFunctions == UsbManager.FUNCTION_NCM) 80 && defaultFunctions == functions) 81 && !mIsStartTethering) { 82 mCurrentFunctions = defaultFunctions; 83 startTethering(); 84 } 85 86 if ((mIsStartTethering || isUsbConfigured) && connected) { 87 mCurrentFunctions = functions; 88 refresh(functions); 89 mIsStartTethering = false; 90 } 91 mIsConnected = connected; 92 }; 93 94 @Override onAttach(Context context)95 public void onAttach(Context context) { 96 super.onAttach(context); 97 mUsbBackend = new UsbBackend(context); 98 mTetheringManager = context.getSystemService(TetheringManager.class); 99 mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener, 100 mUsbBackend); 101 mHandler = new Handler(context.getMainLooper()); 102 getSettingsLifecycle().addObserver(mUsbReceiver); 103 mCurrentFunctions = mUsbBackend.getDefaultUsbFunctions(); 104 } 105 106 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)107 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 108 super.onCreatePreferences(savedInstanceState, rootKey); 109 getPreferenceScreen().addPreference(new FooterPreference.Builder(getActivity()).setTitle( 110 R.string.usb_default_info).build()); 111 } 112 113 @Override getMetricsCategory()114 public int getMetricsCategory() { 115 return SettingsEnums.USB_DEFAULT; 116 } 117 118 @Override getPreferenceScreenResId()119 protected int getPreferenceScreenResId() { 120 return R.xml.usb_default_fragment; 121 } 122 123 @Override getCandidates()124 protected List<? extends CandidateInfo> getCandidates() { 125 List<CandidateInfo> ret = Lists.newArrayList(); 126 for (final long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) { 127 final String title = getContext().getString( 128 UsbDetailsFunctionsController.FUNCTIONS_MAP.get(option)); 129 final String key = UsbBackend.usbFunctionsToString(option); 130 131 // Only show supported functions 132 if (mUsbBackend.areFunctionsSupported(option)) { 133 ret.add(new CandidateInfo(true /* enabled */) { 134 @Override 135 public CharSequence loadLabel() { 136 return title; 137 } 138 139 @Override 140 public Drawable loadIcon() { 141 return null; 142 } 143 144 @Override 145 public String getKey() { 146 return key; 147 } 148 }); 149 } 150 } 151 return ret; 152 } 153 154 @Override getDefaultKey()155 protected String getDefaultKey() { 156 long defaultUsbFunctions = mUsbBackend.getDefaultUsbFunctions(); 157 // Because we didn't have an option for NCM, so make FUNCTION_NCM corresponding to 158 // FUNCTION_RNDIS for initializing the UI. 159 return UsbBackend.usbFunctionsToString(defaultUsbFunctions == UsbManager.FUNCTION_NCM 160 ? UsbManager.FUNCTION_RNDIS : defaultUsbFunctions); 161 } 162 163 @Override setDefaultKey(String key)164 protected boolean setDefaultKey(String key) { 165 long functions = UsbBackend.usbFunctionsFromString(key); 166 mPreviousFunctions = mUsbBackend.getCurrentFunctions(); 167 if (!Utils.isMonkeyRunning()) { 168 if (functions == UsbManager.FUNCTION_RNDIS || functions == UsbManager.FUNCTION_NCM) { 169 // We need to have entitlement check for usb tethering, so use API in 170 // TetheringManager. 171 mCurrentFunctions = functions; 172 startTethering(); 173 } else { 174 mIsStartTethering = false; 175 mCurrentFunctions = functions; 176 mUsbBackend.setDefaultUsbFunctions(functions); 177 } 178 179 } 180 return true; 181 } 182 startTethering()183 private void startTethering() { 184 Log.d(TAG, "startTethering()"); 185 mIsStartTethering = true; 186 mTetheringManager.startTethering(TETHERING_USB, new HandlerExecutor(mHandler), 187 mOnStartTetheringCallback); 188 } 189 190 @Override onPause()191 public void onPause() { 192 super.onPause(); 193 mCurrentFunctions = mUsbBackend.getCurrentFunctions(); 194 Log.d(TAG, "onPause() : current functions : " + mCurrentFunctions); 195 mUsbBackend.setDefaultUsbFunctions(mCurrentFunctions); 196 } 197 198 @VisibleForTesting 199 final class OnStartTetheringCallback implements 200 TetheringManager.StartTetheringCallback { 201 202 @Override onTetheringStarted()203 public void onTetheringStarted() { 204 // Set default usb functions again to make internal data persistent 205 mCurrentFunctions = mUsbBackend.getCurrentFunctions(); 206 Log.d(TAG, "onTetheringStarted() : mCurrentFunctions " + mCurrentFunctions); 207 mUsbBackend.setDefaultUsbFunctions(mCurrentFunctions); 208 } 209 210 @Override onTetheringFailed(int error)211 public void onTetheringFailed(int error) { 212 Log.w(TAG, "onTetheringFailed() error : " + error); 213 mUsbBackend.setDefaultUsbFunctions(mPreviousFunctions); 214 updateCandidates(); 215 } 216 } 217 refresh(long functions)218 private void refresh(long functions) { 219 final PreferenceScreen screen = getPreferenceScreen(); 220 for (long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) { 221 final SelectorWithWidgetPreference pref = 222 screen.findPreference(UsbBackend.usbFunctionsToString(option)); 223 if (pref != null) { 224 final boolean isSupported = mUsbBackend.areFunctionsSupported(option); 225 pref.setEnabled(isSupported); 226 if (isSupported) { 227 if (functions == UsbManager.FUNCTION_NCM) { 228 pref.setChecked(UsbManager.FUNCTION_RNDIS == option); 229 } else { 230 pref.setChecked(functions == option); 231 } 232 } 233 } 234 } 235 } 236 }