1 /* 2 * Copyright (C) 2017 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.wifi.tether; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.ConnectivityManager; 24 import android.net.wifi.WifiConfiguration; 25 import android.net.wifi.WifiManager; 26 import android.provider.Settings; 27 import android.text.BidiFormatter; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceScreen; 32 33 import com.android.settings.R; 34 import com.android.settings.Utils; 35 import com.android.settings.core.PreferenceControllerMixin; 36 import com.android.settingslib.core.AbstractPreferenceController; 37 import com.android.settingslib.core.lifecycle.Lifecycle; 38 import com.android.settingslib.core.lifecycle.LifecycleObserver; 39 import com.android.settingslib.core.lifecycle.events.OnStart; 40 import com.android.settingslib.core.lifecycle.events.OnStop; 41 42 public class WifiTetherPreferenceController extends AbstractPreferenceController 43 implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop { 44 45 private static final String WIFI_TETHER_SETTINGS = "wifi_tether"; 46 47 private final ConnectivityManager mConnectivityManager; 48 private final String[] mWifiRegexs; 49 private final WifiManager mWifiManager; 50 private final Lifecycle mLifecycle; 51 private int mSoftApState; 52 @VisibleForTesting 53 Preference mPreference; 54 @VisibleForTesting 55 WifiTetherSoftApManager mWifiTetherSoftApManager; 56 WifiTetherPreferenceController(Context context, Lifecycle lifecycle)57 public WifiTetherPreferenceController(Context context, Lifecycle lifecycle) { 58 this(context, lifecycle, true /* initSoftApManager */); 59 } 60 61 @VisibleForTesting WifiTetherPreferenceController(Context context, Lifecycle lifecycle, boolean initSoftApManager)62 WifiTetherPreferenceController(Context context, Lifecycle lifecycle, 63 boolean initSoftApManager) { 64 super(context); 65 mConnectivityManager = 66 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 67 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 68 mWifiRegexs = mConnectivityManager.getTetherableWifiRegexs(); 69 mLifecycle = lifecycle; 70 if (lifecycle != null) { 71 lifecycle.addObserver(this); 72 } 73 if (initSoftApManager) { 74 initWifiTetherSoftApManager(); 75 } 76 } 77 78 @Override isAvailable()79 public boolean isAvailable() { 80 return mWifiRegexs != null 81 && mWifiRegexs.length != 0 82 && !Utils.isMonkeyRunning(); 83 } 84 85 @Override displayPreference(PreferenceScreen screen)86 public void displayPreference(PreferenceScreen screen) { 87 super.displayPreference(screen); 88 mPreference = screen.findPreference(WIFI_TETHER_SETTINGS); 89 if (mPreference == null) { 90 // unavailable 91 return; 92 } 93 } 94 95 @Override getPreferenceKey()96 public String getPreferenceKey() { 97 return WIFI_TETHER_SETTINGS; 98 } 99 100 @Override onStart()101 public void onStart() { 102 if (mPreference != null) { 103 if (mWifiTetherSoftApManager != null) { 104 mWifiTetherSoftApManager.registerSoftApCallback(); 105 } 106 } 107 } 108 109 @Override onStop()110 public void onStop() { 111 if (mPreference != null) { 112 if (mWifiTetherSoftApManager != null) { 113 mWifiTetherSoftApManager.unRegisterSoftApCallback(); 114 } 115 } 116 } 117 118 @VisibleForTesting initWifiTetherSoftApManager()119 void initWifiTetherSoftApManager() { 120 // This manager only handles the number of connected devices, other parts are handled by 121 // normal BroadcastReceiver in this controller 122 mWifiTetherSoftApManager = new WifiTetherSoftApManager(mWifiManager, 123 new WifiTetherSoftApManager.WifiTetherSoftApCallback() { 124 @Override 125 public void onStateChanged(int state, int failureReason) { 126 mSoftApState = state; 127 handleWifiApStateChanged(state, failureReason); 128 } 129 130 @Override 131 public void onNumClientsChanged(int numClients) { 132 if (mPreference != null 133 && mSoftApState == WifiManager.WIFI_AP_STATE_ENABLED) { 134 // Only show the number of clients when state is on 135 mPreference.setSummary(mContext.getResources().getQuantityString( 136 R.plurals.wifi_tether_connected_summary, numClients, 137 numClients)); 138 } 139 } 140 }); 141 } 142 143 @VisibleForTesting handleWifiApStateChanged(int state, int reason)144 void handleWifiApStateChanged(int state, int reason) { 145 switch (state) { 146 case WifiManager.WIFI_AP_STATE_ENABLING: 147 mPreference.setSummary(R.string.wifi_tether_starting); 148 break; 149 case WifiManager.WIFI_AP_STATE_ENABLED: 150 WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration(); 151 updateConfigSummary(wifiConfig); 152 break; 153 case WifiManager.WIFI_AP_STATE_DISABLING: 154 mPreference.setSummary(R.string.wifi_tether_stopping); 155 break; 156 case WifiManager.WIFI_AP_STATE_DISABLED: 157 mPreference.setSummary(R.string.wifi_hotspot_off_subtext); 158 break; 159 default: 160 if (reason == WifiManager.SAP_START_FAILURE_NO_CHANNEL) { 161 mPreference.setSummary(R.string.wifi_sap_no_channel_error); 162 } else { 163 mPreference.setSummary(R.string.wifi_error); 164 } 165 } 166 } 167 updateConfigSummary(WifiConfiguration wifiConfig)168 private void updateConfigSummary(WifiConfiguration wifiConfig) { 169 final String s = mContext.getString( 170 com.android.internal.R.string.wifi_tether_configure_ssid_default); 171 172 mPreference.setSummary(mContext.getString(R.string.wifi_tether_enabled_subtext, 173 BidiFormatter.getInstance().unicodeWrap( 174 (wifiConfig == null) ? s : wifiConfig.SSID))); 175 } 176 } 177