• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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;
18 
19 import static com.android.settings.network.SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG;
20 import static com.android.settings.network.SatelliteWarningDialogActivity.TYPE_IS_WIFI;
21 
22 import android.app.settings.SettingsEnums;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.ConnectivityManager;
28 import android.net.NetworkInfo;
29 import android.net.wifi.SupplicantState;
30 import android.net.wifi.WifiInfo;
31 import android.net.wifi.WifiManager;
32 import android.provider.Settings;
33 import android.util.Log;
34 import android.widget.Toast;
35 
36 import androidx.annotation.VisibleForTesting;
37 
38 import com.android.settings.R;
39 import com.android.settings.network.SatelliteRepository;
40 import com.android.settings.network.SatelliteWarningDialogActivity;
41 import com.android.settings.widget.SwitchWidgetController;
42 import com.android.settingslib.WirelessUtils;
43 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
44 
45 import java.util.concurrent.ExecutionException;
46 import java.util.concurrent.Executors;
47 import java.util.concurrent.TimeUnit;
48 import java.util.concurrent.TimeoutException;
49 import java.util.concurrent.atomic.AtomicBoolean;
50 
51 public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListener  {
52     private static final String TAG = WifiEnabler.class.getSimpleName();
53     private final SwitchWidgetController mSwitchWidget;
54     private final WifiManager mWifiManager;
55     private final ConnectivityManager mConnectivityManager;
56     private final MetricsFeatureProvider mMetricsFeatureProvider;
57 
58     private Context mContext;
59     private boolean mListeningToOnSwitchChange = false;
60     private AtomicBoolean mConnected = new AtomicBoolean(false);
61     private SatelliteRepository mSatelliteRepository;
62     @VisibleForTesting
63     AtomicBoolean mIsSatelliteOn = new AtomicBoolean(false);
64 
65     private boolean mStateMachineEvent;
66     private final IntentFilter mIntentFilter;
67     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
68         @Override
69         public void onReceive(Context context, Intent intent) {
70             String action = intent.getAction();
71             if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
72                 handleWifiStateChanged(mWifiManager.getWifiState());
73             } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
74                 if (!mConnected.get()) {
75                     handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
76                             intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
77                 }
78             } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
79                 NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
80                         WifiManager.EXTRA_NETWORK_INFO);
81                 mConnected.set(info.isConnected());
82                 handleStateChanged(info.getDetailedState());
83             }
84         }
85     };
86 
WifiEnabler(Context context, SwitchWidgetController switchWidget, MetricsFeatureProvider metricsFeatureProvider)87     public WifiEnabler(Context context, SwitchWidgetController switchWidget,
88         MetricsFeatureProvider metricsFeatureProvider) {
89         this(context, switchWidget, metricsFeatureProvider,
90             (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
91     }
92 
93     @VisibleForTesting
WifiEnabler(Context context, SwitchWidgetController switchWidget, MetricsFeatureProvider metricsFeatureProvider, ConnectivityManager connectivityManager)94     WifiEnabler(Context context, SwitchWidgetController switchWidget,
95             MetricsFeatureProvider metricsFeatureProvider,
96             ConnectivityManager connectivityManager) {
97         mContext = context;
98         mSwitchWidget = switchWidget;
99         mSwitchWidget.setListener(this);
100         mMetricsFeatureProvider = metricsFeatureProvider;
101         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
102         mConnectivityManager = connectivityManager;
103 
104         mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
105         // The order matters! We really should not depend on this. :(
106         mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
107         mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
108         mSatelliteRepository = new SatelliteRepository(context);
109         setupSwitchController();
110     }
111 
setupSwitchController()112     public void setupSwitchController() {
113         final int state = mWifiManager.getWifiState();
114         handleWifiStateChanged(state);
115         if (!mListeningToOnSwitchChange) {
116             mSwitchWidget.startListening();
117             mListeningToOnSwitchChange = true;
118         }
119         mSwitchWidget.setupView();
120     }
121 
teardownSwitchController()122     public void teardownSwitchController() {
123         if (mListeningToOnSwitchChange) {
124             mSwitchWidget.stopListening();
125             mListeningToOnSwitchChange = false;
126         }
127         mSwitchWidget.teardownView();
128     }
129 
resume(Context context)130     public void resume(Context context) {
131         mContext = context;
132         // Wi-Fi state is sticky, so just let the receiver update UI
133         mContext.registerReceiver(mReceiver, mIntentFilter,
134                 Context.RECEIVER_EXPORTED_UNAUDITED);
135         if (!mListeningToOnSwitchChange) {
136             mSwitchWidget.startListening();
137             mListeningToOnSwitchChange = true;
138         }
139         // Refresh satellite mode status.
140         try {
141             mIsSatelliteOn.set(
142                     mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
143                             .get(2000, TimeUnit.MILLISECONDS));
144         } catch (ExecutionException | TimeoutException | InterruptedException e) {
145             Log.e(TAG, "Error to get satellite status : " + e);
146         }
147     }
148 
pause()149     public void pause() {
150         mContext.unregisterReceiver(mReceiver);
151         if (mListeningToOnSwitchChange) {
152             mSwitchWidget.stopListening();
153             mListeningToOnSwitchChange = false;
154         }
155     }
156 
handleWifiStateChanged(int state)157     private void handleWifiStateChanged(int state) {
158         // Clear any previous state
159         mSwitchWidget.setDisabledByAdmin(null);
160 
161         switch (state) {
162             case WifiManager.WIFI_STATE_ENABLING:
163                 break;
164             case WifiManager.WIFI_STATE_ENABLED:
165                 setSwitchBarChecked(true);
166                 mSwitchWidget.setEnabled(true);
167                 break;
168             case WifiManager.WIFI_STATE_DISABLING:
169                 break;
170             case WifiManager.WIFI_STATE_DISABLED:
171                 setSwitchBarChecked(false);
172                 mSwitchWidget.setEnabled(true);
173                 break;
174             default:
175                 setSwitchBarChecked(false);
176                 mSwitchWidget.setEnabled(true);
177         }
178     }
179 
setSwitchBarChecked(boolean checked)180     private void setSwitchBarChecked(boolean checked) {
181         mStateMachineEvent = true;
182         mSwitchWidget.setChecked(checked);
183         mStateMachineEvent = false;
184     }
185 
handleStateChanged(@uppressWarnings"unused") NetworkInfo.DetailedState state)186     private void handleStateChanged(@SuppressWarnings("unused") NetworkInfo.DetailedState state) {
187         // After the refactoring from a CheckBoxPreference to a Switch, this method is useless since
188         // there is nowhere to display a summary.
189         // This code is kept in case a future change re-introduces an associated text.
190         /*
191         // WifiInfo is valid if and only if Wi-Fi is enabled.
192         // Here we use the state of the switch as an optimization.
193         if (state != null && mSwitch.isChecked()) {
194             WifiInfo info = mWifiManager.getConnectionInfo();
195             if (info != null) {
196                 //setSummary(Summary.get(mContext, info.getSSID(), state));
197             }
198         }
199         */
200     }
201 
202     @Override
onSwitchToggled(boolean isChecked)203     public boolean onSwitchToggled(boolean isChecked) {
204         //Do nothing if called as a result of a state machine event
205         if (mStateMachineEvent) {
206             return true;
207         }
208 
209         // Show dialog and do nothing under satellite mode.
210         if (mIsSatelliteOn.get()) {
211             mContext.startActivity(
212                     new Intent(mContext, SatelliteWarningDialogActivity.class)
213                             .putExtra(
214                                     EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG,
215                                     TYPE_IS_WIFI)
216             );
217             return false;
218         }
219 
220         // Show toast message if Wi-Fi is not allowed in airplane mode
221         if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
222             Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
223             // Reset switch to off. No infinite check/listener loop.
224             mSwitchWidget.setChecked(false);
225             return false;
226         }
227 
228         if (isChecked) {
229             mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_ON);
230         } else {
231             // Log if user was connected at the time of switching off.
232             mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_OFF,
233                     mConnected.get());
234         }
235         if (!mWifiManager.setWifiEnabled(isChecked)) {
236             // Error
237             mSwitchWidget.setEnabled(true);
238             Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
239         }
240         return true;
241     }
242 }
243