Loading packages/SystemUI/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -839,6 +839,8 @@ <string name="quick_settings_user_new_user">New user</string> <!-- QuickSettings: Wifi [CHAR LIMIT=NONE] --> <string name="quick_settings_wifi_label">Wi-Fi</string> <!-- QuickSettings: Internet [CHAR LIMIT=NONE] --> <string name="quick_settings_internet_label">Internet</string> <!-- QuickSettings: Wifi (Not connected) [CHAR LIMIT=NONE] --> <string name="quick_settings_wifi_not_connected">Not Connected</string> <!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] --> Loading packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +12 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.Log; import com.android.internal.logging.InstanceId; Loading Loading @@ -444,6 +445,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D final ArrayList<String> tiles = new ArrayList<String>(); boolean addedDefault = false; Set<String> addedSpecs = new ArraySet<>(); // TODO(b/174753536): Move it into the config file. if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { tiles.add("internet"); addedSpecs.add("internet"); } for (String tile : tileList.split(",")) { tile = tile.trim(); if (tile.isEmpty()) continue; Loading @@ -459,6 +465,12 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D addedDefault = true; } } else { // TODO(b/174753536): Move it into the config file. if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { if (tile.equals("wifi") || tile.equals("cell")) { continue; } } if (!addedSpecs.contains(tile)) { tiles.add(tile); addedSpecs.add(tile); Loading packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.qs.tiles.DataSaverTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.FlashlightTile; import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.InternetTile; import com.android.systemui.qs.tiles.LocationTile; import com.android.systemui.qs.tiles.NfcTile; import com.android.systemui.qs.tiles.NightDisplayTile; Loading @@ -60,6 +61,7 @@ public class QSFactoryImpl implements QSFactory { private static final String TAG = "QSFactory"; private final Provider<WifiTile> mWifiTileProvider; private final Provider<InternetTile> mInternetTileProvider; private final Provider<BluetoothTile> mBluetoothTileProvider; private final Provider<CellularTile> mCellularTileProvider; private final Provider<DndTile> mDndTileProvider; Loading Loading @@ -89,6 +91,7 @@ public class QSFactoryImpl implements QSFactory { Lazy<QSHost> qsHostLazy, Provider<CustomTile.Builder> customTileBuilderProvider, Provider<WifiTile> wifiTileProvider, Provider<InternetTile> internetTileProvider, Provider<BluetoothTile> bluetoothTileProvider, Provider<CellularTile> cellularTileProvider, Provider<DndTile> dndTileProvider, Loading @@ -113,6 +116,7 @@ public class QSFactoryImpl implements QSFactory { mCustomTileBuilderProvider = customTileBuilderProvider; mWifiTileProvider = wifiTileProvider; mInternetTileProvider = internetTileProvider; mBluetoothTileProvider = bluetoothTileProvider; mCellularTileProvider = cellularTileProvider; mDndTileProvider = dndTileProvider; Loading Loading @@ -148,6 +152,8 @@ public class QSFactoryImpl implements QSFactory { switch (tileSpec) { case "wifi": return mWifiTileProvider.get(); case "internet": return mInternetTileProvider.get(); case "bt": return mBluetoothTileProvider.get(); case "cell": Loading packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java 0 → 100644 +449 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.qs.tiles; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.graph.SignalDrawable; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.Icon; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.WifiIcons; import javax.inject.Inject; /** Quick settings tile: Internet **/ public class InternetTile extends QSTileImpl<SignalState> { private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); protected final NetworkController mController; private final DataUsageController mDataController; private final QSTile.SignalState mStateBeforeClick = newTileState(); // The last updated tile state, 0: mobile, 1: wifi private int mLastTileState = -1; protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); @Inject public InternetTile( QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController ) { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); } @Override public SignalState newTileState() { return new SignalState(); } @Override public QSIconView createTileView(Context context) { return new AlphaControlledSignalTileView(context); } @Override public Intent getLongClickIntent() { return WIFI_SETTINGS; } @Override protected void handleClick() { mActivityStarter.postStartActivityDismissingKeyguard(WIFI_SETTINGS, 0); } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_internet_label); } @Override public int getMetricsCategory() { return MetricsEvent.QS_WIFI; } @Override public boolean isAvailable() { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) || (mController.hasMobileDataFeature() && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM); } private CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) { return isTransient ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient) : statusLabel; } private static String removeDoubleQuotes(String string) { if (string == null) return null; final int length = string.length(); if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { return string.substring(1, length - 1); } return string; } private static final class WifiCallbackInfo { boolean mEnabled; boolean mConnected; int mWifiSignalIconId; String mSsid; boolean mActivityIn; boolean mActivityOut; String mWifiSignalContentDescription; boolean mIsTransient; public String mStatusLabel; @Override public String toString() { return new StringBuilder("WifiCallbackInfo[") .append("mEnabled=").append(mEnabled) .append(",mConnected=").append(mConnected) .append(",mWifiSignalIconId=").append(mWifiSignalIconId) .append(",mSsid=").append(mSsid) .append(",mActivityIn=").append(mActivityIn) .append(",mActivityOut=").append(mActivityOut) .append(",mWifiSignalContentDescription=").append(mWifiSignalContentDescription) .append(",mIsTransient=").append(mIsTransient) .append(']').toString(); } } private static final class CellularCallbackInfo { boolean mAirplaneModeEnabled; CharSequence mDataSubscriptionName; CharSequence mDataContentDescription; int mMobileSignalIconId; boolean mActivityIn; boolean mActivityOut; boolean mNoSim; boolean mRoaming; boolean mMultipleSubs; @Override public String toString() { return new StringBuilder("CellularCallbackInfo[") .append("mAirplaneModeEnabled=").append(mAirplaneModeEnabled) .append(",mDataSubscriptionName=").append(mDataSubscriptionName) .append(",mDataContentDescription=").append(mDataContentDescription) .append(",mMobileSignalIconId=").append(mMobileSignalIconId) .append(",mActivityIn=").append(mActivityIn) .append(",mActivityOut=").append(mActivityOut) .append(",mNoSim=").append(mNoSim) .append(",mRoaming=").append(mRoaming) .append(",mMultipleSubs=").append(mMultipleSubs) .append(']').toString(); } } protected final class InternetSignalCallback implements SignalCallback { final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo(); final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo(); @Override public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient, String statusLabel) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setWifiIndicators: " + "enabled = " + enabled + "," + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + "," + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + "," + "activityIn = " + activityIn + "," + "activityOut = " + activityOut + "," + "description = " + description + "," + "isTransient = " + isTransient + "," + "statusLabel = " + statusLabel); } mWifiInfo.mEnabled = enabled; mWifiInfo.mConnected = qsIcon.visible; mWifiInfo.mWifiSignalIconId = qsIcon.icon; mWifiInfo.mSsid = description; mWifiInfo.mActivityIn = activityIn; mWifiInfo.mActivityOut = activityOut; mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription; mWifiInfo.mIsTransient = isTransient; mWifiInfo.mStatusLabel = statusLabel; refreshState(mWifiInfo); } @Override public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, int qsType, boolean activityIn, boolean activityOut, CharSequence typeContentDescription, CharSequence typeContentDescriptionHtml, CharSequence description, boolean isWide, int subId, boolean roaming) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setMobileDataIndicators: " + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + "," + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + "," + "statusType = " + statusType + "," + "qsType = " + qsType + "," + "activityIn = " + activityIn + "," + "activityOut = " + activityOut + "," + "typeContentDescription = " + typeContentDescription + "," + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + "," + "description = " + description + "," + "isWide = " + isWide + "," + "subId = " + subId + "," + "roaming = " + roaming); } if (qsIcon == null) { // Not data sim, don't display. return; } mCellularInfo.mDataSubscriptionName = mController.getMobileDataNetworkName(); mCellularInfo.mDataContentDescription = (description != null) ? typeContentDescriptionHtml : null; mCellularInfo.mMobileSignalIconId = qsIcon.icon; mCellularInfo.mActivityIn = activityIn; mCellularInfo.mActivityOut = activityOut; mCellularInfo.mRoaming = roaming; mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1; refreshState(mCellularInfo); } @Override public void setNoSims(boolean show, boolean simDetected) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setNoSims: " + "show = " + show + "," + "simDetected = " + simDetected); } mCellularInfo.mNoSim = show; if (mCellularInfo.mNoSim) { // Make sure signal gets cleared out when no sims. mCellularInfo.mMobileSignalIconId = 0; } refreshState(mCellularInfo); } @Override public void setIsAirplaneMode(IconState icon) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "InternetTile-setIsAirplaneMode: " + "icon = " + (icon == null ? "" : icon.toString())); } mCellularInfo.mAirplaneModeEnabled = icon.visible; refreshState(mCellularInfo); } } @Override protected void handleUpdateState(SignalState state, Object arg) { Log.d(TAG, "handleUpdateState: " + "arg = " + arg); if (arg instanceof CellularCallbackInfo) { mLastTileState = 0; handleUpdateCellularState(state, arg); } else if (arg instanceof WifiCallbackInfo) { mLastTileState = 1; handleUpdateWifiState(state, arg); } else { // handleUpdateState will be triggered when user expands the QuickSetting panel with // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo // should be used to refresh the tile. if (mLastTileState == 0) { handleUpdateCellularState(state, mSignalCallback.mCellularInfo); } else if (mLastTileState == 1) { handleUpdateWifiState(state, mSignalCallback.mWifiInfo); } } } private void handleUpdateWifiState(SignalState state, Object arg) { WifiCallbackInfo cb = (WifiCallbackInfo) arg; boolean wifiConnected = cb.mEnabled && (cb.mWifiSignalIconId > 0) && (cb.mSsid != null); boolean wifiNotConnected = (cb.mWifiSignalIconId > 0) && (cb.mSsid == null); boolean enabledChanging = state.value != cb.mEnabled; if (enabledChanging) { fireToggleStateChanged(cb.mEnabled); } if (state.slash == null) { state.slash = new SlashState(); state.slash.rotation = 6; } state.slash.isSlashed = false; state.secondaryLabel = getSecondaryLabel(cb.mIsTransient, removeDoubleQuotes(cb.mSsid)); state.state = Tile.STATE_ACTIVE; state.dualTarget = true; state.value = cb.mEnabled; state.activityIn = cb.mEnabled && cb.mActivityIn; state.activityOut = cb.mEnabled && cb.mActivityOut; final StringBuffer minimalContentDescription = new StringBuffer(); final StringBuffer minimalStateDescription = new StringBuffer(); final Resources r = mContext.getResources(); // TODO(b/174753536): Use the new "Internet" string as state.label once available. if (cb.mIsTransient) { state.icon = ResourceIcon.get( com.android.internal.R.drawable.ic_signal_wifi_transient_animation); state.label = r.getString(R.string.quick_settings_internet_label); } else if (!state.value) { state.slash.isSlashed = true; state.state = Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED); state.label = r.getString(R.string.quick_settings_internet_label); } else if (wifiConnected) { state.icon = ResourceIcon.get(cb.mWifiSignalIconId); state.label = r.getString(R.string.quick_settings_internet_label); } else if (wifiNotConnected) { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_internet_label); } else { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_internet_label); } minimalContentDescription.append( mContext.getString(R.string.quick_settings_internet_label)).append(","); if (state.value) { if (wifiConnected) { minimalStateDescription.append(cb.mWifiSignalContentDescription); minimalContentDescription.append(removeDoubleQuotes(cb.mSsid)); if (!TextUtils.isEmpty(state.secondaryLabel)) { minimalContentDescription.append(",").append(state.secondaryLabel); } } } state.stateDescription = minimalStateDescription.toString(); state.contentDescription = minimalContentDescription.toString(); state.dualLabelContentDescription = r.getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); state.expandedAccessibilityClassName = Switch.class.getName(); } private void handleUpdateCellularState(SignalState state, Object arg) { CellularCallbackInfo cb = (CellularCallbackInfo) arg; final Resources r = mContext.getResources(); // TODO(b/174753536): Use the new "Internet" string as state.label once available. state.label = r.getString(R.string.quick_settings_internet_label); boolean mobileDataEnabled = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.value = mobileDataEnabled; state.activityIn = mobileDataEnabled && cb.mActivityIn; state.activityOut = mobileDataEnabled && cb.mActivityOut; state.expandedAccessibilityClassName = Switch.class.getName(); if (cb.mNoSim) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim); } else { state.icon = new SignalIcon(cb.mMobileSignalIconId); } if (cb.mNoSim) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short); } else if (cb.mAirplaneModeEnabled) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.status_bar_airplane); } else if (mobileDataEnabled) { state.state = Tile.STATE_ACTIVE; state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName, getMobileDataContentName(cb)); } else { state.state = Tile.STATE_INACTIVE; state.secondaryLabel = r.getString(R.string.cell_data_off); } state.contentDescription = state.label; if (state.state == Tile.STATE_INACTIVE) { // This information is appended later by converting the Tile.STATE_INACTIVE state. state.stateDescription = ""; } else { state.stateDescription = state.secondaryLabel; } } private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) { if (TextUtils.isEmpty(dataType)) { return Html.fromHtml((current == null ? "" : current.toString()), 0); } if (TextUtils.isEmpty(current)) { return Html.fromHtml((dataType == null ? "" : dataType.toString()), 0); } String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType); return Html.fromHtml(concat, 0); } private CharSequence getMobileDataContentName(CellularCallbackInfo cb) { if (cb.mRoaming && !TextUtils.isEmpty(cb.mDataContentDescription)) { String roaming = mContext.getString(R.string.data_connection_roaming); String dataDescription = cb.mDataContentDescription == null ? "" : cb.mDataContentDescription.toString(); return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription); } if (cb.mRoaming) { return mContext.getString(R.string.data_connection_roaming); } return cb.mDataContentDescription; } private static class SignalIcon extends Icon { private final int mState; SignalIcon(int state) { mState = state; } public int getState() { return mState; } @Override public Drawable getDrawable(Context context) { SignalDrawable d = new SignalDrawable(context); d.setLevel(getState()); return d; } } } packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +9 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,15 @@ public interface NetworkController extends CallbackController<SignalCallback>, D Context context) { this(visible, icon, context.getString(contentDescription)); } @Override public String toString() { StringBuilder builder = new StringBuilder(); return builder.append("[visible=").append(visible).append(',') .append("icon=").append(icon).append(',') .append("contentDescription=").append(contentDescription).append(']') .toString(); } } /** Loading Loading
packages/SystemUI/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -839,6 +839,8 @@ <string name="quick_settings_user_new_user">New user</string> <!-- QuickSettings: Wifi [CHAR LIMIT=NONE] --> <string name="quick_settings_wifi_label">Wi-Fi</string> <!-- QuickSettings: Internet [CHAR LIMIT=NONE] --> <string name="quick_settings_internet_label">Internet</string> <!-- QuickSettings: Wifi (Not connected) [CHAR LIMIT=NONE] --> <string name="quick_settings_wifi_not_connected">Not Connected</string> <!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] --> Loading
packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +12 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.Log; import com.android.internal.logging.InstanceId; Loading Loading @@ -444,6 +445,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D final ArrayList<String> tiles = new ArrayList<String>(); boolean addedDefault = false; Set<String> addedSpecs = new ArraySet<>(); // TODO(b/174753536): Move it into the config file. if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { tiles.add("internet"); addedSpecs.add("internet"); } for (String tile : tileList.split(",")) { tile = tile.trim(); if (tile.isEmpty()) continue; Loading @@ -459,6 +465,12 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D addedDefault = true; } } else { // TODO(b/174753536): Move it into the config file. if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { if (tile.equals("wifi") || tile.equals("cell")) { continue; } } if (!addedSpecs.contains(tile)) { tiles.add(tile); addedSpecs.add(tile); Loading
packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.qs.tiles.DataSaverTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.FlashlightTile; import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.InternetTile; import com.android.systemui.qs.tiles.LocationTile; import com.android.systemui.qs.tiles.NfcTile; import com.android.systemui.qs.tiles.NightDisplayTile; Loading @@ -60,6 +61,7 @@ public class QSFactoryImpl implements QSFactory { private static final String TAG = "QSFactory"; private final Provider<WifiTile> mWifiTileProvider; private final Provider<InternetTile> mInternetTileProvider; private final Provider<BluetoothTile> mBluetoothTileProvider; private final Provider<CellularTile> mCellularTileProvider; private final Provider<DndTile> mDndTileProvider; Loading Loading @@ -89,6 +91,7 @@ public class QSFactoryImpl implements QSFactory { Lazy<QSHost> qsHostLazy, Provider<CustomTile.Builder> customTileBuilderProvider, Provider<WifiTile> wifiTileProvider, Provider<InternetTile> internetTileProvider, Provider<BluetoothTile> bluetoothTileProvider, Provider<CellularTile> cellularTileProvider, Provider<DndTile> dndTileProvider, Loading @@ -113,6 +116,7 @@ public class QSFactoryImpl implements QSFactory { mCustomTileBuilderProvider = customTileBuilderProvider; mWifiTileProvider = wifiTileProvider; mInternetTileProvider = internetTileProvider; mBluetoothTileProvider = bluetoothTileProvider; mCellularTileProvider = cellularTileProvider; mDndTileProvider = dndTileProvider; Loading Loading @@ -148,6 +152,8 @@ public class QSFactoryImpl implements QSFactory { switch (tileSpec) { case "wifi": return mWifiTileProvider.get(); case "internet": return mInternetTileProvider.get(); case "bt": return mBluetoothTileProvider.get(); case "cell": Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java 0 → 100644 +449 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.qs.tiles; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.graph.SignalDrawable; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.Icon; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.WifiIcons; import javax.inject.Inject; /** Quick settings tile: Internet **/ public class InternetTile extends QSTileImpl<SignalState> { private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); protected final NetworkController mController; private final DataUsageController mDataController; private final QSTile.SignalState mStateBeforeClick = newTileState(); // The last updated tile state, 0: mobile, 1: wifi private int mLastTileState = -1; protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); @Inject public InternetTile( QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController ) { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); } @Override public SignalState newTileState() { return new SignalState(); } @Override public QSIconView createTileView(Context context) { return new AlphaControlledSignalTileView(context); } @Override public Intent getLongClickIntent() { return WIFI_SETTINGS; } @Override protected void handleClick() { mActivityStarter.postStartActivityDismissingKeyguard(WIFI_SETTINGS, 0); } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_internet_label); } @Override public int getMetricsCategory() { return MetricsEvent.QS_WIFI; } @Override public boolean isAvailable() { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) || (mController.hasMobileDataFeature() && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM); } private CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) { return isTransient ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient) : statusLabel; } private static String removeDoubleQuotes(String string) { if (string == null) return null; final int length = string.length(); if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { return string.substring(1, length - 1); } return string; } private static final class WifiCallbackInfo { boolean mEnabled; boolean mConnected; int mWifiSignalIconId; String mSsid; boolean mActivityIn; boolean mActivityOut; String mWifiSignalContentDescription; boolean mIsTransient; public String mStatusLabel; @Override public String toString() { return new StringBuilder("WifiCallbackInfo[") .append("mEnabled=").append(mEnabled) .append(",mConnected=").append(mConnected) .append(",mWifiSignalIconId=").append(mWifiSignalIconId) .append(",mSsid=").append(mSsid) .append(",mActivityIn=").append(mActivityIn) .append(",mActivityOut=").append(mActivityOut) .append(",mWifiSignalContentDescription=").append(mWifiSignalContentDescription) .append(",mIsTransient=").append(mIsTransient) .append(']').toString(); } } private static final class CellularCallbackInfo { boolean mAirplaneModeEnabled; CharSequence mDataSubscriptionName; CharSequence mDataContentDescription; int mMobileSignalIconId; boolean mActivityIn; boolean mActivityOut; boolean mNoSim; boolean mRoaming; boolean mMultipleSubs; @Override public String toString() { return new StringBuilder("CellularCallbackInfo[") .append("mAirplaneModeEnabled=").append(mAirplaneModeEnabled) .append(",mDataSubscriptionName=").append(mDataSubscriptionName) .append(",mDataContentDescription=").append(mDataContentDescription) .append(",mMobileSignalIconId=").append(mMobileSignalIconId) .append(",mActivityIn=").append(mActivityIn) .append(",mActivityOut=").append(mActivityOut) .append(",mNoSim=").append(mNoSim) .append(",mRoaming=").append(mRoaming) .append(",mMultipleSubs=").append(mMultipleSubs) .append(']').toString(); } } protected final class InternetSignalCallback implements SignalCallback { final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo(); final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo(); @Override public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient, String statusLabel) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setWifiIndicators: " + "enabled = " + enabled + "," + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + "," + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + "," + "activityIn = " + activityIn + "," + "activityOut = " + activityOut + "," + "description = " + description + "," + "isTransient = " + isTransient + "," + "statusLabel = " + statusLabel); } mWifiInfo.mEnabled = enabled; mWifiInfo.mConnected = qsIcon.visible; mWifiInfo.mWifiSignalIconId = qsIcon.icon; mWifiInfo.mSsid = description; mWifiInfo.mActivityIn = activityIn; mWifiInfo.mActivityOut = activityOut; mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription; mWifiInfo.mIsTransient = isTransient; mWifiInfo.mStatusLabel = statusLabel; refreshState(mWifiInfo); } @Override public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, int qsType, boolean activityIn, boolean activityOut, CharSequence typeContentDescription, CharSequence typeContentDescriptionHtml, CharSequence description, boolean isWide, int subId, boolean roaming) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setMobileDataIndicators: " + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + "," + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + "," + "statusType = " + statusType + "," + "qsType = " + qsType + "," + "activityIn = " + activityIn + "," + "activityOut = " + activityOut + "," + "typeContentDescription = " + typeContentDescription + "," + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + "," + "description = " + description + "," + "isWide = " + isWide + "," + "subId = " + subId + "," + "roaming = " + roaming); } if (qsIcon == null) { // Not data sim, don't display. return; } mCellularInfo.mDataSubscriptionName = mController.getMobileDataNetworkName(); mCellularInfo.mDataContentDescription = (description != null) ? typeContentDescriptionHtml : null; mCellularInfo.mMobileSignalIconId = qsIcon.icon; mCellularInfo.mActivityIn = activityIn; mCellularInfo.mActivityOut = activityOut; mCellularInfo.mRoaming = roaming; mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1; refreshState(mCellularInfo); } @Override public void setNoSims(boolean show, boolean simDetected) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "setNoSims: " + "show = " + show + "," + "simDetected = " + simDetected); } mCellularInfo.mNoSim = show; if (mCellularInfo.mNoSim) { // Make sure signal gets cleared out when no sims. mCellularInfo.mMobileSignalIconId = 0; } refreshState(mCellularInfo); } @Override public void setIsAirplaneMode(IconState icon) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "InternetTile-setIsAirplaneMode: " + "icon = " + (icon == null ? "" : icon.toString())); } mCellularInfo.mAirplaneModeEnabled = icon.visible; refreshState(mCellularInfo); } } @Override protected void handleUpdateState(SignalState state, Object arg) { Log.d(TAG, "handleUpdateState: " + "arg = " + arg); if (arg instanceof CellularCallbackInfo) { mLastTileState = 0; handleUpdateCellularState(state, arg); } else if (arg instanceof WifiCallbackInfo) { mLastTileState = 1; handleUpdateWifiState(state, arg); } else { // handleUpdateState will be triggered when user expands the QuickSetting panel with // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo // should be used to refresh the tile. if (mLastTileState == 0) { handleUpdateCellularState(state, mSignalCallback.mCellularInfo); } else if (mLastTileState == 1) { handleUpdateWifiState(state, mSignalCallback.mWifiInfo); } } } private void handleUpdateWifiState(SignalState state, Object arg) { WifiCallbackInfo cb = (WifiCallbackInfo) arg; boolean wifiConnected = cb.mEnabled && (cb.mWifiSignalIconId > 0) && (cb.mSsid != null); boolean wifiNotConnected = (cb.mWifiSignalIconId > 0) && (cb.mSsid == null); boolean enabledChanging = state.value != cb.mEnabled; if (enabledChanging) { fireToggleStateChanged(cb.mEnabled); } if (state.slash == null) { state.slash = new SlashState(); state.slash.rotation = 6; } state.slash.isSlashed = false; state.secondaryLabel = getSecondaryLabel(cb.mIsTransient, removeDoubleQuotes(cb.mSsid)); state.state = Tile.STATE_ACTIVE; state.dualTarget = true; state.value = cb.mEnabled; state.activityIn = cb.mEnabled && cb.mActivityIn; state.activityOut = cb.mEnabled && cb.mActivityOut; final StringBuffer minimalContentDescription = new StringBuffer(); final StringBuffer minimalStateDescription = new StringBuffer(); final Resources r = mContext.getResources(); // TODO(b/174753536): Use the new "Internet" string as state.label once available. if (cb.mIsTransient) { state.icon = ResourceIcon.get( com.android.internal.R.drawable.ic_signal_wifi_transient_animation); state.label = r.getString(R.string.quick_settings_internet_label); } else if (!state.value) { state.slash.isSlashed = true; state.state = Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED); state.label = r.getString(R.string.quick_settings_internet_label); } else if (wifiConnected) { state.icon = ResourceIcon.get(cb.mWifiSignalIconId); state.label = r.getString(R.string.quick_settings_internet_label); } else if (wifiNotConnected) { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_internet_label); } else { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_internet_label); } minimalContentDescription.append( mContext.getString(R.string.quick_settings_internet_label)).append(","); if (state.value) { if (wifiConnected) { minimalStateDescription.append(cb.mWifiSignalContentDescription); minimalContentDescription.append(removeDoubleQuotes(cb.mSsid)); if (!TextUtils.isEmpty(state.secondaryLabel)) { minimalContentDescription.append(",").append(state.secondaryLabel); } } } state.stateDescription = minimalStateDescription.toString(); state.contentDescription = minimalContentDescription.toString(); state.dualLabelContentDescription = r.getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); state.expandedAccessibilityClassName = Switch.class.getName(); } private void handleUpdateCellularState(SignalState state, Object arg) { CellularCallbackInfo cb = (CellularCallbackInfo) arg; final Resources r = mContext.getResources(); // TODO(b/174753536): Use the new "Internet" string as state.label once available. state.label = r.getString(R.string.quick_settings_internet_label); boolean mobileDataEnabled = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.value = mobileDataEnabled; state.activityIn = mobileDataEnabled && cb.mActivityIn; state.activityOut = mobileDataEnabled && cb.mActivityOut; state.expandedAccessibilityClassName = Switch.class.getName(); if (cb.mNoSim) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim); } else { state.icon = new SignalIcon(cb.mMobileSignalIconId); } if (cb.mNoSim) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short); } else if (cb.mAirplaneModeEnabled) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.status_bar_airplane); } else if (mobileDataEnabled) { state.state = Tile.STATE_ACTIVE; state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName, getMobileDataContentName(cb)); } else { state.state = Tile.STATE_INACTIVE; state.secondaryLabel = r.getString(R.string.cell_data_off); } state.contentDescription = state.label; if (state.state == Tile.STATE_INACTIVE) { // This information is appended later by converting the Tile.STATE_INACTIVE state. state.stateDescription = ""; } else { state.stateDescription = state.secondaryLabel; } } private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) { if (TextUtils.isEmpty(dataType)) { return Html.fromHtml((current == null ? "" : current.toString()), 0); } if (TextUtils.isEmpty(current)) { return Html.fromHtml((dataType == null ? "" : dataType.toString()), 0); } String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType); return Html.fromHtml(concat, 0); } private CharSequence getMobileDataContentName(CellularCallbackInfo cb) { if (cb.mRoaming && !TextUtils.isEmpty(cb.mDataContentDescription)) { String roaming = mContext.getString(R.string.data_connection_roaming); String dataDescription = cb.mDataContentDescription == null ? "" : cb.mDataContentDescription.toString(); return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription); } if (cb.mRoaming) { return mContext.getString(R.string.data_connection_roaming); } return cb.mDataContentDescription; } private static class SignalIcon extends Icon { private final int mState; SignalIcon(int state) { mState = state; } public int getState() { return mState; } @Override public Drawable getDrawable(Context context) { SignalDrawable d = new SignalDrawable(context); d.setLevel(getState()); return d; } } }
packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +9 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,15 @@ public interface NetworkController extends CallbackController<SignalCallback>, D Context context) { this(visible, icon, context.getString(contentDescription)); } @Override public String toString() { StringBuilder builder = new StringBuilder(); return builder.append("[visible=").append(visible).append(',') .append("icon=").append(icon).append(',') .append("contentDescription=").append(contentDescription).append(']') .toString(); } } /** Loading