1/*
2 * Copyright (C) 2015 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 */
16package com.android.systemui.statusbar.policy;
17
18import android.content.Context;
19import android.content.Intent;
20import android.net.NetworkCapabilities;
21import android.net.wifi.WifiManager;
22import android.os.Handler;
23import android.os.Message;
24import android.os.Messenger;
25import android.util.Log;
26
27import com.android.internal.annotations.VisibleForTesting;
28import com.android.internal.util.AsyncChannel;
29import com.android.settingslib.wifi.WifiStatusTracker;
30import com.android.systemui.statusbar.policy.NetworkController.IconState;
31import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
32
33import com.android.systemui.R;
34
35import java.util.Objects;
36
37
38public class WifiSignalController extends
39        SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
40    private final WifiManager mWifiManager;
41    private final AsyncChannel mWifiChannel;
42    private final boolean mHasMobileData;
43    private final WifiStatusTracker mWifiTracker;
44
45    public WifiSignalController(Context context, boolean hasMobileData,
46            CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
47        super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
48                callbackHandler, networkController);
49        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
50        mWifiTracker = new WifiStatusTracker(mWifiManager);
51        mHasMobileData = hasMobileData;
52        Handler handler = new WifiHandler();
53        mWifiChannel = new AsyncChannel();
54        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
55        if (wifiMessenger != null) {
56            mWifiChannel.connect(context, handler, wifiMessenger);
57        }
58        // WiFi only has one state.
59        mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
60                "Wi-Fi Icons",
61                WifiIcons.WIFI_SIGNAL_STRENGTH,
62                WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
63                AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
64                WifiIcons.WIFI_NO_NETWORK,
65                WifiIcons.QS_WIFI_NO_NETWORK,
66                WifiIcons.WIFI_NO_NETWORK,
67                WifiIcons.QS_WIFI_NO_NETWORK,
68                AccessibilityContentDescriptions.WIFI_NO_CONNECTION
69                );
70    }
71
72    @Override
73    protected WifiState cleanState() {
74        return new WifiState();
75    }
76
77    @Override
78    public void notifyListeners(SignalCallback callback) {
79        // only show wifi in the cluster if connected or if wifi-only
80        boolean wifiVisible = mCurrentState.enabled
81                && (mCurrentState.connected || !mHasMobileData);
82        String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
83        boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
84        String contentDescription = getStringIfExists(getContentDescription());
85        if (mCurrentState.inetCondition == 0) {
86            contentDescription +=
87                    ("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
88        }
89
90        IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
91        IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
92                contentDescription);
93        callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
94                ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
95                wifiDesc);
96    }
97
98    /**
99     * Extract wifi state directly from broadcasts about changes in wifi state.
100     */
101    public void handleBroadcast(Intent intent) {
102        mWifiTracker.handleBroadcast(intent);
103        mCurrentState.enabled = mWifiTracker.enabled;
104        mCurrentState.connected = mWifiTracker.connected;
105        mCurrentState.ssid = mWifiTracker.ssid;
106        mCurrentState.rssi = mWifiTracker.rssi;
107        mCurrentState.level = mWifiTracker.level;
108        notifyListenersIfNecessary();
109    }
110
111    @VisibleForTesting
112    void setActivity(int wifiActivity) {
113        mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
114                || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
115        mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
116                || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
117        notifyListenersIfNecessary();
118    }
119
120    /**
121     * Handler to receive the data activity on wifi.
122     */
123    private class WifiHandler extends Handler {
124        @Override
125        public void handleMessage(Message msg) {
126            switch (msg.what) {
127                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
128                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
129                        mWifiChannel.sendMessage(Message.obtain(this,
130                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
131                    } else {
132                        Log.e(mTag, "Failed to connect to wifi");
133                    }
134                    break;
135                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
136                    setActivity(msg.arg1);
137                    break;
138                default:
139                    // Ignore
140                    break;
141            }
142        }
143    }
144
145    static class WifiState extends SignalController.State {
146        String ssid;
147
148        @Override
149        public void copyFrom(State s) {
150            super.copyFrom(s);
151            WifiState state = (WifiState) s;
152            ssid = state.ssid;
153        }
154
155        @Override
156        protected void toString(StringBuilder builder) {
157            super.toString(builder);
158            builder.append(',').append("ssid=").append(ssid);
159        }
160
161        @Override
162        public boolean equals(Object o) {
163            return super.equals(o)
164                    && Objects.equals(((WifiState) o).ssid, ssid);
165        }
166    }
167}
168