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 17package com.android.settings.wifi.tether; 18 19import static android.net.ConnectivityManager.TETHERING_WIFI; 20 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.net.ConnectivityManager; 26import android.net.wifi.WifiManager; 27import android.os.Handler; 28import android.os.Looper; 29import android.provider.Settings; 30import android.support.annotation.VisibleForTesting; 31 32import com.android.settings.datausage.DataSaverBackend; 33import com.android.settings.widget.SwitchWidgetController; 34import com.android.settingslib.core.lifecycle.LifecycleObserver; 35import com.android.settingslib.core.lifecycle.events.OnStart; 36import com.android.settingslib.core.lifecycle.events.OnStop; 37 38public class WifiTetherSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener, 39 LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener { 40 41 private static final IntentFilter WIFI_INTENT_FILTER; 42 43 private final Context mContext; 44 private final SwitchWidgetController mSwitchBar; 45 private final ConnectivityManager mConnectivityManager; 46 private final WifiManager mWifiManager; 47 48 @VisibleForTesting 49 final DataSaverBackend mDataSaverBackend; 50 @VisibleForTesting 51 final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback = 52 new ConnectivityManager.OnStartTetheringCallback() { 53 @Override 54 public void onTetheringFailed() { 55 super.onTetheringFailed(); 56 mSwitchBar.setChecked(false); 57 updateWifiSwitch(); 58 } 59 }; 60 61 static { 62 WIFI_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 63 WIFI_INTENT_FILTER.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 64 } 65 66 WifiTetherSwitchBarController(Context context, SwitchWidgetController switchBar) { 67 mContext = context; 68 mSwitchBar = switchBar; 69 mDataSaverBackend = new DataSaverBackend(context); 70 mConnectivityManager = 71 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 72 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 73 mSwitchBar.setChecked(mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED); 74 mSwitchBar.setListener(this); 75 updateWifiSwitch(); 76 } 77 78 @Override 79 public void onStart() { 80 mDataSaverBackend.addListener(this); 81 mSwitchBar.startListening(); 82 mContext.registerReceiver(mReceiver, WIFI_INTENT_FILTER); 83 } 84 85 @Override 86 public void onStop() { 87 mDataSaverBackend.remListener(this); 88 mSwitchBar.stopListening(); 89 mContext.unregisterReceiver(mReceiver); 90 } 91 92 @Override 93 public boolean onSwitchToggled(boolean isChecked) { 94 if (!isChecked) { 95 stopTether(); 96 } else if (!mWifiManager.isWifiApEnabled()) { 97 startTether(); 98 } 99 return true; 100 } 101 102 void stopTether() { 103 mSwitchBar.setEnabled(false); 104 mConnectivityManager.stopTethering(TETHERING_WIFI); 105 } 106 107 void startTether() { 108 mSwitchBar.setEnabled(false); 109 mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */, 110 mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); 111 } 112 113 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 114 @Override 115 public void onReceive(Context context, Intent intent) { 116 String action = intent.getAction(); 117 if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) { 118 final int state = intent.getIntExtra( 119 WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); 120 handleWifiApStateChanged(state); 121 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 122 updateWifiSwitch(); 123 } 124 } 125 }; 126 127 private void handleWifiApStateChanged(int state) { 128 switch (state) { 129 case WifiManager.WIFI_AP_STATE_ENABLING: 130 mSwitchBar.setEnabled(false); 131 break; 132 case WifiManager.WIFI_AP_STATE_ENABLED: 133 if (!mSwitchBar.isChecked()) { 134 mSwitchBar.setChecked(true); 135 } 136 updateWifiSwitch(); 137 break; 138 case WifiManager.WIFI_AP_STATE_DISABLING: 139 if (mSwitchBar.isChecked()) { 140 mSwitchBar.setChecked(false); 141 } 142 mSwitchBar.setEnabled(false); 143 break; 144 case WifiManager.WIFI_AP_STATE_DISABLED: 145 mSwitchBar.setChecked(false); 146 updateWifiSwitch(); 147 break; 148 default: 149 mSwitchBar.setChecked(false); 150 updateWifiSwitch(); 151 break; 152 } 153 } 154 155 private void updateWifiSwitch() { 156 boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(), 157 Settings.Global.AIRPLANE_MODE_ON, 0) != 0; 158 if (!isAirplaneMode) { 159 mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled()); 160 } else { 161 mSwitchBar.setEnabled(false); 162 } 163 } 164 165 @Override 166 public void onDataSaverChanged(boolean isDataSaving) { 167 updateWifiSwitch(); 168 } 169 170 @Override 171 public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) { 172 // we don't care, since we just want to read the value 173 } 174 175 @Override 176 public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) { 177 // we don't care, since we just want to read the value 178 } 179} 180