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 com.android.internal.view.RotationPolicy;
20import com.android.internal.widget.LockPatternUtils;
21import com.android.systemui.R;
22
23import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
24import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
25import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
26import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
27import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
28import com.android.systemui.statusbar.policy.BatteryController;
29import com.android.systemui.statusbar.policy.BluetoothController;
30import com.android.systemui.statusbar.policy.BrightnessController;
31import com.android.systemui.statusbar.policy.LocationController;
32import com.android.systemui.statusbar.policy.NetworkController;
33import com.android.systemui.statusbar.policy.ToggleSlider;
34
35import android.app.ActivityManagerNative;
36import android.app.AlertDialog;
37import android.app.Dialog;
38import android.app.PendingIntent;
39import android.bluetooth.BluetoothAdapter;
40import android.content.BroadcastReceiver;
41import android.content.ComponentName;
42import android.content.Context;
43import android.content.CursorLoader;
44import android.content.DialogInterface;
45import android.content.DialogInterface.OnClickListener;
46import android.content.Intent;
47import android.content.IntentFilter;
48import android.content.pm.PackageManager.NameNotFoundException;
49import android.content.pm.UserInfo;
50import android.content.res.Resources;
51import android.database.Cursor;
52import android.graphics.Bitmap;
53import android.graphics.drawable.BitmapDrawable;
54import android.graphics.drawable.Drawable;
55import android.graphics.drawable.LevelListDrawable;
56import android.hardware.display.DisplayManager;
57import android.hardware.display.WifiDisplayStatus;
58import android.os.AsyncTask;
59import android.os.Handler;
60import android.os.RemoteException;
61import android.os.UserHandle;
62import android.os.UserManager;
63import android.provider.ContactsContract;
64import android.provider.ContactsContract.CommonDataKinds.Phone;
65import android.provider.ContactsContract.Profile;
66import android.provider.Settings;
67import android.util.Log;
68import android.util.Pair;
69import android.view.LayoutInflater;
70import android.view.View;
71import android.view.ViewGroup;
72import android.view.Window;
73import android.view.WindowManager;
74import android.view.WindowManagerGlobal;
75import android.widget.ImageView;
76import android.widget.TextView;
77
78import java.util.ArrayList;
79
80
81/**
82 *
83 */
84class QuickSettings {
85    private static final String TAG = "QuickSettings";
86    public static final boolean SHOW_IME_TILE = false;
87
88    private Context mContext;
89    private PanelBar mBar;
90    private QuickSettingsModel mModel;
91    private ViewGroup mContainerView;
92
93    private DisplayManager mDisplayManager;
94    private WifiDisplayStatus mWifiDisplayStatus;
95    private PhoneStatusBar mStatusBarService;
96    private BluetoothState mBluetoothState;
97
98    private BrightnessController mBrightnessController;
99    private BluetoothController mBluetoothController;
100
101    private Dialog mBrightnessDialog;
102    private int mBrightnessDialogShortTimeout;
103    private int mBrightnessDialogLongTimeout;
104
105    private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
106
107    private LevelListDrawable mBatteryLevels;
108    private LevelListDrawable mChargingBatteryLevels;
109
110    boolean mTilesSetUp = false;
111
112    private Handler mHandler;
113
114    // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
115    // configuration change)
116    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
117            new ArrayList<QuickSettingsTileView>();
118
119    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
120            new RotationPolicy.RotationPolicyListener() {
121        @Override
122        public void onChange() {
123            mModel.onRotationLockChanged();
124        }
125    };
126
127    public QuickSettings(Context context, QuickSettingsContainerView container) {
128        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
129        mContext = context;
130        mContainerView = container;
131        mModel = new QuickSettingsModel(context);
132        mWifiDisplayStatus = new WifiDisplayStatus();
133        mBluetoothState = new QuickSettingsModel.BluetoothState();
134        mHandler = new Handler();
135
136        Resources r = mContext.getResources();
137        mBatteryLevels = (LevelListDrawable) r.getDrawable(R.drawable.qs_sys_battery);
138        mChargingBatteryLevels =
139                (LevelListDrawable) r.getDrawable(R.drawable.qs_sys_battery_charging);
140        mBrightnessDialogLongTimeout =
141                r.getInteger(R.integer.quick_settings_brightness_dialog_long_timeout);
142        mBrightnessDialogShortTimeout =
143                r.getInteger(R.integer.quick_settings_brightness_dialog_short_timeout);
144
145        IntentFilter filter = new IntentFilter();
146        filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
147        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
148        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
149        filter.addAction(Intent.ACTION_USER_SWITCHED);
150        mContext.registerReceiver(mReceiver, filter);
151
152        IntentFilter profileFilter = new IntentFilter();
153        profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
154        profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
155        mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
156                null, null);
157    }
158
159    void setBar(PanelBar bar) {
160        mBar = bar;
161    }
162
163    public void setService(PhoneStatusBar phoneStatusBar) {
164        mStatusBarService = phoneStatusBar;
165    }
166
167    public PhoneStatusBar getService() {
168        return mStatusBarService;
169    }
170
171    public void setImeWindowStatus(boolean visible) {
172        mModel.onImeWindowStatusChanged(visible);
173    }
174
175    void setup(NetworkController networkController, BluetoothController bluetoothController,
176            BatteryController batteryController, LocationController locationController) {
177        mBluetoothController = bluetoothController;
178
179        setupQuickSettings();
180        updateWifiDisplayStatus();
181        updateResources();
182
183        networkController.addNetworkSignalChangedCallback(mModel);
184        bluetoothController.addStateChangedCallback(mModel);
185        batteryController.addStateChangedCallback(mModel);
186        locationController.addStateChangedCallback(mModel);
187        RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
188                UserHandle.USER_ALL);
189    }
190
191    private void queryForUserInformation() {
192        Context currentUserContext = null;
193        UserInfo userInfo = null;
194        try {
195            userInfo = ActivityManagerNative.getDefault().getCurrentUser();
196            currentUserContext = mContext.createPackageContextAsUser("android", 0,
197                    new UserHandle(userInfo.id));
198        } catch (NameNotFoundException e) {
199            Log.e(TAG, "Couldn't create user context", e);
200            throw new RuntimeException(e);
201        } catch (RemoteException e) {
202            Log.e(TAG, "Couldn't get user info", e);
203        }
204        final int userId = userInfo.id;
205        final String userName = userInfo.name;
206
207        final Context context = currentUserContext;
208        mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
209            @Override
210            protected Pair<String, Drawable> doInBackground(Void... params) {
211                final UserManager um =
212                        (UserManager) mContext.getSystemService(Context.USER_SERVICE);
213
214                // Fall back to the UserManager nickname if we can't read the name from the local
215                // profile below.
216                String name = userName;
217                Drawable avatar = null;
218                Bitmap rawAvatar = um.getUserIcon(userId);
219                if (rawAvatar != null) {
220                    avatar = new BitmapDrawable(mContext.getResources(), rawAvatar);
221                } else {
222                    avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
223                }
224
225                // If it's a single-user device, get the profile name, since the nickname is not
226                // usually valid
227                if (um.getUsers().size() <= 1) {
228                    // Try and read the display name from the local profile
229                    final Cursor cursor = context.getContentResolver().query(
230                            Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
231                            null, null, null);
232                    if (cursor != null) {
233                        try {
234                            if (cursor.moveToFirst()) {
235                                name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
236                            }
237                        } finally {
238                            cursor.close();
239                        }
240                    }
241                }
242                return new Pair<String, Drawable>(name, avatar);
243            }
244
245            @Override
246            protected void onPostExecute(Pair<String, Drawable> result) {
247                super.onPostExecute(result);
248                mModel.setUserTileInfo(result.first, result.second);
249                mUserInfoTask = null;
250            }
251        };
252        mUserInfoTask.execute();
253    }
254
255    private void setupQuickSettings() {
256        // Setup the tiles that we are going to be showing (including the temporary ones)
257        LayoutInflater inflater = LayoutInflater.from(mContext);
258
259        addUserTiles(mContainerView, inflater);
260        addSystemTiles(mContainerView, inflater);
261        addTemporaryTiles(mContainerView, inflater);
262
263        queryForUserInformation();
264        mTilesSetUp = true;
265    }
266
267    private void startSettingsActivity(String action) {
268        Intent intent = new Intent(action);
269        startSettingsActivity(intent);
270    }
271
272    private void startSettingsActivity(Intent intent) {
273        startSettingsActivity(intent, true);
274    }
275
276    private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
277        if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
278        try {
279            // Dismiss the lock screen when Settings starts.
280            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
281        } catch (RemoteException e) {
282        }
283        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
284        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
285        getService().animateCollapsePanels();
286    }
287
288    private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
289        QuickSettingsTileView userTile = (QuickSettingsTileView)
290                inflater.inflate(R.layout.quick_settings_tile, parent, false);
291        userTile.setContent(R.layout.quick_settings_tile_user, inflater);
292        userTile.setOnClickListener(new View.OnClickListener() {
293            @Override
294            public void onClick(View v) {
295                mBar.collapseAllPanels(true);
296                final UserManager um =
297                        (UserManager) mContext.getSystemService(Context.USER_SERVICE);
298                if (um.getUsers(true).size() > 1) {
299                    try {
300                        WindowManagerGlobal.getWindowManagerService().lockNow(
301                                LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
302                    } catch (RemoteException e) {
303                        Log.e(TAG, "Couldn't show user switcher", e);
304                    }
305                } else {
306                    Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
307                            mContext, v, ContactsContract.Profile.CONTENT_URI,
308                            ContactsContract.QuickContact.MODE_LARGE, null);
309                    mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
310                }
311            }
312        });
313        mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
314            @Override
315            public void refreshView(QuickSettingsTileView view, State state) {
316                UserState us = (UserState) state;
317                ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
318                TextView tv = (TextView) view.findViewById(R.id.user_textview);
319                tv.setText(state.label);
320                iv.setImageDrawable(us.avatar);
321                view.setContentDescription(mContext.getString(
322                        R.string.accessibility_quick_settings_user, state.label));
323            }
324        });
325        parent.addView(userTile);
326        mDynamicSpannedTiles.add(userTile);
327
328        // Brightness
329        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
330                inflater.inflate(R.layout.quick_settings_tile, parent, false);
331        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
332        brightnessTile.setOnClickListener(new View.OnClickListener() {
333            @Override
334            public void onClick(View v) {
335                mBar.collapseAllPanels(true);
336                showBrightnessDialog();
337            }
338        });
339        mModel.addBrightnessTile(brightnessTile, new QuickSettingsModel.RefreshCallback() {
340            @Override
341            public void refreshView(QuickSettingsTileView view, State state) {
342                TextView tv = (TextView) view.findViewById(R.id.brightness_textview);
343                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
344                tv.setText(state.label);
345                dismissBrightnessDialog(mBrightnessDialogShortTimeout);
346            }
347        });
348        parent.addView(brightnessTile);
349        mDynamicSpannedTiles.add(brightnessTile);
350
351        // Time tile
352        /*
353        QuickSettingsTileView timeTile = (QuickSettingsTileView)
354                inflater.inflate(R.layout.quick_settings_tile, parent, false);
355        timeTile.setContent(R.layout.quick_settings_tile_time, inflater);
356        timeTile.setOnClickListener(new View.OnClickListener() {
357            @Override
358            public void onClick(View v) {
359                // Quick. Clock. Quick. Clock. Quick. Clock.
360                startSettingsActivity(Intent.ACTION_QUICK_CLOCK);
361            }
362        });
363        mModel.addTimeTile(timeTile, new QuickSettingsModel.RefreshCallback() {
364            @Override
365            public void refreshView(QuickSettingsTileView view, State alarmState) {}
366        });
367        parent.addView(timeTile);
368        mDynamicSpannedTiles.add(timeTile);
369        */
370
371        // Settings tile
372        QuickSettingsTileView settingsTile = (QuickSettingsTileView)
373                inflater.inflate(R.layout.quick_settings_tile, parent, false);
374        settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater);
375        settingsTile.setOnClickListener(new View.OnClickListener() {
376            @Override
377            public void onClick(View v) {
378                startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
379            }
380        });
381        mModel.addSettingsTile(settingsTile, new QuickSettingsModel.RefreshCallback() {
382            @Override
383            public void refreshView(QuickSettingsTileView view, State state) {
384                TextView tv = (TextView) view.findViewById(R.id.settings_tileview);
385                tv.setText(state.label);
386            }
387        });
388        parent.addView(settingsTile);
389        mDynamicSpannedTiles.add(settingsTile);
390    }
391
392    private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
393        // Wi-fi
394        QuickSettingsTileView wifiTile = (QuickSettingsTileView)
395                inflater.inflate(R.layout.quick_settings_tile, parent, false);
396        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
397        wifiTile.setOnClickListener(new View.OnClickListener() {
398            @Override
399            public void onClick(View v) {
400                startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
401            }
402        });
403        mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
404            @Override
405            public void refreshView(QuickSettingsTileView view, State state) {
406                WifiState wifiState = (WifiState) state;
407                TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
408                tv.setCompoundDrawablesWithIntrinsicBounds(0, wifiState.iconId, 0, 0);
409                tv.setText(wifiState.label);
410                view.setContentDescription(mContext.getString(
411                        R.string.accessibility_quick_settings_wifi,
412                        wifiState.signalContentDescription,
413                        (wifiState.connected) ? wifiState.label : ""));
414            }
415        });
416        parent.addView(wifiTile);
417
418        if (mModel.deviceSupportsTelephony()) {
419            // RSSI
420            QuickSettingsTileView rssiTile = (QuickSettingsTileView)
421                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
422            rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
423            rssiTile.setOnClickListener(new View.OnClickListener() {
424                @Override
425                public void onClick(View v) {
426                    Intent intent = new Intent();
427                    intent.setComponent(new ComponentName(
428                            "com.android.settings",
429                            "com.android.settings.Settings$DataUsageSummaryActivity"));
430                    startSettingsActivity(intent);
431                }
432            });
433            mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
434                @Override
435                public void refreshView(QuickSettingsTileView view, State state) {
436                    RSSIState rssiState = (RSSIState) state;
437                    ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
438                    ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
439                    TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
440                    iv.setImageResource(rssiState.signalIconId);
441
442                    if (rssiState.dataTypeIconId > 0) {
443                        iov.setImageResource(rssiState.dataTypeIconId);
444                    } else {
445                        iov.setImageDrawable(null);
446                    }
447                    tv.setText(state.label);
448                    view.setContentDescription(mContext.getResources().getString(
449                            R.string.accessibility_quick_settings_mobile,
450                            rssiState.signalContentDescription, rssiState.dataContentDescription,
451                            state.label));
452                }
453            });
454            parent.addView(rssiTile);
455        }
456
457        // Rotation Lock
458        if (mContext.getResources().getBoolean(R.bool.quick_settings_show_rotation_lock)) {
459            QuickSettingsTileView rotationLockTile = (QuickSettingsTileView)
460                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
461            rotationLockTile.setContent(R.layout.quick_settings_tile_rotation_lock, inflater);
462            rotationLockTile.setOnClickListener(new View.OnClickListener() {
463                @Override
464                public void onClick(View v) {
465                    boolean locked = RotationPolicy.isRotationLocked(mContext);
466                    RotationPolicy.setRotationLock(mContext, !locked);
467                }
468            });
469            mModel.addRotationLockTile(rotationLockTile, new QuickSettingsModel.RefreshCallback() {
470                @Override
471                public void refreshView(QuickSettingsTileView view, State state) {
472                    TextView tv = (TextView) view.findViewById(R.id.rotation_lock_textview);
473                    tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
474                    tv.setText(state.label);
475                }
476            });
477            parent.addView(rotationLockTile);
478        }
479
480        // Battery
481        QuickSettingsTileView batteryTile = (QuickSettingsTileView)
482                inflater.inflate(R.layout.quick_settings_tile, parent, false);
483        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
484        batteryTile.setOnClickListener(new View.OnClickListener() {
485            @Override
486            public void onClick(View v) {
487                startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
488            }
489        });
490        mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
491            @Override
492            public void refreshView(QuickSettingsTileView view, State state) {
493                QuickSettingsModel.BatteryState batteryState =
494                        (QuickSettingsModel.BatteryState) state;
495                TextView tv = (TextView) view.findViewById(R.id.battery_textview);
496                ImageView iv = (ImageView) view.findViewById(R.id.battery_image);
497                Drawable d = batteryState.pluggedIn
498                        ? mChargingBatteryLevels
499                        : mBatteryLevels;
500                String t;
501                if (batteryState.batteryLevel == 100) {
502                    t = mContext.getString(R.string.quick_settings_battery_charged_label);
503                } else {
504                    t = batteryState.pluggedIn
505                        ? mContext.getString(R.string.quick_settings_battery_charging_label,
506                                batteryState.batteryLevel)
507                        : mContext.getString(R.string.status_bar_settings_battery_meter_format,
508                                batteryState.batteryLevel);
509                }
510                iv.setImageDrawable(d);
511                iv.setImageLevel(batteryState.batteryLevel);
512                tv.setText(t);
513                view.setContentDescription(
514                        mContext.getString(R.string.accessibility_quick_settings_battery, t));
515            }
516        });
517        parent.addView(batteryTile);
518
519        // Airplane Mode
520        QuickSettingsTileView airplaneTile = (QuickSettingsTileView)
521                inflater.inflate(R.layout.quick_settings_tile, parent, false);
522        airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater);
523        mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
524            @Override
525            public void refreshView(QuickSettingsTileView view, State state) {
526                TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
527                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
528
529                String airplaneState = mContext.getString(
530                        (state.enabled) ? R.string.accessibility_desc_on
531                                : R.string.accessibility_desc_off);
532                view.setContentDescription(
533                        mContext.getString(R.string.accessibility_quick_settings_airplane, airplaneState));
534                tv.setText(state.label);
535            }
536        });
537        parent.addView(airplaneTile);
538
539        // Bluetooth
540        if (mModel.deviceSupportsBluetooth()) {
541            QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
542                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
543            bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
544            bluetoothTile.setOnClickListener(new View.OnClickListener() {
545                @Override
546                public void onClick(View v) {
547                    startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
548                }
549            });
550            mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
551                @Override
552                public void refreshView(QuickSettingsTileView view, State state) {
553                    BluetoothState bluetoothState = (BluetoothState) state;
554                    TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
555                    tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
556
557                    Resources r = mContext.getResources();
558                    String label = state.label;
559                    /*
560                    //TODO: Show connected bluetooth device label
561                    Set<BluetoothDevice> btDevices =
562                            mBluetoothController.getBondedBluetoothDevices();
563                    if (btDevices.size() == 1) {
564                        // Show the name of the bluetooth device you are connected to
565                        label = btDevices.iterator().next().getName();
566                    } else if (btDevices.size() > 1) {
567                        // Show a generic label about the number of bluetooth devices
568                        label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label,
569                                btDevices.size());
570                    }
571                    */
572                    view.setContentDescription(mContext.getString(
573                            R.string.accessibility_quick_settings_bluetooth,
574                            bluetoothState.stateContentDescription));
575                    tv.setText(label);
576                }
577            });
578            parent.addView(bluetoothTile);
579        }
580
581    }
582
583    private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
584        // Alarm tile
585        QuickSettingsTileView alarmTile = (QuickSettingsTileView)
586                inflater.inflate(R.layout.quick_settings_tile, parent, false);
587        alarmTile.setContent(R.layout.quick_settings_tile_alarm, inflater);
588        alarmTile.setOnClickListener(new View.OnClickListener() {
589            @Override
590            public void onClick(View v) {
591                // TODO: Jump into the alarm application
592                Intent intent = new Intent();
593                intent.setComponent(new ComponentName(
594                        "com.google.android.deskclock",
595                        "com.android.deskclock.AlarmClock"));
596                startSettingsActivity(intent);
597            }
598        });
599        mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
600            @Override
601            public void refreshView(QuickSettingsTileView view, State alarmState) {
602                TextView tv = (TextView) view.findViewById(R.id.alarm_textview);
603                tv.setText(alarmState.label);
604                view.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
605                view.setContentDescription(mContext.getString(
606                        R.string.accessibility_quick_settings_alarm, alarmState.label));
607            }
608        });
609        parent.addView(alarmTile);
610
611        // Location
612        QuickSettingsTileView locationTile = (QuickSettingsTileView)
613                inflater.inflate(R.layout.quick_settings_tile, parent, false);
614        locationTile.setContent(R.layout.quick_settings_tile_location, inflater);
615        locationTile.setOnClickListener(new View.OnClickListener() {
616            @Override
617            public void onClick(View v) {
618                startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
619            }
620        });
621        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
622            @Override
623            public void refreshView(QuickSettingsTileView view, State state) {
624                TextView tv = (TextView) view.findViewById(R.id.location_textview);
625                tv.setText(state.label);
626                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
627            }
628        });
629        parent.addView(locationTile);
630
631        // Wifi Display
632        QuickSettingsTileView wifiDisplayTile = (QuickSettingsTileView)
633                inflater.inflate(R.layout.quick_settings_tile, parent, false);
634        wifiDisplayTile.setContent(R.layout.quick_settings_tile_wifi_display, inflater);
635        wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
636            @Override
637            public void onClick(View v) {
638                startSettingsActivity(android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
639            }
640        });
641        mModel.addWifiDisplayTile(wifiDisplayTile, new QuickSettingsModel.RefreshCallback() {
642            @Override
643            public void refreshView(QuickSettingsTileView view, State state) {
644                TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
645                tv.setText(state.label);
646                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
647                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
648            }
649        });
650        parent.addView(wifiDisplayTile);
651
652        if (SHOW_IME_TILE) {
653            // IME
654            QuickSettingsTileView imeTile = (QuickSettingsTileView)
655                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
656            imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
657            imeTile.setOnClickListener(new View.OnClickListener() {
658                @Override
659                public void onClick(View v) {
660                    try {
661                        mBar.collapseAllPanels(true);
662                        Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
663                        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
664                        pendingIntent.send();
665                    } catch (Exception e) {}
666                }
667            });
668            mModel.addImeTile(imeTile, new QuickSettingsModel.RefreshCallback() {
669                @Override
670                public void refreshView(QuickSettingsTileView view, State state) {
671                    TextView tv = (TextView) view.findViewById(R.id.ime_textview);
672                    if (state.label != null) {
673                        tv.setText(state.label);
674                    }
675                    view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
676                }
677            });
678            parent.addView(imeTile);
679        }
680
681        // Bug reports
682        QuickSettingsTileView bugreportTile = (QuickSettingsTileView)
683                inflater.inflate(R.layout.quick_settings_tile, parent, false);
684        bugreportTile.setContent(R.layout.quick_settings_tile_bugreport, inflater);
685        bugreportTile.setOnClickListener(new View.OnClickListener() {
686            @Override
687            public void onClick(View v) {
688                mBar.collapseAllPanels(true);
689                showBugreportDialog();
690            }
691        });
692        mModel.addBugreportTile(bugreportTile, new QuickSettingsModel.RefreshCallback() {
693            @Override
694            public void refreshView(QuickSettingsTileView view, State state) {
695                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
696            }
697        });
698        parent.addView(bugreportTile);
699        /*
700        QuickSettingsTileView mediaTile = (QuickSettingsTileView)
701                inflater.inflate(R.layout.quick_settings_tile, parent, false);
702        mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
703        parent.addView(mediaTile);
704        QuickSettingsTileView imeTile = (QuickSettingsTileView)
705                inflater.inflate(R.layout.quick_settings_tile, parent, false);
706        imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
707        imeTile.setOnClickListener(new View.OnClickListener() {
708            @Override
709            public void onClick(View v) {
710                parent.removeViewAt(0);
711            }
712        });
713        parent.addView(imeTile);
714        */
715    }
716
717    void updateResources() {
718        Resources r = mContext.getResources();
719
720        // Update the model
721        mModel.updateResources();
722
723        // Update the User, Time, and Settings tiles spans, and reset everything else
724        int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
725        for (QuickSettingsTileView v : mDynamicSpannedTiles) {
726            v.setColumnSpan(span);
727        }
728        ((QuickSettingsContainerView)mContainerView).updateResources();
729        mContainerView.requestLayout();
730
731        // Reset the dialog
732        boolean isBrightnessDialogVisible = false;
733        if (mBrightnessDialog != null) {
734            removeAllBrightnessDialogCallbacks();
735
736            isBrightnessDialogVisible = mBrightnessDialog.isShowing();
737            mBrightnessDialog.dismiss();
738        }
739        mBrightnessDialog = null;
740        if (isBrightnessDialogVisible) {
741            showBrightnessDialog();
742        }
743    }
744
745    private void removeAllBrightnessDialogCallbacks() {
746        mHandler.removeCallbacks(mDismissBrightnessDialogRunnable);
747    }
748
749    private Runnable mDismissBrightnessDialogRunnable = new Runnable() {
750        public void run() {
751            if (mBrightnessDialog != null && mBrightnessDialog.isShowing()) {
752                mBrightnessDialog.dismiss();
753            }
754            removeAllBrightnessDialogCallbacks();
755        };
756    };
757
758    private void showBrightnessDialog() {
759        if (mBrightnessDialog == null) {
760            mBrightnessDialog = new Dialog(mContext);
761            mBrightnessDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
762            mBrightnessDialog.setContentView(R.layout.quick_settings_brightness_dialog);
763            mBrightnessDialog.setCanceledOnTouchOutside(true);
764
765            mBrightnessController = new BrightnessController(mContext,
766                    (ImageView) mBrightnessDialog.findViewById(R.id.brightness_icon),
767                    (ToggleSlider) mBrightnessDialog.findViewById(R.id.brightness_slider));
768            mBrightnessController.addStateChangedCallback(mModel);
769            mBrightnessDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
770                @Override
771                public void onDismiss(DialogInterface dialog) {
772                    mBrightnessController = null;
773                }
774            });
775
776            mBrightnessDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
777            mBrightnessDialog.getWindow().getAttributes().privateFlags |=
778                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
779            mBrightnessDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
780        }
781        if (!mBrightnessDialog.isShowing()) {
782            try {
783                WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
784            } catch (RemoteException e) {
785            }
786            mBrightnessDialog.show();
787            dismissBrightnessDialog(mBrightnessDialogLongTimeout);
788        }
789    }
790
791    private void dismissBrightnessDialog(int timeout) {
792        removeAllBrightnessDialogCallbacks();
793        if (mBrightnessDialog != null) {
794            mHandler.postDelayed(mDismissBrightnessDialogRunnable, timeout);
795        }
796    }
797
798    private void showBugreportDialog() {
799        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
800        builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
801            @Override
802            public void onClick(DialogInterface dialog, int which) {
803                if (which == DialogInterface.BUTTON_POSITIVE) {
804                    // Add a little delay before executing, to give the
805                    // dialog a chance to go away before it takes a
806                    // screenshot.
807                    mHandler.postDelayed(new Runnable() {
808                        @Override public void run() {
809                            try {
810                                ActivityManagerNative.getDefault()
811                                        .requestBugReport();
812                            } catch (RemoteException e) {
813                            }
814                        }
815                    }, 500);
816                }
817            }
818        });
819        builder.setMessage(com.android.internal.R.string.bugreport_message);
820        builder.setTitle(com.android.internal.R.string.bugreport_title);
821        builder.setCancelable(true);
822        final Dialog dialog = builder.create();
823        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
824        try {
825            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
826        } catch (RemoteException e) {
827        }
828        dialog.show();
829    }
830
831    private void updateWifiDisplayStatus() {
832        mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
833        applyWifiDisplayStatus();
834    }
835
836    private void applyWifiDisplayStatus() {
837        mModel.onWifiDisplayStateChanged(mWifiDisplayStatus);
838    }
839
840    private void applyBluetoothStatus() {
841        mModel.onBluetoothStateChange(mBluetoothState);
842    }
843
844    void reloadUserInfo() {
845        if (mUserInfoTask != null) {
846            mUserInfoTask.cancel(false);
847            mUserInfoTask = null;
848        }
849        if (mTilesSetUp) {
850            queryForUserInformation();
851        }
852    }
853
854    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
855        @Override
856        public void onReceive(Context context, Intent intent) {
857            final String action = intent.getAction();
858            if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
859                WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
860                        DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
861                mWifiDisplayStatus = status;
862                applyWifiDisplayStatus();
863            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
864                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
865                        BluetoothAdapter.ERROR);
866                mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
867                applyBluetoothStatus();
868            } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
869                int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
870                        BluetoothAdapter.STATE_DISCONNECTED);
871                mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
872                applyBluetoothStatus();
873            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
874                reloadUserInfo();
875            }
876        }
877    };
878
879    private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
880        @Override
881        public void onReceive(Context context, Intent intent) {
882            final String action = intent.getAction();
883            if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
884                    Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
885                try {
886                    final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
887                    if (getSendingUserId() == userId) {
888                        reloadUserInfo();
889                    }
890                } catch (RemoteException e) {
891                    Log.e(TAG, "Couldn't get current user id for profile change", e);
892                }
893            }
894
895        }
896    };
897}
898