StatusBarIconView.java revision 7579bca7a02477353700d3b716f172b4fab267c0
1/* 2 * Copyright (C) 2008 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.statusbar; 18 19import android.app.Notification; 20import android.content.Context; 21import android.content.pm.PackageManager; 22import android.content.res.Resources; 23import android.graphics.drawable.Drawable; 24import android.graphics.Canvas; 25import android.graphics.Paint; 26import android.graphics.Rect; 27import android.text.TextUtils; 28import android.util.Slog; 29import android.util.Log; 30import android.view.ViewDebug; 31import android.view.accessibility.AccessibilityEvent; 32 33import java.text.NumberFormat; 34 35import com.android.internal.statusbar.StatusBarIcon; 36 37import com.android.systemui.R; 38 39public class StatusBarIconView extends AnimatedImageView { 40 private static final String TAG = "StatusBarIconView"; 41 42 private StatusBarIcon mIcon; 43 @ViewDebug.ExportedProperty private String mSlot; 44 private Drawable mNumberBackground; 45 private Paint mNumberPain; 46 private int mNumberX; 47 private int mNumberY; 48 private String mNumberText; 49 private Notification mNotification; 50 51 public StatusBarIconView(Context context, String slot, Notification notification) { 52 super(context); 53 final Resources res = context.getResources(); 54 mSlot = slot; 55 mNumberPain = new Paint(); 56 mNumberPain.setTextAlign(Paint.Align.CENTER); 57 mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color)); 58 mNumberPain.setAntiAlias(true); 59 mNotification = notification; 60 setContentDescription(notification); 61 62 // We do not resize and scale system icons (on the right), only notification icons (on the 63 // left). 64 if (notification != null) { 65 final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size); 66 final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size); 67 final float scale = (float)imageBounds / (float)outerBounds; 68 setScaleX(scale); 69 setScaleY(scale); 70 final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1); 71 setAlpha(alpha); 72 } 73 } 74 75 private static boolean streq(String a, String b) { 76 if (a == b) { 77 return true; 78 } 79 if (a == null && b != null) { 80 return false; 81 } 82 if (a != null && b == null) { 83 return false; 84 } 85 return a.equals(b); 86 } 87 88 /** 89 * Returns whether the set succeeded. 90 */ 91 public boolean set(StatusBarIcon icon) { 92 final boolean iconEquals = mIcon != null 93 && streq(mIcon.iconPackage, icon.iconPackage) 94 && mIcon.iconId == icon.iconId; 95 final boolean levelEquals = iconEquals 96 && mIcon.iconLevel == icon.iconLevel; 97 final boolean visibilityEquals = mIcon != null 98 && mIcon.visible == icon.visible; 99 final boolean numberEquals = mIcon != null 100 && mIcon.number == icon.number; 101 mIcon = icon.clone(); 102 setContentDescription(icon.contentDescription); 103 if (!iconEquals) { 104 Drawable drawable = getIcon(icon); 105 if (drawable == null) { 106 Slog.w(StatusBar.TAG, "No icon for slot " + mSlot); 107 return false; 108 } 109 setImageDrawable(drawable); 110 } 111 if (!levelEquals) { 112 setImageLevel(icon.iconLevel); 113 } 114 115 if (!numberEquals) { 116 if (icon.number > 0 && mContext.getResources().getBoolean( 117 R.bool.config_statusBarShowNumber)) { 118 if (mNumberBackground == null) { 119 mNumberBackground = getContext().getResources().getDrawable( 120 R.drawable.ic_notification_overlay); 121 } 122 placeNumber(); 123 } else { 124 mNumberBackground = null; 125 mNumberText = null; 126 } 127 invalidate(); 128 } 129 if (!visibilityEquals) { 130 setVisibility(icon.visible ? VISIBLE : GONE); 131 } 132 return true; 133 } 134 135 private Drawable getIcon(StatusBarIcon icon) { 136 return getIcon(getContext(), icon); 137 } 138 139 /** 140 * Returns the right icon to use for this item, respecting the iconId and 141 * iconPackage (if set) 142 * 143 * @param context Context to use to get resources if iconPackage is not set 144 * @return Drawable for this item, or null if the package or item could not 145 * be found 146 */ 147 public static Drawable getIcon(Context context, StatusBarIcon icon) { 148 Resources r = null; 149 150 if (icon.iconPackage != null) { 151 try { 152 r = context.getPackageManager().getResourcesForApplication(icon.iconPackage); 153 } catch (PackageManager.NameNotFoundException ex) { 154 Slog.e(StatusBar.TAG, "Icon package not found: " + icon.iconPackage); 155 return null; 156 } 157 } else { 158 r = context.getResources(); 159 } 160 161 if (icon.iconId == 0) { 162 return null; 163 } 164 165 try { 166 return r.getDrawable(icon.iconId); 167 } catch (RuntimeException e) { 168 Slog.w(StatusBar.TAG, "Icon not found in " 169 + (icon.iconPackage != null ? icon.iconId : "<system>") 170 + ": " + Integer.toHexString(icon.iconId)); 171 } 172 173 return null; 174 } 175 176 public StatusBarIcon getStatusBarIcon() { 177 return mIcon; 178 } 179 180 @Override 181 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 182 super.onInitializeAccessibilityEvent(event); 183 if (mNotification != null) { 184 event.setParcelableData(mNotification); 185 } 186 } 187 188 @Override 189 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 190 super.onSizeChanged(w, h, oldw, oldh); 191 if (mNumberBackground != null) { 192 placeNumber(); 193 } 194 } 195 196 @Override 197 protected void onDraw(Canvas canvas) { 198 super.onDraw(canvas); 199 200 if (mNumberBackground != null) { 201 mNumberBackground.draw(canvas); 202 canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain); 203 } 204 } 205 206 @Override 207 protected void debug(int depth) { 208 super.debug(depth); 209 Log.d("View", debugIndent(depth) + "slot=" + mSlot); 210 Log.d("View", debugIndent(depth) + "icon=" + mIcon); 211 } 212 213 void placeNumber() { 214 final String str; 215 final int tooBig = mContext.getResources().getInteger( 216 android.R.integer.status_bar_notification_info_maxnum); 217 if (mIcon.number > tooBig) { 218 str = mContext.getResources().getString( 219 android.R.string.status_bar_notification_info_overflow); 220 } else { 221 NumberFormat f = NumberFormat.getIntegerInstance(); 222 str = f.format(mIcon.number); 223 } 224 mNumberText = str; 225 226 final int w = getWidth(); 227 final int h = getHeight(); 228 final Rect r = new Rect(); 229 mNumberPain.getTextBounds(str, 0, str.length(), r); 230 final int tw = r.right - r.left; 231 final int th = r.bottom - r.top; 232 mNumberBackground.getPadding(r); 233 int dw = r.left + tw + r.right; 234 if (dw < mNumberBackground.getMinimumWidth()) { 235 dw = mNumberBackground.getMinimumWidth(); 236 } 237 mNumberX = w-r.right-((dw-r.right-r.left)/2); 238 int dh = r.top + th + r.bottom; 239 if (dh < mNumberBackground.getMinimumWidth()) { 240 dh = mNumberBackground.getMinimumWidth(); 241 } 242 mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2); 243 mNumberBackground.setBounds(w-dw, h-dh, w, h); 244 } 245 246 private void setContentDescription(Notification notification) { 247 if (notification != null) { 248 CharSequence tickerText = notification.tickerText; 249 if (!TextUtils.isEmpty(tickerText)) { 250 setContentDescription(tickerText); 251 } 252 } 253 } 254 255 public String toString() { 256 return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon 257 + " notification=" + mNotification + ")"; 258 } 259} 260