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