1 /* 2 * Copyright (C) 2019 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.car.settings.wifi; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.net.TetheringManager; 22 import android.net.wifi.SoftApConfiguration; 23 import android.os.Handler; 24 import android.os.HandlerExecutor; 25 import android.os.Looper; 26 27 import androidx.annotation.VisibleForTesting; 28 29 import com.android.car.settings.common.FragmentController; 30 import com.android.car.settings.common.PreferenceController; 31 import com.android.car.ui.preference.CarUiTwoActionSwitchPreference; 32 33 /** 34 * Controls the availability of wifi tethering preference based on whether tethering is supported 35 */ 36 public class WifiTetherPreferenceController extends 37 PreferenceController<CarUiTwoActionSwitchPreference> 38 implements WifiTetheringHandler.WifiTetheringAvailabilityListener { 39 40 private final TetheringManager mTetheringManager; 41 private final CarWifiManager mCarWifiManager; 42 private final Handler mHandler; 43 private final WifiTetheringHandler mWifiTetheringHandler; 44 private int mConnectedDevicesCount; 45 private volatile boolean mIsTetheringSupported; 46 private volatile boolean mReceivedTetheringEventCallback = false; 47 48 private final TetheringManager.TetheringEventCallback mTetheringCallback = 49 new TetheringManager.TetheringEventCallback() { 50 @Override 51 public void onTetheringSupported(boolean supported) { 52 mReceivedTetheringEventCallback = true; 53 if (mIsTetheringSupported != supported) { 54 mIsTetheringSupported = supported; 55 } 56 refreshUi(); 57 } 58 }; 59 WifiTetherPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)60 public WifiTetherPreferenceController(Context context, String preferenceKey, 61 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 62 this(context, preferenceKey, fragmentController, uxRestrictions, 63 new CarWifiManager(context, fragmentController.getSettingsLifecycle()), 64 context.getSystemService(TetheringManager.class)); 65 } 66 67 @VisibleForTesting WifiTetherPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, CarWifiManager carWifiManager, TetheringManager tetheringManager)68 WifiTetherPreferenceController(Context context, String preferenceKey, 69 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 70 CarWifiManager carWifiManager, TetheringManager tetheringManager) { 71 super(context, preferenceKey, fragmentController, uxRestrictions); 72 mCarWifiManager = carWifiManager; 73 mTetheringManager = tetheringManager; 74 mHandler = new Handler(Looper.getMainLooper()); 75 mWifiTetheringHandler = new WifiTetheringHandler(context, mCarWifiManager, 76 mTetheringManager, this, /* monitorRestarts= */ true); 77 } 78 79 @Override getPreferenceType()80 protected Class<CarUiTwoActionSwitchPreference> getPreferenceType() { 81 return CarUiTwoActionSwitchPreference.class; 82 } 83 84 @Override onCreateInternal()85 protected void onCreateInternal() { 86 getPreference().setOnSecondaryActionClickListener(isChecked -> { 87 mWifiTetheringHandler.updateWifiTetheringState(isChecked); 88 }); 89 setClickableWhileDisabled(getPreference(), /* clickable= */ true, p -> { 90 WifiUtil.runClickableWhileDisabled(getContext(), getFragmentController()); 91 }); 92 } 93 94 @Override onStartInternal()95 protected void onStartInternal() { 96 mTetheringManager.registerTetheringEventCallback( 97 new HandlerExecutor(mHandler), mTetheringCallback); 98 boolean tetheringEnabled = mWifiTetheringHandler.isWifiTetheringEnabled(); 99 updateSwitchPreference(tetheringEnabled); 100 mWifiTetheringHandler.onStartInternal(); 101 } 102 103 @Override onStopInternal()104 protected void onStopInternal() { 105 mTetheringManager.unregisterTetheringEventCallback(mTetheringCallback); 106 mWifiTetheringHandler.onStopInternal(); 107 } 108 109 @Override getDefaultAvailabilityStatus()110 protected int getDefaultAvailabilityStatus() { 111 if (!mReceivedTetheringEventCallback) { 112 return AVAILABLE_FOR_VIEWING; 113 } 114 if (!mIsTetheringSupported) { 115 return UNSUPPORTED_ON_DEVICE; 116 } 117 if (WifiUtil.isConfigWifiRestrictedByUm(getContext()) 118 || WifiUtil.isConfigWifiRestrictedByDpm(getContext())) { 119 return AVAILABLE_FOR_VIEWING; 120 } 121 return AVAILABLE; 122 } 123 124 @Override onWifiTetheringAvailable()125 public void onWifiTetheringAvailable() { 126 updateSwitchPreference(true); 127 } 128 129 @Override onWifiTetheringUnavailable()130 public void onWifiTetheringUnavailable() { 131 updateSwitchPreference(false); 132 } 133 134 @Override onConnectedClientsChanged(int clientCount)135 public void onConnectedClientsChanged(int clientCount) { 136 mConnectedDevicesCount = clientCount; 137 updateSummary(mWifiTetheringHandler.isWifiTetheringEnabled()); 138 } 139 140 @Override enablePreference()141 public void enablePreference() { 142 getPreference().setSecondaryActionEnabled(true); 143 } 144 145 @Override disablePreference()146 public void disablePreference() { 147 getPreference().setSecondaryActionEnabled(false); 148 } 149 updateSwitchPreference(boolean switchOn)150 private void updateSwitchPreference(boolean switchOn) { 151 updateSummary(switchOn); 152 getPreference().setSecondaryActionChecked(switchOn); 153 } 154 updateSummary(boolean hotspotEnabled)155 private void updateSummary(boolean hotspotEnabled) { 156 SoftApConfiguration config = mCarWifiManager.getSoftApConfig(); 157 if (config != null) { 158 String subtitle = WifiTetherUtil.getHotspotSubtitle(getContext(), 159 config, hotspotEnabled, mConnectedDevicesCount); 160 getPreference().setSummary(subtitle); 161 } 162 } 163 } 164