CellularTile.java revision 9ca184877e858782abde8c2ef3c011498845a55d
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui.qs.tiles; 18 19import android.app.AlertDialog; 20import android.app.AlertDialog.Builder; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.res.Resources; 25import android.service.quicksettings.Tile; 26import android.view.LayoutInflater; 27import android.view.View; 28import android.view.ViewGroup; 29import android.view.WindowManager.LayoutParams; 30import android.widget.Switch; 31 32import com.android.internal.logging.MetricsLogger; 33import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 34import com.android.settingslib.net.DataUsageController; 35import com.android.systemui.Dependency; 36import com.android.systemui.R; 37import com.android.systemui.R.string; 38import com.android.systemui.plugins.ActivityStarter; 39import com.android.systemui.plugins.qs.DetailAdapter; 40import com.android.systemui.plugins.qs.QSIconView; 41import com.android.systemui.plugins.qs.QSTile.SignalState; 42import com.android.systemui.qs.CellTileView; 43import com.android.systemui.qs.CellTileView.SignalIcon; 44import com.android.systemui.qs.QSHost; 45import com.android.systemui.qs.tileimpl.QSTileImpl; 46import com.android.systemui.statusbar.phone.SystemUIDialog; 47import com.android.systemui.statusbar.policy.KeyguardMonitor; 48import com.android.systemui.statusbar.policy.NetworkController; 49import com.android.systemui.statusbar.policy.NetworkController.IconState; 50import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; 51 52/** Quick settings tile: Cellular **/ 53public class CellularTile extends QSTileImpl<SignalState> { 54 static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName( 55 "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity")); 56 57 private final NetworkController mController; 58 private final DataUsageController mDataController; 59 private final CellularDetailAdapter mDetailAdapter; 60 61 private final CellSignalCallback mSignalCallback = new CellSignalCallback(); 62 private final ActivityStarter mActivityStarter; 63 private final KeyguardMonitor mKeyguardMonitor; 64 65 public CellularTile(QSHost host) { 66 super(host); 67 mController = Dependency.get(NetworkController.class); 68 mActivityStarter = Dependency.get(ActivityStarter.class); 69 mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); 70 mDataController = mController.getMobileDataController(); 71 mDetailAdapter = new CellularDetailAdapter(); 72 } 73 74 @Override 75 public SignalState newTileState() { 76 return new SignalState(); 77 } 78 79 @Override 80 public DetailAdapter getDetailAdapter() { 81 return mDetailAdapter; 82 } 83 84 @Override 85 public void setListening(boolean listening) { 86 if (listening) { 87 mController.addCallback(mSignalCallback); 88 } else { 89 mController.removeCallback(mSignalCallback); 90 } 91 } 92 93 @Override 94 public QSIconView createTileView(Context context) { 95 return new CellTileView(context); 96 } 97 98 @Override 99 public Intent getLongClickIntent() { 100 return CELLULAR_SETTINGS; 101 } 102 103 @Override 104 protected void handleClick() { 105 if (mDataController.isMobileDataEnabled()) { 106 if (mKeyguardMonitor.isSecure() && !mKeyguardMonitor.canSkipBouncer()) { 107 mActivityStarter.postQSRunnableDismissingKeyguard(this::showDisableDialog); 108 } else { 109 mUiHandler.post(this::showDisableDialog); 110 } 111 } else { 112 mDataController.setMobileDataEnabled(true); 113 } 114 } 115 116 private void showDisableDialog() { 117 mHost.collapsePanels(); 118 AlertDialog dialog = new Builder(mContext) 119 .setMessage(string.data_usage_disable_mobile) 120 .setNegativeButton(android.R.string.cancel, null) 121 .setPositiveButton( 122 com.android.internal.R.string.alert_windows_notification_turn_off_action, 123 (d, w) -> mDataController.setMobileDataEnabled(false)) 124 .create(); 125 dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG); 126 SystemUIDialog.setShowForAllUsers(dialog, true); 127 SystemUIDialog.registerDismissListener(dialog); 128 SystemUIDialog.setWindowOnTop(dialog); 129 dialog.show(); 130 } 131 132 @Override 133 protected void handleSecondaryClick() { 134 if (mDataController.isMobileDataSupported()) { 135 showDetail(true); 136 } else { 137 mActivityStarter.postStartActivityDismissingKeyguard(CELLULAR_SETTINGS, 0); 138 } 139 } 140 141 @Override 142 public CharSequence getTileLabel() { 143 return mContext.getString(R.string.quick_settings_cellular_detail_title); 144 } 145 146 @Override 147 protected void handleUpdateState(SignalState state, Object arg) { 148 CallbackInfo cb = (CallbackInfo) arg; 149 if (cb == null) { 150 cb = mSignalCallback.mInfo; 151 } 152 153 final Resources r = mContext.getResources(); 154 state.activityIn = cb.enabled && cb.activityIn; 155 state.activityOut = cb.enabled && cb.activityOut; 156 state.isOverlayIconWide = cb.isDataTypeIconWide; 157 state.overlayIconId = cb.dataTypeIconId; 158 159 state.label = r.getString(R.string.mobile_data); 160 161 final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0) 162 ? cb.signalContentDescription 163 : r.getString(R.string.accessibility_no_signal); 164 if (cb.noSim) { 165 state.contentDescription = state.label; 166 } else { 167 state.contentDescription = signalContentDesc + ", " + state.label; 168 } 169 170 state.expandedAccessibilityClassName = Switch.class.getName(); 171 state.value = mDataController.isMobileDataSupported() 172 && mDataController.isMobileDataEnabled(); 173 174 state.icon = new SignalIcon(cb.mobileSignalIconId); 175 if (cb.airplaneModeEnabled) { 176 state.state = Tile.STATE_INACTIVE; 177 } else { 178 state.state = Tile.STATE_ACTIVE; 179 } 180 } 181 182 @Override 183 public int getMetricsCategory() { 184 return MetricsEvent.QS_CELLULAR; 185 } 186 187 @Override 188 public boolean isAvailable() { 189 return mController.hasMobileDataFeature(); 190 } 191 192 // Remove the period from the network name 193 public static String removeTrailingPeriod(String string) { 194 if (string == null) return null; 195 final int length = string.length(); 196 if (string.endsWith(".")) { 197 return string.substring(0, length - 1); 198 } 199 return string; 200 } 201 202 private static final class CallbackInfo { 203 boolean enabled; 204 boolean wifiEnabled; 205 boolean airplaneModeEnabled; 206 int mobileSignalIconId; 207 String signalContentDescription; 208 int dataTypeIconId; 209 String dataContentDescription; 210 boolean activityIn; 211 boolean activityOut; 212 String enabledDesc; 213 boolean noSim; 214 boolean isDataTypeIconWide; 215 boolean roaming; 216 } 217 218 private final class CellSignalCallback implements SignalCallback { 219 private final CallbackInfo mInfo = new CallbackInfo(); 220 @Override 221 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, 222 boolean activityIn, boolean activityOut, String description, boolean isTransient) { 223 mInfo.wifiEnabled = enabled; 224 refreshState(mInfo); 225 } 226 227 @Override 228 public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, 229 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, 230 String description, boolean isWide, int subId, boolean roaming) { 231 if (qsIcon == null) { 232 // Not data sim, don't display. 233 return; 234 } 235 mInfo.enabled = qsIcon.visible; 236 mInfo.mobileSignalIconId = qsIcon.icon; 237 mInfo.signalContentDescription = qsIcon.contentDescription; 238 mInfo.dataTypeIconId = qsType; 239 mInfo.dataContentDescription = typeContentDescription; 240 mInfo.activityIn = activityIn; 241 mInfo.activityOut = activityOut; 242 mInfo.enabledDesc = description; 243 mInfo.isDataTypeIconWide = qsType != 0 && isWide; 244 mInfo.roaming = roaming; 245 refreshState(mInfo); 246 } 247 248 @Override 249 public void setNoSims(boolean show) { 250 mInfo.noSim = show; 251 if (mInfo.noSim) { 252 // Make sure signal gets cleared out when no sims. 253 mInfo.mobileSignalIconId = 0; 254 mInfo.dataTypeIconId = 0; 255 // Show a No SIMs description to avoid emergency calls message. 256 mInfo.enabled = true; 257 mInfo.enabledDesc = mContext.getString( 258 R.string.keyguard_missing_sim_message_short); 259 mInfo.signalContentDescription = mInfo.enabledDesc; 260 } 261 refreshState(mInfo); 262 } 263 264 @Override 265 public void setIsAirplaneMode(IconState icon) { 266 mInfo.airplaneModeEnabled = icon.visible; 267 refreshState(mInfo); 268 } 269 270 @Override 271 public void setMobileDataEnabled(boolean enabled) { 272 mDetailAdapter.setMobileDataEnabled(enabled); 273 } 274 }; 275 276 private final class CellularDetailAdapter implements DetailAdapter { 277 278 @Override 279 public CharSequence getTitle() { 280 return mContext.getString(R.string.quick_settings_cellular_detail_title); 281 } 282 283 @Override 284 public Boolean getToggleState() { 285 return mDataController.isMobileDataSupported() 286 ? mDataController.isMobileDataEnabled() 287 : null; 288 } 289 290 @Override 291 public Intent getSettingsIntent() { 292 return CELLULAR_SETTINGS; 293 } 294 295 @Override 296 public void setToggleState(boolean state) { 297 MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, state); 298 mDataController.setMobileDataEnabled(state); 299 } 300 301 @Override 302 public int getMetricsCategory() { 303 return MetricsEvent.QS_DATAUSAGEDETAIL; 304 } 305 306 @Override 307 public View createDetailView(Context context, View convertView, ViewGroup parent) { 308 final DataUsageDetailView v = (DataUsageDetailView) (convertView != null 309 ? convertView 310 : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false)); 311 final DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo(); 312 if (info == null) return v; 313 v.bind(info); 314 v.findViewById(R.id.roaming_text).setVisibility(mSignalCallback.mInfo.roaming 315 ? View.VISIBLE : View.INVISIBLE); 316 return v; 317 } 318 319 public void setMobileDataEnabled(boolean enabled) { 320 fireToggleStateChanged(enabled); 321 } 322 } 323} 324