blob: aa85f784fe4bcd6773e56d6f6e51859bfb4de1a3 [file] [log] [blame]
Jason Monk62b63a02016-02-02 15:15:31 -05001/*
2 * Copyright (C) 2016 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
17package com.android.systemui.qs.customize;
18
Jason Monkb53b6c52016-02-24 17:25:49 -050019import android.Manifest.permission;
Jason Monk62b63a02016-02-02 15:15:31 -050020import android.app.ActivityManager;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.content.pm.ResolveInfo;
26import android.graphics.drawable.Drawable;
27import android.os.AsyncTask;
28import android.os.Handler;
29import android.os.Looper;
30import android.service.quicksettings.TileService;
Jason Monkcb654cb2016-02-25 15:43:07 -050031import com.android.systemui.Prefs;
32import com.android.systemui.Prefs.Key;
Jason Monk62b63a02016-02-02 15:15:31 -050033import com.android.systemui.R;
34import com.android.systemui.qs.QSTile;
35import com.android.systemui.qs.QSTile.DrawableIcon;
36import com.android.systemui.qs.external.CustomTile;
37import com.android.systemui.statusbar.phone.QSTileHost;
Jason Monkcb654cb2016-02-25 15:43:07 -050038import com.android.systemui.tuner.TunerService;
Jason Monk62b63a02016-02-02 15:15:31 -050039
40import java.util.ArrayList;
41import java.util.Collection;
42import java.util.List;
43
44public class TileQueryHelper {
45
46 private static final String TAG = "TileQueryHelper";
47
48 private final ArrayList<TileInfo> mTiles = new ArrayList<>();
Jason Monke24194f2016-02-05 14:55:05 -050049 private final ArrayList<String> mSpecs = new ArrayList<>();
Jason Monk62b63a02016-02-02 15:15:31 -050050 private final Context mContext;
51 private TileStateListener mListener;
52
53 public TileQueryHelper(Context context, QSTileHost host) {
54 mContext = context;
55 addSystemTiles(host);
56 // TODO: Live?
57 }
58
59 private void addSystemTiles(QSTileHost host) {
Jason Monkcb654cb2016-02-25 15:43:07 -050060 boolean hasColorMod = Prefs.getBoolean(host.getContext(), Key.QS_NIGHT_ADDED, false)
61 && TunerService.isTunerEnabled(host.getContext());
Jason Monk62b63a02016-02-02 15:15:31 -050062 String possible = mContext.getString(R.string.quick_settings_tiles_default)
Jason Monk5dbd4aa2016-02-07 13:13:39 -050063 + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
Jason Monk62b63a02016-02-02 15:15:31 -050064 String[] possibleTiles = possible.split(",");
65 final Handler qsHandler = new Handler(host.getLooper());
66 final Handler mainHandler = new Handler(Looper.getMainLooper());
67 for (int i = 0; i < possibleTiles.length; i++) {
68 final String spec = possibleTiles[i];
69 final QSTile<?> tile = host.createTile(spec);
Jason Monkc3f42c12016-02-05 12:33:13 -050070 if (tile == null || !tile.isAvailable()) {
Jason Monk62b63a02016-02-02 15:15:31 -050071 continue;
72 }
73 tile.setListening(true);
74 tile.clearState();
75 tile.refreshState();
76 tile.setListening(false);
77 qsHandler.post(new Runnable() {
78 @Override
79 public void run() {
80 final QSTile.State state = tile.newTileState();
81 tile.getState().copyTo(state);
82 mainHandler.post(new Runnable() {
83 @Override
84 public void run() {
Jason Monke24194f2016-02-05 14:55:05 -050085 addTile(spec, state);
Jason Monk62b63a02016-02-02 15:15:31 -050086 mListener.onTilesChanged(mTiles);
87 }
88 });
89 }
90 });
91 }
92 qsHandler.post(new Runnable() {
93 @Override
94 public void run() {
Jason Monkcb654cb2016-02-25 15:43:07 -050095 mainHandler.post(new Runnable() {
96 @Override
97 public void run() {
98 new QueryTilesTask().execute();
99 }
100 });
Jason Monk62b63a02016-02-02 15:15:31 -0500101 }
102 });
103 }
104
105 public void setListener(TileStateListener listener) {
106 mListener = listener;
107 }
108
Jason Monke24194f2016-02-05 14:55:05 -0500109 private void addTile(String spec, QSTile.State state) {
110 if (mSpecs.contains(spec)) {
111 return;
112 }
Jason Monk62b63a02016-02-02 15:15:31 -0500113 TileInfo info = new TileInfo();
114 info.state = state;
115 info.spec = spec;
Jason Monke24194f2016-02-05 14:55:05 -0500116 mTiles.add(info);
117 mSpecs.add(spec);
Jason Monk62b63a02016-02-02 15:15:31 -0500118 }
119
Jason Monke24194f2016-02-05 14:55:05 -0500120 private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
Jason Monk62b63a02016-02-02 15:15:31 -0500121 QSTile.State state = new QSTile.State();
122 state.label = label;
123 state.contentDescription = label;
124 state.icon = new DrawableIcon(drawable);
Jason Monke24194f2016-02-05 14:55:05 -0500125 addTile(spec, state);
Jason Monk62b63a02016-02-02 15:15:31 -0500126 }
127
128 public static class TileInfo {
129 public String spec;
130 public QSTile.State state;
131 }
132
133 private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
134 @Override
135 protected Collection<TileInfo> doInBackground(Void... params) {
136 List<TileInfo> tiles = new ArrayList<>();
137 PackageManager pm = mContext.getPackageManager();
138 List<ResolveInfo> services = pm.queryIntentServicesAsUser(
139 new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
140 for (ResolveInfo info : services) {
141 String packageName = info.serviceInfo.packageName;
142 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
143 String spec = CustomTile.toSpec(componentName);
144 Drawable icon = info.serviceInfo.loadIcon(pm);
Jason Monkb53b6c52016-02-24 17:25:49 -0500145 if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
146 continue;
147 }
Jason Monk62b63a02016-02-02 15:15:31 -0500148 if (icon != null) {
149 icon.mutate();
150 icon.setTint(mContext.getColor(android.R.color.white));
151 }
152 CharSequence label = info.serviceInfo.loadLabel(pm);
Jason Monke24194f2016-02-05 14:55:05 -0500153 addTile(spec, icon, label != null ? label.toString() : "null", mContext);
Jason Monk62b63a02016-02-02 15:15:31 -0500154 }
155 return tiles;
156 }
157
158 @Override
159 protected void onPostExecute(Collection<TileInfo> result) {
160 mTiles.addAll(result);
161 mListener.onTilesChanged(mTiles);
162 }
163 }
164
165 public interface TileStateListener {
166 void onTilesChanged(List<TileInfo> tiles);
167 }
168}