Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.Resources;
     22 import android.database.ContentObserver;
     23 import android.net.Uri;
     24 import android.os.Handler;
     25 import android.os.HandlerThread;
     26 import android.os.Looper;
     27 import android.provider.Settings.Secure;
     28 import android.util.Log;
     29 
     30 import com.android.systemui.R;
     31 import com.android.systemui.qs.QSTile;
     32 import com.android.systemui.qs.tiles.AirplaneModeTile;
     33 import com.android.systemui.qs.tiles.BluetoothTile;
     34 import com.android.systemui.qs.tiles.CastTile;
     35 import com.android.systemui.qs.tiles.CellularTile;
     36 import com.android.systemui.qs.tiles.ColorInversionTile;
     37 import com.android.systemui.qs.tiles.FlashlightTile;
     38 import com.android.systemui.qs.tiles.HotspotTile;
     39 import com.android.systemui.qs.tiles.IntentTile;
     40 import com.android.systemui.qs.tiles.LocationTile;
     41 import com.android.systemui.qs.tiles.RotationLockTile;
     42 import com.android.systemui.qs.tiles.WifiTile;
     43 import com.android.systemui.settings.CurrentUserTracker;
     44 import com.android.systemui.statusbar.policy.BluetoothController;
     45 import com.android.systemui.statusbar.policy.CastController;
     46 import com.android.systemui.statusbar.policy.FlashlightController;
     47 import com.android.systemui.statusbar.policy.KeyguardMonitor;
     48 import com.android.systemui.statusbar.policy.LocationController;
     49 import com.android.systemui.statusbar.policy.NetworkController;
     50 import com.android.systemui.statusbar.policy.RotationLockController;
     51 import com.android.systemui.statusbar.policy.HotspotController;
     52 import com.android.systemui.statusbar.policy.SecurityController;
     53 import com.android.systemui.statusbar.policy.UserSwitcherController;
     54 import com.android.systemui.statusbar.policy.ZenModeController;
     55 
     56 import java.util.ArrayList;
     57 import java.util.Arrays;
     58 import java.util.Collection;
     59 import java.util.LinkedHashMap;
     60 import java.util.List;
     61 import java.util.Map;
     62 
     63 /** Platform implementation of the quick settings tile host **/
     64 public class QSTileHost implements QSTile.Host {
     65     private static final String TAG = "QSTileHost";
     66     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     67 
     68     private static final String TILES_SETTING = "sysui_qs_tiles";
     69 
     70     private final Context mContext;
     71     private final PhoneStatusBar mStatusBar;
     72     private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
     73     private final Observer mObserver = new Observer();
     74     private final BluetoothController mBluetooth;
     75     private final LocationController mLocation;
     76     private final RotationLockController mRotation;
     77     private final NetworkController mNetwork;
     78     private final ZenModeController mZen;
     79     private final HotspotController mHotspot;
     80     private final CastController mCast;
     81     private final Looper mLooper;
     82     private final CurrentUserTracker mUserTracker;
     83     private final FlashlightController mFlashlight;
     84     private final UserSwitcherController mUserSwitcherController;
     85     private final KeyguardMonitor mKeyguard;
     86     private final SecurityController mSecurity;
     87 
     88     private Callback mCallback;
     89 
     90     public QSTileHost(Context context, PhoneStatusBar statusBar,
     91             BluetoothController bluetooth, LocationController location,
     92             RotationLockController rotation, NetworkController network,
     93             ZenModeController zen, HotspotController hotspot,
     94             CastController cast, FlashlightController flashlight,
     95             UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
     96             SecurityController security) {
     97         mContext = context;
     98         mStatusBar = statusBar;
     99         mBluetooth = bluetooth;
    100         mLocation = location;
    101         mRotation = rotation;
    102         mNetwork = network;
    103         mZen = zen;
    104         mHotspot = hotspot;
    105         mCast = cast;
    106         mFlashlight = flashlight;
    107         mUserSwitcherController = userSwitcher;
    108         mKeyguard = keyguard;
    109         mSecurity = security;
    110 
    111         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
    112         ht.start();
    113         mLooper = ht.getLooper();
    114 
    115         mUserTracker = new CurrentUserTracker(mContext) {
    116             @Override
    117             public void onUserSwitched(int newUserId) {
    118                 recreateTiles();
    119                 for (QSTile<?> tile : mTiles.values()) {
    120                     tile.userSwitch(newUserId);
    121                 }
    122                 mSecurity.onUserSwitched(newUserId);
    123                 mObserver.register();
    124             }
    125         };
    126         recreateTiles();
    127 
    128         mUserTracker.startTracking();
    129         mObserver.register();
    130     }
    131 
    132     @Override
    133     public void setCallback(Callback callback) {
    134         mCallback = callback;
    135     }
    136 
    137     @Override
    138     public Collection<QSTile<?>> getTiles() {
    139         return mTiles.values();
    140     }
    141 
    142     @Override
    143     public void startSettingsActivity(final Intent intent) {
    144         mStatusBar.postStartSettingsActivity(intent, 0);
    145     }
    146 
    147     @Override
    148     public void warn(String message, Throwable t) {
    149         // already logged
    150     }
    151 
    152     @Override
    153     public void collapsePanels() {
    154         mStatusBar.postAnimateCollapsePanels();
    155     }
    156 
    157     @Override
    158     public Looper getLooper() {
    159         return mLooper;
    160     }
    161 
    162     @Override
    163     public Context getContext() {
    164         return mContext;
    165     }
    166 
    167     @Override
    168     public BluetoothController getBluetoothController() {
    169         return mBluetooth;
    170     }
    171 
    172     @Override
    173     public LocationController getLocationController() {
    174         return mLocation;
    175     }
    176 
    177     @Override
    178     public RotationLockController getRotationLockController() {
    179         return mRotation;
    180     }
    181 
    182     @Override
    183     public NetworkController getNetworkController() {
    184         return mNetwork;
    185     }
    186 
    187     @Override
    188     public ZenModeController getZenModeController() {
    189         return mZen;
    190     }
    191 
    192     @Override
    193     public HotspotController getHotspotController() {
    194         return mHotspot;
    195     }
    196 
    197     @Override
    198     public CastController getCastController() {
    199         return mCast;
    200     }
    201 
    202     @Override
    203     public FlashlightController getFlashlightController() {
    204         return mFlashlight;
    205     }
    206 
    207     @Override
    208     public KeyguardMonitor getKeyguardMonitor() {
    209         return mKeyguard;
    210     }
    211 
    212     public UserSwitcherController getUserSwitcherController() {
    213         return mUserSwitcherController;
    214     }
    215 
    216     public SecurityController getSecurityController() {
    217         return mSecurity;
    218     }
    219 
    220     private void recreateTiles() {
    221         if (DEBUG) Log.d(TAG, "Recreating tiles");
    222         final List<String> tileSpecs = loadTileSpecs();
    223         for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
    224             if (!tileSpecs.contains(tile.getKey())) {
    225                 if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
    226                 tile.getValue().destroy();
    227             }
    228         }
    229         final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
    230         for (String tileSpec : tileSpecs) {
    231             if (mTiles.containsKey(tileSpec)) {
    232                 newTiles.put(tileSpec, mTiles.get(tileSpec));
    233             } else {
    234                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
    235                 try {
    236                     newTiles.put(tileSpec, createTile(tileSpec));
    237                 } catch (Throwable t) {
    238                     Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
    239                 }
    240             }
    241         }
    242         if (mTiles.equals(newTiles)) return;
    243         mTiles.clear();
    244         mTiles.putAll(newTiles);
    245         if (mCallback != null) {
    246             mCallback.onTilesChanged();
    247         }
    248     }
    249 
    250     private QSTile<?> createTile(String tileSpec) {
    251         if (tileSpec.equals("wifi")) return new WifiTile(this);
    252         else if (tileSpec.equals("bt")) return new BluetoothTile(this);
    253         else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
    254         else if (tileSpec.equals("cell")) return new CellularTile(this);
    255         else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
    256         else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
    257         else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
    258         else if (tileSpec.equals("location")) return new LocationTile(this);
    259         else if (tileSpec.equals("cast")) return new CastTile(this);
    260         else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
    261         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
    262         else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
    263     }
    264 
    265     private List<String> loadTileSpecs() {
    266         final Resources res = mContext.getResources();
    267         final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
    268         String tileList = Secure.getStringForUser(mContext.getContentResolver(), TILES_SETTING,
    269                 mUserTracker.getCurrentUserId());
    270         if (tileList == null) {
    271             tileList = res.getString(R.string.quick_settings_tiles);
    272             if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);
    273         } else {
    274             if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
    275         }
    276         final ArrayList<String> tiles = new ArrayList<String>();
    277         boolean addedDefault = false;
    278         for (String tile : tileList.split(",")) {
    279             tile = tile.trim();
    280             if (tile.isEmpty()) continue;
    281             if (tile.equals("default")) {
    282                 if (!addedDefault) {
    283                     tiles.addAll(Arrays.asList(defaultTileList.split(",")));
    284                     addedDefault = true;
    285                 }
    286             } else {
    287                 tiles.add(tile);
    288             }
    289         }
    290         return tiles;
    291     }
    292 
    293     private class Observer extends ContentObserver {
    294         private boolean mRegistered;
    295 
    296         public Observer() {
    297             super(new Handler(Looper.getMainLooper()));
    298         }
    299 
    300         public void register() {
    301             if (mRegistered) {
    302                 mContext.getContentResolver().unregisterContentObserver(this);
    303             }
    304             mContext.getContentResolver().registerContentObserver(Secure.getUriFor(TILES_SETTING),
    305                     false, this, mUserTracker.getCurrentUserId());
    306             mRegistered = true;
    307         }
    308 
    309         @Override
    310         public void onChange(boolean selfChange, Uri uri) {
    311             recreateTiles();
    312         }
    313     }
    314 }
    315