Home | History | Annotate | Download | only in customize
      1 /*
      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 
     17 package com.android.systemui.qs.customize;
     18 
     19 import android.Manifest.permission;
     20 import android.app.ActivityManager;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.graphics.drawable.Drawable;
     27 import android.os.AsyncTask;
     28 import android.os.Handler;
     29 import android.os.Looper;
     30 import android.service.quicksettings.TileService;
     31 import android.widget.Button;
     32 
     33 import com.android.systemui.R;
     34 import com.android.systemui.qs.QSTile;
     35 import com.android.systemui.qs.QSTile.DrawableIcon;
     36 import com.android.systemui.qs.QSTile.State;
     37 import com.android.systemui.qs.external.CustomTile;
     38 import com.android.systemui.statusbar.phone.QSTileHost;
     39 
     40 import java.util.ArrayList;
     41 import java.util.Collection;
     42 import java.util.List;
     43 
     44 public class TileQueryHelper {
     45 
     46     private static final String TAG = "TileQueryHelper";
     47 
     48     private final ArrayList<TileInfo> mTiles = new ArrayList<>();
     49     private final ArrayList<String> mSpecs = new ArrayList<>();
     50     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(final QSTileHost host) {
     60         String possible = mContext.getString(R.string.quick_settings_tiles_default)
     61                 + ",hotspot,inversion,saver,work,cast,night";
     62         String[] possibleTiles = possible.split(",");
     63         final Handler qsHandler = new Handler(host.getLooper());
     64         final Handler mainHandler = new Handler(Looper.getMainLooper());
     65         for (int i = 0; i < possibleTiles.length; i++) {
     66             final String spec = possibleTiles[i];
     67             final QSTile<?> tile = host.createTile(spec);
     68             if (tile == null || !tile.isAvailable()) {
     69                 continue;
     70             }
     71             tile.setListening(this, true);
     72             tile.clearState();
     73             tile.refreshState();
     74             tile.setListening(this, false);
     75             qsHandler.post(new Runnable() {
     76                 @Override
     77                 public void run() {
     78                     final QSTile.State state = tile.newTileState();
     79                     tile.getState().copyTo(state);
     80                     // Ignore the current state and get the generic label instead.
     81                     state.label = tile.getTileLabel();
     82                     mainHandler.post(new Runnable() {
     83                         @Override
     84                         public void run() {
     85                             addTile(spec, null, state, true);
     86                             mListener.onTilesChanged(mTiles);
     87                         }
     88                     });
     89                 }
     90             });
     91         }
     92         qsHandler.post(new Runnable() {
     93             @Override
     94             public void run() {
     95                 mainHandler.post(new Runnable() {
     96                     @Override
     97                     public void run() {
     98                         new QueryTilesTask().execute(host.getTiles());
     99                     }
    100                 });
    101             }
    102         });
    103     }
    104 
    105     public void setListener(TileStateListener listener) {
    106         mListener = listener;
    107     }
    108 
    109     private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
    110         if (mSpecs.contains(spec)) {
    111             return;
    112         }
    113         TileInfo info = new TileInfo();
    114         info.state = state;
    115         info.state.minimalAccessibilityClassName = info.state.expandedAccessibilityClassName =
    116                 Button.class.getName();
    117         info.spec = spec;
    118         info.appLabel = appLabel;
    119         info.isSystem = isSystem;
    120         mTiles.add(info);
    121         mSpecs.add(spec);
    122     }
    123 
    124     private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
    125             Context context) {
    126         QSTile.State state = new QSTile.State();
    127         state.label = label;
    128         state.contentDescription = label;
    129         state.icon = new DrawableIcon(drawable);
    130         addTile(spec, appLabel, state, false);
    131     }
    132 
    133     public static class TileInfo {
    134         public String spec;
    135         public CharSequence appLabel;
    136         public QSTile.State state;
    137         public boolean isSystem;
    138     }
    139 
    140     private class QueryTilesTask extends
    141             AsyncTask<Collection<QSTile<?>>, Void, Collection<TileInfo>> {
    142         @Override
    143         protected Collection<TileInfo> doInBackground(Collection<QSTile<?>>... params) {
    144             List<TileInfo> tiles = new ArrayList<>();
    145             PackageManager pm = mContext.getPackageManager();
    146             List<ResolveInfo> services = pm.queryIntentServicesAsUser(
    147                     new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
    148             for (ResolveInfo info : services) {
    149                 String packageName = info.serviceInfo.packageName;
    150                 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
    151                 final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
    152                 String spec = CustomTile.toSpec(componentName);
    153                 State state = getState(params[0], spec);
    154                 if (state != null) {
    155                     addTile(spec, appLabel, state, false);
    156                     continue;
    157                 }
    158                 if (info.serviceInfo.icon == 0 && info.serviceInfo.applicationInfo.icon == 0) {
    159                     continue;
    160                 }
    161                 Drawable icon = info.serviceInfo.loadIcon(pm);
    162                 if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
    163                     continue;
    164                 }
    165                 if (icon == null) {
    166                     continue;
    167                 }
    168                 icon.mutate();
    169                 icon.setTint(mContext.getColor(android.R.color.white));
    170                 CharSequence label = info.serviceInfo.loadLabel(pm);
    171                 addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
    172             }
    173             return tiles;
    174         }
    175 
    176         private State getState(Collection<QSTile<?>> tiles, String spec) {
    177             for (QSTile<?> tile : tiles) {
    178                 if (spec.equals(tile.getTileSpec())) {
    179                     final QSTile.State state = tile.newTileState();
    180                     tile.getState().copyTo(state);
    181                     return state;
    182                 }
    183             }
    184             return null;
    185         }
    186 
    187         @Override
    188         protected void onPostExecute(Collection<TileInfo> result) {
    189             mTiles.addAll(result);
    190             mListener.onTilesChanged(mTiles);
    191         }
    192     }
    193 
    194     public interface TileStateListener {
    195         void onTilesChanged(List<TileInfo> tiles);
    196     }
    197 }
    198