Loading packages/SystemUI/src/com/android/systemui/lineage/LineageModule.kt +14 −0 Original line number Diff line number Diff line Loading @@ -20,11 +20,13 @@ import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.AmbientDisplayTile import com.android.systemui.qs.tiles.AODTile import com.android.systemui.qs.tiles.CaffeineTile import com.android.systemui.qs.tiles.CellularTile import com.android.systemui.qs.tiles.HeadsUpTile import com.android.systemui.qs.tiles.PowerShareTile import com.android.systemui.qs.tiles.ReadingModeTile import com.android.systemui.qs.tiles.SyncTile import com.android.systemui.qs.tiles.UsbTetherTile import com.android.systemui.qs.tiles.WifiTile import dagger.Binds import dagger.Module Loading @@ -51,6 +53,12 @@ interface LineageModule { @StringKey(CaffeineTile.TILE_SPEC) fun bindCaffeineTile(caffeineTile: CaffeineTile): QSTileImpl<*> /** Inject CellularTile into tileMap in QSModule */ @Binds @IntoMap @StringKey(CellularTile.TILE_SPEC) fun bindCellularTile(cellularTile: CellularTile): QSTileImpl<*> /** Inject HeadsUpTile into tileMap in QSModule */ @Binds @IntoMap Loading Loading @@ -80,4 +88,10 @@ interface LineageModule { @IntoMap @StringKey(UsbTetherTile.TILE_SPEC) fun bindUsbTetherTile(usbTetherTile: UsbTetherTile): QSTileImpl<*> /** Inject WifiTile into tileMap in QSModule */ @Binds @IntoMap @StringKey(WifiTile.TILE_SPEC) fun bindWifiTile(wifiTile: WifiTile): QSTileImpl<*> } packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java 0 → 100644 +294 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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 static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA; import android.annotation.NonNull; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.service.quicksettings.Tile; import android.telephony.SubscriptionManager; import android.text.Html; import android.text.TextUtils; import android.view.WindowManager.LayoutParams; import android.widget.Switch; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; import com.android.systemui.Prefs; import com.android.systemui.animation.Expandable; 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.FalsingManager; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.IconState; import com.android.systemui.statusbar.connectivity.MobileDataIndicators; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.KeyguardStateController; import javax.inject.Inject; /** Quick settings tile: Cellular **/ public class CellularTile extends QSTileImpl<BooleanState> { public static final String TILE_SPEC = "cell"; private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan"; private final NetworkController mController; private final DataUsageController mDataController; private final KeyguardStateController mKeyguard; private final CellSignalCallback mSignalCallback = new CellSignalCallback(); @Inject public CellularTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController, KeyguardStateController keyguardStateController ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mKeyguard = keyguardStateController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); } @Override public BooleanState newTileState() { return new BooleanState(); } @Override public Intent getLongClickIntent() { if (getState().state == Tile.STATE_UNAVAILABLE) { return new Intent(Settings.ACTION_WIRELESS_SETTINGS); } return getCellularSettingIntent(); } @Override protected void handleClick(@Nullable Expandable expandable) { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } if (mDataController.isMobileDataEnabled()) { maybeShowDisableDialog(); } else { mDataController.setMobileDataEnabled(true); } } private void maybeShowDisableDialog() { if (Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, false)) { // Directly turn off mobile data if the user has seen the dialog before. mDataController.setMobileDataEnabled(false); return; } String carrierName = mController.getMobileDataNetworkName(); boolean isInService = mController.isMobileDataNetworkInService(); if (TextUtils.isEmpty(carrierName) || !isInService) { carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier); } AlertDialog dialog = new Builder(mContext) .setTitle(R.string.mobile_data_disable_title) .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName)) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton( com.android.internal.R.string.alert_windows_notification_turn_off_action, (d, w) -> { mDataController.setMobileDataEnabled(false); Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true); }) .create(); dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG); SystemUIDialog.setShowForAllUsers(dialog, true); SystemUIDialog.registerDismissListener(dialog); SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing()); dialog.show(); } @Override protected void handleSecondaryClick(@Nullable Expandable expandable) { handleLongClick(expandable); } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_cellular_detail_title); } @Override protected void handleUpdateState(BooleanState state, Object arg) { CallbackInfo cb = (CallbackInfo) arg; if (cb == null) { cb = mSignalCallback.mInfo; } final Resources r = mContext.getResources(); state.label = r.getString(R.string.mobile_data); boolean mobileDataEnabled = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.value = mobileDataEnabled; state.expandedAccessibilityClassName = Switch.class.getName(); if (cb.noSim) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim); } else { state.icon = ResourceIcon.get(R.drawable.ic_swap_vert); } if (cb.noSim) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short); } else if (cb.airplaneModeEnabled) { 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( // Only show carrier name if there are more than 1 subscription cb.multipleSubs ? cb.dataSubscriptionName : "", 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.toString(), 0); } if (TextUtils.isEmpty(current)) { return Html.fromHtml(dataType.toString(), 0); } String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType); return Html.fromHtml(concat, 0); } private CharSequence getMobileDataContentName(CallbackInfo cb) { if (cb.roaming && !TextUtils.isEmpty(cb.dataContentDescription)) { String roaming = mContext.getString(R.string.data_connection_roaming); String dataDescription = cb.dataContentDescription.toString(); return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription); } if (cb.roaming) { return mContext.getString(R.string.data_connection_roaming); } return cb.dataContentDescription; } @Override public int getMetricsCategory() { return MetricsEvent.QS_CELLULAR; } @Override public boolean isAvailable() { return mController.hasMobileDataFeature() && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM; } private static final class CallbackInfo { boolean airplaneModeEnabled; @Nullable CharSequence dataSubscriptionName; @Nullable CharSequence dataContentDescription; boolean noSim; boolean roaming; boolean multipleSubs; } private final class CellSignalCallback implements SignalCallback { private final CallbackInfo mInfo = new CallbackInfo(); @Override public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) { if (indicators.qsIcon == null) { // Not data sim, don't display. return; } mInfo.dataSubscriptionName = mController.getMobileDataNetworkName(); mInfo.dataContentDescription = indicators.qsDescription != null ? indicators.typeContentDescriptionHtml : null; mInfo.roaming = indicators.roaming; mInfo.multipleSubs = mController.getNumberSubscriptions() > 1; refreshState(mInfo); } @Override public void setNoSims(boolean show, boolean simDetected) { mInfo.noSim = show; refreshState(mInfo); } @Override public void setIsAirplaneMode(@NonNull IconState icon) { mInfo.airplaneModeEnabled = icon.visible; refreshState(mInfo); } } static Intent getCellularSettingIntent() { Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); int dataSub = SubscriptionManager.getDefaultDataSubscriptionId(); if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { intent.putExtra(Settings.EXTRA_SUB_ID, SubscriptionManager.getDefaultDataSubscriptionId()); } return intent; } } packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java 0 → 100644 +271 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.annotation.NonNull; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.animation.Expandable; 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.FalsingManager; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSIconViewImpl; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.AccessPointController; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.connectivity.WifiIcons; import com.android.systemui.statusbar.connectivity.WifiIndicators; import javax.inject.Inject; /** Quick settings tile: Wifi **/ public class WifiTile extends QSTileImpl<BooleanState> { public static final String TILE_SPEC = "wifi"; private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); protected final NetworkController mController; private final AccessPointController mWifiController; private final QSTile.BooleanState mStateBeforeClick = newTileState(); protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); private boolean mExpectDisabled; @Inject public WifiTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController, AccessPointController accessPointController ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mWifiController = accessPointController; mController.observe(getLifecycle(), mSignalCallback); mStateBeforeClick.spec = "wifi"; } @Override public BooleanState newTileState() { return new BooleanState(); } @Override public Intent getLongClickIntent() { return WIFI_SETTINGS; } @Override protected void handleClick(@Nullable Expandable expandable) { // Secondary clicks are header clicks, just toggle. mState.copyTo(mStateBeforeClick); boolean wifiEnabled = mState.value; // Immediately enter transient state when turning on wifi. refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING); mController.setWifiEnabled(!wifiEnabled); mExpectDisabled = wifiEnabled; if (mExpectDisabled) { mHandler.postDelayed(() -> { if (mExpectDisabled) { mExpectDisabled = false; refreshState(); } }, QSIconViewImpl.QS_ANIM_LENGTH); } } @Override protected void handleSecondaryClick(@Nullable Expandable expandable) { if (!mWifiController.canConfigWifi()) { mActivityStarter.postStartActivityDismissingKeyguard( new Intent(Settings.ACTION_WIFI_SETTINGS), 0); return; } if (!mState.value) { mController.setWifiEnabled(true); } } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_wifi_label); } @Override protected void handleUpdateState(BooleanState state, Object arg) { if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg); final CallbackInfo cb = mSignalCallback.mInfo; if (mExpectDisabled) { if (cb.enabled) { return; // Ignore updates until disabled event occurs. } else { mExpectDisabled = false; } } boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING; boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null || cb.wifiSignalIconId != WifiIcons.QS_WIFI_NO_NETWORK); boolean wifiNotConnected = (cb.ssid == null) && (cb.wifiSignalIconId == WifiIcons.QS_WIFI_NO_NETWORK); boolean isTransient = transientEnabling || cb.isTransient; state.secondaryLabel = getSecondaryLabel(isTransient, cb.statusLabel); state.state = Tile.STATE_ACTIVE; state.dualTarget = true; state.value = transientEnabling || cb.enabled; final StringBuffer minimalContentDescription = new StringBuffer(); final StringBuffer minimalStateDescription = new StringBuffer(); final Resources r = mContext.getResources(); if (isTransient) { state.icon = ResourceIcon.get( com.android.internal.R.drawable.ic_signal_wifi_transient_animation); state.label = r.getString(R.string.quick_settings_wifi_label); } else if (!state.value) { state.state = Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED); state.label = r.getString(R.string.quick_settings_wifi_label); } else if (wifiConnected) { state.icon = ResourceIcon.get(cb.wifiSignalIconId); state.label = cb.ssid != null ? removeDoubleQuotes(cb.ssid) : getTileLabel(); } else if (wifiNotConnected) { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_wifi_label); } else { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_wifi_label); } minimalContentDescription.append( mContext.getString(R.string.quick_settings_wifi_label)).append(","); if (state.value) { if (wifiConnected) { minimalStateDescription.append(cb.wifiSignalContentDescription); minimalContentDescription.append(removeDoubleQuotes(cb.ssid)); 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 CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) { return isTransient ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient) : statusLabel; } @Override public int getMetricsCategory() { return MetricsEvent.QS_WIFI; } @Override public boolean isAvailable() { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI); } @Nullable 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; } protected static final class CallbackInfo { boolean enabled; boolean connected; int wifiSignalIconId; @Nullable String ssid; @Nullable String wifiSignalContentDescription; boolean isTransient; @Nullable public String statusLabel; @Override public String toString() { return new StringBuilder("CallbackInfo[") .append("enabled=").append(enabled) .append(",connected=").append(connected) .append(",wifiSignalIconId=").append(wifiSignalIconId) .append(",ssid=").append(ssid) .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription) .append(",isTransient=").append(isTransient) .append(']').toString(); } } protected final class WifiSignalCallback implements SignalCallback { final CallbackInfo mInfo = new CallbackInfo(); @Override public void setWifiIndicators(@NonNull WifiIndicators indicators) { if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled); if (indicators.qsIcon == null) { return; } mInfo.enabled = indicators.enabled; mInfo.connected = indicators.qsIcon.visible; mInfo.wifiSignalIconId = indicators.qsIcon.icon; mInfo.ssid = indicators.description; mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription; mInfo.isTransient = indicators.isTransient; mInfo.statusLabel = indicators.statusLabel; refreshState(); } } } Loading
packages/SystemUI/src/com/android/systemui/lineage/LineageModule.kt +14 −0 Original line number Diff line number Diff line Loading @@ -20,11 +20,13 @@ import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.AmbientDisplayTile import com.android.systemui.qs.tiles.AODTile import com.android.systemui.qs.tiles.CaffeineTile import com.android.systemui.qs.tiles.CellularTile import com.android.systemui.qs.tiles.HeadsUpTile import com.android.systemui.qs.tiles.PowerShareTile import com.android.systemui.qs.tiles.ReadingModeTile import com.android.systemui.qs.tiles.SyncTile import com.android.systemui.qs.tiles.UsbTetherTile import com.android.systemui.qs.tiles.WifiTile import dagger.Binds import dagger.Module Loading @@ -51,6 +53,12 @@ interface LineageModule { @StringKey(CaffeineTile.TILE_SPEC) fun bindCaffeineTile(caffeineTile: CaffeineTile): QSTileImpl<*> /** Inject CellularTile into tileMap in QSModule */ @Binds @IntoMap @StringKey(CellularTile.TILE_SPEC) fun bindCellularTile(cellularTile: CellularTile): QSTileImpl<*> /** Inject HeadsUpTile into tileMap in QSModule */ @Binds @IntoMap Loading Loading @@ -80,4 +88,10 @@ interface LineageModule { @IntoMap @StringKey(UsbTetherTile.TILE_SPEC) fun bindUsbTetherTile(usbTetherTile: UsbTetherTile): QSTileImpl<*> /** Inject WifiTile into tileMap in QSModule */ @Binds @IntoMap @StringKey(WifiTile.TILE_SPEC) fun bindWifiTile(wifiTile: WifiTile): QSTileImpl<*> }
packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java 0 → 100644 +294 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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 static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA; import android.annotation.NonNull; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.service.quicksettings.Tile; import android.telephony.SubscriptionManager; import android.text.Html; import android.text.TextUtils; import android.view.WindowManager.LayoutParams; import android.widget.Switch; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; import com.android.systemui.Prefs; import com.android.systemui.animation.Expandable; 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.FalsingManager; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.IconState; import com.android.systemui.statusbar.connectivity.MobileDataIndicators; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.KeyguardStateController; import javax.inject.Inject; /** Quick settings tile: Cellular **/ public class CellularTile extends QSTileImpl<BooleanState> { public static final String TILE_SPEC = "cell"; private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan"; private final NetworkController mController; private final DataUsageController mDataController; private final KeyguardStateController mKeyguard; private final CellSignalCallback mSignalCallback = new CellSignalCallback(); @Inject public CellularTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController, KeyguardStateController keyguardStateController ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mKeyguard = keyguardStateController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); } @Override public BooleanState newTileState() { return new BooleanState(); } @Override public Intent getLongClickIntent() { if (getState().state == Tile.STATE_UNAVAILABLE) { return new Intent(Settings.ACTION_WIRELESS_SETTINGS); } return getCellularSettingIntent(); } @Override protected void handleClick(@Nullable Expandable expandable) { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } if (mDataController.isMobileDataEnabled()) { maybeShowDisableDialog(); } else { mDataController.setMobileDataEnabled(true); } } private void maybeShowDisableDialog() { if (Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, false)) { // Directly turn off mobile data if the user has seen the dialog before. mDataController.setMobileDataEnabled(false); return; } String carrierName = mController.getMobileDataNetworkName(); boolean isInService = mController.isMobileDataNetworkInService(); if (TextUtils.isEmpty(carrierName) || !isInService) { carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier); } AlertDialog dialog = new Builder(mContext) .setTitle(R.string.mobile_data_disable_title) .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName)) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton( com.android.internal.R.string.alert_windows_notification_turn_off_action, (d, w) -> { mDataController.setMobileDataEnabled(false); Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true); }) .create(); dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG); SystemUIDialog.setShowForAllUsers(dialog, true); SystemUIDialog.registerDismissListener(dialog); SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing()); dialog.show(); } @Override protected void handleSecondaryClick(@Nullable Expandable expandable) { handleLongClick(expandable); } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_cellular_detail_title); } @Override protected void handleUpdateState(BooleanState state, Object arg) { CallbackInfo cb = (CallbackInfo) arg; if (cb == null) { cb = mSignalCallback.mInfo; } final Resources r = mContext.getResources(); state.label = r.getString(R.string.mobile_data); boolean mobileDataEnabled = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.value = mobileDataEnabled; state.expandedAccessibilityClassName = Switch.class.getName(); if (cb.noSim) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim); } else { state.icon = ResourceIcon.get(R.drawable.ic_swap_vert); } if (cb.noSim) { state.state = Tile.STATE_UNAVAILABLE; state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short); } else if (cb.airplaneModeEnabled) { 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( // Only show carrier name if there are more than 1 subscription cb.multipleSubs ? cb.dataSubscriptionName : "", 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.toString(), 0); } if (TextUtils.isEmpty(current)) { return Html.fromHtml(dataType.toString(), 0); } String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType); return Html.fromHtml(concat, 0); } private CharSequence getMobileDataContentName(CallbackInfo cb) { if (cb.roaming && !TextUtils.isEmpty(cb.dataContentDescription)) { String roaming = mContext.getString(R.string.data_connection_roaming); String dataDescription = cb.dataContentDescription.toString(); return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription); } if (cb.roaming) { return mContext.getString(R.string.data_connection_roaming); } return cb.dataContentDescription; } @Override public int getMetricsCategory() { return MetricsEvent.QS_CELLULAR; } @Override public boolean isAvailable() { return mController.hasMobileDataFeature() && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM; } private static final class CallbackInfo { boolean airplaneModeEnabled; @Nullable CharSequence dataSubscriptionName; @Nullable CharSequence dataContentDescription; boolean noSim; boolean roaming; boolean multipleSubs; } private final class CellSignalCallback implements SignalCallback { private final CallbackInfo mInfo = new CallbackInfo(); @Override public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) { if (indicators.qsIcon == null) { // Not data sim, don't display. return; } mInfo.dataSubscriptionName = mController.getMobileDataNetworkName(); mInfo.dataContentDescription = indicators.qsDescription != null ? indicators.typeContentDescriptionHtml : null; mInfo.roaming = indicators.roaming; mInfo.multipleSubs = mController.getNumberSubscriptions() > 1; refreshState(mInfo); } @Override public void setNoSims(boolean show, boolean simDetected) { mInfo.noSim = show; refreshState(mInfo); } @Override public void setIsAirplaneMode(@NonNull IconState icon) { mInfo.airplaneModeEnabled = icon.visible; refreshState(mInfo); } } static Intent getCellularSettingIntent() { Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); int dataSub = SubscriptionManager.getDefaultDataSubscriptionId(); if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { intent.putExtra(Settings.EXTRA_SUB_ID, SubscriptionManager.getDefaultDataSubscriptionId()); } return intent; } }
packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java 0 → 100644 +271 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.annotation.NonNull; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.animation.Expandable; 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.FalsingManager; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSIconViewImpl; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.AccessPointController; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.connectivity.WifiIcons; import com.android.systemui.statusbar.connectivity.WifiIndicators; import javax.inject.Inject; /** Quick settings tile: Wifi **/ public class WifiTile extends QSTileImpl<BooleanState> { public static final String TILE_SPEC = "wifi"; private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); protected final NetworkController mController; private final AccessPointController mWifiController; private final QSTile.BooleanState mStateBeforeClick = newTileState(); protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); private boolean mExpectDisabled; @Inject public WifiTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController, AccessPointController accessPointController ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; mWifiController = accessPointController; mController.observe(getLifecycle(), mSignalCallback); mStateBeforeClick.spec = "wifi"; } @Override public BooleanState newTileState() { return new BooleanState(); } @Override public Intent getLongClickIntent() { return WIFI_SETTINGS; } @Override protected void handleClick(@Nullable Expandable expandable) { // Secondary clicks are header clicks, just toggle. mState.copyTo(mStateBeforeClick); boolean wifiEnabled = mState.value; // Immediately enter transient state when turning on wifi. refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING); mController.setWifiEnabled(!wifiEnabled); mExpectDisabled = wifiEnabled; if (mExpectDisabled) { mHandler.postDelayed(() -> { if (mExpectDisabled) { mExpectDisabled = false; refreshState(); } }, QSIconViewImpl.QS_ANIM_LENGTH); } } @Override protected void handleSecondaryClick(@Nullable Expandable expandable) { if (!mWifiController.canConfigWifi()) { mActivityStarter.postStartActivityDismissingKeyguard( new Intent(Settings.ACTION_WIFI_SETTINGS), 0); return; } if (!mState.value) { mController.setWifiEnabled(true); } } @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_wifi_label); } @Override protected void handleUpdateState(BooleanState state, Object arg) { if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg); final CallbackInfo cb = mSignalCallback.mInfo; if (mExpectDisabled) { if (cb.enabled) { return; // Ignore updates until disabled event occurs. } else { mExpectDisabled = false; } } boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING; boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null || cb.wifiSignalIconId != WifiIcons.QS_WIFI_NO_NETWORK); boolean wifiNotConnected = (cb.ssid == null) && (cb.wifiSignalIconId == WifiIcons.QS_WIFI_NO_NETWORK); boolean isTransient = transientEnabling || cb.isTransient; state.secondaryLabel = getSecondaryLabel(isTransient, cb.statusLabel); state.state = Tile.STATE_ACTIVE; state.dualTarget = true; state.value = transientEnabling || cb.enabled; final StringBuffer minimalContentDescription = new StringBuffer(); final StringBuffer minimalStateDescription = new StringBuffer(); final Resources r = mContext.getResources(); if (isTransient) { state.icon = ResourceIcon.get( com.android.internal.R.drawable.ic_signal_wifi_transient_animation); state.label = r.getString(R.string.quick_settings_wifi_label); } else if (!state.value) { state.state = Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED); state.label = r.getString(R.string.quick_settings_wifi_label); } else if (wifiConnected) { state.icon = ResourceIcon.get(cb.wifiSignalIconId); state.label = cb.ssid != null ? removeDoubleQuotes(cb.ssid) : getTileLabel(); } else if (wifiNotConnected) { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_wifi_label); } else { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_wifi_label); } minimalContentDescription.append( mContext.getString(R.string.quick_settings_wifi_label)).append(","); if (state.value) { if (wifiConnected) { minimalStateDescription.append(cb.wifiSignalContentDescription); minimalContentDescription.append(removeDoubleQuotes(cb.ssid)); 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 CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) { return isTransient ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient) : statusLabel; } @Override public int getMetricsCategory() { return MetricsEvent.QS_WIFI; } @Override public boolean isAvailable() { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI); } @Nullable 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; } protected static final class CallbackInfo { boolean enabled; boolean connected; int wifiSignalIconId; @Nullable String ssid; @Nullable String wifiSignalContentDescription; boolean isTransient; @Nullable public String statusLabel; @Override public String toString() { return new StringBuilder("CallbackInfo[") .append("enabled=").append(enabled) .append(",connected=").append(connected) .append(",wifiSignalIconId=").append(wifiSignalIconId) .append(",ssid=").append(ssid) .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription) .append(",isTransient=").append(isTransient) .append(']').toString(); } } protected final class WifiSignalCallback implements SignalCallback { final CallbackInfo mInfo = new CallbackInfo(); @Override public void setWifiIndicators(@NonNull WifiIndicators indicators) { if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled); if (indicators.qsIcon == null) { return; } mInfo.enabled = indicators.enabled; mInfo.connected = indicators.qsIcon.visible; mInfo.wifiSignalIconId = indicators.qsIcon.icon; mInfo.ssid = indicators.description; mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription; mInfo.isTransient = indicators.isTransient; mInfo.statusLabel = indicators.statusLabel; refreshState(); } } }