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.app.PendingIntent; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.res.Resources; 23 import android.os.HandlerThread; 24 import android.os.Looper; 25 import android.os.Process; 26 import android.util.Log; 27 28 import com.android.systemui.R; 29 import com.android.systemui.qs.QSTile; 30 import com.android.systemui.qs.tiles.AirplaneModeTile; 31 import com.android.systemui.qs.tiles.BluetoothTile; 32 import com.android.systemui.qs.tiles.CastTile; 33 import com.android.systemui.qs.tiles.CellularTile; 34 import com.android.systemui.qs.tiles.ColorInversionTile; 35 import com.android.systemui.qs.tiles.DndTile; 36 import com.android.systemui.qs.tiles.FlashlightTile; 37 import com.android.systemui.qs.tiles.HotspotTile; 38 import com.android.systemui.qs.tiles.IntentTile; 39 import com.android.systemui.qs.tiles.LocationTile; 40 import com.android.systemui.qs.tiles.RotationLockTile; 41 import com.android.systemui.qs.tiles.WifiTile; 42 import com.android.systemui.statusbar.policy.BluetoothController; 43 import com.android.systemui.statusbar.policy.CastController; 44 import com.android.systemui.statusbar.policy.FlashlightController; 45 import com.android.systemui.statusbar.policy.HotspotController; 46 import com.android.systemui.statusbar.policy.KeyguardMonitor; 47 import com.android.systemui.statusbar.policy.LocationController; 48 import com.android.systemui.statusbar.policy.NetworkController; 49 import com.android.systemui.statusbar.policy.RotationLockController; 50 import com.android.systemui.statusbar.policy.SecurityController; 51 import com.android.systemui.statusbar.policy.UserSwitcherController; 52 import com.android.systemui.statusbar.policy.ZenModeController; 53 import com.android.systemui.tuner.TunerService; 54 import com.android.systemui.tuner.TunerService.Tunable; 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, Tunable { 65 private static final String TAG = "QSTileHost"; 66 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 67 68 protected 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 protected final ArrayList<String> mTileSpecs = new ArrayList<>(); 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 FlashlightController mFlashlight; 83 private final UserSwitcherController mUserSwitcherController; 84 private final KeyguardMonitor mKeyguard; 85 private final SecurityController mSecurity; 86 87 private Callback mCallback; 88 QSTileHost(Context context, PhoneStatusBar statusBar, BluetoothController bluetooth, LocationController location, RotationLockController rotation, NetworkController network, ZenModeController zen, HotspotController hotspot, CastController cast, FlashlightController flashlight, UserSwitcherController userSwitcher, KeyguardMonitor keyguard, SecurityController security)89 public QSTileHost(Context context, PhoneStatusBar statusBar, 90 BluetoothController bluetooth, LocationController location, 91 RotationLockController rotation, NetworkController network, 92 ZenModeController zen, HotspotController hotspot, 93 CastController cast, FlashlightController flashlight, 94 UserSwitcherController userSwitcher, KeyguardMonitor keyguard, 95 SecurityController security) { 96 mContext = context; 97 mStatusBar = statusBar; 98 mBluetooth = bluetooth; 99 mLocation = location; 100 mRotation = rotation; 101 mNetwork = network; 102 mZen = zen; 103 mHotspot = hotspot; 104 mCast = cast; 105 mFlashlight = flashlight; 106 mUserSwitcherController = userSwitcher; 107 mKeyguard = keyguard; 108 mSecurity = security; 109 110 final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(), 111 Process.THREAD_PRIORITY_BACKGROUND); 112 ht.start(); 113 mLooper = ht.getLooper(); 114 115 TunerService.get(mContext).addTunable(this, TILES_SETTING); 116 } 117 destroy()118 public void destroy() { 119 TunerService.get(mContext).removeTunable(this); 120 } 121 122 @Override setCallback(Callback callback)123 public void setCallback(Callback callback) { 124 mCallback = callback; 125 } 126 127 @Override getTiles()128 public Collection<QSTile<?>> getTiles() { 129 return mTiles.values(); 130 } 131 132 @Override startActivityDismissingKeyguard(final Intent intent)133 public void startActivityDismissingKeyguard(final Intent intent) { 134 mStatusBar.postStartActivityDismissingKeyguard(intent, 0); 135 } 136 137 @Override startActivityDismissingKeyguard(PendingIntent intent)138 public void startActivityDismissingKeyguard(PendingIntent intent) { 139 mStatusBar.postStartActivityDismissingKeyguard(intent); 140 } 141 142 @Override warn(String message, Throwable t)143 public void warn(String message, Throwable t) { 144 // already logged 145 } 146 147 @Override collapsePanels()148 public void collapsePanels() { 149 mStatusBar.postAnimateCollapsePanels(); 150 } 151 152 @Override getLooper()153 public Looper getLooper() { 154 return mLooper; 155 } 156 157 @Override getContext()158 public Context getContext() { 159 return mContext; 160 } 161 162 @Override getBluetoothController()163 public BluetoothController getBluetoothController() { 164 return mBluetooth; 165 } 166 167 @Override getLocationController()168 public LocationController getLocationController() { 169 return mLocation; 170 } 171 172 @Override getRotationLockController()173 public RotationLockController getRotationLockController() { 174 return mRotation; 175 } 176 177 @Override getNetworkController()178 public NetworkController getNetworkController() { 179 return mNetwork; 180 } 181 182 @Override getZenModeController()183 public ZenModeController getZenModeController() { 184 return mZen; 185 } 186 187 @Override getHotspotController()188 public HotspotController getHotspotController() { 189 return mHotspot; 190 } 191 192 @Override getCastController()193 public CastController getCastController() { 194 return mCast; 195 } 196 197 @Override getFlashlightController()198 public FlashlightController getFlashlightController() { 199 return mFlashlight; 200 } 201 202 @Override getKeyguardMonitor()203 public KeyguardMonitor getKeyguardMonitor() { 204 return mKeyguard; 205 } 206 getUserSwitcherController()207 public UserSwitcherController getUserSwitcherController() { 208 return mUserSwitcherController; 209 } 210 getSecurityController()211 public SecurityController getSecurityController() { 212 return mSecurity; 213 } 214 215 @Override onTuningChanged(String key, String newValue)216 public void onTuningChanged(String key, String newValue) { 217 if (!TILES_SETTING.equals(key)) { 218 return; 219 } 220 if (DEBUG) Log.d(TAG, "Recreating tiles"); 221 final List<String> tileSpecs = loadTileSpecs(newValue); 222 if (tileSpecs.equals(mTileSpecs)) return; 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 mTileSpecs.clear(); 243 mTileSpecs.addAll(tileSpecs); 244 mTiles.clear(); 245 mTiles.putAll(newTiles); 246 if (mCallback != null) { 247 mCallback.onTilesChanged(); 248 } 249 } 250 createTile(String tileSpec)251 protected QSTile<?> createTile(String tileSpec) { 252 if (tileSpec.equals("wifi")) return new WifiTile(this); 253 else if (tileSpec.equals("bt")) return new BluetoothTile(this); 254 else if (tileSpec.equals("inversion")) return new ColorInversionTile(this); 255 else if (tileSpec.equals("cell")) return new CellularTile(this); 256 else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this); 257 else if (tileSpec.equals("dnd")) return new DndTile(this); 258 else if (tileSpec.equals("rotation")) return new RotationLockTile(this); 259 else if (tileSpec.equals("flashlight")) return new FlashlightTile(this); 260 else if (tileSpec.equals("location")) return new LocationTile(this); 261 else if (tileSpec.equals("cast")) return new CastTile(this); 262 else if (tileSpec.equals("hotspot")) return new HotspotTile(this); 263 else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec); 264 else throw new IllegalArgumentException("Bad tile spec: " + tileSpec); 265 } 266 loadTileSpecs(String tileList)267 protected List<String> loadTileSpecs(String tileList) { 268 final Resources res = mContext.getResources(); 269 final String defaultTileList = res.getString(R.string.quick_settings_tiles_default); 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