blob: d04a2fc7e148a7eef84e596237a8754a8ba9224b [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;
31import com.android.systemui.R;
32import com.android.systemui.qs.QSTile;
33import com.android.systemui.qs.QSTile.DrawableIcon;
Jason Monk0b349ad2016-04-04 11:18:03 -040034import com.android.systemui.qs.QSTile.State;
Jason Monk62b63a02016-02-02 15:15:31 -050035import com.android.systemui.qs.external.CustomTile;
36import com.android.systemui.statusbar.phone.QSTileHost;
37
38import java.util.ArrayList;
39import java.util.Collection;
40import java.util.List;
41
42public class TileQueryHelper {
43
44 private static final String TAG = "TileQueryHelper";
45
46 private final ArrayList<TileInfo> mTiles = new ArrayList<>();
Jason Monke24194f2016-02-05 14:55:05 -050047 private final ArrayList<String> mSpecs = new ArrayList<>();
Jason Monk62b63a02016-02-02 15:15:31 -050048 private final Context mContext;
49 private TileStateListener mListener;
50
51 public TileQueryHelper(Context context, QSTileHost host) {
52 mContext = context;
53 addSystemTiles(host);
54 // TODO: Live?
55 }
56
57 private void addSystemTiles(QSTileHost host) {
Jason Monk62b63a02016-02-02 15:15:31 -050058 String possible = mContext.getString(R.string.quick_settings_tiles_default)
Jason Monk1b0afeb2016-03-03 18:25:54 -050059 + ",hotspot,inversion,saver,work,cast,night";
Jason Monk62b63a02016-02-02 15:15:31 -050060 String[] possibleTiles = possible.split(",");
61 final Handler qsHandler = new Handler(host.getLooper());
62 final Handler mainHandler = new Handler(Looper.getMainLooper());
63 for (int i = 0; i < possibleTiles.length; i++) {
64 final String spec = possibleTiles[i];
65 final QSTile<?> tile = host.createTile(spec);
Jason Monkc3f42c12016-02-05 12:33:13 -050066 if (tile == null || !tile.isAvailable()) {
Jason Monk62b63a02016-02-02 15:15:31 -050067 continue;
68 }
69 tile.setListening(true);
70 tile.clearState();
71 tile.refreshState();
72 tile.setListening(false);
73 qsHandler.post(new Runnable() {
74 @Override
75 public void run() {
76 final QSTile.State state = tile.newTileState();
77 tile.getState().copyTo(state);
Jason Monk39c98e62016-03-16 09:18:35 -040078 // Ignore the current state and get the generic label instead.
79 state.label = tile.getTileLabel();
Jason Monk62b63a02016-02-02 15:15:31 -050080 mainHandler.post(new Runnable() {
81 @Override
82 public void run() {
Jason Monk0b349ad2016-04-04 11:18:03 -040083 addTile(spec, null, state, true);
Jason Monk62b63a02016-02-02 15:15:31 -050084 mListener.onTilesChanged(mTiles);
85 }
86 });
87 }
88 });
89 }
90 qsHandler.post(new Runnable() {
91 @Override
92 public void run() {
Jason Monkcb654cb2016-02-25 15:43:07 -050093 mainHandler.post(new Runnable() {
94 @Override
95 public void run() {
96 new QueryTilesTask().execute();
97 }
98 });
Jason Monk62b63a02016-02-02 15:15:31 -050099 }
100 });
101 }
102
103 public void setListener(TileStateListener listener) {
104 mListener = listener;
105 }
106
Jason Monk0b349ad2016-04-04 11:18:03 -0400107 private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
Jason Monke24194f2016-02-05 14:55:05 -0500108 if (mSpecs.contains(spec)) {
109 return;
110 }
Jason Monk62b63a02016-02-02 15:15:31 -0500111 TileInfo info = new TileInfo();
112 info.state = state;
113 info.spec = spec;
Jason Monk0b349ad2016-04-04 11:18:03 -0400114 info.appLabel = appLabel;
115 info.isSystem = isSystem;
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 Monk0b349ad2016-04-04 11:18:03 -0400120 private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
121 Context context) {
Jason Monk62b63a02016-02-02 15:15:31 -0500122 QSTile.State state = new QSTile.State();
123 state.label = label;
124 state.contentDescription = label;
125 state.icon = new DrawableIcon(drawable);
Jason Monk0b349ad2016-04-04 11:18:03 -0400126 addTile(spec, appLabel, state, false);
Jason Monk62b63a02016-02-02 15:15:31 -0500127 }
128
129 public static class TileInfo {
130 public String spec;
Jason Monk0b349ad2016-04-04 11:18:03 -0400131 public CharSequence appLabel;
Jason Monk62b63a02016-02-02 15:15:31 -0500132 public QSTile.State state;
Jason Monk0b349ad2016-04-04 11:18:03 -0400133 public boolean isSystem;
Jason Monk62b63a02016-02-02 15:15:31 -0500134 }
135
136 private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
137 @Override
138 protected Collection<TileInfo> doInBackground(Void... params) {
139 List<TileInfo> tiles = new ArrayList<>();
140 PackageManager pm = mContext.getPackageManager();
141 List<ResolveInfo> services = pm.queryIntentServicesAsUser(
142 new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
143 for (ResolveInfo info : services) {
144 String packageName = info.serviceInfo.packageName;
145 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
146 String spec = CustomTile.toSpec(componentName);
147 Drawable icon = info.serviceInfo.loadIcon(pm);
Jason Monkb53b6c52016-02-24 17:25:49 -0500148 if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
149 continue;
150 }
Jason Monk62b63a02016-02-02 15:15:31 -0500151 if (icon != null) {
152 icon.mutate();
153 icon.setTint(mContext.getColor(android.R.color.white));
154 }
155 CharSequence label = info.serviceInfo.loadLabel(pm);
Jason Monk0b349ad2016-04-04 11:18:03 -0400156 final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
157 addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
Jason Monk62b63a02016-02-02 15:15:31 -0500158 }
159 return tiles;
160 }
161
162 @Override
163 protected void onPostExecute(Collection<TileInfo> result) {
164 mTiles.addAll(result);
165 mListener.onTilesChanged(mTiles);
166 }
167 }
168
169 public interface TileStateListener {
170 void onTilesChanged(List<TileInfo> tiles);
171 }
172}