diff options
| author | 2015-01-07 10:55:58 -0500 | |
|---|---|---|
| committer | 2015-01-07 11:19:10 -0500 | |
| commit | da68f596282e60bee832dff07cc96bf64bd15939 (patch) | |
| tree | 9b635d2b797fd7e100aceda7dc9c6816679e9a3e | |
| parent | 3f0545a7dcba1fbd9951e06009df8054a278051d (diff) | |
SysUI: Separate SignalControllers into separate files
and remove the TODO that says to do it.
Change-Id: I54ac3f27f9246aea87d21f2a1da6608ae675aae6
7 files changed, 1122 insertions, 1004 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java new file mode 100644 index 000000000000..45b1e24a5d8e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.content.Intent; +import android.net.NetworkCapabilities; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.cdma.EriInfo; +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; + +import java.io.PrintWriter; +import java.util.List; +import java.util.Objects; + + +public class MobileSignalController extends SignalController< + MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> { + private final TelephonyManager mPhone; + private final String mNetworkNameDefault; + private final String mNetworkNameSeparator; + @VisibleForTesting + final PhoneStateListener mPhoneStateListener; + // Save entire info for logging, we only use the id. + private final SubscriptionInfo mSubscriptionInfo; + + // @VisibleForDemoMode + final SparseArray<MobileIconGroup> mNetworkToIconLookup; + + // Since some pieces of the phone state are interdependent we store it locally, + // this could potentially become part of MobileState for simplification/complication + // of code. + private IccCardConstants.State mSimState = IccCardConstants.State.READY; + private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + private int mDataState = TelephonyManager.DATA_DISCONNECTED; + private ServiceState mServiceState; + private SignalStrength mSignalStrength; + private MobileIconGroup mDefaultIcons; + private Config mConfig; + + // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't + // need listener lists anymore. + public MobileSignalController(Context context, Config config, boolean hasMobileData, + TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks, + List<SignalCluster> signalClusters, NetworkControllerImpl networkController, + SubscriptionInfo info) { + super("MobileSignalController(" + info.getSubscriptionId() + ")", context, + NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters, + networkController); + mNetworkToIconLookup = new SparseArray<>(); + mConfig = config; + mPhone = phone; + mSubscriptionInfo = info; + mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId()); + mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); + mNetworkNameDefault = getStringIfExists( + com.android.internal.R.string.lockscreen_carrier_default); + + mapIconSets(); + + mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault; + mLastState.enabled = mCurrentState.enabled = hasMobileData; + mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; + // Get initial data sim state. + updateDataSim(); + } + + public void setConfiguration(Config config) { + mConfig = config; + mapIconSets(); + updateTelephony(); + } + + /** + * Get (the mobile parts of) the carrier string. + * + * @param currentLabel can be used for concatenation, currently just empty + * @param connected whether the device has connection to the internet at all + * @param isMobileLabel whether to always return the network or just when data is connected + */ + public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) { + if (!mCurrentState.enabled) { + return ""; + } else { + String mobileLabel = ""; + // We want to show the carrier name if in service and either: + // - We are connected to mobile data, or + // - We are not connected to mobile data, as long as the *reason* packets are not + // being routed over that link is that we have better connectivity via wifi. + // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) + // is connected, we show nothing. + // Otherwise (nothing connected) we show "No internet connection". + if (mCurrentState.dataConnected) { + mobileLabel = mCurrentState.networkName; + } else if (connected || mCurrentState.isEmergency) { + if (mCurrentState.connected || mCurrentState.isEmergency) { + // The isEmergencyOnly test covers the case of a phone with no SIM + mobileLabel = mCurrentState.networkName; + } + } else { + mobileLabel = mContext.getString( + R.string.status_bar_settings_signal_meter_disconnected); + } + + if (currentLabel.length() != 0) { + currentLabel = currentLabel + mNetworkNameSeparator; + } + // Now for things that should only be shown when actually using mobile data. + if (isMobileLabel) { + return currentLabel + mobileLabel; + } else { + return currentLabel + + (mCurrentState.dataConnected ? mobileLabel : currentLabel); + } + } + } + + public int getDataContentDescription() { + return getIcons().mDataContentDescription; + } + + @VisibleForTesting + protected IccCardConstants.State getSimState() { + return mSimState; + } + + public void setAirplaneMode(boolean airplaneMode) { + mCurrentState.airplaneMode = airplaneMode; + notifyListenersIfNecessary(); + } + + public void setInetCondition(int inetCondition, int inetConditionForNetwork) { + // For mobile data, use general inet condition for phone signal indexing, + // and network specific for data indexing (I think this might be a bug, but + // keeping for now). + // TODO: Update with explanation of why. + mCurrentState.inetForNetwork = inetConditionForNetwork; + setInetCondition(inetCondition); + } + + /** + * Start listening for phone state changes. + */ + public void registerListener() { + mPhone.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_SERVICE_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS + | PhoneStateListener.LISTEN_CALL_STATE + | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_DATA_ACTIVITY); + } + + /** + * Stop listening for phone state changes. + */ + public void unregisterListener() { + mPhone.listen(mPhoneStateListener, 0); + } + + /** + * Produce a mapping of data network types to icon groups for simple and quick use in + * updateTelephony. + */ + private void mapIconSets() { + mNetworkToIconLookup.clear(); + + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G); + + if (!mConfig.showAtLeast3G) { + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyIcons.UNKNOWN); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X); + + mDefaultIcons = TelephonyIcons.G; + } else { + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, + TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, + TelephonyIcons.THREE_G); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, + TelephonyIcons.THREE_G); + mDefaultIcons = TelephonyIcons.THREE_G; + } + + MobileIconGroup hGroup = TelephonyIcons.THREE_G; + if (mConfig.hspaDataDistinguishable) { + hGroup = TelephonyIcons.H; + } + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup); + + if (mConfig.show4gForLte) { + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G); + } else { + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE); + } + } + + @Override + public void notifyListeners() { + MobileIconGroup icons = getIcons(); + + String contentDescription = getStringIfExists(getContentDescription()); + String dataContentDescription = getStringIfExists(icons.mDataContentDescription); + // Only send data sim callbacks to QS. + if (mCurrentState.dataSim) { + int qsTypeIcon = mCurrentState.dataConnected ? + icons.mQsDataType[mCurrentState.inetForNetwork] : 0; + int length = mSignalsChangedCallbacks.size(); + for (int i = 0; i < length; i++) { + mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled + && !mCurrentState.isEmergency && !mCurrentState.airplaneMode, + getQsCurrentIconId(), contentDescription, + qsTypeIcon, + mCurrentState.dataConnected && mCurrentState.activityIn, + mCurrentState.dataConnected && mCurrentState.activityOut, + dataContentDescription, + mCurrentState.isEmergency ? null : mCurrentState.networkName, + // Only wide if actually showing something. + icons.mIsWide && qsTypeIcon != 0); + } + } + boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0 + || mCurrentState.iconGroup == TelephonyIcons.ROAMING; + int typeIcon = showDataIcon ? icons.mDataType : 0; + int signalClustersLength = mSignalClusters.size(); + for (int i = 0; i < signalClustersLength; i++) { + mSignalClusters.get(i).setMobileDataIndicators( + mCurrentState.enabled && !mCurrentState.airplaneMode, + getCurrentIconId(), + typeIcon, + contentDescription, + dataContentDescription, + // Only wide if actually showing something. + icons.mIsWide && typeIcon != 0, + mSubscriptionInfo.getSubscriptionId()); + } + } + + @Override + protected MobileState cleanState() { + return new MobileState(); + } + + private boolean hasService() { + if (mServiceState != null) { + // Consider the device to be in service if either voice or data + // service is available. Some SIM cards are marketed as data-only + // and do not support voice service, and on these SIM cards, we + // want to show signal bars for data service as well as the "no + // service" or "emergency calls only" text that indicates that voice + // is not available. + switch (mServiceState.getVoiceRegState()) { + case ServiceState.STATE_POWER_OFF: + return false; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; + default: + return true; + } + } else { + return false; + } + } + + private boolean isCdma() { + return (mSignalStrength != null) && !mSignalStrength.isGsm(); + } + + public boolean isEmergencyOnly() { + return (mServiceState != null && mServiceState.isEmergencyOnly()); + } + + private boolean isRoaming() { + if (isCdma()) { + final int iconMode = mServiceState.getCdmaEriIconMode(); + return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF + && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL + || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); + } else { + return mServiceState != null && mServiceState.getRoaming(); + } + } + + public void handleBroadcast(Intent intent) { + String action = intent.getAction(); + if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { + updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), + intent.getStringExtra(TelephonyIntents.EXTRA_SPN), + intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), + intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); + notifyListenersIfNecessary(); + } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { + updateDataSim(); + } + } + + private void updateDataSim() { + int defaultDataSub = SubscriptionManager.getDefaultDataSubId(); + if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) { + mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId(); + } else { + // There doesn't seem to be a data sim selected, however if + // there isn't a MobileSignalController with dataSim set, then + // QS won't get any callbacks and will be blank. Instead + // lets just assume we are the data sim (which will basically + // show one at random) in QS until one is selected. The user + // should pick one soon after, so we shouldn't be in this state + // for long. + mCurrentState.dataSim = true; + } + notifyListenersIfNecessary(); + } + + /** + * Updates the network's name based on incoming spn and plmn. + */ + void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { + if (CHATTY) { + Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn + + " showPlmn=" + showPlmn + " plmn=" + plmn); + } + StringBuilder str = new StringBuilder(); + if (showPlmn && plmn != null) { + str.append(plmn); + } + if (showSpn && spn != null) { + if (str.length() != 0) { + str.append(mNetworkNameSeparator); + } + str.append(spn); + } + if (str.length() != 0) { + mCurrentState.networkName = str.toString(); + } else { + mCurrentState.networkName = mNetworkNameDefault; + } + } + + /** + * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, + * mDataState, and mSimState. It should be called any time one of these is updated. + * This will call listeners if necessary. + */ + private final void updateTelephony() { + if (DEBUG) { + Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService() + + " ss=" + mSignalStrength); + } + mCurrentState.connected = hasService() && mSignalStrength != null; + if (mCurrentState.connected) { + if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { + mCurrentState.level = mSignalStrength.getCdmaLevel(); + } else { + mCurrentState.level = mSignalStrength.getLevel(); + } + } + if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) { + mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType); + } else { + mCurrentState.iconGroup = mDefaultIcons; + } + mCurrentState.dataConnected = mCurrentState.connected + && mDataState == TelephonyManager.DATA_CONNECTED; + + if (isRoaming()) { + mCurrentState.iconGroup = TelephonyIcons.ROAMING; + } + if (isEmergencyOnly() != mCurrentState.isEmergency) { + mCurrentState.isEmergency = isEmergencyOnly(); + mNetworkController.recalculateEmergency(); + } + // Fill in the network name if we think we have it. + if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null + && mServiceState.getOperatorAlphaShort() != null) { + mCurrentState.networkName = mServiceState.getOperatorAlphaShort(); + } + notifyListenersIfNecessary(); + } + + @VisibleForTesting + void setActivity(int activity) { + mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT + || activity == TelephonyManager.DATA_ACTIVITY_IN; + mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT + || activity == TelephonyManager.DATA_ACTIVITY_OUT; + notifyListenersIfNecessary(); + } + + @Override + public void dump(PrintWriter pw) { + super.dump(pw); + pw.println(" mSubscription=" + mSubscriptionInfo + ","); + pw.println(" mServiceState=" + mServiceState + ","); + pw.println(" mSignalStrength=" + mSignalStrength + ","); + pw.println(" mDataState=" + mDataState + ","); + pw.println(" mDataNetType=" + mDataNetType + ","); + } + + class MobilePhoneStateListener extends PhoneStateListener { + public MobilePhoneStateListener(int subId) { + super(subId); + } + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + if (DEBUG) { + Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength + + ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); + } + mSignalStrength = signalStrength; + updateTelephony(); + } + + @Override + public void onServiceStateChanged(ServiceState state) { + if (DEBUG) { + Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState() + + " dataState=" + state.getDataRegState()); + } + mServiceState = state; + updateTelephony(); + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + if (DEBUG) { + Log.d(mTag, "onDataConnectionStateChanged: state=" + state + + " type=" + networkType); + } + mDataState = state; + mDataNetType = networkType; + updateTelephony(); + } + + @Override + public void onDataActivity(int direction) { + if (DEBUG) { + Log.d(mTag, "onDataActivity: direction=" + direction); + } + setActivity(direction); + } + }; + + static class MobileIconGroup extends SignalController.IconGroup { + final int mDataContentDescription; // mContentDescriptionDataType + final int mDataType; + final boolean mIsWide; + final int[] mQsDataType; + + public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, + int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, + int discContentDesc, int dataContentDesc, int dataType, boolean isWide, + int[] qsDataType) { + super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, + qsDiscState, discContentDesc); + mDataContentDescription = dataContentDesc; + mDataType = dataType; + mIsWide = isWide; + mQsDataType = qsDataType; + } + } + + static class MobileState extends SignalController.State { + String networkName; + boolean dataSim; + boolean dataConnected; + boolean isEmergency; + boolean airplaneMode; + int inetForNetwork; + + @Override + public void copyFrom(State s) { + super.copyFrom(s); + MobileState state = (MobileState) s; + dataSim = state.dataSim; + networkName = state.networkName; + dataConnected = state.dataConnected; + inetForNetwork = state.inetForNetwork; + isEmergency = state.isEmergency; + airplaneMode = state.airplaneMode; + } + + @Override + protected void toString(StringBuilder builder) { + super.toString(builder); + builder.append(','); + builder.append("dataSim=").append(dataSim).append(','); + builder.append("networkName=").append(networkName).append(','); + builder.append("dataConnected=").append(dataConnected).append(','); + builder.append("inetForNetwork=").append(inetForNetwork).append(','); + builder.append("isEmergency=").append(isEmergency).append(','); + builder.append("airplaneMode=").append(airplaneMode); + } + + @Override + public boolean equals(Object o) { + return super.equals(o) + && Objects.equals(((MobileState) o).networkName, networkName) + && ((MobileState) o).dataSim == dataSim + && ((MobileState) o).dataConnected == dataConnected + && ((MobileState) o).isEmergency == isEmergency + && ((MobileState) o).airplaneMode == airplaneMode + && ((MobileState) o).inetForNetwork == inetForNetwork; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 3642eae44944..5fce0cf5a7d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -18,9 +18,8 @@ package com.android.systemui.statusbar.policy; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -28,34 +27,20 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.text.format.DateFormat; import android.util.Log; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.cdma.EriInfo; -import com.android.internal.util.AsyncChannel; import com.android.systemui.DemoMode; import com.android.systemui.R; @@ -69,7 +54,6 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; /** Platform implementation of the network controller. **/ public class NetworkControllerImpl extends BroadcastReceiver @@ -79,12 +63,6 @@ public class NetworkControllerImpl extends BroadcastReceiver static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); // additional diagnostics, but not logspew static final boolean CHATTY = Log.isLoggable(TAG + ".Chat", Log.DEBUG); - // Save the previous SignalController.States of all SignalControllers for dumps. - static final boolean RECORD_HISTORY = true; - // If RECORD_HISTORY how many to save, must be a power of 2. - static final int HISTORY_SIZE = 16; - - private static final int INET_CONDITION_THRESHOLD = 50; private final Context mContext; private final TelephonyManager mPhone; @@ -821,969 +799,6 @@ public class NetworkControllerImpl extends BroadcastReceiver }; }; - // TODO: Move to its own file. - static class WifiSignalController extends - SignalController<WifiSignalController.WifiState, SignalController.IconGroup> { - private final WifiManager mWifiManager; - private final AsyncChannel mWifiChannel; - private final boolean mHasMobileData; - - public WifiSignalController(Context context, boolean hasMobileData, - List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { - super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, - signalCallbacks, signalClusters, networkController); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - mHasMobileData = hasMobileData; - Handler handler = new WifiHandler(); - mWifiChannel = new AsyncChannel(); - Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); - if (wifiMessenger != null) { - mWifiChannel.connect(context, handler, wifiMessenger); - } - // WiFi only has one state. - mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup( - "Wi-Fi Icons", - WifiIcons.WIFI_SIGNAL_STRENGTH, - WifiIcons.QS_WIFI_SIGNAL_STRENGTH, - AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH, - WifiIcons.WIFI_NO_NETWORK, - WifiIcons.QS_WIFI_NO_NETWORK, - WifiIcons.WIFI_NO_NETWORK, - WifiIcons.QS_WIFI_NO_NETWORK, - AccessibilityContentDescriptions.WIFI_NO_CONNECTION - ); - } - - @Override - protected WifiState cleanState() { - return new WifiState(); - } - - @Override - public void notifyListeners() { - // only show wifi in the cluster if connected or if wifi-only - boolean wifiVisible = mCurrentState.enabled - && (mCurrentState.connected || !mHasMobileData); - String wifiDesc = wifiVisible ? mCurrentState.ssid : null; - boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; - String contentDescription = getStringIfExists(getContentDescription()); - int length = mSignalsChangedCallbacks.size(); - for (int i = 0; i < length; i++) { - mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled, - mCurrentState.connected, getQsCurrentIconId(), - ssidPresent && mCurrentState.activityIn, - ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc); - } - - int signalClustersLength = mSignalClusters.size(); - for (int i = 0; i < signalClustersLength; i++) { - mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(), - contentDescription); - } - } - - /** - * Extract wifi state directly from broadcasts about changes in wifi state. - */ - public void handleBroadcast(Intent intent) { - String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - mCurrentState.connected = networkInfo != null && networkInfo.isConnected(); - // If Connected grab the signal strength and ssid. - if (mCurrentState.connected) { - // try getting it out of the intent first - WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null - ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) - : mWifiManager.getConnectionInfo(); - if (info != null) { - mCurrentState.ssid = getSsid(info); - } else { - mCurrentState.ssid = null; - } - } else if (!mCurrentState.connected) { - mCurrentState.ssid = null; - } - } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - // Default to -200 as its below WifiManager.MIN_RSSI. - mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); - mCurrentState.level = WifiManager.calculateSignalLevel( - mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT); - } - - notifyListenersIfNecessary(); - } - - private String getSsid(WifiInfo info) { - String ssid = info.getSSID(); - if (ssid != null) { - return ssid; - } - // OK, it's not in the connectionInfo; we have to go hunting for it - List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); - int length = networks.size(); - for (int i = 0; i < length; i++) { - if (networks.get(i).networkId == info.getNetworkId()) { - return networks.get(i).SSID; - } - } - return null; - } - - @VisibleForTesting - void setActivity(int wifiActivity) { - mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT - || wifiActivity == WifiManager.DATA_ACTIVITY_IN; - mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT - || wifiActivity == WifiManager.DATA_ACTIVITY_OUT; - notifyListenersIfNecessary(); - } - - /** - * Handler to receive the data activity on wifi. - */ - class WifiHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - mWifiChannel.sendMessage(Message.obtain(this, - AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); - } else { - Log.e(mTag, "Failed to connect to wifi"); - } - break; - case WifiManager.DATA_ACTIVITY_NOTIFICATION: - setActivity(msg.arg1); - break; - default: - // Ignore - break; - } - } - } - - static class WifiState extends SignalController.State { - String ssid; - - @Override - public void copyFrom(State s) { - super.copyFrom(s); - WifiState state = (WifiState) s; - ssid = state.ssid; - } - - @Override - protected void toString(StringBuilder builder) { - super.toString(builder); - builder.append(',').append("ssid=").append(ssid); - } - - @Override - public boolean equals(Object o) { - return super.equals(o) - && Objects.equals(((WifiState) o).ssid, ssid); - } - } - } - - // TODO: Move to its own file. - public static class MobileSignalController extends SignalController< - MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> { - private final TelephonyManager mPhone; - private final String mNetworkNameDefault; - private final String mNetworkNameSeparator; - @VisibleForTesting - final PhoneStateListener mPhoneStateListener; - // Save entire info for logging, we only use the id. - private final SubscriptionInfo mSubscriptionInfo; - - // @VisibleForDemoMode - final SparseArray<MobileIconGroup> mNetworkToIconLookup; - - // Since some pieces of the phone state are interdependent we store it locally, - // this could potentially become part of MobileState for simplification/complication - // of code. - private IccCardConstants.State mSimState = IccCardConstants.State.READY; - private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - private int mDataState = TelephonyManager.DATA_DISCONNECTED; - private ServiceState mServiceState; - private SignalStrength mSignalStrength; - private MobileIconGroup mDefaultIcons; - private Config mConfig; - - // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't - // need listener lists anymore. - public MobileSignalController(Context context, Config config, boolean hasMobileData, - TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController, - SubscriptionInfo info) { - super("MobileSignalController(" + info.getSubscriptionId() + ")", context, - NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters, - networkController); - mNetworkToIconLookup = new SparseArray<>(); - mConfig = config; - mPhone = phone; - mSubscriptionInfo = info; - mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId()); - mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); - mNetworkNameDefault = getStringIfExists( - com.android.internal.R.string.lockscreen_carrier_default); - - mapIconSets(); - - mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault; - mLastState.enabled = mCurrentState.enabled = hasMobileData; - mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; - // Get initial data sim state. - updateDataSim(); - } - - public void setConfiguration(Config config) { - mConfig = config; - mapIconSets(); - updateTelephony(); - } - - /** - * Get (the mobile parts of) the carrier string. - * - * @param currentLabel can be used for concatenation, currently just empty - * @param connected whether the device has connection to the internet at all - * @param isMobileLabel whether to always return the network or just when data is connected - */ - public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) { - if (!mCurrentState.enabled) { - return ""; - } else { - String mobileLabel = ""; - // We want to show the carrier name if in service and either: - // - We are connected to mobile data, or - // - We are not connected to mobile data, as long as the *reason* packets are not - // being routed over that link is that we have better connectivity via wifi. - // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) - // is connected, we show nothing. - // Otherwise (nothing connected) we show "No internet connection". - if (mCurrentState.dataConnected) { - mobileLabel = mCurrentState.networkName; - } else if (connected || mCurrentState.isEmergency) { - if (mCurrentState.connected || mCurrentState.isEmergency) { - // The isEmergencyOnly test covers the case of a phone with no SIM - mobileLabel = mCurrentState.networkName; - } - } else { - mobileLabel = mContext.getString( - R.string.status_bar_settings_signal_meter_disconnected); - } - - if (currentLabel.length() != 0) { - currentLabel = currentLabel + mNetworkNameSeparator; - } - // Now for things that should only be shown when actually using mobile data. - if (isMobileLabel) { - return currentLabel + mobileLabel; - } else { - return currentLabel - + (mCurrentState.dataConnected ? mobileLabel : currentLabel); - } - } - } - - public int getDataContentDescription() { - return getIcons().mDataContentDescription; - } - - @VisibleForTesting - protected IccCardConstants.State getSimState() { - return mSimState; - } - - public void setAirplaneMode(boolean airplaneMode) { - mCurrentState.airplaneMode = airplaneMode; - notifyListenersIfNecessary(); - } - - public void setInetCondition(int inetCondition, int inetConditionForNetwork) { - // For mobile data, use general inet condition for phone signal indexing, - // and network specific for data indexing (I think this might be a bug, but - // keeping for now). - // TODO: Update with explanation of why. - mCurrentState.inetForNetwork = inetConditionForNetwork; - setInetCondition(inetCondition); - } - - /** - * Start listening for phone state changes. - */ - public void registerListener() { - mPhone.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE - | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS - | PhoneStateListener.LISTEN_CALL_STATE - | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_DATA_ACTIVITY); - } - - /** - * Stop listening for phone state changes. - */ - public void unregisterListener() { - mPhone.listen(mPhoneStateListener, 0); - } - - /** - * Produce a mapping of data network types to icon groups for simple and quick use in - * updateTelephony. - */ - private void mapIconSets() { - mNetworkToIconLookup.clear(); - - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G); - - if (!mConfig.showAtLeast3G) { - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, - TelephonyIcons.UNKNOWN); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X); - - mDefaultIcons = TelephonyIcons.G; - } else { - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, - TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, - TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, - TelephonyIcons.THREE_G); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, - TelephonyIcons.THREE_G); - mDefaultIcons = TelephonyIcons.THREE_G; - } - - MobileIconGroup hGroup = TelephonyIcons.THREE_G; - if (mConfig.hspaDataDistinguishable) { - hGroup = TelephonyIcons.H; - } - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup); - - if (mConfig.show4gForLte) { - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G); - } else { - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE); - } - } - - @Override - public void notifyListeners() { - MobileIconGroup icons = getIcons(); - - String contentDescription = getStringIfExists(getContentDescription()); - String dataContentDescription = getStringIfExists(icons.mDataContentDescription); - // Only send data sim callbacks to QS. - if (mCurrentState.dataSim) { - int qsTypeIcon = mCurrentState.dataConnected ? - icons.mQsDataType[mCurrentState.inetForNetwork] : 0; - int length = mSignalsChangedCallbacks.size(); - for (int i = 0; i < length; i++) { - mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled - && !mCurrentState.isEmergency && !mCurrentState.airplaneMode, - getQsCurrentIconId(), contentDescription, - qsTypeIcon, - mCurrentState.dataConnected && mCurrentState.activityIn, - mCurrentState.dataConnected && mCurrentState.activityOut, - dataContentDescription, - mCurrentState.isEmergency ? null : mCurrentState.networkName, - // Only wide if actually showing something. - icons.mIsWide && qsTypeIcon != 0); - } - } - boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0 - || mCurrentState.iconGroup == TelephonyIcons.ROAMING; - int typeIcon = showDataIcon ? icons.mDataType : 0; - int signalClustersLength = mSignalClusters.size(); - for (int i = 0; i < signalClustersLength; i++) { - mSignalClusters.get(i).setMobileDataIndicators( - mCurrentState.enabled && !mCurrentState.airplaneMode, - getCurrentIconId(), - typeIcon, - contentDescription, - dataContentDescription, - // Only wide if actually showing something. - icons.mIsWide && typeIcon != 0, - mSubscriptionInfo.getSubscriptionId()); - } - } - - @Override - protected MobileState cleanState() { - return new MobileState(); - } - - private boolean hasService() { - if (mServiceState != null) { - // Consider the device to be in service if either voice or data - // service is available. Some SIM cards are marketed as data-only - // and do not support voice service, and on these SIM cards, we - // want to show signal bars for data service as well as the "no - // service" or "emergency calls only" text that indicates that voice - // is not available. - switch (mServiceState.getVoiceRegState()) { - case ServiceState.STATE_POWER_OFF: - return false; - case ServiceState.STATE_OUT_OF_SERVICE: - case ServiceState.STATE_EMERGENCY_ONLY: - return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; - default: - return true; - } - } else { - return false; - } - } - - private boolean isCdma() { - return (mSignalStrength != null) && !mSignalStrength.isGsm(); - } - - public boolean isEmergencyOnly() { - return (mServiceState != null && mServiceState.isEmergencyOnly()); - } - - private boolean isRoaming() { - if (isCdma()) { - final int iconMode = mServiceState.getCdmaEriIconMode(); - return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF - && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL - || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); - } else { - return mServiceState != null && mServiceState.getRoaming(); - } - } - - public void handleBroadcast(Intent intent) { - String action = intent.getAction(); - if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { - updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), - intent.getStringExtra(TelephonyIntents.EXTRA_SPN), - intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), - intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); - notifyListenersIfNecessary(); - } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { - updateDataSim(); - } - } - - private void updateDataSim() { - int defaultDataSub = SubscriptionManager.getDefaultDataSubId(); - if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) { - mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId(); - } else { - // There doesn't seem to be a data sim selected, however if - // there isn't a MobileSignalController with dataSim set, then - // QS won't get any callbacks and will be blank. Instead - // lets just assume we are the data sim (which will basically - // show one at random) in QS until one is selected. The user - // should pick one soon after, so we shouldn't be in this state - // for long. - mCurrentState.dataSim = true; - } - notifyListenersIfNecessary(); - } - - /** - * Updates the network's name based on incoming spn and plmn. - */ - void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { - if (CHATTY) { - Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn - + " showPlmn=" + showPlmn + " plmn=" + plmn); - } - StringBuilder str = new StringBuilder(); - if (showPlmn && plmn != null) { - str.append(plmn); - } - if (showSpn && spn != null) { - if (str.length() != 0) { - str.append(mNetworkNameSeparator); - } - str.append(spn); - } - if (str.length() != 0) { - mCurrentState.networkName = str.toString(); - } else { - mCurrentState.networkName = mNetworkNameDefault; - } - } - - /** - * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, - * mDataState, and mSimState. It should be called any time one of these is updated. - * This will call listeners if necessary. - */ - private final void updateTelephony() { - if (DEBUG) { - Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() - + " ss=" + mSignalStrength); - } - mCurrentState.connected = hasService() && mSignalStrength != null; - if (mCurrentState.connected) { - if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { - mCurrentState.level = mSignalStrength.getCdmaLevel(); - } else { - mCurrentState.level = mSignalStrength.getLevel(); - } - } - if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) { - mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType); - } else { - mCurrentState.iconGroup = mDefaultIcons; - } - mCurrentState.dataConnected = mCurrentState.connected - && mDataState == TelephonyManager.DATA_CONNECTED; - - if (isRoaming()) { - mCurrentState.iconGroup = TelephonyIcons.ROAMING; - } - if (isEmergencyOnly() != mCurrentState.isEmergency) { - mCurrentState.isEmergency = isEmergencyOnly(); - mNetworkController.recalculateEmergency(); - } - // Fill in the network name if we think we have it. - if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null - && mServiceState.getOperatorAlphaShort() != null) { - mCurrentState.networkName = mServiceState.getOperatorAlphaShort(); - } - notifyListenersIfNecessary(); - } - - @VisibleForTesting - void setActivity(int activity) { - mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT - || activity == TelephonyManager.DATA_ACTIVITY_IN; - mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT - || activity == TelephonyManager.DATA_ACTIVITY_OUT; - notifyListenersIfNecessary(); - } - - @Override - public void dump(PrintWriter pw) { - super.dump(pw); - pw.println(" mSubscription=" + mSubscriptionInfo + ","); - pw.println(" mServiceState=" + mServiceState + ","); - pw.println(" mSignalStrength=" + mSignalStrength + ","); - pw.println(" mDataState=" + mDataState + ","); - pw.println(" mDataNetType=" + mDataNetType + ","); - } - - class MobilePhoneStateListener extends PhoneStateListener { - public MobilePhoneStateListener(int subId) { - super(subId); - } - - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - if (DEBUG) { - Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength + - ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); - } - mSignalStrength = signalStrength; - updateTelephony(); - } - - @Override - public void onServiceStateChanged(ServiceState state) { - if (DEBUG) { - Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState() - + " dataState=" + state.getDataRegState()); - } - mServiceState = state; - updateTelephony(); - } - - @Override - public void onDataConnectionStateChanged(int state, int networkType) { - if (DEBUG) { - Log.d(mTag, "onDataConnectionStateChanged: state=" + state - + " type=" + networkType); - } - mDataState = state; - mDataNetType = networkType; - updateTelephony(); - } - - @Override - public void onDataActivity(int direction) { - if (DEBUG) { - Log.d(mTag, "onDataActivity: direction=" + direction); - } - setActivity(direction); - } - }; - - static class MobileIconGroup extends SignalController.IconGroup { - final int mDataContentDescription; // mContentDescriptionDataType - final int mDataType; - final boolean mIsWide; - final int[] mQsDataType; - - public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, - int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, - int discContentDesc, int dataContentDesc, int dataType, boolean isWide, - int[] qsDataType) { - super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, - qsDiscState, discContentDesc); - mDataContentDescription = dataContentDesc; - mDataType = dataType; - mIsWide = isWide; - mQsDataType = qsDataType; - } - } - - static class MobileState extends SignalController.State { - String networkName; - boolean dataSim; - boolean dataConnected; - boolean isEmergency; - boolean airplaneMode; - int inetForNetwork; - - @Override - public void copyFrom(State s) { - super.copyFrom(s); - MobileState state = (MobileState) s; - dataSim = state.dataSim; - networkName = state.networkName; - dataConnected = state.dataConnected; - inetForNetwork = state.inetForNetwork; - isEmergency = state.isEmergency; - airplaneMode = state.airplaneMode; - } - - @Override - protected void toString(StringBuilder builder) { - super.toString(builder); - builder.append(','); - builder.append("dataSim=").append(dataSim).append(','); - builder.append("networkName=").append(networkName).append(','); - builder.append("dataConnected=").append(dataConnected).append(','); - builder.append("inetForNetwork=").append(inetForNetwork).append(','); - builder.append("isEmergency=").append(isEmergency).append(','); - builder.append("airplaneMode=").append(airplaneMode); - } - - @Override - public boolean equals(Object o) { - return super.equals(o) - && Objects.equals(((MobileState) o).networkName, networkName) - && ((MobileState) o).dataSim == dataSim - && ((MobileState) o).dataConnected == dataConnected - && ((MobileState) o).isEmergency == isEmergency - && ((MobileState) o).airplaneMode == airplaneMode - && ((MobileState) o).inetForNetwork == inetForNetwork; - } - } - } - - /** - * Common base class for handling signal for both wifi and mobile data. - */ - static abstract class SignalController<T extends SignalController.State, - I extends SignalController.IconGroup> { - protected final String mTag; - protected final T mCurrentState; - protected final T mLastState; - protected final int mTransportType; - protected final Context mContext; - // The owner of the SignalController (i.e. NetworkController will maintain the following - // lists and call notifyListeners whenever the list has changed to ensure everyone - // is aware of current state. - protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks; - protected final List<SignalCluster> mSignalClusters; - protected final NetworkControllerImpl mNetworkController; - - // Save the previous HISTORY_SIZE states for logging. - private final State[] mHistory; - // Where to copy the next state into. - private int mHistoryIndex; - - public SignalController(String tag, Context context, int type, - List<NetworkSignalChangedCallback> signalCallbacks, - List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { - mTag = TAG + "." + tag; - mNetworkController = networkController; - mTransportType = type; - mContext = context; - mSignalsChangedCallbacks = signalCallbacks; - mSignalClusters = signalClusters; - mCurrentState = cleanState(); - mLastState = cleanState(); - if (RECORD_HISTORY) { - mHistory = new State[HISTORY_SIZE]; - for (int i = 0; i < HISTORY_SIZE; i++) { - mHistory[i] = cleanState(); - } - } - } - - public T getState() { - return mCurrentState; - } - - public int getTransportType() { - return mTransportType; - } - - public void setInetCondition(int inetCondition) { - mCurrentState.inetCondition = inetCondition; - notifyListenersIfNecessary(); - } - - /** - * Used at the end of demo mode to clear out any ugly state that it has created. - * Since we haven't had any callbacks, then isDirty will not have been triggered, - * so we can just take the last good state directly from there. - * - * Used for demo mode. - */ - void resetLastState() { - mCurrentState.copyFrom(mLastState); - } - - /** - * Determines if the state of this signal controller has changed and - * needs to trigger callbacks related to it. - */ - public boolean isDirty() { - if (!mLastState.equals(mCurrentState)) { - if (DEBUG) { - Log.d(mTag, "Change in state from: " + mLastState + "\n" - + "\tto: " + mCurrentState); - } - return true; - } - return false; - } - - public void saveLastState() { - if (RECORD_HISTORY) { - recordLastState(); - } - // Updates the current time. - mCurrentState.time = System.currentTimeMillis(); - mLastState.copyFrom(mCurrentState); - } - - /** - * Gets the signal icon for QS based on current state of connected, enabled, and level. - */ - public int getQsCurrentIconId() { - if (mCurrentState.connected) { - return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level]; - } else if (mCurrentState.enabled) { - return getIcons().mQsDiscState; - } else { - return getIcons().mQsNullState; - } - } - - /** - * Gets the signal icon for SB based on current state of connected, enabled, and level. - */ - public int getCurrentIconId() { - if (mCurrentState.connected) { - return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level]; - } else if (mCurrentState.enabled) { - return getIcons().mSbDiscState; - } else { - return getIcons().mSbNullState; - } - } - - /** - * Gets the content description id for the signal based on current state of connected and - * level. - */ - public int getContentDescription() { - if (mCurrentState.connected) { - return getIcons().mContentDesc[mCurrentState.level]; - } else { - return getIcons().mDiscContentDesc; - } - } - - public void notifyListenersIfNecessary() { - if (isDirty()) { - saveLastState(); - notifyListeners(); - mNetworkController.refreshCarrierLabel(); - } - } - - /** - * Returns the resource if resId is not 0, and an empty string otherwise. - */ - protected String getStringIfExists(int resId) { - return resId != 0 ? mContext.getString(resId) : ""; - } - - protected I getIcons() { - return (I) mCurrentState.iconGroup; - } - - /** - * Saves the last state of any changes, so we can log the current - * and last value of any state data. - */ - protected void recordLastState() { - mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState); - } - - public void dump(PrintWriter pw) { - pw.println(" - " + mTag + " -----"); - pw.println(" Current State: " + mCurrentState); - if (RECORD_HISTORY) { - // Count up the states that actually contain time stamps, and only display those. - int size = 0; - for (int i = 0; i < HISTORY_SIZE; i++) { - if (mHistory[i].time != 0) size++; - } - // Print out the previous states in ordered number. - for (int i = mHistoryIndex + HISTORY_SIZE - 1; - i >= mHistoryIndex + HISTORY_SIZE - size; i--) { - pw.println(" Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + ": " - + mHistory[i & (HISTORY_SIZE - 1)]); - } - } - } - - /** - * Trigger callbacks based on current state. The callbacks should be completely - * based on current state, and only need to be called in the scenario where - * mCurrentState != mLastState. - */ - public abstract void notifyListeners(); - - /** - * Generate a blank T. - */ - protected abstract T cleanState(); - - /* - * Holds icons for a given state. Arrays are generally indexed as inet - * state (full connectivity or not) first, and second dimension as - * signal strength. - */ - static class IconGroup { - final int[][] mSbIcons; - final int[][] mQsIcons; - final int[] mContentDesc; - final int mSbNullState; - final int mQsNullState; - final int mSbDiscState; - final int mQsDiscState; - final int mDiscContentDesc; - // For logging. - final String mName; - - public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, - int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, - int discContentDesc) { - mName = name; - mSbIcons = sbIcons; - mQsIcons = qsIcons; - mContentDesc = contentDesc; - mSbNullState = sbNullState; - mQsNullState = qsNullState; - mSbDiscState = sbDiscState; - mQsDiscState = qsDiscState; - mDiscContentDesc = discContentDesc; - } - - @Override - public String toString() { - return "IconGroup(" + mName + ")"; - } - } - - static class State { - boolean connected; - boolean enabled; - boolean activityIn; - boolean activityOut; - int level; - IconGroup iconGroup; - int inetCondition; - int rssi; // Only for logging. - - // Not used for comparison, just used for logging. - long time; - - public void copyFrom(State state) { - connected = state.connected; - enabled = state.enabled; - level = state.level; - iconGroup = state.iconGroup; - inetCondition = state.inetCondition; - activityIn = state.activityIn; - activityOut = state.activityOut; - rssi = state.rssi; - time = state.time; - } - - @Override - public String toString() { - if (time != 0) { - StringBuilder builder = new StringBuilder(); - toString(builder); - return builder.toString(); - } else { - return "Empty " + getClass().getSimpleName(); - } - } - - protected void toString(StringBuilder builder) { - builder.append("connected=").append(connected).append(',') - .append("enabled=").append(enabled).append(',') - .append("level=").append(level).append(',') - .append("inetCondition=").append(inetCondition).append(',') - .append("iconGroup=").append(iconGroup).append(',') - .append("activityIn=").append(activityIn).append(',') - .append("activityOut=").append(activityOut).append(',') - .append("rssi=").append(rssi).append(',') - .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time)); - } - - @Override - public boolean equals(Object o) { - if (!o.getClass().equals(getClass())) { - return false; - } - State other = (State) o; - return other.connected == connected - && other.enabled == enabled - && other.level == level - && other.inetCondition == inetCondition - && other.iconGroup == iconGroup - && other.activityIn == activityIn - && other.activityOut == activityOut - && other.rssi == rssi; - } - } - } - public interface SignalCluster { void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java new file mode 100644 index 000000000000..14c3d9c493ab --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG; + +import android.content.Context; +import android.text.format.DateFormat; +import android.util.Log; + +import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; + +import java.io.PrintWriter; +import java.util.List; + + +/** + * Common base class for handling signal for both wifi and mobile data. + */ +public abstract class SignalController<T extends SignalController.State, + I extends SignalController.IconGroup> { + // Save the previous SignalController.States of all SignalControllers for dumps. + static final boolean RECORD_HISTORY = true; + // If RECORD_HISTORY how many to save, must be a power of 2. + static final int HISTORY_SIZE = 16; + + protected static final boolean DEBUG = NetworkControllerImpl.DEBUG; + protected static final boolean CHATTY = NetworkControllerImpl.CHATTY; + + protected final String mTag; + protected final T mCurrentState; + protected final T mLastState; + protected final int mTransportType; + protected final Context mContext; + // The owner of the SignalController (i.e. NetworkController will maintain the following + // lists and call notifyListeners whenever the list has changed to ensure everyone + // is aware of current state. + protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks; + protected final List<SignalCluster> mSignalClusters; + protected final NetworkControllerImpl mNetworkController; + + // Save the previous HISTORY_SIZE states for logging. + private final State[] mHistory; + // Where to copy the next state into. + private int mHistoryIndex; + + public SignalController(String tag, Context context, int type, + List<NetworkSignalChangedCallback> signalCallbacks, + List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { + mTag = TAG + "." + tag; + mNetworkController = networkController; + mTransportType = type; + mContext = context; + mSignalsChangedCallbacks = signalCallbacks; + mSignalClusters = signalClusters; + mCurrentState = cleanState(); + mLastState = cleanState(); + if (RECORD_HISTORY) { + mHistory = new State[HISTORY_SIZE]; + for (int i = 0; i < HISTORY_SIZE; i++) { + mHistory[i] = cleanState(); + } + } + } + + public T getState() { + return mCurrentState; + } + + public int getTransportType() { + return mTransportType; + } + + public void setInetCondition(int inetCondition) { + mCurrentState.inetCondition = inetCondition; + notifyListenersIfNecessary(); + } + + /** + * Used at the end of demo mode to clear out any ugly state that it has created. + * Since we haven't had any callbacks, then isDirty will not have been triggered, + * so we can just take the last good state directly from there. + * + * Used for demo mode. + */ + public void resetLastState() { + mCurrentState.copyFrom(mLastState); + } + + /** + * Determines if the state of this signal controller has changed and + * needs to trigger callbacks related to it. + */ + public boolean isDirty() { + if (!mLastState.equals(mCurrentState)) { + if (DEBUG) { + Log.d(mTag, "Change in state from: " + mLastState + "\n" + + "\tto: " + mCurrentState); + } + return true; + } + return false; + } + + public void saveLastState() { + if (RECORD_HISTORY) { + recordLastState(); + } + // Updates the current time. + mCurrentState.time = System.currentTimeMillis(); + mLastState.copyFrom(mCurrentState); + } + + /** + * Gets the signal icon for QS based on current state of connected, enabled, and level. + */ + public int getQsCurrentIconId() { + if (mCurrentState.connected) { + return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level]; + } else if (mCurrentState.enabled) { + return getIcons().mQsDiscState; + } else { + return getIcons().mQsNullState; + } + } + + /** + * Gets the signal icon for SB based on current state of connected, enabled, and level. + */ + public int getCurrentIconId() { + if (mCurrentState.connected) { + return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level]; + } else if (mCurrentState.enabled) { + return getIcons().mSbDiscState; + } else { + return getIcons().mSbNullState; + } + } + + /** + * Gets the content description id for the signal based on current state of connected and + * level. + */ + public int getContentDescription() { + if (mCurrentState.connected) { + return getIcons().mContentDesc[mCurrentState.level]; + } else { + return getIcons().mDiscContentDesc; + } + } + + public void notifyListenersIfNecessary() { + if (isDirty()) { + saveLastState(); + notifyListeners(); + mNetworkController.refreshCarrierLabel(); + } + } + + /** + * Returns the resource if resId is not 0, and an empty string otherwise. + */ + protected String getStringIfExists(int resId) { + return resId != 0 ? mContext.getString(resId) : ""; + } + + protected I getIcons() { + return (I) mCurrentState.iconGroup; + } + + /** + * Saves the last state of any changes, so we can log the current + * and last value of any state data. + */ + protected void recordLastState() { + mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState); + } + + public void dump(PrintWriter pw) { + pw.println(" - " + mTag + " -----"); + pw.println(" Current State: " + mCurrentState); + if (RECORD_HISTORY) { + // Count up the states that actually contain time stamps, and only display those. + int size = 0; + for (int i = 0; i < HISTORY_SIZE; i++) { + if (mHistory[i].time != 0) size++; + } + // Print out the previous states in ordered number. + for (int i = mHistoryIndex + HISTORY_SIZE - 1; + i >= mHistoryIndex + HISTORY_SIZE - size; i--) { + pw.println(" Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + "): " + + mHistory[i & (HISTORY_SIZE - 1)]); + } + } + } + + /** + * Trigger callbacks based on current state. The callbacks should be completely + * based on current state, and only need to be called in the scenario where + * mCurrentState != mLastState. + */ + public abstract void notifyListeners(); + + /** + * Generate a blank T. + */ + protected abstract T cleanState(); + + /* + * Holds icons for a given state. Arrays are generally indexed as inet + * state (full connectivity or not) first, and second dimension as + * signal strength. + */ + static class IconGroup { + final int[][] mSbIcons; + final int[][] mQsIcons; + final int[] mContentDesc; + final int mSbNullState; + final int mQsNullState; + final int mSbDiscState; + final int mQsDiscState; + final int mDiscContentDesc; + // For logging. + final String mName; + + public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, + int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, + int discContentDesc) { + mName = name; + mSbIcons = sbIcons; + mQsIcons = qsIcons; + mContentDesc = contentDesc; + mSbNullState = sbNullState; + mQsNullState = qsNullState; + mSbDiscState = sbDiscState; + mQsDiscState = qsDiscState; + mDiscContentDesc = discContentDesc; + } + + @Override + public String toString() { + return "IconGroup(" + mName + ")"; + } + } + + static class State { + boolean connected; + boolean enabled; + boolean activityIn; + boolean activityOut; + int level; + IconGroup iconGroup; + int inetCondition; + int rssi; // Only for logging. + + // Not used for comparison, just used for logging. + long time; + + public void copyFrom(State state) { + connected = state.connected; + enabled = state.enabled; + level = state.level; + iconGroup = state.iconGroup; + inetCondition = state.inetCondition; + activityIn = state.activityIn; + activityOut = state.activityOut; + rssi = state.rssi; + time = state.time; + } + + @Override + public String toString() { + if (time != 0) { + StringBuilder builder = new StringBuilder(); + toString(builder); + return builder.toString(); + } else { + return "Empty " + getClass().getSimpleName(); + } + } + + protected void toString(StringBuilder builder) { + builder.append("connected=").append(connected).append(',') + .append("enabled=").append(enabled).append(',') + .append("level=").append(level).append(',') + .append("inetCondition=").append(inetCondition).append(',') + .append("iconGroup=").append(iconGroup).append(',') + .append("activityIn=").append(activityIn).append(',') + .append("activityOut=").append(activityOut).append(',') + .append("rssi=").append(rssi).append(',') + .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time)); + } + + @Override + public boolean equals(Object o) { + if (!o.getClass().equals(getClass())) { + return false; + } + State other = (State) o; + return other.connected == connected + && other.enabled == enabled + && other.level == level + && other.inetCondition == inetCondition + && other.iconGroup == iconGroup + && other.activityIn == activityIn + && other.activityOut == activityOut + && other.rssi == rssi; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index 4091619aa879..d266ed88b5e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.policy; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController.MobileIconGroup; +import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup; class TelephonyIcons { //***** Signal strength icons diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java new file mode 100644 index 000000000000..a97ca5009341 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.content.Intent; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.AsyncChannel; +import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; +import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; + +import java.util.List; +import java.util.Objects; + + +public class WifiSignalController extends + SignalController<WifiSignalController.WifiState, SignalController.IconGroup> { + private final WifiManager mWifiManager; + private final AsyncChannel mWifiChannel; + private final boolean mHasMobileData; + + public WifiSignalController(Context context, boolean hasMobileData, + List<NetworkSignalChangedCallback> signalCallbacks, + List<SignalCluster> signalClusters, NetworkControllerImpl networkController) { + super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, + signalCallbacks, signalClusters, networkController); + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mHasMobileData = hasMobileData; + Handler handler = new WifiHandler(); + mWifiChannel = new AsyncChannel(); + Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); + if (wifiMessenger != null) { + mWifiChannel.connect(context, handler, wifiMessenger); + } + // WiFi only has one state. + mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup( + "Wi-Fi Icons", + WifiIcons.WIFI_SIGNAL_STRENGTH, + WifiIcons.QS_WIFI_SIGNAL_STRENGTH, + AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH, + WifiIcons.WIFI_NO_NETWORK, + WifiIcons.QS_WIFI_NO_NETWORK, + WifiIcons.WIFI_NO_NETWORK, + WifiIcons.QS_WIFI_NO_NETWORK, + AccessibilityContentDescriptions.WIFI_NO_CONNECTION + ); + } + + @Override + protected WifiState cleanState() { + return new WifiState(); + } + + @Override + public void notifyListeners() { + // only show wifi in the cluster if connected or if wifi-only + boolean wifiVisible = mCurrentState.enabled + && (mCurrentState.connected || !mHasMobileData); + String wifiDesc = wifiVisible ? mCurrentState.ssid : null; + boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; + String contentDescription = getStringIfExists(getContentDescription()); + int length = mSignalsChangedCallbacks.size(); + for (int i = 0; i < length; i++) { + mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled, + mCurrentState.connected, getQsCurrentIconId(), + ssidPresent && mCurrentState.activityIn, + ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc); + } + + int signalClustersLength = mSignalClusters.size(); + for (int i = 0; i < signalClustersLength; i++) { + mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(), + contentDescription); + } + } + + /** + * Extract wifi state directly from broadcasts about changes in wifi state. + */ + public void handleBroadcast(Intent intent) { + String action = intent.getAction(); + if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + mCurrentState.connected = networkInfo != null && networkInfo.isConnected(); + // If Connected grab the signal strength and ssid. + if (mCurrentState.connected) { + // try getting it out of the intent first + WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null + ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) + : mWifiManager.getConnectionInfo(); + if (info != null) { + mCurrentState.ssid = getSsid(info); + } else { + mCurrentState.ssid = null; + } + } else if (!mCurrentState.connected) { + mCurrentState.ssid = null; + } + } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { + // Default to -200 as its below WifiManager.MIN_RSSI. + mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); + mCurrentState.level = WifiManager.calculateSignalLevel( + mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT); + } + + notifyListenersIfNecessary(); + } + + private String getSsid(WifiInfo info) { + String ssid = info.getSSID(); + if (ssid != null) { + return ssid; + } + // OK, it's not in the connectionInfo; we have to go hunting for it + List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); + int length = networks.size(); + for (int i = 0; i < length; i++) { + if (networks.get(i).networkId == info.getNetworkId()) { + return networks.get(i).SSID; + } + } + return null; + } + + @VisibleForTesting + void setActivity(int wifiActivity) { + mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT + || wifiActivity == WifiManager.DATA_ACTIVITY_IN; + mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT + || wifiActivity == WifiManager.DATA_ACTIVITY_OUT; + notifyListenersIfNecessary(); + } + + /** + * Handler to receive the data activity on wifi. + */ + private class WifiHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + mWifiChannel.sendMessage(Message.obtain(this, + AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); + } else { + Log.e(mTag, "Failed to connect to wifi"); + } + break; + case WifiManager.DATA_ACTIVITY_NOTIFICATION: + setActivity(msg.arg1); + break; + default: + // Ignore + break; + } + } + } + + static class WifiState extends SignalController.State { + String ssid; + + @Override + public void copyFrom(State s) { + super.copyFrom(s); + WifiState state = (WifiState) s; + ssid = state.ssid; + } + + @Override + protected void toString(StringBuilder builder) { + super.toString(builder); + builder.append(',').append("ssid=").append(ssid); + } + + @Override + public boolean equals(Object o) { + return super.equals(o) + && Objects.equals(((WifiState) o).ssid, ssid); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 8a2d62f821d2..9b95d5cad4d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -1,17 +1,24 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.systemui.statusbar.policy; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; @@ -26,13 +33,19 @@ import android.test.AndroidTestCase; import android.util.Log; import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController; import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + public class NetworkControllerBaseTest extends AndroidTestCase { private static final String TAG = "NetworkControllerBaseTest"; protected static final int DEFAULT_LEVEL = 2; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 142c7e6f7570..65b09710cf0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -1,12 +1,21 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.systemui.statusbar.policy; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.List; - -import org.mockito.Mockito; import android.content.Intent; import android.net.ConnectivityManager; @@ -18,7 +27,11 @@ import android.telephony.TelephonyManager; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController; + +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; public class NetworkControllerSignalTest extends NetworkControllerBaseTest { |