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