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.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26
27import com.android.internal.logging.MetricsLogger;
28import com.android.systemui.R;
29import com.android.systemui.qs.QSTile;
30import com.android.systemui.qs.QSTileView;
31import com.android.systemui.qs.SignalTileView;
32import com.android.systemui.statusbar.policy.NetworkController;
33import com.android.systemui.statusbar.policy.NetworkController.IconState;
34import com.android.systemui.statusbar.policy.NetworkController.MobileDataController;
35import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;
36import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
37import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
38
39/** Quick settings tile: Cellular **/
40public 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