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