Home | History | Annotate | Download | only in tiles
      1 /*
      2  * Copyright (C) 2014 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.tiles;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.BroadcastReceiver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.IntentFilter;
     24 import android.graphics.Bitmap;
     25 import android.graphics.BitmapFactory;
     26 import android.graphics.drawable.BitmapDrawable;
     27 import android.graphics.drawable.Drawable;
     28 import android.os.UserHandle;
     29 import android.text.TextUtils;
     30 import android.util.Log;
     31 
     32 import com.android.systemui.qs.QSTile;
     33 
     34 import java.util.Arrays;
     35 import java.util.Objects;
     36 
     37 public class IntentTile extends QSTile<QSTile.State> {
     38     public static final String PREFIX = "intent(";
     39 
     40     private PendingIntent mOnClick;
     41     private String mOnClickUri;
     42     private PendingIntent mOnLongClick;
     43     private String mOnLongClickUri;
     44     private int mCurrentUserId;
     45 
     46     private IntentTile(Host host, String action) {
     47         super(host);
     48         mContext.registerReceiver(mReceiver, new IntentFilter(action));
     49     }
     50 
     51     @Override
     52     protected void handleDestroy() {
     53         super.handleDestroy();
     54         mContext.unregisterReceiver(mReceiver);
     55     }
     56 
     57     public static QSTile<?> create(Host host, String spec) {
     58         if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
     59             throw new IllegalArgumentException("Bad intent tile spec: " + spec);
     60         }
     61         final String action = spec.substring(PREFIX.length(), spec.length() - 1);
     62         if (action.isEmpty()) {
     63             throw new IllegalArgumentException("Empty intent tile spec action");
     64         }
     65         return new IntentTile(host, action);
     66     }
     67 
     68     @Override
     69     public void setListening(boolean listening) {
     70     }
     71 
     72     @Override
     73     protected State newTileState() {
     74         return new State();
     75     }
     76 
     77     @Override
     78     protected void handleUserSwitch(int newUserId) {
     79         super.handleUserSwitch(newUserId);
     80         mCurrentUserId = newUserId;
     81     }
     82 
     83     @Override
     84     protected void handleClick() {
     85         sendIntent("click", mOnClick, mOnClickUri);
     86     }
     87 
     88     @Override
     89     protected void handleLongClick() {
     90         sendIntent("long-click", mOnLongClick, mOnLongClickUri);
     91     }
     92 
     93     private void sendIntent(String type, PendingIntent pi, String uri) {
     94         try {
     95             if (pi != null) {
     96                 pi.send();
     97             } else if (uri != null) {
     98                 final Intent intent = Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
     99                 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
    100             }
    101         } catch (Throwable t) {
    102             Log.w(TAG, "Error sending " + type + " intent", t);
    103         }
    104     }
    105 
    106     @Override
    107     protected void handleUpdateState(State state, Object arg) {
    108         if (!(arg instanceof Intent)) return;
    109         final Intent intent = (Intent) arg;
    110         state.visible = intent.getBooleanExtra("visible", true);
    111         state.contentDescription = intent.getStringExtra("contentDescription");
    112         state.label = intent.getStringExtra("label");
    113         state.icon = null;
    114         final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap");
    115         if (iconBitmap != null) {
    116             try {
    117                 state.icon = new BytesIcon(iconBitmap);
    118             } catch (Throwable t) {
    119                 Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t);
    120             }
    121         } else {
    122             final int iconId = intent.getIntExtra("iconId", 0);
    123             if (iconId != 0) {
    124                 final String iconPackage = intent.getStringExtra("iconPackage");
    125                 if (!TextUtils.isEmpty(iconPackage)) {
    126                     state.icon = new PackageDrawableIcon(iconPackage, iconId);
    127                 } else {
    128                     state.icon = ResourceIcon.get(iconId);
    129                 }
    130             }
    131         }
    132         mOnClick = intent.getParcelableExtra("onClick");
    133         mOnClickUri = intent.getStringExtra("onClickUri");
    134         mOnLongClick = intent.getParcelableExtra("onLongClick");
    135         mOnLongClickUri = intent.getStringExtra("onLongClickUri");
    136     }
    137 
    138     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    139         @Override
    140         public void onReceive(Context context, Intent intent) {
    141             refreshState(intent);
    142         }
    143     };
    144 
    145     private static class BytesIcon extends Icon {
    146         private final byte[] mBytes;
    147 
    148         public BytesIcon(byte[] bytes) {
    149             mBytes = bytes;
    150         }
    151 
    152         @Override
    153         public Drawable getDrawable(Context context) {
    154             final Bitmap b = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
    155             return new BitmapDrawable(context.getResources(), b);
    156         }
    157 
    158         @Override
    159         public boolean equals(Object o) {
    160             return o instanceof BytesIcon && Arrays.equals(((BytesIcon) o).mBytes, mBytes);
    161         }
    162 
    163         @Override
    164         public String toString() {
    165             return String.format("BytesIcon[len=%s]", mBytes.length);
    166         }
    167     }
    168 
    169     private class PackageDrawableIcon extends Icon {
    170         private final String mPackage;
    171         private final int mResId;
    172 
    173         public PackageDrawableIcon(String pkg, int resId) {
    174             mPackage = pkg;
    175             mResId = resId;
    176         }
    177 
    178         @Override
    179         public boolean equals(Object o) {
    180             if (!(o instanceof PackageDrawableIcon)) return false;
    181             final PackageDrawableIcon other = (PackageDrawableIcon) o;
    182             return Objects.equals(other.mPackage, mPackage) && other.mResId == mResId;
    183         }
    184 
    185         @Override
    186         public Drawable getDrawable(Context context) {
    187             try {
    188                 return context.createPackageContext(mPackage, 0).getDrawable(mResId);
    189             } catch (Throwable t) {
    190                 Log.w(TAG, "Error loading package drawable pkg=" + mPackage + " id=" + mResId, t);
    191                 return null;
    192             }
    193         }
    194 
    195         @Override
    196         public String toString() {
    197             return String.format("PackageDrawableIcon[pkg=%s,id=0x%08x]", mPackage, mResId);
    198         }
    199     }
    200 }
    201