TileServices.java revision 34a5cef6298cc44fc0614c4747c4b17137cff441
1d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk/*
2d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * Copyright (C) 2015 The Android Open Source Project
3d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk *
4d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * you may not use this file except in compliance with the License.
6d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * You may obtain a copy of the License at
7d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk *
8d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk *
10d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * Unless required by applicable law or agreed to in writing, software
11d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * See the License for the specific language governing permissions and
14d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * limitations under the License
15d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk */
16d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkpackage com.android.systemui.qs.external;
17d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
18fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.content.BroadcastReceiver;
19d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.content.ComponentName;
20d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.content.Context;
21fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.content.Intent;
22fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.content.IntentFilter;
2366c89c15a0baabf001e69498dbc09903f72cc63dJason Monkimport android.content.pm.PackageInfo;
24d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.content.pm.PackageManager;
2566c89c15a0baabf001e69498dbc09903f72cc63dJason Monkimport android.graphics.drawable.Icon;
26d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.os.Binder;
27d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.os.Handler;
28d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.os.Looper;
29fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.os.RemoteException;
3066c89c15a0baabf001e69498dbc09903f72cc63dJason Monkimport android.os.UserHandle;
31d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.service.quicksettings.IQSService;
32d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.service.quicksettings.Tile;
33fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.service.quicksettings.TileService;
34d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport android.util.ArrayMap;
35fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monkimport android.util.Log;
36c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
3766c89c15a0baabf001e69498dbc09903f72cc63dJason Monkimport com.android.internal.statusbar.StatusBarIcon;
38d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport com.android.systemui.statusbar.phone.QSTileHost;
3966c89c15a0baabf001e69498dbc09903f72cc63dJason Monkimport com.android.systemui.statusbar.phone.StatusBarIconController;
409429513cc3ea6e58e330865bd621b57cb3477551Jason Monkimport com.android.systemui.statusbar.policy.KeyguardMonitor;
41d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
42d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport java.util.ArrayList;
43d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport java.util.Collections;
44d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkimport java.util.Comparator;
45d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
46d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk/**
47d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk * Runs the day-to-day operations of which tiles should be bound and when.
48d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk */
49d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monkpublic class TileServices extends IQSService.Stub {
50d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    static final int DEFAULT_MAX_BOUND = 3;
51d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    static final int REDUCED_MAX_BOUND = 1;
52d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
53d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
54d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
55d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private final Context mContext;
56d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private final Handler mHandler;
5766c89c15a0baabf001e69498dbc09903f72cc63dJason Monk    private final Handler mMainHandler;
58d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private final QSTileHost mHost;
59d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
60d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private int mMaxBound = DEFAULT_MAX_BOUND;
61d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
62d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public TileServices(QSTileHost host, Looper looper) {
63d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        mHost = host;
64d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        mContext = mHost.getContext();
65fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        mContext.registerReceiver(mRequestListeningReceiver,
66fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
67d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        mHandler = new Handler(looper);
6866c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        mMainHandler = new Handler(Looper.getMainLooper());
69d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
70d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
71d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public Context getContext() {
72d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        return mContext;
73d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
74d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
75d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public TileServiceManager getTileWrapper(CustomTile tile) {
76d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        ComponentName component = tile.getComponent();
77d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        TileServiceManager service = onCreateTileService(component);
78d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        synchronized (mServices) {
79d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            mServices.put(tile, service);
80d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            mTiles.put(component, tile);
81d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
82d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        return service;
83d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
84d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
85d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    protected TileServiceManager onCreateTileService(ComponentName component) {
86d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        return new TileServiceManager(this, mHandler, component);
87d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
88d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
89d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public void freeService(CustomTile tile, TileServiceManager service) {
90d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        synchronized (mServices) {
91d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            service.setBindAllowed(false);
92d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            mServices.remove(tile);
93d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            mTiles.remove(tile.getComponent());
9466c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            final String slot = tile.getComponent().getClassName();
9566c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            mMainHandler.post(new Runnable() {
9666c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                @Override
9766c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                public void run() {
9866c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                    mHost.getIconController().removeIcon(slot);
9966c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                }
10066c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            });
101d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
102d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
103d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
104d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public void setMemoryPressure(boolean memoryPressure) {
105d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
106d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        recalculateBindAllowance();
107d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
108d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
109d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public void recalculateBindAllowance() {
110d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        final ArrayList<TileServiceManager> services;
111d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        synchronized (mServices) {
112d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            services = new ArrayList<>(mServices.values());
113d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
114d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        final int N = services.size();
115d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        if (N > mMaxBound) {
116d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            long currentTime = System.currentTimeMillis();
117d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            // Precalculate the priority of services for binding.
118d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            for (int i = 0; i < N; i++) {
119d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk                services.get(i).calculateBindPriority(currentTime);
120d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            }
121d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            // Sort them so we can bind the most important first.
122d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            Collections.sort(services, SERVICE_SORT);
123d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
124d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        int i;
125d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        // Allow mMaxBound items to bind.
126d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        for (i = 0; i < mMaxBound && i < N; i++) {
127d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            services.get(i).setBindAllowed(true);
128d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
129d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        // The rest aren't allowed to bind for now.
130d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        while (i < N) {
131d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            services.get(i).setBindAllowed(false);
132d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            i++;
133d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
134d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
135d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
136d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private void verifyCaller(String packageName) {
137d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        try {
138e06b4d1d9f718b9fe02980fea794a36831a16db2Jeff Sharkey            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
139d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk                    Binder.getCallingUserHandle().getIdentifier());
140d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            if (Binder.getCallingUid() != uid) {
141d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk                throw new SecurityException("Component outside caller's uid");
142d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            }
143d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        } catch (PackageManager.NameNotFoundException e) {
144d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            throw new SecurityException(e);
145d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
146d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
147d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
148fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    private void requestListening(ComponentName component) {
149fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        synchronized (mServices) {
150fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            CustomTile customTile = getTileForComponent(component);
151fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            if (customTile == null) {
152fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                Log.d("TileServices", "Couldn't find tile for " + component);
153fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                return;
154fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
155fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            TileServiceManager service = mServices.get(customTile);
156fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            if (service.getType() != TileService.TILE_MODE_ACTIVE) {
157fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                return;
158fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
159fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            service.setBindRequested(true);
160fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            try {
161fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                service.getTileService().onStartListening();
162fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            } catch (RemoteException e) {
163fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
164fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        }
165fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    }
166fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk
167fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    @Override
168fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    public void setTileMode(ComponentName component, int mode) {
169fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        verifyCaller(component.getPackageName());
170fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        CustomTile customTile = getTileForComponent(component);
171fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        if (customTile != null) {
172fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            synchronized (mServices) {
173fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                mServices.get(customTile).setType(mode);
174fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
175fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        }
176fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    }
177fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk
178d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    @Override
179d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public void updateQsTile(Tile tile) {
18066c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        ComponentName componentName = tile.getComponentName();
18166c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        verifyCaller(componentName.getPackageName());
18266c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        CustomTile customTile = getTileForComponent(componentName);
183d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        if (customTile != null) {
184fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            synchronized (mServices) {
185fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
186fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
187d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            customTile.updateState(tile);
188d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            customTile.refreshState();
189d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
190d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
191d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
192d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    @Override
193d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    public void onShowDialog(Tile tile) {
19466c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        ComponentName componentName = tile.getComponentName();
19566c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        verifyCaller(componentName.getPackageName());
19666c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        CustomTile customTile = getTileForComponent(componentName);
197d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        if (customTile != null) {
198d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            customTile.onDialogShown();
199d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            mHost.collapsePanels();
20034a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk            mServices.get(customTile).setShowingDialog(true);
20134a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk        }
20234a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk    }
20334a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk
20434a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk    @Override
20534a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk    public void onDialogHidden(Tile tile) {
20634a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk        ComponentName componentName = tile.getComponentName();
20734a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk        verifyCaller(componentName.getPackageName());
20834a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk        CustomTile customTile = getTileForComponent(componentName);
20934a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk        if (customTile != null) {
21034a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk            mServices.get(customTile).setShowingDialog(false);
21134a5cef6298cc44fc0614c4747c4b17137cff441Jason Monk            customTile.onDialogHidden();
212d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
213d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
214d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
21566c89c15a0baabf001e69498dbc09903f72cc63dJason Monk    @Override
2169429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    public void onStartActivity(Tile tile) {
2179429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        ComponentName componentName = tile.getComponentName();
2189429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        verifyCaller(componentName.getPackageName());
2199429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        CustomTile customTile = getTileForComponent(componentName);
2209429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        if (customTile != null) {
2219429513cc3ea6e58e330865bd621b57cb3477551Jason Monk            mHost.collapsePanels();
2229429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        }
2239429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    }
2249429513cc3ea6e58e330865bd621b57cb3477551Jason Monk
2259429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    @Override
22666c89c15a0baabf001e69498dbc09903f72cc63dJason Monk    public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
22766c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        final ComponentName componentName = tile.getComponentName();
22866c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        String packageName = componentName.getPackageName();
22966c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        verifyCaller(packageName);
23066c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        CustomTile customTile = getTileForComponent(componentName);
23166c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        if (customTile != null) {
23266c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            try {
23366c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                UserHandle userHandle = getCallingUserHandle();
23466c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
23566c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                        userHandle.getIdentifier());
23666c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                if (info.applicationInfo.isSystemApp()) {
23766c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                    final StatusBarIcon statusIcon = icon != null
23866c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                            ? new StatusBarIcon(userHandle, packageName, icon, 0, 0,
23966c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                                    contentDescription)
24066c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                            : null;
24166c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                    mMainHandler.post(new Runnable() {
24266c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                        @Override
24366c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                        public void run() {
24466c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                            StatusBarIconController iconController = mHost.getIconController();
24566c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                            iconController.setIcon(componentName.getClassName(), statusIcon);
24666c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                            iconController.setExternalIcon(componentName.getClassName());
24766c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                        }
24866c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                    });
24966c89c15a0baabf001e69498dbc09903f72cc63dJason Monk                }
25066c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            } catch (PackageManager.NameNotFoundException e) {
25166c89c15a0baabf001e69498dbc09903f72cc63dJason Monk            }
25266c89c15a0baabf001e69498dbc09903f72cc63dJason Monk        }
25366c89c15a0baabf001e69498dbc09903f72cc63dJason Monk    }
25466c89c15a0baabf001e69498dbc09903f72cc63dJason Monk
2559429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    @Override
2569429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    public void startUnlockAndRun(Tile tile) {
2579429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        ComponentName componentName = tile.getComponentName();
2589429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        verifyCaller(componentName.getPackageName());
2599429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        CustomTile customTile = getTileForComponent(componentName);
2609429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        if (customTile != null) {
2619429513cc3ea6e58e330865bd621b57cb3477551Jason Monk            customTile.startUnlockAndRun();
2629429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        }
2639429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    }
2649429513cc3ea6e58e330865bd621b57cb3477551Jason Monk
2659429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    @Override
2669429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    public boolean isLocked() {
2679429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
2689429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        return keyguardMonitor.isShowing();
2699429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    }
2709429513cc3ea6e58e330865bd621b57cb3477551Jason Monk
2719429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    @Override
2729429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    public boolean isSecure() {
2739429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
2749429513cc3ea6e58e330865bd621b57cb3477551Jason Monk        return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
2759429513cc3ea6e58e330865bd621b57cb3477551Jason Monk    }
2769429513cc3ea6e58e330865bd621b57cb3477551Jason Monk
277d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private CustomTile getTileForComponent(ComponentName component) {
278fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        synchronized (mServices) {
279fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            return mTiles.get(component);
280fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        }
281d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    }
282d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk
283fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
284fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        @Override
285fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        public void onReceive(Context context, Intent intent) {
286fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
287fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                requestListening(
288fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk                        (ComponentName) intent.getParcelableExtra(TileService.EXTRA_COMPONENT));
289fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk            }
290fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk        }
291fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk    };
292fe8f6826ce3c2beeb1fce54c67978ce69f849407Jason Monk
293d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    private static final Comparator<TileServiceManager> SERVICE_SORT =
294d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            new Comparator<TileServiceManager>() {
295d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        @Override
296d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        public int compare(TileServiceManager left, TileServiceManager right) {
297d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk            return -Integer.compare(left.getBindPriority(), right.getBindPriority());
298d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk        }
299d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk    };
300d5a204f16e7c71ffdbc6c8307a4134dcc1efd60dJason Monk}
301