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 17 package com.android.systemui.qs.tiles; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.res.Resources; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 import android.view.ViewGroup; 26 27 import com.android.internal.logging.MetricsLogger; 28 import com.android.systemui.R; 29 import com.android.systemui.qs.QSTile; 30 import com.android.systemui.qs.QSTileView; 31 import com.android.systemui.qs.SignalTileView; 32 import com.android.systemui.statusbar.policy.NetworkController; 33 import com.android.systemui.statusbar.policy.NetworkController.IconState; 34 import com.android.systemui.statusbar.policy.NetworkController.MobileDataController; 35 import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo; 36 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; 37 import com.android.systemui.statusbar.policy.SignalCallbackAdapter; 38 39 /** Quick settings tile: Cellular **/ 40 public class CellularTile extends QSTile<QSTile.SignalState> { 41 private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName( 42 "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity")); 43 44 private final NetworkController mController; 45 private final MobileDataController mDataController; 46 private final CellularDetailAdapter mDetailAdapter; 47 48 private final CellSignalCallback mSignalCallback = new CellSignalCallback(); 49 50 public CellularTile(Host host) { 51 super(host); 52 mController = host.getNetworkController(); 53 mDataController = mController.getMobileDataController(); 54 mDetailAdapter = new CellularDetailAdapter(); 55 } 56 57 @Override 58 protected SignalState newTileState() { 59 return new SignalState(); 60 } 61 62 @Override 63 public DetailAdapter getDetailAdapter() { 64 return mDetailAdapter; 65 } 66 67 @Override 68 public void setListening(boolean listening) { 69 if (listening) { 70 mController.addSignalCallback(mSignalCallback); 71 } else { 72 mController.removeSignalCallback(mSignalCallback); 73 } 74 } 75 76 @Override 77 public QSTileView createTileView(Context context) { 78 return new SignalTileView(context); 79 } 80 81 @Override 82 protected void handleClick() { 83 MetricsLogger.action(mContext, getMetricsCategory()); 84 if (mDataController.isMobileDataSupported()) { 85 showDetail(true); 86 } else { 87 mHost.startActivityDismissingKeyguard(CELLULAR_SETTINGS); 88 } 89 } 90 91 @Override 92 protected void handleUpdateState(SignalState state, Object arg) { 93 state.visible = mController.hasMobileDataFeature(); 94 if (!state.visible) return; 95 CallbackInfo cb = (CallbackInfo) arg; 96 if (cb == null) { 97 cb = mSignalCallback.mInfo; 98 } 99 100 final Resources r = mContext.getResources(); 101 final int iconId = cb.noSim ? R.drawable.ic_qs_no_sim 102 : !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled 103 : cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId 104 : R.drawable.ic_qs_signal_no_signal; 105 state.icon = ResourceIcon.get(iconId); 106 state.isOverlayIconWide = cb.isDataTypeIconWide; 107 state.autoMirrorDrawable = !cb.noSim; 108 state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) ? cb.dataTypeIconId : 0; 109 state.filter = iconId != R.drawable.ic_qs_no_sim; 110 state.activityIn = cb.enabled && cb.activityIn; 111 state.activityOut = cb.enabled && cb.activityOut; 112 113 state.label = cb.enabled 114 ? removeTrailingPeriod(cb.enabledDesc) 115 : r.getString(R.string.quick_settings_rssi_emergency_only); 116 117 final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0) 118 ? cb.signalContentDescription 119 : r.getString(R.string.accessibility_no_signal); 120 final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled 121 ? cb.dataContentDescription 122 : r.getString(R.string.accessibility_no_data); 123 state.contentDescription = r.getString( 124 R.string.accessibility_quick_settings_mobile, 125 signalContentDesc, dataContentDesc, 126 state.label); 127 } 128 129 @Override 130 public int getMetricsCategory() { 131 return MetricsLogger.QS_CELLULAR; 132 } 133 134 // Remove the period from the network name 135 public static String removeTrailingPeriod(String string) { 136 if (string == null) return null; 137 final int length = string.length(); 138 if (string.endsWith(".")) { 139 return string.substring(0, length - 1); 140 } 141 return string; 142 } 143 144 private static final class CallbackInfo { 145 boolean enabled; 146 boolean wifiEnabled; 147 boolean airplaneModeEnabled; 148 int mobileSignalIconId; 149 String signalContentDescription; 150 int dataTypeIconId; 151 String dataContentDescription; 152 boolean activityIn; 153 boolean activityOut; 154 String enabledDesc; 155 boolean noSim; 156 boolean isDataTypeIconWide; 157 } 158 159 private final class CellSignalCallback extends SignalCallbackAdapter { 160 private final CallbackInfo mInfo = new CallbackInfo(); 161 @Override 162 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, 163 boolean activityIn, boolean activityOut, String description) { 164 mInfo.wifiEnabled = enabled; 165 refreshState(mInfo); 166 } 167 168 @Override 169 public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, 170 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, 171 String description, boolean isWide, int subId) { 172 if (qsIcon == null) { 173 // Not data sim, don't display. 174 return; 175 } 176 mInfo.enabled = qsIcon.visible; 177 mInfo.mobileSignalIconId = qsIcon.icon; 178 mInfo.signalContentDescription = qsIcon.contentDescription; 179 mInfo.dataTypeIconId = qsType; 180 mInfo.dataContentDescription = typeContentDescription; 181 mInfo.activityIn = activityIn; 182 mInfo.activityOut = activityOut; 183 mInfo.enabledDesc = description; 184 mInfo.isDataTypeIconWide = qsType != 0 && isWide; 185 refreshState(mInfo); 186 } 187 188 @Override 189 public void setNoSims(boolean show) { 190 mInfo.noSim = show; 191 if (mInfo.noSim) { 192 // Make sure signal gets cleared out when no sims. 193 mInfo.mobileSignalIconId = 0; 194 mInfo.dataTypeIconId = 0; 195 // Show a No SIMs description to avoid emergency calls message. 196 mInfo.enabled = true; 197 mInfo.enabledDesc = mContext.getString( 198 R.string.keyguard_missing_sim_message_short); 199 mInfo.signalContentDescription = mInfo.enabledDesc; 200 } 201 refreshState(mInfo); 202 } 203 204 @Override 205 public void setIsAirplaneMode(IconState icon) { 206 mInfo.airplaneModeEnabled = icon.visible; 207 refreshState(mInfo); 208 } 209 210 @Override 211 public void setMobileDataEnabled(boolean enabled) { 212 mDetailAdapter.setMobileDataEnabled(enabled); 213 } 214 }; 215 216 private final class CellularDetailAdapter implements DetailAdapter { 217 218 @Override 219 public int getTitle() { 220 return R.string.quick_settings_cellular_detail_title; 221 } 222 223 @Override 224 public Boolean getToggleState() { 225 return mDataController.isMobileDataSupported() 226 ? mDataController.isMobileDataEnabled() 227 : null; 228 } 229 230 @Override 231 public Intent getSettingsIntent() { 232 return CELLULAR_SETTINGS; 233 } 234 235 @Override 236 public void setToggleState(boolean state) { 237 MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, state); 238 mDataController.setMobileDataEnabled(state); 239 } 240 241 @Override 242 public int getMetricsCategory() { 243 return MetricsLogger.QS_DATAUSAGEDETAIL; 244 } 245 246 @Override 247 public View createDetailView(Context context, View convertView, ViewGroup parent) { 248 final DataUsageDetailView v = (DataUsageDetailView) (convertView != null 249 ? convertView 250 : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false)); 251 final DataUsageInfo info = mDataController.getDataUsageInfo(); 252 if (info == null) return v; 253 v.bind(info); 254 return v; 255 } 256 257 public void setMobileDataEnabled(boolean enabled) { 258 fireToggleStateChanged(enabled); 259 } 260 } 261 } 262