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