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