1da68f596282e60bee832dff07cc96bf64bd15939Jason Monk/*
2da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Copyright (C) 2015 The Android Open Source Project
3da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
4da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * you may not use this file except in compliance with the License.
6da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * You may obtain a copy of the License at
7da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
8da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9da68f596282e60bee832dff07cc96bf64bd15939Jason Monk *
10da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * Unless required by applicable law or agreed to in writing, software
11da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * See the License for the specific language governing permissions and
14da68f596282e60bee832dff07cc96bf64bd15939Jason Monk * limitations under the License.
15da68f596282e60bee832dff07cc96bf64bd15939Jason Monk */
16da68f596282e60bee832dff07cc96bf64bd15939Jason Monkpackage com.android.systemui.statusbar.policy;
17da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
18da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.content.Context;
19da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.content.Intent;
20e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikhimport android.net.ConnectivityManager;
21da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.net.NetworkCapabilities;
22e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikhimport android.net.NetworkScoreManager;
23da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.net.wifi.WifiManager;
24da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.os.Handler;
252c403db659db615831d8bd02661f8769c7762241Geoffrey Pitschimport android.os.Looper;
26da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.os.Message;
27da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.os.Messenger;
28e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikhimport android.text.TextUtils;
29da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport android.util.Log;
30c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
31da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.internal.annotations.VisibleForTesting;
32da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport com.android.internal.util.AsyncChannel;
334cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monkimport com.android.settingslib.wifi.WifiStatusTracker;
349d10a3cf306d34f598216c6354c87c45a059b5b3Sundeep Ghumanimport com.android.systemui.R;
3507b75fe65dcb5b8add8246654c65f95f1191933eJason Monkimport com.android.systemui.statusbar.policy.NetworkController.IconState;
36e06b065f6e0d0f939b8519ccd3699b90aef818e9Jason Monkimport com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
37da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
38da68f596282e60bee832dff07cc96bf64bd15939Jason Monkimport java.util.Objects;
39da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
40da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
41da68f596282e60bee832dff07cc96bf64bd15939Jason Monkpublic class WifiSignalController extends
42da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
43da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final AsyncChannel mWifiChannel;
44da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private final boolean mHasMobileData;
454cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk    private final WifiStatusTracker mWifiTracker;
46da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
47da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public WifiSignalController(Context context, boolean hasMobileData,
48c7593b1e1a46bc78a1404b91eabdf5bd5c58b55dAmin Shaikh            CallbackHandler callbackHandler, NetworkControllerImpl networkController,
49c7593b1e1a46bc78a1404b91eabdf5bd5c58b55dAmin Shaikh            WifiManager wifiManager) {
50da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
5107b75fe65dcb5b8add8246654c65f95f1191933eJason Monk                callbackHandler, networkController);
52e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        NetworkScoreManager networkScoreManager =
53e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                context.getSystemService(NetworkScoreManager.class);
54e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        ConnectivityManager connectivityManager =
55e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                context.getSystemService(ConnectivityManager.class);
56e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
57e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                connectivityManager, this::handleStatusUpdated);
58e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        mWifiTracker.setListening(true);
59da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mHasMobileData = hasMobileData;
602c403db659db615831d8bd02661f8769c7762241Geoffrey Pitsch        Handler handler = new WifiHandler(Looper.getMainLooper());
61da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mWifiChannel = new AsyncChannel();
62e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        Messenger wifiMessenger = wifiManager.getWifiServiceMessenger();
63da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        if (wifiMessenger != null) {
64da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            mWifiChannel.connect(context, handler, wifiMessenger);
65da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
66da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // WiFi only has one state.
67da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
68da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                "Wi-Fi Icons",
69da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                WifiIcons.WIFI_SIGNAL_STRENGTH,
70da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
71da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
72da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                WifiIcons.WIFI_NO_NETWORK,
73da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                WifiIcons.QS_WIFI_NO_NETWORK,
747e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                WifiIcons.WIFI_NO_NETWORK,
75da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                WifiIcons.QS_WIFI_NO_NETWORK,
76da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                AccessibilityContentDescriptions.WIFI_NO_CONNECTION
77da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                );
78da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
79da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
80da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
81da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    protected WifiState cleanState() {
82da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        return new WifiState();
83da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
84da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
85da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @Override
86e06b065f6e0d0f939b8519ccd3699b90aef818e9Jason Monk    public void notifyListeners(SignalCallback callback) {
87da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        // only show wifi in the cluster if connected or if wifi-only
887e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk        boolean wifiVisible = mCurrentState.enabled
897e6c83c752e0825320e44bd87661b6422d3a3db6Jason Monk                && (mCurrentState.connected || !mHasMobileData);
90da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
91da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
92da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String contentDescription = getStringIfExists(getContentDescription());
9320aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds        if (mCurrentState.inetCondition == 0) {
9443ad7fef062e82260532e55879f1b07325b14e3bAmin Shaikh            contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
9520aef8a2914478a85aa679ec31bf739c7818eb3cJulia Reynolds        }
969d10a3cf306d34f598216c6354c87c45a059b5b3Sundeep Ghuman        IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
979d10a3cf306d34f598216c6354c87c45a059b5b3Sundeep Ghuman        IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
989d10a3cf306d34f598216c6354c87c45a059b5b3Sundeep Ghuman                contentDescription);
99e06b065f6e0d0f939b8519ccd3699b90aef818e9Jason Monk        callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
10007b75fe65dcb5b8add8246654c65f95f1191933eJason Monk                ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
101e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
102da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
103da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
104da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
105da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Extract wifi state directly from broadcasts about changes in wifi state.
106da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
107da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    public void handleBroadcast(Intent intent) {
1084cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mWifiTracker.handleBroadcast(intent);
1094cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mCurrentState.enabled = mWifiTracker.enabled;
1104cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mCurrentState.connected = mWifiTracker.connected;
1114cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mCurrentState.ssid = mWifiTracker.ssid;
1124cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mCurrentState.rssi = mWifiTracker.rssi;
1134cf95aef839701a43c9bde292f5e2d8ca3213509Jason Monk        mCurrentState.level = mWifiTracker.level;
114e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        mCurrentState.statusLabel = mWifiTracker.statusLabel;
115e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        notifyListenersIfNecessary();
116e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh    }
117e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh
118e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh    private void handleStatusUpdated() {
119e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        mCurrentState.statusLabel = mWifiTracker.statusLabel;
120da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
121da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
122da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
123da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    @VisibleForTesting
124da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    void setActivity(int wifiActivity) {
125da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
126da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
127da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
128da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
129da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        notifyListenersIfNecessary();
130da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
131da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
132da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    /**
133da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     * Handler to receive the data activity on wifi.
134da68f596282e60bee832dff07cc96bf64bd15939Jason Monk     */
135da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    private class WifiHandler extends Handler {
1362c403db659db615831d8bd02661f8769c7762241Geoffrey Pitsch        WifiHandler(Looper looper) {
1372c403db659db615831d8bd02661f8769c7762241Geoffrey Pitsch            super(looper);
1382c403db659db615831d8bd02661f8769c7762241Geoffrey Pitsch        }
1392c403db659db615831d8bd02661f8769c7762241Geoffrey Pitsch
140da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
141da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void handleMessage(Message msg) {
142da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            switch (msg.what) {
143da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
144da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
145da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        mWifiChannel.sendMessage(Message.obtain(this,
146da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
147da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    } else {
148da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                        Log.e(mTag, "Failed to connect to wifi");
149da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    }
150da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    break;
151da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
152da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    setActivity(msg.arg1);
153da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    break;
154da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                default:
155da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    // Ignore
156da68f596282e60bee832dff07cc96bf64bd15939Jason Monk                    break;
157da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            }
158da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
159da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
160da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
161da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    static class WifiState extends SignalController.State {
162da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        String ssid;
163110e5f6c169bed3d0312ed5003833bd12d562455Jason Monk        boolean isTransient;
164e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh        String statusLabel;
165da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
166da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
167da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public void copyFrom(State s) {
168da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.copyFrom(s);
169da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            WifiState state = (WifiState) s;
170da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            ssid = state.ssid;
171110e5f6c169bed3d0312ed5003833bd12d562455Jason Monk            isTransient = state.isTransient;
172e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            statusLabel = state.statusLabel;
173da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
174da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
175da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
176da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        protected void toString(StringBuilder builder) {
177da68f596282e60bee832dff07cc96bf64bd15939Jason Monk            super.toString(builder);
178e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            builder.append(",ssid=").append(ssid)
179e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                .append(",isTransient=").append(isTransient)
180e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                .append(",statusLabel=").append(statusLabel);
181da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
182da68f596282e60bee832dff07cc96bf64bd15939Jason Monk
183da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        @Override
184da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        public boolean equals(Object o) {
185e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            if (!super.equals(o)) {
186e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                return false;
187e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            }
188e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            WifiState other = (WifiState) o;
189e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh            return Objects.equals(other.ssid, ssid)
190e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                    && other.isTransient == isTransient
191e74dbdd364f0ed5ab1b208e9a5643bddfbafb76fAmin Shaikh                    && TextUtils.equals(other.statusLabel, statusLabel);
192da68f596282e60bee832dff07cc96bf64bd15939Jason Monk        }
193da68f596282e60bee832dff07cc96bf64bd15939Jason Monk    }
194da68f596282e60bee832dff07cc96bf64bd15939Jason Monk}
195