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