HotspotControllerImpl.java revision 2ffe412b0eb8f53043356fe50dc4ceb04d267fa2
1/*
2 * Copyright (C) 2014 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.systemui.statusbar.policy;
18
19import android.app.ActivityManager;
20import android.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.net.ConnectivityManager;
27import android.net.wifi.WifiManager;
28import android.os.SystemProperties;
29import android.os.UserHandle;
30import android.provider.Settings;
31import android.util.Log;
32
33import java.util.ArrayList;
34
35public class HotspotControllerImpl implements HotspotController {
36
37    private static final String TAG = "HotspotController";
38    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
39    // Keep these in sync with Settings TetherService.java
40    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
41    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
42    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
43    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
44    // Keep this in sync with Settings TetherSettings.java
45    public static final int WIFI_TETHERING = 0;
46
47    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
48    private final Receiver mReceiver = new Receiver();
49    private final Context mContext;
50    private final WifiManager mWifiManager;
51    private final ConnectivityManager mConnectivityManager;
52
53    public HotspotControllerImpl(Context context) {
54        mContext = context;
55        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
56        mConnectivityManager = (ConnectivityManager)
57                mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
58    }
59
60    public void addCallback(Callback callback) {
61        if (callback == null || mCallbacks.contains(callback)) return;
62        if (DEBUG) Log.d(TAG, "addCallback " + callback);
63        mCallbacks.add(callback);
64        mReceiver.setListening(!mCallbacks.isEmpty());
65    }
66
67    public void removeCallback(Callback callback) {
68        if (callback == null) return;
69        if (DEBUG) Log.d(TAG, "removeCallback " + callback);
70        mCallbacks.remove(callback);
71        mReceiver.setListening(!mCallbacks.isEmpty());
72    }
73
74    @Override
75    public boolean isHotspotEnabled() {
76        return mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
77    }
78
79    @Override
80    public boolean isHotspotSupported() {
81        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
82        return !isSecondaryUser && mConnectivityManager.isTetheringSupported();
83    }
84
85    @Override
86    public boolean isProvisioningNeeded() {
87        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
88        // TetherSettings#isProvisioningNeeded and
89        // ConnectivityManager#enforceTetherChangePermission
90        String[] provisionApp = mContext.getResources().getStringArray(
91                com.android.internal.R.array.config_mobile_hotspot_provision_app);
92        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
93                || provisionApp == null) {
94            return false;
95        }
96        return (provisionApp.length == 2);
97    }
98
99    @Override
100    public void setHotspotEnabled(boolean enabled) {
101        final ContentResolver cr = mContext.getContentResolver();
102        // Call provisioning app which is called when enabling Tethering from Settings
103        if (enabled) {
104            if (isProvisioningNeeded()) {
105                String tetherEnable = mContext.getResources().getString(
106                        com.android.internal.R.string.config_wifi_tether_enable);
107                Intent intent = new Intent();
108                intent.putExtra(EXTRA_ADD_TETHER_TYPE, WIFI_TETHERING);
109                intent.putExtra(EXTRA_SET_ALARM, true);
110                intent.putExtra(EXTRA_RUN_PROVISION, true);
111                intent.putExtra(EXTRA_ENABLE_WIFI_TETHER, true);
112                intent.setComponent(ComponentName.unflattenFromString(tetherEnable));
113                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
114            } else {
115                int wifiState = mWifiManager.getWifiState();
116                if ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
117                        (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
118                    mWifiManager.setWifiEnabled(false);
119                    Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
120                }
121                mWifiManager.setWifiApEnabled(null, true);
122            }
123        } else {
124            mWifiManager.setWifiApEnabled(null, false);
125            if (Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0) == 1) {
126                mWifiManager.setWifiEnabled(true);
127                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
128            }
129        }
130    }
131
132    private void fireCallback(boolean isEnabled) {
133        for (Callback callback : mCallbacks) {
134            callback.onHotspotChanged(isEnabled);
135        }
136    }
137
138    private final class Receiver extends BroadcastReceiver {
139        private boolean mRegistered;
140
141        public void setListening(boolean listening) {
142            if (listening && !mRegistered) {
143                if (DEBUG) Log.d(TAG, "Registering receiver");
144                final IntentFilter filter = new IntentFilter();
145                filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
146                mContext.registerReceiver(this, filter);
147                mRegistered = true;
148            } else if (!listening && mRegistered) {
149                if (DEBUG) Log.d(TAG, "Unregistering receiver");
150                mContext.unregisterReceiver(this);
151                mRegistered = false;
152            }
153        }
154
155        @Override
156        public void onReceive(Context context, Intent intent) {
157            if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
158            fireCallback(isHotspotEnabled());
159        }
160    }
161}
162