• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.net.ConnectivityManager.TETHERING_WIFI;
20 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
21 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
22 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
23 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
24 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
25 
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.net.ConnectivityManager;
31 import android.net.wifi.WifiManager;
32 import android.os.Handler;
33 import android.os.Looper;
34 import android.util.Log;
35 import android.widget.Switch;
36 
37 import androidx.annotation.VisibleForTesting;
38 
39 import com.android.settings.datausage.DataSaverBackend;
40 import com.android.settings.widget.SettingsMainSwitchBar;
41 import com.android.settingslib.core.lifecycle.LifecycleObserver;
42 import com.android.settingslib.core.lifecycle.events.OnStart;
43 import com.android.settingslib.core.lifecycle.events.OnStop;
44 import com.android.settingslib.widget.OnMainSwitchChangeListener;
45 
46 /**
47  * Controller for logic pertaining to switch Wi-Fi tethering.
48  */
49 public class WifiTetherSwitchBarController implements
50         LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener, OnMainSwitchChangeListener {
51 
52     private static final String TAG = "WifiTetherSBC";
53     private static final IntentFilter WIFI_INTENT_FILTER;
54 
55     private final Context mContext;
56     private final SettingsMainSwitchBar mSwitchBar;
57     private final Switch mSwitch;
58     private final ConnectivityManager mConnectivityManager;
59     private final WifiManager mWifiManager;
60 
61     @VisibleForTesting
62     DataSaverBackend mDataSaverBackend;
63     @VisibleForTesting
64     final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback =
65             new ConnectivityManager.OnStartTetheringCallback() {
66                 @Override
67                 public void onTetheringFailed() {
68                     super.onTetheringFailed();
69                     Log.e(TAG, "Failed to start Wi-Fi Tethering.");
70                     handleWifiApStateChanged(mWifiManager.getWifiApState());
71                 }
72             };
73 
74     static {
75         WIFI_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
76     }
77 
WifiTetherSwitchBarController(Context context, SettingsMainSwitchBar switchBar)78     WifiTetherSwitchBarController(Context context, SettingsMainSwitchBar switchBar) {
79         mContext = context;
80         mSwitchBar = switchBar;
81         mSwitch = mSwitchBar.getSwitch();
82         mDataSaverBackend = new DataSaverBackend(context);
83         mConnectivityManager =
84                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
85         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
86         mSwitchBar.setChecked(mWifiManager.getWifiApState() == WIFI_AP_STATE_ENABLED);
87         updateWifiSwitch();
88     }
89 
90     @Override
onStart()91     public void onStart() {
92         mDataSaverBackend.addListener(this);
93         mSwitchBar.addOnSwitchChangeListener(this);
94         mContext.registerReceiver(mReceiver, WIFI_INTENT_FILTER,
95                 Context.RECEIVER_EXPORTED_UNAUDITED);
96         handleWifiApStateChanged(mWifiManager.getWifiApState());
97     }
98 
99     @Override
onStop()100     public void onStop() {
101         mDataSaverBackend.remListener(this);
102         mContext.unregisterReceiver(mReceiver);
103     }
104 
105     @Override
onSwitchChanged(Switch switchView, boolean isChecked)106     public void onSwitchChanged(Switch switchView, boolean isChecked) {
107         // Filter out unnecessary callbacks when switch is disabled.
108         if (!switchView.isEnabled()) return;
109 
110         if (isChecked) {
111             startTether();
112         } else {
113             stopTether();
114         }
115     }
116 
stopTether()117     void stopTether() {
118         if (!isWifiApActivated()) return;
119 
120         mSwitchBar.setEnabled(false);
121         mConnectivityManager.stopTethering(TETHERING_WIFI);
122     }
123 
startTether()124     void startTether() {
125         if (isWifiApActivated()) return;
126 
127         mSwitchBar.setEnabled(false);
128         mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
129                 mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
130     }
131 
isWifiApActivated()132     private boolean isWifiApActivated() {
133         final int wifiApState = mWifiManager.getWifiApState();
134         if (wifiApState == WIFI_AP_STATE_ENABLED || wifiApState == WIFI_AP_STATE_ENABLING) {
135             return true;
136         }
137         return false;
138     }
139 
140     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
141         @Override
142         public void onReceive(Context context, Intent intent) {
143             String action = intent.getAction();
144             if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
145                 final int state = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_FAILED);
146                 handleWifiApStateChanged(state);
147             }
148         }
149     };
150 
151     @VisibleForTesting
handleWifiApStateChanged(int state)152     void handleWifiApStateChanged(int state) {
153         if (state == WIFI_AP_STATE_ENABLING || state == WIFI_AP_STATE_DISABLING) return;
154 
155         final boolean shouldBeChecked = (state == WIFI_AP_STATE_ENABLED);
156         if (mSwitch.isChecked() != shouldBeChecked) {
157             mSwitch.setChecked(shouldBeChecked);
158         }
159         updateWifiSwitch();
160     }
161 
updateWifiSwitch()162     private void updateWifiSwitch() {
163         mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
164     }
165 
166     @Override
onDataSaverChanged(boolean isDataSaving)167     public void onDataSaverChanged(boolean isDataSaving) {
168         updateWifiSwitch();
169     }
170 
171     @Override
onAllowlistStatusChanged(int uid, boolean isAllowlisted)172     public void onAllowlistStatusChanged(int uid, boolean isAllowlisted) {
173         // we don't care, since we just want to read the value
174     }
175 
176     @Override
onDenylistStatusChanged(int uid, boolean isDenylisted)177     public void onDenylistStatusChanged(int uid, boolean isDenylisted) {
178         // we don't care, since we just want to read the value
179     }
180 }
181