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