TileServices.java revision d5a204f16e7c71ffdbc6c8307a4134dcc1efd60d
1/* 2 * Copyright (C) 2015 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 */ 16package com.android.systemui.qs.external; 17 18import android.content.ComponentName; 19import android.content.Context; 20import android.content.pm.PackageManager; 21import android.os.Binder; 22import android.os.Handler; 23import android.os.Looper; 24import android.service.quicksettings.IQSService; 25import android.service.quicksettings.Tile; 26import android.util.ArrayMap; 27import com.android.systemui.statusbar.phone.QSTileHost; 28 29import java.util.ArrayList; 30import java.util.Collections; 31import java.util.Comparator; 32 33/** 34 * Runs the day-to-day operations of which tiles should be bound and when. 35 */ 36public class TileServices extends IQSService.Stub { 37 static final int DEFAULT_MAX_BOUND = 3; 38 static final int REDUCED_MAX_BOUND = 1; 39 40 private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>(); 41 private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>(); 42 private final Context mContext; 43 private final Handler mHandler; 44 private final QSTileHost mHost; 45 46 private int mMaxBound = DEFAULT_MAX_BOUND; 47 48 public TileServices(QSTileHost host, Looper looper) { 49 mHost = host; 50 mContext = mHost.getContext(); 51 mHandler = new Handler(looper); 52 } 53 54 public Context getContext() { 55 return mContext; 56 } 57 58 public TileServiceManager getTileWrapper(CustomTile tile) { 59 ComponentName component = tile.getComponent(); 60 TileServiceManager service = onCreateTileService(component); 61 synchronized (mServices) { 62 mServices.put(tile, service); 63 mTiles.put(component, tile); 64 } 65 return service; 66 } 67 68 protected TileServiceManager onCreateTileService(ComponentName component) { 69 return new TileServiceManager(this, mHandler, component); 70 } 71 72 public void freeService(CustomTile tile, TileServiceManager service) { 73 synchronized (mServices) { 74 service.setBindAllowed(false); 75 mServices.remove(tile); 76 mTiles.remove(tile.getComponent()); 77 } 78 } 79 80 public void setMemoryPressure(boolean memoryPressure) { 81 mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND; 82 recalculateBindAllowance(); 83 } 84 85 public void recalculateBindAllowance() { 86 final ArrayList<TileServiceManager> services; 87 synchronized (mServices) { 88 services = new ArrayList<>(mServices.values()); 89 } 90 final int N = services.size(); 91 if (N > mMaxBound) { 92 long currentTime = System.currentTimeMillis(); 93 // Precalculate the priority of services for binding. 94 for (int i = 0; i < N; i++) { 95 services.get(i).calculateBindPriority(currentTime); 96 } 97 // Sort them so we can bind the most important first. 98 Collections.sort(services, SERVICE_SORT); 99 } 100 int i; 101 // Allow mMaxBound items to bind. 102 for (i = 0; i < mMaxBound && i < N; i++) { 103 services.get(i).setBindAllowed(true); 104 } 105 // The rest aren't allowed to bind for now. 106 while (i < N) { 107 services.get(i).setBindAllowed(false); 108 i++; 109 } 110 } 111 112 private void verifyCaller(String packageName) { 113 try { 114 int uid = mContext.getPackageManager().getPackageUid(packageName, 115 Binder.getCallingUserHandle().getIdentifier()); 116 if (Binder.getCallingUid() != uid) { 117 throw new SecurityException("Component outside caller's uid"); 118 } 119 } catch (PackageManager.NameNotFoundException e) { 120 throw new SecurityException(e); 121 } 122 } 123 124 @Override 125 public void updateQsTile(Tile tile) { 126 verifyCaller(tile.getComponentName().getPackageName()); 127 CustomTile customTile = getTileForComponent(tile.getComponentName()); 128 if (customTile != null) { 129 mServices.get(customTile).setLastUpdate(System.currentTimeMillis()); 130 customTile.updateState(tile); 131 customTile.refreshState(); 132 } 133 } 134 135 @Override 136 public void onShowDialog(Tile tile) { 137 verifyCaller(tile.getComponentName().getPackageName()); 138 CustomTile customTile = getTileForComponent(tile.getComponentName()); 139 if (customTile != null) { 140 customTile.onDialogShown(); 141 mHost.collapsePanels(); 142 } 143 } 144 145 private CustomTile getTileForComponent(ComponentName component) { 146 return mTiles.get(component); 147 } 148 149 private static final Comparator<TileServiceManager> SERVICE_SORT = 150 new Comparator<TileServiceManager>() { 151 @Override 152 public int compare(TileServiceManager left, TileServiceManager right) { 153 return -Integer.compare(left.getBindPriority(), right.getBindPriority()); 154 } 155 }; 156} 157