WifiTile.java revision b98f747c714ff8252471ca0a3295c2cb9ccb4f3a
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.Context;
20import android.content.Intent;
21import android.content.res.Resources;
22import android.provider.Settings;
23import android.util.Log;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.View.OnClickListener;
27import android.view.ViewGroup;
28import android.widget.ImageView;
29import android.widget.LinearLayout;
30import android.widget.TextView;
31
32import com.android.systemui.R;
33import com.android.systemui.qs.QSTile;
34import com.android.systemui.qs.QSTileView;
35import com.android.systemui.qs.SignalTileView;
36import com.android.systemui.statusbar.policy.NetworkController;
37import com.android.systemui.statusbar.policy.NetworkController.AccessPoint;
38import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
39
40/** Quick settings tile: Wifi **/
41public class WifiTile extends QSTile<QSTile.SignalState> {
42    private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
43    private static final int MAX_ITEMS = 4; // TODO temporary visual restriction
44
45    private final NetworkController mController;
46    private final WifiDetailAdapter mDetailAdapter;
47
48    public WifiTile(Host host) {
49        super(host);
50        mController = host.getNetworkController();
51        mDetailAdapter = new WifiDetailAdapter();
52    }
53
54    @Override
55    public boolean supportsDualTargets() {
56        return true;
57    }
58
59    @Override
60    protected SignalState newTileState() {
61        return new SignalState();
62    }
63
64    @Override
65    public void setListening(boolean listening) {
66        if (listening) {
67            mController.addNetworkSignalChangedCallback(mCallback);
68            mController.addAccessPointCallback(mDetailAdapter);
69            mController.scanForAccessPoints();
70        } else {
71            mController.removeNetworkSignalChangedCallback(mCallback);
72            mController.removeAccessPointCallback(mDetailAdapter);
73        }
74    }
75
76    @Override
77    public DetailAdapter getDetailAdapter() {
78        return mDetailAdapter;
79    }
80
81    @Override
82    public QSTileView createTileView(Context context) {
83        return new SignalTileView(context);
84    }
85
86    @Override
87    protected void handleClick() {
88        mController.setWifiEnabled(!mState.enabled);
89    }
90
91    @Override
92    protected void handleSecondaryClick() {
93        showDetail(true);
94    }
95
96    @Override
97    protected void handleUpdateState(SignalState state, Object arg) {
98        state.visible = true;
99        if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
100        if (arg == null) return;
101        CallbackInfo cb = (CallbackInfo) arg;
102
103        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
104        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
105        boolean enabledChanging = state.enabled != cb.enabled;
106        if (enabledChanging) {
107            mDetailAdapter.postUpdateItems();
108            fireToggleStateChanged(cb.enabled);
109        }
110        state.enabled = cb.enabled;
111        state.connected = wifiConnected;
112        state.activityIn = cb.enabled && cb.activityIn;
113        state.activityOut = cb.enabled && cb.activityOut;
114        state.filter = true;
115        final String signalContentDescription;
116        final Resources r = mContext.getResources();
117        if (wifiConnected) {
118            state.iconId = cb.wifiSignalIconId;
119            state.label = removeDoubleQuotes(cb.enabledDesc);
120            signalContentDescription = cb.wifiSignalContentDescription;
121        } else if (wifiNotConnected) {
122            state.iconId = R.drawable.ic_qs_wifi_0;
123            state.label = r.getString(R.string.quick_settings_wifi_label);
124            signalContentDescription = r.getString(R.string.accessibility_no_wifi);
125        } else {
126            state.iconId = R.drawable.ic_qs_wifi_no_network;
127            state.label = r.getString(R.string.quick_settings_wifi_label);
128            signalContentDescription = r.getString(R.string.accessibility_wifi_off);
129        }
130        state.contentDescription = mContext.getString(
131                R.string.accessibility_quick_settings_wifi,
132                signalContentDescription,
133                state.connected ? state.label : "");
134    }
135
136    private static String removeDoubleQuotes(String string) {
137        if (string == null) return null;
138        final int length = string.length();
139        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
140            return string.substring(1, length - 1);
141        }
142        return string;
143    }
144
145    private static final class CallbackInfo {
146        boolean enabled;
147        int wifiSignalIconId;
148        String enabledDesc;
149        boolean activityIn;
150        boolean activityOut;
151        String wifiSignalContentDescription;
152
153        @Override
154        public String toString() {
155            return new StringBuilder("CallbackInfo[")
156                .append("enabled=").append(enabled)
157                .append(",wifiSignalIconId=").append(wifiSignalIconId)
158                .append(",enabledDesc=").append(enabledDesc)
159                .append(",activityIn=").append(activityIn)
160                .append(",activityOut=").append(activityOut)
161                .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
162                .append(']').toString();
163        }
164    }
165
166    private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
167        @Override
168        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
169                boolean activityIn, boolean activityOut,
170                String wifiSignalContentDescriptionId, String description) {
171            if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
172            final CallbackInfo info = new CallbackInfo();
173            info.enabled = enabled;
174            info.wifiSignalIconId = wifiSignalIconId;
175            info.enabledDesc = description;
176            info.activityIn = activityIn;
177            info.activityOut = activityOut;
178            info.wifiSignalContentDescription = wifiSignalContentDescriptionId;
179            refreshState(info);
180        }
181
182        @Override
183        public void onMobileDataSignalChanged(boolean enabled,
184                int mobileSignalIconId,
185                String mobileSignalContentDescriptionId, int dataTypeIconId,
186                boolean activityIn, boolean activityOut,
187                String dataTypeContentDescriptionId, String description, boolean noSim) {
188            // noop
189        }
190
191        @Override
192        public void onAirplaneModeChanged(boolean enabled) {
193            // noop
194        }
195
196        @Override
197        public void onMobileDataEnabled(boolean enabled) {
198            // noop
199        }
200    };
201
202    private final class WifiDetailAdapter implements DetailAdapter,
203            NetworkController.AccessPointCallback {
204
205        private LinearLayout mItems;
206        private AccessPoint[] mAccessPoints;
207
208        @Override
209        public int getTitle() {
210            return R.string.quick_settings_wifi_label;
211        }
212
213        public Intent getSettingsIntent() {
214            return WIFI_SETTINGS;
215        }
216
217        @Override
218        public Boolean getToggleState() {
219            return mState.enabled;
220        }
221
222        @Override
223        public void setToggleState(boolean state) {
224            if (DEBUG) Log.d(TAG, "setToggleState " + state);
225            mController.setWifiEnabled(state);
226            showDetail(false);
227        }
228
229        @Override
230        public View createDetailView(Context context, View convertView, ViewGroup parent) {
231            if (convertView != null) return convertView;
232            mItems = new LinearLayout(context);
233            mItems.setOrientation(LinearLayout.VERTICAL);
234            updateItems();
235            return mItems;
236        }
237
238        @Override
239        public void onAccessPointsChanged(final AccessPoint[] accessPoints) {
240            mUiHandler.post(new Runnable() {
241                @Override
242                public void run() {
243                    mAccessPoints = accessPoints;
244                    updateItems();
245                }
246            });
247        }
248
249        public void postUpdateItems() {
250            mUiHandler.post(new Runnable() {
251                @Override
252                public void run() {
253                    updateItems();
254                }
255            });
256        }
257
258        private void updateItems() {
259            if (mItems == null) return;
260            mItems.removeAllViews();
261            if (mAccessPoints == null || mAccessPoints.length == 0 || !mState.enabled) return;
262            for (int i = 0; i < mAccessPoints.length; i++) {
263                final AccessPoint ap = mAccessPoints[i];
264                if (ap == null) continue;
265                final View item = LayoutInflater.from(mContext).inflate(R.layout.qs_detail_item,
266                        mItems, false);
267                final ImageView iv = (ImageView) item.findViewById(android.R.id.icon);
268                iv.setImageResource(ap.iconId);
269                final TextView title = (TextView) item.findViewById(android.R.id.title);
270                title.setText(ap.ssid);
271                final TextView summary = (TextView) item.findViewById(android.R.id.summary);
272                if (ap.isConnected) {
273                    item.setMinimumHeight(mContext.getResources()
274                            .getDimensionPixelSize(R.dimen.qs_detail_item_height_twoline));
275                    summary.setText(R.string.quick_settings_connected);
276                } else {
277                    summary.setVisibility(View.GONE);
278                }
279                item.setOnClickListener(new OnClickListener() {
280                    @Override
281                    public void onClick(View v) {
282                        if (!ap.isConnected) {
283                            mController.connect(ap);
284                        }
285                        showDetail(false);
286                    }
287                });
288                mItems.addView(item);
289                if (mItems.getChildCount() == MAX_ITEMS) break;
290            }
291        }
292    };
293}
294