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