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