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