QuickSettings.java revision 21c7153d30071dcbeb92daa1fd48ed181e42aef3
1/*
2 * Copyright (C) 2012 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.statusbar.phone;
18
19import android.app.Dialog;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.CursorLoader;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.Loader;
28import android.content.res.Resources;
29import android.database.Cursor;
30import android.graphics.drawable.ClipDrawable;
31import android.hardware.display.DisplayManager;
32import android.hardware.display.WifiDisplay;
33import android.hardware.display.WifiDisplayStatus;
34import android.net.Uri;
35import android.provider.ContactsContract;
36import android.provider.Settings;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.ViewGroup;
40import android.view.WindowManager;
41import android.widget.AdapterView;
42import android.widget.ArrayAdapter;
43import android.widget.Button;
44import android.widget.ListView;
45import android.widget.TextView;
46
47import java.util.ArrayList;
48import java.util.Comparator;
49
50import com.android.systemui.R;
51import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
52import com.android.systemui.statusbar.policy.BatteryController;
53import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
54import com.android.systemui.statusbar.policy.BluetoothController;
55import com.android.systemui.statusbar.policy.LocationController;
56import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
57import com.android.systemui.statusbar.policy.NetworkController;
58import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
59
60class QuickSettingsModel implements BluetoothStateChangeCallback,
61        NetworkSignalChangedCallback,
62        BatteryStateChangeCallback,
63        LocationGpsStateChangeCallback {
64
65    /** Represents the state of a given attribute. */
66    static class State {
67        int iconId;
68        String label;
69        boolean enabled;
70    }
71    static class BatteryState extends State {
72        int batteryLevel;
73        boolean pluggedIn;
74    }
75
76    /** The callback to update a given tile. */
77    interface RefreshCallback {
78        public void refreshView(QuickSettingsTileView view, State state);
79    }
80
81    private Context mContext;
82
83    private QuickSettingsTileView mUserTile;
84    private RefreshCallback mUserCallback;
85    private State mUserState = new State();
86
87    private QuickSettingsTileView mAirplaneModeTile;
88    private RefreshCallback mAirplaneModeCallback;
89    private State mAirplaneModeState = new State();
90
91    private QuickSettingsTileView mWifiTile;
92    private RefreshCallback mWifiCallback;
93    private State mWifiState = new State();
94
95    private QuickSettingsTileView mWifiDisplayTile;
96    private RefreshCallback mWifiDisplayCallback;
97    private State mWifiDisplayState = new State();
98
99    private QuickSettingsTileView mRSSITile;
100    private RefreshCallback mRSSICallback;
101    private State mRSSIState = new State();
102
103    private QuickSettingsTileView mBluetoothTile;
104    private RefreshCallback mBluetoothCallback;
105    private State mBluetoothState = new State();
106
107    private QuickSettingsTileView mBatteryTile;
108    private RefreshCallback mBatteryCallback;
109    private BatteryState mBatteryState = new BatteryState();
110
111    private QuickSettingsTileView mLocationTile;
112    private RefreshCallback mLocationCallback;
113    private State mLocationState = new State();
114
115    public QuickSettingsModel(Context context) {
116        mContext = context;
117    }
118
119    // User
120    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
121        mUserTile = view;
122        mUserCallback = cb;
123        mUserCallback.refreshView(mUserTile, mUserState);
124    }
125    void setUserTileInfo(String name) {
126        mUserState.label = name;
127        mUserCallback.refreshView(mUserTile, mUserState);
128    }
129
130    // Airplane Mode
131    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
132        mAirplaneModeTile = view;
133        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
134            @Override
135            public void onClick(View v) {
136                if (mAirplaneModeState.enabled) {
137                    setAirplaneModeState(false);
138                } else {
139                    setAirplaneModeState(true);
140                }
141            }
142        });
143        mAirplaneModeCallback = cb;
144        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
145    }
146    private void setAirplaneModeState(boolean enabled) {
147        // TODO: Sets the view to be "awaiting" if not already awaiting
148
149        // Change the system setting
150        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
151                                enabled ? 1 : 0);
152
153        // TODO: Update the UI to reflect system setting
154        // mCheckBoxPref.setChecked(enabled);
155
156        // Post the intent
157        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
158        intent.putExtra("state", enabled);
159        mContext.sendBroadcast(intent);
160    }
161    // NetworkSignalChanged callback
162    @Override
163    public void onAirplaneModeChanged(boolean enabled) {
164        // TODO: If view is in awaiting state, disable
165        Resources r = mContext.getResources();
166        mAirplaneModeState.enabled = enabled;
167        mAirplaneModeState.iconId = (enabled ?
168                R.drawable.ic_qs_airplane_enabled :
169                R.drawable.ic_qs_airplane_normal);
170        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
171    }
172
173    // Wifi
174    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
175        mWifiTile = view;
176        mWifiCallback = cb;
177        mWifiCallback.refreshView(mWifiTile, mWifiState);
178    }
179    // NetworkSignalChanged callback
180    @Override
181    public void onWifiSignalChanged(boolean enabled, String description) {
182        // TODO: If view is in awaiting state, disable
183        Resources r = mContext.getResources();
184        // TODO: Check if wifi is enabled
185        mWifiState.enabled = enabled;
186        mWifiState.iconId = (enabled ?
187                R.drawable.ic_qs_wifi_enabled :
188                R.drawable.ic_qs_wifi_normal);
189        mWifiState.label = (enabled ?
190                description :
191                r.getString(R.string.quick_settings_wifi_no_network));
192        mWifiCallback.refreshView(mWifiTile, mWifiState);
193    }
194
195    // RSSI
196    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
197        mRSSITile = view;
198        mRSSICallback = cb;
199        mRSSICallback.refreshView(mRSSITile, mRSSIState);
200    }
201    private void setRSSIState(boolean enabled) {
202        // TODO: Set RSSI enabled
203        // TODO: Sets the view to be "awaiting" if not already awaiting
204    }
205    // NetworkSignalChanged callback
206    @Override
207    public void onMobileDataSignalChanged(boolean enabled, String description) {
208        // TODO: If view is in awaiting state, disable
209        Resources r = mContext.getResources();
210        // TODO: Check if RSSI is enabled
211        mRSSIState.enabled = enabled;
212        mRSSIState.iconId = (enabled ?
213                R.drawable.ic_qs_rssi_enabled :
214                R.drawable.ic_qs_rssi_normal);
215        mRSSIState.label = (enabled ?
216                description :
217                r.getString(R.string.quick_settings_rssi_emergency_only));
218        mRSSICallback.refreshView(mRSSITile, mRSSIState);
219    }
220
221    // Bluetooth
222    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
223        mBluetoothTile = view;
224        mBluetoothTile.setOnClickListener(new View.OnClickListener() {
225            @Override
226            public void onClick(View v) {
227                if (mBluetoothState.enabled) {
228                    setBluetoothState(false);
229                } else {
230                    setBluetoothState(true);
231                }
232            }
233        });
234        mBluetoothCallback = cb;
235
236        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
237        onBluetoothStateChange(adapter.isEnabled());
238    }
239    private void setBluetoothState(boolean enabled) {
240        // TODO: Sets the view to be "awaiting" if not already awaiting
241        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
242        if (adapter != null) {
243            if (enabled) {
244                adapter.enable();
245            } else {
246                adapter.disable();
247            }
248        }
249    }
250    // BluetoothController callback
251    @Override
252    public void onBluetoothStateChange(boolean on) {
253        // TODO: If view is in awaiting state, disable
254        Resources r = mContext.getResources();
255        mBluetoothState.enabled = on;
256        if (on) {
257            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_enabled;
258        } else {
259            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_normal;
260        }
261        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
262    }
263
264    // Battery
265    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
266        mBatteryTile = view;
267        mBatteryCallback = cb;
268        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
269    }
270    // BatteryController callback
271    @Override
272    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
273        mBatteryState.batteryLevel = level;
274        mBatteryState.pluggedIn = pluggedIn;
275        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
276    }
277
278    // Location
279    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
280        mLocationTile = view;
281        mLocationCallback = cb;
282        mLocationCallback.refreshView(mLocationTile, mLocationState);
283        disableLocationTile();
284    }
285    private void enableLocationTile() {
286        mLocationTile.setVisibility(View.VISIBLE);
287    }
288    private void disableLocationTile() {
289        mLocationTile.setVisibility(View.GONE);
290    }
291    // LocationController callback
292    @Override
293    public void onLocationGpsStateChanged(boolean inUse, String description) {
294        if (inUse) {
295            mLocationState.enabled = inUse;
296            mLocationState.label = description;
297            mLocationCallback.refreshView(mLocationTile, mLocationState);
298            enableLocationTile();
299        } else {
300            disableLocationTile();
301        }
302    }
303
304    // Wifi Display
305    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
306        mWifiDisplayTile = view;
307        mWifiDisplayCallback = cb;
308    }
309    private void enableWifiDisplayTile() {
310        mWifiDisplayTile.setVisibility(View.VISIBLE);
311    }
312    private void disableWifiDisplayTile() {
313        mWifiDisplayTile.setVisibility(View.GONE);
314    }
315    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
316        if (status.isEnabled()) {
317            if (status.getActiveDisplay() != null) {
318                mWifiDisplayState.label = status.getActiveDisplay().getDeviceName();
319            } else {
320                mWifiDisplayState.label = mContext.getString(
321                        R.string.quick_settings_wifi_display_no_connection_label);
322            }
323            mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
324            enableWifiDisplayTile();
325        } else {
326            disableWifiDisplayTile();
327        }
328    }
329
330}
331
332/**
333 *
334 */
335class QuickSettings {
336
337    private Context mContext;
338    private PanelBar mBar;
339    private QuickSettingsModel mModel;
340    private QuickSettingsContainerView mContainerView;
341
342    private DisplayManager mDisplayManager;
343    private WifiDisplayStatus mWifiDisplayStatus;
344    private WifiDisplayListAdapter mWifiDisplayListAdapter;
345
346    private CursorLoader mUserInfoLoader;
347
348    // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
349    // configuration change)
350    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
351            new ArrayList<QuickSettingsTileView>();
352
353    public QuickSettings(Context context, QuickSettingsContainerView container) {
354        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
355        mContext = context;
356        mContainerView = container;
357        mModel = new QuickSettingsModel(context);
358        mWifiDisplayStatus = new WifiDisplayStatus();
359        mWifiDisplayListAdapter = new WifiDisplayListAdapter(context);
360
361        IntentFilter filter = new IntentFilter();
362        filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
363        mContext.registerReceiver(mReceiver, filter);
364
365        setupQuickSettings();
366        updateWifiDisplayStatus();
367        updateResources();
368    }
369
370    void setBar(PanelBar bar) {
371        mBar = bar;
372    }
373
374    void setup(NetworkController networkController, BluetoothController bluetoothController,
375            BatteryController batteryController, LocationController locationController) {
376        networkController.addNetworkSignalChangedCallback(mModel);
377        bluetoothController.addStateChangedCallback(mModel);
378        batteryController.addStateChangedCallback(mModel);
379        locationController.addStateChangedCallback(mModel);
380    }
381
382    private void queryForUserInformation() {
383        Uri userContactUri = Uri.withAppendedPath(
384            ContactsContract.Profile.CONTENT_URI,
385            ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
386
387        String[] selectArgs = {
388            ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
389            ContactsContract.CommonDataKinds.Photo.PHOTO
390        };
391        String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL",
392            ContactsContract.Contacts.Data.MIMETYPE,
393            ContactsContract.Contacts.Data.MIMETYPE,
394            ContactsContract.RawContacts.ACCOUNT_TYPE);
395        String[] whereArgs = {
396            ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
397            ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
398        };
399
400        mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs,
401                null);
402        mUserInfoLoader.registerListener(0,
403                new Loader.OnLoadCompleteListener<Cursor>() {
404                    @Override
405                    public void onLoadComplete(Loader<Cursor> loader,
406                            Cursor cursor) {
407                        if (cursor.moveToFirst()) {
408                            String name = cursor.getString(0); // DISPLAY_NAME
409                            mModel.setUserTileInfo(name);
410                            /*
411                            byte[] photoData = cursor.getBlob(0);
412                            Bitmap b =
413                                BitmapFactory.decodeByteArray(photoData, 0, photoData.length);
414                             */
415                        }
416                        mUserInfoLoader.stopLoading();
417                    }
418                });
419        mUserInfoLoader.startLoading();
420    }
421
422    private void setupQuickSettings() {
423        // Setup the tiles that we are going to be showing (including the temporary ones)
424        LayoutInflater inflater = LayoutInflater.from(mContext);
425
426        addUserTiles(mContainerView, inflater);
427        addSystemTiles(mContainerView, inflater);
428        addTemporaryTiles(mContainerView, inflater);
429
430        queryForUserInformation();
431    }
432
433    private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
434        QuickSettingsTileView userTile = (QuickSettingsTileView)
435                inflater.inflate(R.layout.quick_settings_tile, parent, false);
436        userTile.setContent(R.layout.quick_settings_tile_user, inflater);
437        mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
438            @Override
439            public void refreshView(QuickSettingsTileView view, State state) {
440                TextView tv = (TextView) view.findViewById(R.id.user_textview);
441                tv.setText(state.label);
442            }
443        });
444        parent.addView(userTile);
445        mDynamicSpannedTiles.add(userTile);
446
447        // Time tile
448        QuickSettingsTileView timeTile = (QuickSettingsTileView)
449                inflater.inflate(R.layout.quick_settings_tile, parent, false);
450        timeTile.setContent(R.layout.quick_settings_tile_time, inflater);
451        parent.addView(timeTile);
452        mDynamicSpannedTiles.add(timeTile);
453
454        // Settings tile
455        QuickSettingsTileView settingsTile = (QuickSettingsTileView)
456                inflater.inflate(R.layout.quick_settings_tile, parent, false);
457        settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater);
458        settingsTile.setOnClickListener(new View.OnClickListener() {
459            @Override
460            public void onClick(View v) {
461                Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
462                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
463                mContext.startActivity(intent);
464                mBar.collapseAllPanels(true);
465            }
466        });
467        parent.addView(settingsTile);
468        mDynamicSpannedTiles.add(settingsTile);
469    }
470
471    private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
472        // Wi-fi
473        QuickSettingsTileView wifiTile = (QuickSettingsTileView)
474                inflater.inflate(R.layout.quick_settings_tile, parent, false);
475        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
476        wifiTile.setOnClickListener(new View.OnClickListener() {
477            @Override
478            public void onClick(View v) {
479                Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
480                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
481                mContext.startActivity(intent);
482                mBar.collapseAllPanels(true);
483            }
484        });
485        mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
486            @Override
487            public void refreshView(QuickSettingsTileView view, State state) {
488                TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
489                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
490                tv.setText(state.label);
491            }
492        });
493        parent.addView(wifiTile);
494
495        // RSSI
496        QuickSettingsTileView rssiTile = (QuickSettingsTileView)
497                inflater.inflate(R.layout.quick_settings_tile, parent, false);
498        rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
499        rssiTile.setOnClickListener(new View.OnClickListener() {
500            @Override
501            public void onClick(View v) {
502                Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
503                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
504                mContext.startActivity(intent);
505                mBar.collapseAllPanels(true);
506            }
507        });
508        mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
509            @Override
510            public void refreshView(QuickSettingsTileView view, State state) {
511                TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
512                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
513                tv.setText(state.label);
514            }
515        });
516        parent.addView(rssiTile);
517
518        // Battery
519        QuickSettingsTileView batteryTile = (QuickSettingsTileView)
520                inflater.inflate(R.layout.quick_settings_tile, parent, false);
521        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
522        batteryTile.setOnClickListener(new View.OnClickListener() {
523            @Override
524            public void onClick(View v) {
525                Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
526                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
527                mContext.startActivity(intent);
528                mBar.collapseAllPanels(true);
529            }
530        });
531        mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
532            @Override
533            public void refreshView(QuickSettingsTileView view, State state) {
534                QuickSettingsModel.BatteryState batteryState =
535                        (QuickSettingsModel.BatteryState) state;
536                TextView tv = (TextView) view.findViewById(R.id.battery_textview);
537                ClipDrawable drawable = (ClipDrawable) tv.getCompoundDrawables()[1];
538                drawable.setLevel((int) (10000 * (batteryState.batteryLevel / 100.0f)));
539                // TODO: use format string
540                tv.setText(batteryState.batteryLevel + "%");
541            }
542        });
543        parent.addView(batteryTile);
544
545        // Airplane Mode
546        QuickSettingsTileView airplaneTile = (QuickSettingsTileView)
547                inflater.inflate(R.layout.quick_settings_tile, parent, false);
548        airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater);
549        mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
550            @Override
551            public void refreshView(QuickSettingsTileView view, State state) {
552                TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
553                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
554            }
555        });
556        parent.addView(airplaneTile);
557
558        // Bluetooth
559        QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
560                inflater.inflate(R.layout.quick_settings_tile, parent, false);
561        bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
562        mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
563            @Override
564            public void refreshView(QuickSettingsTileView view, State state) {
565                TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
566                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
567            }
568        });
569        parent.addView(bluetoothTile);
570
571        // Brightness
572        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
573                inflater.inflate(R.layout.quick_settings_tile, parent, false);
574        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
575        brightnessTile.setOnClickListener(new View.OnClickListener() {
576            @Override
577            public void onClick(View v) {
578                Intent intent = new Intent(android.provider.Settings.ACTION_DISPLAY_SETTINGS);
579                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
580                mContext.startActivity(intent);
581                mBar.collapseAllPanels(true);
582            }
583        });
584        parent.addView(brightnessTile);
585    }
586
587    private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
588        // Location
589        QuickSettingsTileView locationTile = (QuickSettingsTileView)
590                inflater.inflate(R.layout.quick_settings_tile, parent, false);
591        locationTile.setContent(R.layout.quick_settings_tile_location, inflater);
592        locationTile.setOnClickListener(new View.OnClickListener() {
593            @Override
594            public void onClick(View v) {
595                Intent intent =
596                        new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
597                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
598                mContext.startActivity(intent);
599                mBar.collapseAllPanels(true);
600            }
601        });
602        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
603            @Override
604            public void refreshView(QuickSettingsTileView view, State state) {
605                TextView tv = (TextView) view.findViewById(R.id.location_textview);
606                tv.setText(state.label);
607            }
608        });
609        parent.addView(locationTile);
610
611        // Wifi Display
612        QuickSettingsTileView wifiDisplayTile = (QuickSettingsTileView)
613                inflater.inflate(R.layout.quick_settings_tile, parent, false);
614        wifiDisplayTile.setContent(R.layout.quick_settings_tile_wifi_display, inflater);
615        wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
616            @Override
617            public void onClick(View v) {
618                showWifiDisplayDialog();
619                mBar.collapseAllPanels(true);
620            }
621        });
622        mModel.addWifiDisplayTile(wifiDisplayTile, new QuickSettingsModel.RefreshCallback() {
623            @Override
624            public void refreshView(QuickSettingsTileView view, State state) {
625                TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
626                tv.setText(state.label);
627            }
628        });
629        parent.addView(wifiDisplayTile);
630
631        /*
632        QuickSettingsTileView mediaTile = (QuickSettingsTileView)
633                inflater.inflate(R.layout.quick_settings_tile, parent, false);
634        mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
635        parent.addView(mediaTile);
636        QuickSettingsTileView imeTile = (QuickSettingsTileView)
637                inflater.inflate(R.layout.quick_settings_tile, parent, false);
638        imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
639        imeTile.setOnClickListener(new View.OnClickListener() {
640            @Override
641            public void onClick(View v) {
642                parent.removeViewAt(0);
643            }
644        });
645        parent.addView(imeTile);
646        */
647    }
648
649    void updateResources() {
650        Resources r = mContext.getResources();
651
652        // Update the User, Time, and Settings tiles spans, and reset everything else
653        int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
654        for (QuickSettingsTileView v : mDynamicSpannedTiles) {
655            v.setColumnSpan(span);
656        }
657        mContainerView.requestLayout();
658    }
659
660    private void showWifiDisplayDialog() {
661        mDisplayManager.scanWifiDisplays();
662        updateWifiDisplayStatus();
663
664        Dialog dialog = new Dialog(mContext);
665        dialog.setContentView(R.layout.wifi_display_dialog);
666        dialog.setCanceledOnTouchOutside(true);
667        dialog.setTitle(R.string.wifi_display_dialog_title);
668
669        Button scanButton = (Button)dialog.findViewById(R.id.scan);
670        scanButton.setOnClickListener(new View.OnClickListener() {
671            @Override
672            public void onClick(View v) {
673                mDisplayManager.scanWifiDisplays();
674            }
675        });
676
677        Button disconnectButton = (Button)dialog.findViewById(R.id.disconnect);
678        disconnectButton.setOnClickListener(new View.OnClickListener() {
679            @Override
680            public void onClick(View v) {
681                mDisplayManager.disconnectWifiDisplay();
682            }
683        });
684
685        ListView list = (ListView)dialog.findViewById(R.id.list);
686        list.setAdapter(mWifiDisplayListAdapter);
687        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
688            @Override
689            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
690                WifiDisplay display = mWifiDisplayListAdapter.getItem(position);
691                mDisplayManager.connectWifiDisplay(display.getDeviceAddress());
692            }
693        });
694
695        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
696        dialog.show();
697    }
698
699    private void updateWifiDisplayStatus() {
700        applyWifiDisplayStatus(mDisplayManager.getWifiDisplayStatus());
701    }
702
703    private void applyWifiDisplayStatus(WifiDisplayStatus status) {
704        mWifiDisplayStatus = status;
705
706        mWifiDisplayListAdapter.clear();
707        mWifiDisplayListAdapter.addAll(status.getKnownDisplays());
708        if (status.getActiveDisplay() != null
709                && !contains(status.getKnownDisplays(), status.getActiveDisplay())) {
710            mWifiDisplayListAdapter.add(status.getActiveDisplay());
711        }
712        mWifiDisplayListAdapter.sort(mWifiDisplayComparator);
713
714        mModel.onWifiDisplayStateChanged(status);
715    }
716
717    private static boolean contains(WifiDisplay[] displays, WifiDisplay display) {
718        for (WifiDisplay d : displays) {
719            if (d.equals(display)) {
720                return true;
721            }
722        }
723        return false;
724    }
725
726    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
727        @Override
728        public void onReceive(Context context, Intent intent) {
729            if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
730                WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
731                        DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
732                applyWifiDisplayStatus(status);
733            }
734        }
735    };
736
737    private final class WifiDisplayListAdapter extends ArrayAdapter<WifiDisplay> {
738        private final LayoutInflater mInflater;
739
740        public WifiDisplayListAdapter(Context context) {
741            super(context, android.R.layout.simple_list_item_2);
742            mInflater = LayoutInflater.from(context);
743        }
744
745        @Override
746        public View getView(int position, View convertView, ViewGroup parent) {
747            WifiDisplay item = getItem(position);
748            View view = convertView;
749            if (view == null) {
750                view = mInflater.inflate(android.R.layout.simple_list_item_2,
751                        parent, false);
752            }
753            TextView headline = (TextView) view.findViewById(android.R.id.text1);
754            TextView subText = (TextView) view.findViewById(android.R.id.text2);
755            headline.setText(item.getDeviceName());
756
757            int state = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
758            if (item.equals(mWifiDisplayStatus.getActiveDisplay())) {
759                state = mWifiDisplayStatus.getActiveDisplayState();
760            }
761            switch (state) {
762                case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
763                    subText.setText(R.string.wifi_display_state_connecting);
764                    break;
765                case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
766                    subText.setText(R.string.wifi_display_state_connected);
767                    break;
768                case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED:
769                default:
770                    subText.setText(R.string.wifi_display_state_available);
771                    break;
772            }
773            return view;
774        }
775    }
776
777    private final Comparator<WifiDisplay> mWifiDisplayComparator = new Comparator<WifiDisplay>() {
778        @Override
779        public int compare(WifiDisplay lhs, WifiDisplay rhs) {
780            int c = lhs.getDeviceName().compareToIgnoreCase(rhs.getDeviceName());
781            if (c == 0) {
782                c = lhs.getDeviceAddress().compareToIgnoreCase(rhs.getDeviceAddress());
783            }
784            return c;
785        }
786    };
787}