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 17 package com.android.systemui.statusbar; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.content.res.Resources; 22 import android.graphics.drawable.Drawable; 23 import android.graphics.Canvas; 24 import android.graphics.Paint; 25 import android.graphics.Rect; 26 import android.util.Slog; 27 import android.util.Log; 28 import android.view.View; 29 import android.view.ViewDebug; 30 import android.widget.FrameLayout; 31 32 import com.android.internal.statusbar.StatusBarIcon; 33 34 import com.android.systemui.R; 35 36 public class StatusBarIconView extends AnimatedImageView { 37 private static final String TAG = "StatusBarIconView"; 38 39 private StatusBarIcon mIcon; 40 @ViewDebug.ExportedProperty private String mSlot; 41 private Drawable mNumberBackground; 42 private Paint mNumberPain; 43 private int mNumberX; 44 private int mNumberY; 45 private String mNumberText; 46 47 public StatusBarIconView(Context context, String slot) { 48 super(context); 49 final Resources res = context.getResources(); 50 mSlot = slot; 51 mNumberPain = new Paint(); 52 mNumberPain.setTextAlign(Paint.Align.CENTER); 53 mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color)); 54 mNumberPain.setAntiAlias(true); 55 } 56 57 private static boolean streq(String a, String b) { 58 if (a == b) { 59 return true; 60 } 61 if (a == null && b != null) { 62 return false; 63 } 64 if (a != null && b == null) { 65 return false; 66 } 67 return a.equals(b); 68 } 69 70 /** 71 * Returns whether the set succeeded. 72 */ 73 public boolean set(StatusBarIcon icon) { 74 final boolean iconEquals = mIcon != null 75 && streq(mIcon.iconPackage, icon.iconPackage) 76 && mIcon.iconId == icon.iconId; 77 final boolean levelEquals = iconEquals 78 && mIcon.iconLevel == icon.iconLevel; 79 final boolean visibilityEquals = mIcon != null 80 && mIcon.visible == icon.visible; 81 final boolean numberEquals = mIcon != null 82 && mIcon.number == icon.number; 83 mIcon = icon.clone(); 84 if (!iconEquals) { 85 Drawable drawable = getIcon(icon); 86 if (drawable == null) { 87 Slog.w(StatusBarService.TAG, "No icon for slot " + mSlot); 88 return false; 89 } 90 setImageDrawable(drawable); 91 } 92 if (!levelEquals) { 93 setImageLevel(icon.iconLevel); 94 } 95 if (!numberEquals) { 96 if (icon.number > 0) { 97 if (mNumberBackground == null) { 98 mNumberBackground = getContext().getResources().getDrawable( 99 R.drawable.ic_notification_overlay); 100 } 101 placeNumber(); 102 } else { 103 mNumberBackground = null; 104 mNumberText = null; 105 } 106 invalidate(); 107 } 108 if (!visibilityEquals) { 109 setVisibility(icon.visible ? VISIBLE : GONE); 110 } 111 return true; 112 } 113 114 private Drawable getIcon(StatusBarIcon icon) { 115 return getIcon(getContext(), icon); 116 } 117 118 /** 119 * Returns the right icon to use for this item, respecting the iconId and 120 * iconPackage (if set) 121 * 122 * @param context Context to use to get resources if iconPackage is not set 123 * @return Drawable for this item, or null if the package or item could not 124 * be found 125 */ 126 public static Drawable getIcon(Context context, StatusBarIcon icon) { 127 Resources r = null; 128 129 if (icon.iconPackage != null) { 130 try { 131 r = context.getPackageManager().getResourcesForApplication(icon.iconPackage); 132 } catch (PackageManager.NameNotFoundException ex) { 133 Slog.e(StatusBarService.TAG, "Icon package not found: " + icon.iconPackage); 134 return null; 135 } 136 } else { 137 r = context.getResources(); 138 } 139 140 if (icon.iconId == 0) { 141 return null; 142 } 143 144 try { 145 return r.getDrawable(icon.iconId); 146 } catch (RuntimeException e) { 147 Slog.w(StatusBarService.TAG, "Icon not found in " 148 + (icon.iconPackage != null ? icon.iconId : "<system>") 149 + ": " + Integer.toHexString(icon.iconId)); 150 } 151 152 return null; 153 } 154 155 public StatusBarIcon getStatusBarIcon() { 156 return mIcon; 157 } 158 159 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 160 super.onSizeChanged(w, h, oldw, oldh); 161 if (mNumberBackground != null) { 162 placeNumber(); 163 } 164 } 165 166 protected void onDraw(Canvas canvas) { 167 super.onDraw(canvas); 168 169 if (mNumberBackground != null) { 170 mNumberBackground.draw(canvas); 171 canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain); 172 } 173 } 174 175 protected void debug(int depth) { 176 super.debug(depth); 177 Log.d("View", debugIndent(depth) + "slot=" + mSlot); 178 Log.d("View", debugIndent(depth) + "icon=" + mIcon); 179 } 180 181 void placeNumber() { 182 final String str = mNumberText = Integer.toString(mIcon.number); 183 final int w = getWidth(); 184 final int h = getHeight(); 185 final Rect r = new Rect(); 186 mNumberPain.getTextBounds(str, 0, str.length(), r); 187 final int tw = r.right - r.left; 188 final int th = r.bottom - r.top; 189 mNumberBackground.getPadding(r); 190 int dw = r.left + tw + r.right; 191 if (dw < mNumberBackground.getMinimumWidth()) { 192 dw = mNumberBackground.getMinimumWidth(); 193 } 194 mNumberX = w-r.right-((dw-r.right-r.left)/2); 195 int dh = r.top + th + r.bottom; 196 if (dh < mNumberBackground.getMinimumWidth()) { 197 dh = mNumberBackground.getMinimumWidth(); 198 } 199 mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2); 200 mNumberBackground.setBounds(w-dw, h-dh, w, h); 201 } 202 } 203