Home | History | Annotate | Download | only in phone
      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 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import android.animation.ValueAnimator;
     20 import android.app.ActivityManagerNative;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.PendingIntent;
     24 import android.app.admin.DevicePolicyManager;
     25 import android.bluetooth.BluetoothAdapter;
     26 import android.content.BroadcastReceiver;
     27 import android.content.ComponentName;
     28 import android.content.Context;
     29 import android.content.DialogInterface;
     30 import android.content.DialogInterface.OnClickListener;
     31 import android.content.Intent;
     32 import android.content.IntentFilter;
     33 import android.content.pm.PackageManager.NameNotFoundException;
     34 import android.content.pm.UserInfo;
     35 import android.content.res.Resources;
     36 import android.database.Cursor;
     37 import android.graphics.Bitmap;
     38 import android.graphics.drawable.BitmapDrawable;
     39 import android.graphics.drawable.Drawable;
     40 import android.hardware.display.DisplayManager;
     41 import android.media.MediaRouter;
     42 import android.net.wifi.WifiManager;
     43 import android.os.AsyncTask;
     44 import android.os.Handler;
     45 import android.os.RemoteException;
     46 import android.os.UserHandle;
     47 import android.os.UserManager;
     48 import android.provider.AlarmClock;
     49 import android.provider.ContactsContract;
     50 import android.provider.ContactsContract.CommonDataKinds.Phone;
     51 import android.provider.ContactsContract.Profile;
     52 import android.provider.Settings;
     53 import android.security.KeyChain;
     54 import android.util.Log;
     55 import android.util.Pair;
     56 import android.view.LayoutInflater;
     57 import android.view.View;
     58 import android.view.ViewGroup;
     59 import android.view.WindowManager;
     60 import android.view.WindowManagerGlobal;
     61 import android.widget.ImageView;
     62 import android.widget.TextView;
     63 
     64 import com.android.internal.app.MediaRouteDialogPresenter;
     65 import com.android.systemui.R;
     66 import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
     67 import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
     68 import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
     69 import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
     70 import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
     71 import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
     72 import com.android.systemui.statusbar.policy.BatteryController;
     73 import com.android.systemui.statusbar.policy.BluetoothController;
     74 import com.android.systemui.statusbar.policy.LocationController;
     75 import com.android.systemui.statusbar.policy.NetworkController;
     76 import com.android.systemui.statusbar.policy.RotationLockController;
     77 
     78 import java.util.ArrayList;
     79 
     80 /**
     81  *
     82  */
     83 class QuickSettings {
     84     static final boolean DEBUG_GONE_TILES = false;
     85     private static final String TAG = "QuickSettings";
     86     public static final boolean SHOW_IME_TILE = false;
     87 
     88     public static final boolean LONG_PRESS_TOGGLES = true;
     89 
     90     private Context mContext;
     91     private PanelBar mBar;
     92     private QuickSettingsModel mModel;
     93     private ViewGroup mContainerView;
     94 
     95     private DevicePolicyManager mDevicePolicyManager;
     96     private PhoneStatusBar mStatusBarService;
     97     private BluetoothState mBluetoothState;
     98     private BluetoothAdapter mBluetoothAdapter;
     99     private WifiManager mWifiManager;
    100 
    101     private BluetoothController mBluetoothController;
    102     private RotationLockController mRotationLockController;
    103     private LocationController mLocationController;
    104 
    105     private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
    106     private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask;
    107 
    108     boolean mTilesSetUp = false;
    109     boolean mUseDefaultAvatar = false;
    110 
    111     private Handler mHandler;
    112 
    113     // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
    114     // configuration change)
    115     private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
    116             new ArrayList<QuickSettingsTileView>();
    117 
    118     public QuickSettings(Context context, QuickSettingsContainerView container) {
    119         mDevicePolicyManager
    120             = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
    121         mContext = context;
    122         mContainerView = container;
    123         mModel = new QuickSettingsModel(context);
    124         mBluetoothState = new QuickSettingsModel.BluetoothState();
    125         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    126         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    127 
    128         mHandler = new Handler();
    129 
    130         IntentFilter filter = new IntentFilter();
    131         filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
    132         filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
    133         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
    134         filter.addAction(Intent.ACTION_USER_SWITCHED);
    135         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
    136         filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
    137         mContext.registerReceiver(mReceiver, filter);
    138 
    139         IntentFilter profileFilter = new IntentFilter();
    140         profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
    141         profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
    142         mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
    143                 null, null);
    144     }
    145 
    146     void setBar(PanelBar bar) {
    147         mBar = bar;
    148     }
    149 
    150     public void setService(PhoneStatusBar phoneStatusBar) {
    151         mStatusBarService = phoneStatusBar;
    152     }
    153 
    154     public PhoneStatusBar getService() {
    155         return mStatusBarService;
    156     }
    157 
    158     public void setImeWindowStatus(boolean visible) {
    159         mModel.onImeWindowStatusChanged(visible);
    160     }
    161 
    162     void setup(NetworkController networkController, BluetoothController bluetoothController,
    163             BatteryController batteryController, LocationController locationController,
    164             RotationLockController rotationLockController) {
    165         mBluetoothController = bluetoothController;
    166         mRotationLockController = rotationLockController;
    167         mLocationController = locationController;
    168 
    169         setupQuickSettings();
    170         updateResources();
    171         applyLocationEnabledStatus();
    172 
    173         networkController.addNetworkSignalChangedCallback(mModel);
    174         bluetoothController.addStateChangedCallback(mModel);
    175         batteryController.addStateChangedCallback(mModel);
    176         locationController.addSettingsChangedCallback(mModel);
    177         rotationLockController.addRotationLockControllerCallback(mModel);
    178     }
    179 
    180     private void queryForSslCaCerts() {
    181         mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
    182             @Override
    183             protected Pair<Boolean, Boolean> doInBackground(Void... params) {
    184                 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
    185                 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
    186 
    187                 return Pair.create(hasCert, isManaged);
    188             }
    189             @Override
    190             protected void onPostExecute(Pair<Boolean, Boolean> result) {
    191                 super.onPostExecute(result);
    192                 boolean hasCert = result.first;
    193                 boolean isManaged = result.second;
    194                 mModel.setSslCaCertWarningTileInfo(hasCert, isManaged);
    195             }
    196         };
    197         mQueryCertTask.execute();
    198     }
    199 
    200     private void queryForUserInformation() {
    201         Context currentUserContext = null;
    202         UserInfo userInfo = null;
    203         try {
    204             userInfo = ActivityManagerNative.getDefault().getCurrentUser();
    205             currentUserContext = mContext.createPackageContextAsUser("android", 0,
    206                     new UserHandle(userInfo.id));
    207         } catch (NameNotFoundException e) {
    208             Log.e(TAG, "Couldn't create user context", e);
    209             throw new RuntimeException(e);
    210         } catch (RemoteException e) {
    211             Log.e(TAG, "Couldn't get user info", e);
    212         }
    213         final int userId = userInfo.id;
    214         final String userName = userInfo.name;
    215 
    216         final Context context = currentUserContext;
    217         mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
    218             @Override
    219             protected Pair<String, Drawable> doInBackground(Void... params) {
    220                 final UserManager um = UserManager.get(mContext);
    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                     mUseDefaultAvatar = true;
    232                 }
    233 
    234                 // If it's a single-user device, get the profile name, since the nickname is not
    235                 // usually valid
    236                 if (um.getUsers().size() <= 1) {
    237                     // Try and read the display name from the local profile
    238                     final Cursor cursor = context.getContentResolver().query(
    239                             Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
    240                             null, null, null);
    241                     if (cursor != null) {
    242                         try {
    243                             if (cursor.moveToFirst()) {
    244                                 name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
    245                             }
    246                         } finally {
    247                             cursor.close();
    248                         }
    249                     }
    250                 }
    251                 return new Pair<String, Drawable>(name, avatar);
    252             }
    253 
    254             @Override
    255             protected void onPostExecute(Pair<String, Drawable> result) {
    256                 super.onPostExecute(result);
    257                 mModel.setUserTileInfo(result.first, result.second);
    258                 mUserInfoTask = null;
    259             }
    260         };
    261         mUserInfoTask.execute();
    262     }
    263 
    264     private void setupQuickSettings() {
    265         // Setup the tiles that we are going to be showing (including the temporary ones)
    266         LayoutInflater inflater = LayoutInflater.from(mContext);
    267 
    268         addUserTiles(mContainerView, inflater);
    269         addSystemTiles(mContainerView, inflater);
    270         addTemporaryTiles(mContainerView, inflater);
    271 
    272         queryForUserInformation();
    273         queryForSslCaCerts();
    274         mTilesSetUp = true;
    275     }
    276 
    277     private void startSettingsActivity(String action) {
    278         Intent intent = new Intent(action);
    279         startSettingsActivity(intent);
    280     }
    281 
    282     private void startSettingsActivity(Intent intent) {
    283         startSettingsActivity(intent, true);
    284     }
    285 
    286     private void collapsePanels() {
    287         getService().animateCollapsePanels();
    288     }
    289 
    290     private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
    291         if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
    292         try {
    293             // Dismiss the lock screen when Settings starts.
    294             ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
    295         } catch (RemoteException e) {
    296         }
    297         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    298         mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
    299         collapsePanels();
    300     }
    301 
    302     private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
    303         QuickSettingsTileView userTile = (QuickSettingsTileView)
    304                 inflater.inflate(R.layout.quick_settings_tile, parent, false);
    305         userTile.setContent(R.layout.quick_settings_tile_user, inflater);
    306         userTile.setOnClickListener(new View.OnClickListener() {
    307             @Override
    308             public void onClick(View v) {
    309                 collapsePanels();
    310                 final UserManager um = UserManager.get(mContext);
    311                 if (um.getUsers(true).size() > 1) {
    312                     // Since keyguard and systemui were merged into the same process to save
    313                     // memory, they share the same Looper and graphics context.  As a result,
    314                     // there's no way to allow concurrent animation while keyguard inflates.
    315                     // The workaround is to add a slight delay to allow the animation to finish.
    316                     mHandler.postDelayed(new Runnable() {
    317                         public void run() {
    318                             try {
    319                                 WindowManagerGlobal.getWindowManagerService().lockNow(null);
    320                             } catch (RemoteException e) {
    321                                 Log.e(TAG, "Couldn't show user switcher", e);
    322                             }
    323                         }
    324                     }, 400); // TODO: ideally this would be tied to the collapse of the panel
    325                 } else {
    326                     Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
    327                             mContext, v, ContactsContract.Profile.CONTENT_URI,
    328                             ContactsContract.QuickContact.MODE_LARGE, null);
    329                     mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
    330                 }
    331             }
    332         });
    333         mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
    334             @Override
    335             public void refreshView(QuickSettingsTileView view, State state) {
    336                 UserState us = (UserState) state;
    337                 ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
    338                 TextView tv = (TextView) view.findViewById(R.id.user_textview);
    339                 tv.setText(state.label);
    340                 iv.setImageDrawable(us.avatar);
    341                 view.setContentDescription(mContext.getString(
    342                         R.string.accessibility_quick_settings_user, state.label));
    343             }
    344         });
    345         parent.addView(userTile);
    346         mDynamicSpannedTiles.add(userTile);
    347 
    348         // Brightness
    349         final QuickSettingsBasicTile brightnessTile
    350                 = new QuickSettingsBasicTile(mContext);
    351         brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off);
    352         brightnessTile.setOnClickListener(new View.OnClickListener() {
    353             @Override
    354             public void onClick(View v) {
    355                 collapsePanels();
    356                 showBrightnessDialog();
    357             }
    358         });
    359         mModel.addBrightnessTile(brightnessTile,
    360                 new QuickSettingsModel.BasicRefreshCallback(brightnessTile));
    361         parent.addView(brightnessTile);
    362         mDynamicSpannedTiles.add(brightnessTile);
    363 
    364         // Settings tile
    365         final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext);
    366         settingsTile.setImageResource(R.drawable.ic_qs_settings);
    367         settingsTile.setOnClickListener(new View.OnClickListener() {
    368             @Override
    369             public void onClick(View v) {
    370                 startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
    371             }
    372         });
    373         mModel.addSettingsTile(settingsTile,
    374                 new QuickSettingsModel.BasicRefreshCallback(settingsTile));
    375         parent.addView(settingsTile);
    376         mDynamicSpannedTiles.add(settingsTile);
    377     }
    378 
    379     private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
    380         // Wi-fi
    381         final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
    382                 inflater.inflate(R.layout.quick_settings_tile, parent, false);
    383         wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
    384         wifiTile.setOnClickListener(new View.OnClickListener() {
    385             @Override
    386             public void onClick(View v) {
    387                 startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
    388             }
    389         });
    390         if (LONG_PRESS_TOGGLES) {
    391             wifiTile.setOnLongClickListener(new View.OnLongClickListener() {
    392                 @Override
    393                 public boolean onLongClick(View v) {
    394                     final boolean enable =
    395                             (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED);
    396                     new AsyncTask<Void, Void, Void>() {
    397                         @Override
    398                         protected Void doInBackground(Void... args) {
    399                             // Disable tethering if enabling Wifi
    400                             final int wifiApState = mWifiManager.getWifiApState();
    401                             if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
    402                                            (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
    403                                 mWifiManager.setWifiApEnabled(null, false);
    404                             }
    405 
    406                             mWifiManager.setWifiEnabled(enable);
    407                             return null;
    408                         }
    409                     }.execute();
    410                     wifiTile.setPressed(false);
    411                     return true;
    412                 }} );
    413         }
    414         mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
    415             @Override
    416             public void refreshView(QuickSettingsTileView view, State state) {
    417                 WifiState wifiState = (WifiState) state;
    418                 ImageView iv = (ImageView) view.findViewById(R.id.image);
    419                 iv.setImageResource(wifiState.iconId);
    420                 setActivity(view, wifiState);
    421                 TextView tv = (TextView) view.findViewById(R.id.text);
    422                 tv.setText(wifiState.label);
    423                 wifiTile.setContentDescription(mContext.getString(
    424                         R.string.accessibility_quick_settings_wifi,
    425                         wifiState.signalContentDescription,
    426                         (wifiState.connected) ? wifiState.label : ""));
    427             }
    428         });
    429         parent.addView(wifiTile);
    430 
    431         if (mModel.deviceHasMobileData()) {
    432             // RSSI
    433             QuickSettingsTileView rssiTile = (QuickSettingsTileView)
    434                     inflater.inflate(R.layout.quick_settings_tile, parent, false);
    435             rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
    436             rssiTile.setOnClickListener(new View.OnClickListener() {
    437                 @Override
    438                 public void onClick(View v) {
    439                     Intent intent = new Intent();
    440                     intent.setComponent(new ComponentName(
    441                             "com.android.settings",
    442                             "com.android.settings.Settings$DataUsageSummaryActivity"));
    443                     startSettingsActivity(intent);
    444                 }
    445             });
    446             mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
    447                 @Override
    448                 public void refreshView(QuickSettingsTileView view, State state) {
    449                     RSSIState rssiState = (RSSIState) state;
    450                     ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
    451                     ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
    452                     TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
    453                     // Force refresh
    454                     iv.setImageDrawable(null);
    455                     iv.setImageResource(rssiState.signalIconId);
    456 
    457                     if (rssiState.dataTypeIconId > 0) {
    458                         iov.setImageResource(rssiState.dataTypeIconId);
    459                     } else {
    460                         iov.setImageDrawable(null);
    461                     }
    462                     setActivity(view, rssiState);
    463 
    464                     tv.setText(state.label);
    465                     view.setContentDescription(mContext.getResources().getString(
    466                             R.string.accessibility_quick_settings_mobile,
    467                             rssiState.signalContentDescription, rssiState.dataContentDescription,
    468                             state.label));
    469                 }
    470             });
    471             parent.addView(rssiTile);
    472         }
    473 
    474         // Rotation Lock
    475         if (mContext.getResources().getBoolean(R.bool.quick_settings_show_rotation_lock)
    476                 || DEBUG_GONE_TILES) {
    477             final QuickSettingsBasicTile rotationLockTile
    478                     = new QuickSettingsBasicTile(mContext);
    479             rotationLockTile.setOnClickListener(new View.OnClickListener() {
    480                 @Override
    481                 public void onClick(View view) {
    482                     final boolean locked = mRotationLockController.isRotationLocked();
    483                     mRotationLockController.setRotationLocked(!locked);
    484                 }
    485             });
    486             mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
    487                     new QuickSettingsModel.RefreshCallback() {
    488                         @Override
    489                         public void refreshView(QuickSettingsTileView view, State state) {
    490                             QuickSettingsModel.RotationLockState rotationLockState =
    491                                     (QuickSettingsModel.RotationLockState) state;
    492                             view.setVisibility(rotationLockState.visible
    493                                     ? View.VISIBLE : View.GONE);
    494                             if (state.iconId != 0) {
    495                                 // needed to flush any cached IDs
    496                                 rotationLockTile.setImageDrawable(null);
    497                                 rotationLockTile.setImageResource(state.iconId);
    498                             }
    499                             if (state.label != null) {
    500                                 rotationLockTile.setText(state.label);
    501                             }
    502                         }
    503                     });
    504             parent.addView(rotationLockTile);
    505         }
    506 
    507         // Battery
    508         final QuickSettingsTileView batteryTile = (QuickSettingsTileView)
    509                 inflater.inflate(R.layout.quick_settings_tile, parent, false);
    510         batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
    511         batteryTile.setOnClickListener(new View.OnClickListener() {
    512             @Override
    513             public void onClick(View v) {
    514                 startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
    515             }
    516         });
    517         mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
    518             @Override
    519             public void refreshView(QuickSettingsTileView unused, State state) {
    520                 QuickSettingsModel.BatteryState batteryState =
    521                         (QuickSettingsModel.BatteryState) state;
    522                 String t;
    523                 if (batteryState.batteryLevel == 100) {
    524                     t = mContext.getString(R.string.quick_settings_battery_charged_label);
    525                 } else {
    526                     t = batteryState.pluggedIn
    527                         ? mContext.getString(R.string.quick_settings_battery_charging_label,
    528                                 batteryState.batteryLevel)
    529                         : mContext.getString(R.string.status_bar_settings_battery_meter_format,
    530                                 batteryState.batteryLevel);
    531                 }
    532                 ((TextView)batteryTile.findViewById(R.id.text)).setText(t);
    533                 batteryTile.setContentDescription(
    534                         mContext.getString(R.string.accessibility_quick_settings_battery, t));
    535             }
    536         });
    537         parent.addView(batteryTile);
    538 
    539         // Airplane Mode
    540         final QuickSettingsBasicTile airplaneTile
    541                 = new QuickSettingsBasicTile(mContext);
    542         mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
    543             @Override
    544             public void refreshView(QuickSettingsTileView unused, State state) {
    545                 airplaneTile.setImageResource(state.iconId);
    546 
    547                 String airplaneState = mContext.getString(
    548                         (state.enabled) ? R.string.accessibility_desc_on
    549                                 : R.string.accessibility_desc_off);
    550                 airplaneTile.setContentDescription(
    551                         mContext.getString(R.string.accessibility_quick_settings_airplane, airplaneState));
    552                 airplaneTile.setText(state.label);
    553             }
    554         });
    555         parent.addView(airplaneTile);
    556 
    557         // Bluetooth
    558         if (mModel.deviceSupportsBluetooth()
    559                 || DEBUG_GONE_TILES) {
    560             final QuickSettingsBasicTile bluetoothTile
    561                     = new QuickSettingsBasicTile(mContext);
    562             bluetoothTile.setOnClickListener(new View.OnClickListener() {
    563                 @Override
    564                 public void onClick(View v) {
    565                     startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
    566                 }
    567             });
    568             if (LONG_PRESS_TOGGLES) {
    569                 bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() {
    570                     @Override
    571                     public boolean onLongClick(View v) {
    572                         if (mBluetoothAdapter.isEnabled()) {
    573                             mBluetoothAdapter.disable();
    574                         } else {
    575                             mBluetoothAdapter.enable();
    576                         }
    577                         bluetoothTile.setPressed(false);
    578                         return true;
    579                     }});
    580             }
    581             mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
    582                 @Override
    583                 public void refreshView(QuickSettingsTileView unused, State state) {
    584                     BluetoothState bluetoothState = (BluetoothState) state;
    585                     bluetoothTile.setImageResource(state.iconId);
    586 
    587                     /*
    588                     Resources r = mContext.getResources();
    589                     //TODO: Show connected bluetooth device label
    590                     Set<BluetoothDevice> btDevices =
    591                             mBluetoothController.getBondedBluetoothDevices();
    592                     if (btDevices.size() == 1) {
    593                         // Show the name of the bluetooth device you are connected to
    594                         label = btDevices.iterator().next().getName();
    595                     } else if (btDevices.size() > 1) {
    596                         // Show a generic label about the number of bluetooth devices
    597                         label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label,
    598                                 btDevices.size());
    599                     }
    600                     */
    601                     bluetoothTile.setContentDescription(mContext.getString(
    602                             R.string.accessibility_quick_settings_bluetooth,
    603                             bluetoothState.stateContentDescription));
    604                     bluetoothTile.setText(state.label);
    605                 }
    606             });
    607             parent.addView(bluetoothTile);
    608         }
    609 
    610         // Location
    611         final QuickSettingsBasicTile locationTile
    612                 = new QuickSettingsBasicTile(mContext);
    613         locationTile.setImageResource(R.drawable.ic_qs_location_on);
    614         locationTile.setTextResource(R.string.quick_settings_location_label);
    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         if (LONG_PRESS_TOGGLES) {
    622             locationTile.setOnLongClickListener(new View.OnLongClickListener() {
    623                 @Override
    624                 public boolean onLongClick(View v) {
    625                     boolean newLocationEnabledState = !mLocationController.isLocationEnabled();
    626                     if (mLocationController.setLocationEnabled(newLocationEnabledState)
    627                             && newLocationEnabledState) {
    628                         // If we've successfully switched from location off to on, close the
    629                         // notifications tray to show the network location provider consent dialog.
    630                         Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    631                         mContext.sendBroadcast(closeDialog);
    632                     }
    633                     return true; // Consume click
    634                 }} );
    635         }
    636         mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
    637             @Override
    638             public void refreshView(QuickSettingsTileView unused, State state) {
    639                 locationTile.setImageResource(state.iconId);
    640                 String locationState = mContext.getString(
    641                         (state.enabled) ? R.string.accessibility_desc_on
    642                                 : R.string.accessibility_desc_off);
    643                 locationTile.setContentDescription(mContext.getString(
    644                         R.string.accessibility_quick_settings_location,
    645                         locationState));
    646                 locationTile.setText(state.label);
    647             }
    648         });
    649         parent.addView(locationTile);
    650     }
    651 
    652     private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
    653         // Alarm tile
    654         final QuickSettingsBasicTile alarmTile
    655                 = new QuickSettingsBasicTile(mContext);
    656         alarmTile.setImageResource(R.drawable.ic_qs_alarm_on);
    657         alarmTile.setOnClickListener(new View.OnClickListener() {
    658             @Override
    659             public void onClick(View v) {
    660                 startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
    661             }
    662         });
    663         mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
    664             @Override
    665             public void refreshView(QuickSettingsTileView unused, State alarmState) {
    666                 alarmTile.setText(alarmState.label);
    667                 alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
    668                 alarmTile.setContentDescription(mContext.getString(
    669                         R.string.accessibility_quick_settings_alarm, alarmState.label));
    670             }
    671         });
    672         parent.addView(alarmTile);
    673 
    674         // Remote Display
    675         QuickSettingsBasicTile remoteDisplayTile
    676                 = new QuickSettingsBasicTile(mContext);
    677         remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
    678             @Override
    679             public void onClick(View v) {
    680                 collapsePanels();
    681 
    682                 final Dialog[] dialog = new Dialog[1];
    683                 dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
    684                         MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
    685                         new View.OnClickListener() {
    686                     @Override
    687                     public void onClick(View v) {
    688                         dialog[0].dismiss();
    689                         startSettingsActivity(
    690                                 android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
    691                     }
    692                 });
    693                 dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
    694                 dialog[0].show();
    695             }
    696         });
    697         mModel.addRemoteDisplayTile(remoteDisplayTile,
    698                 new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
    699                         .setShowWhenEnabled(true));
    700         parent.addView(remoteDisplayTile);
    701 
    702         if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
    703             // IME
    704             final QuickSettingsBasicTile imeTile
    705                     = new QuickSettingsBasicTile(mContext);
    706             imeTile.setImageResource(R.drawable.ic_qs_ime);
    707             imeTile.setOnClickListener(new View.OnClickListener() {
    708                 @Override
    709                 public void onClick(View v) {
    710                     try {
    711                         collapsePanels();
    712                         Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
    713                         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
    714                         pendingIntent.send();
    715                     } catch (Exception e) {}
    716                 }
    717             });
    718             mModel.addImeTile(imeTile,
    719                     new QuickSettingsModel.BasicRefreshCallback(imeTile)
    720                             .setShowWhenEnabled(true));
    721             parent.addView(imeTile);
    722         }
    723 
    724         // Bug reports
    725         final QuickSettingsBasicTile bugreportTile
    726                 = new QuickSettingsBasicTile(mContext);
    727         bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb);
    728         bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title);
    729         bugreportTile.setOnClickListener(new View.OnClickListener() {
    730             @Override
    731             public void onClick(View v) {
    732                 collapsePanels();
    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         // SSL CA Cert Warning.
    761         final QuickSettingsBasicTile sslCaCertWarningTile =
    762                 new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring);
    763         sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() {
    764             @Override
    765             public void onClick(View v) {
    766                 collapsePanels();
    767                 startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
    768             }
    769         });
    770 
    771         sslCaCertWarningTile.setImageResource(
    772                 com.android.internal.R.drawable.indicator_input_error);
    773         sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning);
    774 
    775         mModel.addSslCaCertWarningTile(sslCaCertWarningTile,
    776                 new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile)
    777                         .setShowWhenEnabled(true));
    778         parent.addView(sslCaCertWarningTile);
    779     }
    780 
    781     void updateResources() {
    782         Resources r = mContext.getResources();
    783 
    784         // Update the model
    785         mModel.updateResources();
    786 
    787         // Update the User, Time, and Settings tiles spans, and reset everything else
    788         int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
    789         for (QuickSettingsTileView v : mDynamicSpannedTiles) {
    790             v.setColumnSpan(span);
    791         }
    792         ((QuickSettingsContainerView)mContainerView).updateResources();
    793         mContainerView.requestLayout();
    794     }
    795 
    796 
    797     private void showBrightnessDialog() {
    798         Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
    799         mContext.sendBroadcast(intent);
    800     }
    801 
    802     private void showBugreportDialog() {
    803         final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
    804         builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
    805             @Override
    806             public void onClick(DialogInterface dialog, int which) {
    807                 if (which == DialogInterface.BUTTON_POSITIVE) {
    808                     // Add a little delay before executing, to give the
    809                     // dialog a chance to go away before it takes a
    810                     // screenshot.
    811                     mHandler.postDelayed(new Runnable() {
    812                         @Override public void run() {
    813                             try {
    814                                 ActivityManagerNative.getDefault()
    815                                         .requestBugReport();
    816                             } catch (RemoteException e) {
    817                             }
    818                         }
    819                     }, 500);
    820                 }
    821             }
    822         });
    823         builder.setMessage(com.android.internal.R.string.bugreport_message);
    824         builder.setTitle(com.android.internal.R.string.bugreport_title);
    825         builder.setCancelable(true);
    826         final Dialog dialog = builder.create();
    827         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    828         try {
    829             WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
    830         } catch (RemoteException e) {
    831         }
    832         dialog.show();
    833     }
    834 
    835     private void applyBluetoothStatus() {
    836         mModel.onBluetoothStateChange(mBluetoothState);
    837     }
    838 
    839     private void applyLocationEnabledStatus() {
    840         mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled());
    841     }
    842 
    843     void reloadUserInfo() {
    844         if (mUserInfoTask != null) {
    845             mUserInfoTask.cancel(false);
    846             mUserInfoTask = null;
    847         }
    848         if (mTilesSetUp) {
    849             queryForUserInformation();
    850             queryForSslCaCerts();
    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 (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
    859                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
    860                         BluetoothAdapter.ERROR);
    861                 mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
    862                 applyBluetoothStatus();
    863             } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
    864                 int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
    865                         BluetoothAdapter.STATE_DISCONNECTED);
    866                 mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
    867                 applyBluetoothStatus();
    868             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
    869                 reloadUserInfo();
    870             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
    871                 if (mUseDefaultAvatar) {
    872                     queryForUserInformation();
    873                 }
    874             } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
    875                 queryForSslCaCerts();
    876             }
    877         }
    878     };
    879 
    880     private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
    881         @Override
    882         public void onReceive(Context context, Intent intent) {
    883             final String action = intent.getAction();
    884             if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
    885                     Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
    886                 try {
    887                     final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
    888                     final int changedUser =
    889                             intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
    890                     if (changedUser == currentUser) {
    891                         reloadUserInfo();
    892                     }
    893                 } catch (RemoteException e) {
    894                     Log.e(TAG, "Couldn't get current user id for profile change", e);
    895                 }
    896             }
    897 
    898         }
    899     };
    900 
    901     private abstract static class NetworkActivityCallback
    902             implements QuickSettingsModel.RefreshCallback {
    903         private final long mDefaultDuration = new ValueAnimator().getDuration();
    904         private final long mShortDuration = mDefaultDuration / 3;
    905 
    906         public void setActivity(View view, ActivityState state) {
    907             setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
    908             setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
    909         }
    910 
    911         private void setVisibility(View view, boolean visible) {
    912             final float newAlpha = visible ? 1 : 0;
    913             if (view.getAlpha() != newAlpha) {
    914                 view.animate()
    915                     .setDuration(visible ? mShortDuration : mDefaultDuration)
    916                     .alpha(newAlpha)
    917                     .start();
    918             }
    919         }
    920     }
    921 }
    922