Home | History | Annotate | Download | only in keyguard
      1 /*
      2  * Copyright (C) 2017 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.keyguard;
     18 
     19 import static android.app.slice.Slice.HINT_LIST_ITEM;
     20 import static android.view.Display.DEFAULT_DISPLAY;
     21 import static android.view.Display.INVALID_DISPLAY;
     22 
     23 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
     24 
     25 import android.animation.LayoutTransition;
     26 import android.animation.ObjectAnimator;
     27 import android.animation.PropertyValuesHolder;
     28 import android.annotation.ColorInt;
     29 import android.annotation.StyleRes;
     30 import android.app.PendingIntent;
     31 import android.content.Context;
     32 import android.graphics.Color;
     33 import android.graphics.drawable.Drawable;
     34 import android.net.Uri;
     35 import android.os.Trace;
     36 import android.provider.Settings;
     37 import android.text.TextUtils;
     38 import android.text.TextUtils.TruncateAt;
     39 import android.util.AttributeSet;
     40 import android.util.Log;
     41 import android.util.TypedValue;
     42 import android.view.View;
     43 import android.view.animation.Animation;
     44 import android.widget.Button;
     45 import android.widget.LinearLayout;
     46 import android.widget.TextView;
     47 
     48 import androidx.lifecycle.LiveData;
     49 import androidx.lifecycle.Observer;
     50 import androidx.slice.Slice;
     51 import androidx.slice.SliceItem;
     52 import androidx.slice.SliceViewManager;
     53 import androidx.slice.core.SliceQuery;
     54 import androidx.slice.widget.ListContent;
     55 import androidx.slice.widget.RowContent;
     56 import androidx.slice.widget.SliceContent;
     57 import androidx.slice.widget.SliceLiveData;
     58 
     59 import com.android.internal.annotations.VisibleForTesting;
     60 import com.android.internal.graphics.ColorUtils;
     61 import com.android.settingslib.Utils;
     62 import com.android.systemui.Dependency;
     63 import com.android.systemui.Interpolators;
     64 import com.android.systemui.R;
     65 import com.android.systemui.keyguard.KeyguardSliceProvider;
     66 import com.android.systemui.plugins.ActivityStarter;
     67 import com.android.systemui.statusbar.policy.ConfigurationController;
     68 import com.android.systemui.tuner.TunerService;
     69 import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
     70 
     71 import java.io.FileDescriptor;
     72 import java.io.PrintWriter;
     73 import java.util.ArrayList;
     74 import java.util.HashMap;
     75 import java.util.List;
     76 
     77 import javax.inject.Inject;
     78 import javax.inject.Named;
     79 
     80 /**
     81  * View visible under the clock on the lock screen and AoD.
     82  */
     83 public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
     84         Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener {
     85 
     86     private static final String TAG = "KeyguardSliceView";
     87     public static final int DEFAULT_ANIM_DURATION = 550;
     88 
     89     private final HashMap<View, PendingIntent> mClickActions;
     90     private final ActivityStarter mActivityStarter;
     91     private final ConfigurationController mConfigurationController;
     92     private final LayoutTransition mLayoutTransition;
     93     private Uri mKeyguardSliceUri;
     94     @VisibleForTesting
     95     TextView mTitle;
     96     private Row mRow;
     97     private int mTextColor;
     98     private float mDarkAmount = 0;
     99 
    100     private LiveData<Slice> mLiveData;
    101     private int mDisplayId = INVALID_DISPLAY;
    102     private int mIconSize;
    103     private int mIconSizeWithHeader;
    104     /**
    105      * Runnable called whenever the view contents change.
    106      */
    107     private Runnable mContentChangeListener;
    108     private Slice mSlice;
    109     private boolean mHasHeader;
    110     private final int mRowWithHeaderPadding;
    111     private final int mRowPadding;
    112     private float mRowTextSize;
    113     private float mRowWithHeaderTextSize;
    114 
    115     @Inject
    116     public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
    117             ActivityStarter activityStarter, ConfigurationController configurationController) {
    118         super(context, attrs);
    119 
    120         TunerService tunerService = Dependency.get(TunerService.class);
    121         tunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
    122 
    123         mClickActions = new HashMap<>();
    124         mRowPadding = context.getResources().getDimensionPixelSize(R.dimen.subtitle_clock_padding);
    125         mRowWithHeaderPadding = context.getResources()
    126                 .getDimensionPixelSize(R.dimen.header_subtitle_padding);
    127         mActivityStarter = activityStarter;
    128         mConfigurationController = configurationController;
    129 
    130         mLayoutTransition = new LayoutTransition();
    131         mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
    132         mLayoutTransition.setDuration(LayoutTransition.APPEARING, DEFAULT_ANIM_DURATION);
    133         mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 2);
    134         mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
    135         mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
    136         mLayoutTransition.setInterpolator(LayoutTransition.APPEARING,
    137                 Interpolators.FAST_OUT_SLOW_IN);
    138         mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
    139         mLayoutTransition.setAnimateParentHierarchy(false);
    140     }
    141 
    142     @Override
    143     protected void onFinishInflate() {
    144         super.onFinishInflate();
    145         mTitle = findViewById(R.id.title);
    146         mRow = findViewById(R.id.row);
    147         mTextColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
    148         mIconSize = (int) mContext.getResources().getDimension(R.dimen.widget_icon_size);
    149         mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
    150         mRowTextSize = mContext.getResources().getDimensionPixelSize(
    151                 R.dimen.widget_label_font_size);
    152         mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize(
    153                 R.dimen.header_row_font_size);
    154         mTitle.setOnClickListener(this);
    155     }
    156 
    157     @Override
    158     protected void onAttachedToWindow() {
    159         super.onAttachedToWindow();
    160 
    161         mDisplayId = getDisplay().getDisplayId();
    162         // Make sure we always have the most current slice
    163         mLiveData.observeForever(this);
    164         mConfigurationController.addCallback(this);
    165     }
    166 
    167     @Override
    168     protected void onDetachedFromWindow() {
    169         super.onDetachedFromWindow();
    170 
    171         // TODO(b/117344873) Remove below work around after this issue be fixed.
    172         if (mDisplayId == DEFAULT_DISPLAY) {
    173             mLiveData.removeObserver(this);
    174         }
    175         mConfigurationController.removeCallback(this);
    176     }
    177 
    178     @Override
    179     public void onVisibilityAggregated(boolean isVisible) {
    180         super.onVisibilityAggregated(isVisible);
    181         setLayoutTransition(isVisible ? mLayoutTransition : null);
    182     }
    183 
    184     /**
    185      * Returns whether the current visible slice has a title/header.
    186      */
    187     public boolean hasHeader() {
    188         return mHasHeader;
    189     }
    190 
    191     private void showSlice() {
    192         Trace.beginSection("KeyguardSliceView#showSlice");
    193         if (mSlice == null) {
    194             mTitle.setVisibility(GONE);
    195             mRow.setVisibility(GONE);
    196             mHasHeader = false;
    197             if (mContentChangeListener != null) {
    198                 mContentChangeListener.run();
    199             }
    200             Trace.endSection();
    201             return;
    202         }
    203         mClickActions.clear();
    204 
    205         ListContent lc = new ListContent(getContext(), mSlice);
    206         SliceContent headerContent = lc.getHeader();
    207         mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
    208         List<SliceContent> subItems = new ArrayList<>();
    209         for (int i = 0; i < lc.getRowItems().size(); i++) {
    210             SliceContent subItem = lc.getRowItems().get(i);
    211             String itemUri = subItem.getSliceItem().getSlice().getUri().toString();
    212             // Filter out the action row
    213             if (!KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri)) {
    214                 subItems.add(subItem);
    215             }
    216         }
    217         if (!mHasHeader) {
    218             mTitle.setVisibility(GONE);
    219         } else {
    220             mTitle.setVisibility(VISIBLE);
    221 
    222             RowContent header = lc.getHeader();
    223             SliceItem mainTitle = header.getTitleItem();
    224             CharSequence title = mainTitle != null ? mainTitle.getText() : null;
    225             mTitle.setText(title);
    226             if (header.getPrimaryAction() != null
    227                     && header.getPrimaryAction().getAction() != null) {
    228                 mClickActions.put(mTitle, header.getPrimaryAction().getAction());
    229             }
    230         }
    231 
    232         final int subItemsCount = subItems.size();
    233         final int blendedColor = getTextColor();
    234         final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
    235         mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
    236         LinearLayout.LayoutParams layoutParams = (LayoutParams) mRow.getLayoutParams();
    237         layoutParams.topMargin = mHasHeader ? mRowWithHeaderPadding : mRowPadding;
    238         mRow.setLayoutParams(layoutParams);
    239 
    240         for (int i = startIndex; i < subItemsCount; i++) {
    241             RowContent rc = (RowContent) subItems.get(i);
    242             SliceItem item = rc.getSliceItem();
    243             final Uri itemTag = item.getSlice().getUri();
    244             // Try to reuse the view if already exists in the layout
    245             KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
    246             if (button == null) {
    247                 button = new KeyguardSliceButton(mContext);
    248                 button.setTextColor(blendedColor);
    249                 button.setTag(itemTag);
    250                 final int viewIndex = i - (mHasHeader ? 1 : 0);
    251                 mRow.addView(button, viewIndex);
    252             }
    253 
    254             PendingIntent pendingIntent = null;
    255             if (rc.getPrimaryAction() != null) {
    256                 pendingIntent = rc.getPrimaryAction().getAction();
    257             }
    258             mClickActions.put(button, pendingIntent);
    259 
    260             final SliceItem titleItem = rc.getTitleItem();
    261             button.setText(titleItem == null ? null : titleItem.getText());
    262             button.setContentDescription(rc.getContentDescription());
    263             button.setTextSize(TypedValue.COMPLEX_UNIT_PX,
    264                     mHasHeader ? mRowWithHeaderTextSize : mRowTextSize);
    265 
    266             Drawable iconDrawable = null;
    267             SliceItem icon = SliceQuery.find(item.getSlice(),
    268                     android.app.slice.SliceItem.FORMAT_IMAGE);
    269             if (icon != null) {
    270                 final int iconSize = mHasHeader ? mIconSizeWithHeader : mIconSize;
    271                 iconDrawable = icon.getIcon().loadDrawable(mContext);
    272                 if (iconDrawable != null) {
    273                     final int width = (int) (iconDrawable.getIntrinsicWidth()
    274                             / (float) iconDrawable.getIntrinsicHeight() * iconSize);
    275                     iconDrawable.setBounds(0, 0, Math.max(width, 1), iconSize);
    276                 }
    277             }
    278             button.setCompoundDrawables(iconDrawable, null, null, null);
    279             button.setOnClickListener(this);
    280             button.setClickable(pendingIntent != null);
    281         }
    282 
    283         // Removing old views
    284         for (int i = 0; i < mRow.getChildCount(); i++) {
    285             View child = mRow.getChildAt(i);
    286             if (!mClickActions.containsKey(child)) {
    287                 mRow.removeView(child);
    288                 i--;
    289             }
    290         }
    291 
    292         if (mContentChangeListener != null) {
    293             mContentChangeListener.run();
    294         }
    295         Trace.endSection();
    296     }
    297 
    298     public void setDarkAmount(float darkAmount) {
    299         mDarkAmount = darkAmount;
    300         mRow.setDarkAmount(darkAmount);
    301         updateTextColors();
    302     }
    303 
    304     private void updateTextColors() {
    305         final int blendedColor = getTextColor();
    306         mTitle.setTextColor(blendedColor);
    307         int childCount = mRow.getChildCount();
    308         for (int i = 0; i < childCount; i++) {
    309             View v = mRow.getChildAt(i);
    310             if (v instanceof Button) {
    311                 ((Button) v).setTextColor(blendedColor);
    312             }
    313         }
    314     }
    315 
    316     @Override
    317     public void onClick(View v) {
    318         final PendingIntent action = mClickActions.get(v);
    319         if (action != null) {
    320             mActivityStarter.startPendingIntentDismissingKeyguard(action);
    321         }
    322     }
    323 
    324     /**
    325      * Runnable that gets invoked every time the title or the row visibility changes.
    326      * @param contentChangeListener The listener.
    327      */
    328     public void setContentChangeListener(Runnable contentChangeListener) {
    329         mContentChangeListener = contentChangeListener;
    330     }
    331 
    332     /**
    333      * LiveData observer lifecycle.
    334      * @param slice the new slice content.
    335      */
    336     @Override
    337     public void onChanged(Slice slice) {
    338         mSlice = slice;
    339         showSlice();
    340     }
    341 
    342     @Override
    343     public void onTuningChanged(String key, String newValue) {
    344         setupUri(newValue);
    345     }
    346 
    347     /**
    348      * Sets the slice provider Uri.
    349      */
    350     public void setupUri(String uriString) {
    351         if (uriString == null) {
    352             uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
    353         }
    354 
    355         boolean wasObserving = false;
    356         if (mLiveData != null && mLiveData.hasActiveObservers()) {
    357             wasObserving = true;
    358             mLiveData.removeObserver(this);
    359         }
    360 
    361         mKeyguardSliceUri = Uri.parse(uriString);
    362         mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);
    363 
    364         if (wasObserving) {
    365             mLiveData.observeForever(this);
    366         }
    367     }
    368 
    369     @VisibleForTesting
    370     int getTextColor() {
    371         return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
    372     }
    373 
    374     @VisibleForTesting
    375     void setTextColor(@ColorInt int textColor) {
    376         mTextColor = textColor;
    377         updateTextColors();
    378     }
    379 
    380     @Override
    381     public void onDensityOrFontScaleChanged() {
    382         mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
    383         mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
    384         mRowTextSize = mContext.getResources().getDimensionPixelSize(
    385                 R.dimen.widget_label_font_size);
    386         mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize(
    387                 R.dimen.header_row_font_size);
    388     }
    389 
    390     public void refresh() {
    391         Slice slice;
    392         Trace.beginSection("KeyguardSliceView#refresh");
    393         // We can optimize performance and avoid binder calls when we know that we're bound
    394         // to a Slice on the same process.
    395         if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
    396             KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
    397             if (instance != null) {
    398                 slice = instance.onBindSlice(mKeyguardSliceUri);
    399             } else {
    400                 Log.w(TAG, "Keyguard slice not bound yet?");
    401                 slice = null;
    402             }
    403         } else {
    404             slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
    405         }
    406         onChanged(slice);
    407         Trace.endSection();
    408     }
    409 
    410     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    411         pw.println("KeyguardSliceView:");
    412         pw.println("  mClickActions: " + mClickActions);
    413         pw.println("  mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE));
    414         pw.println("  mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE));
    415         pw.println("  mTextColor: " + Integer.toHexString(mTextColor));
    416         pw.println("  mDarkAmount: " + mDarkAmount);
    417         pw.println("  mSlice: " + mSlice);
    418         pw.println("  mHasHeader: " + mHasHeader);
    419     }
    420 
    421     public static class Row extends LinearLayout {
    422 
    423         /**
    424          * This view is visible in AOD, which means that the device will sleep if we
    425          * don't hold a wake lock. We want to enter doze only after all views have reached
    426          * their desired positions.
    427          */
    428         private final Animation.AnimationListener mKeepAwakeListener;
    429         private LayoutTransition mLayoutTransition;
    430         private float mDarkAmount;
    431 
    432         public Row(Context context) {
    433             this(context, null);
    434         }
    435 
    436         public Row(Context context, AttributeSet attrs) {
    437             this(context, attrs, 0);
    438         }
    439 
    440         public Row(Context context, AttributeSet attrs, int defStyleAttr) {
    441             this(context, attrs, defStyleAttr, 0);
    442         }
    443 
    444         public Row(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    445             super(context, attrs, defStyleAttr, defStyleRes);
    446             mKeepAwakeListener = new KeepAwakeAnimationListener(mContext);
    447         }
    448 
    449         @Override
    450         protected void onFinishInflate() {
    451             mLayoutTransition = new LayoutTransition();
    452             mLayoutTransition.setDuration(DEFAULT_ANIM_DURATION);
    453 
    454             PropertyValuesHolder left = PropertyValuesHolder.ofInt("left", 0, 1);
    455             PropertyValuesHolder right = PropertyValuesHolder.ofInt("right", 0, 1);
    456             ObjectAnimator changeAnimator = ObjectAnimator.ofPropertyValuesHolder((Object) null,
    457                     left, right);
    458             mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAnimator);
    459             mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeAnimator);
    460             mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_APPEARING,
    461                     Interpolators.ACCELERATE_DECELERATE);
    462             mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING,
    463                     Interpolators.ACCELERATE_DECELERATE);
    464             mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_APPEARING,
    465                     DEFAULT_ANIM_DURATION);
    466             mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING,
    467                     DEFAULT_ANIM_DURATION);
    468 
    469             ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
    470             mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearAnimator);
    471             mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN);
    472 
    473             ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
    474             mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING,
    475                     Interpolators.ALPHA_OUT);
    476             mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 4);
    477             mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator);
    478 
    479             mLayoutTransition.setAnimateParentHierarchy(false);
    480         }
    481 
    482         @Override
    483         public void onVisibilityAggregated(boolean isVisible) {
    484             super.onVisibilityAggregated(isVisible);
    485             setLayoutTransition(isVisible ? mLayoutTransition : null);
    486         }
    487 
    488         @Override
    489         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    490             int width = MeasureSpec.getSize(widthMeasureSpec);
    491             int childCount = getChildCount();
    492             for (int i = 0; i < childCount; i++) {
    493                 View child = getChildAt(i);
    494                 if (child instanceof KeyguardSliceButton) {
    495                     ((KeyguardSliceButton) child).setMaxWidth(width / childCount);
    496                 }
    497             }
    498             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    499         }
    500 
    501         public void setDarkAmount(float darkAmount) {
    502             boolean isAwake = darkAmount != 0;
    503             boolean wasAwake = mDarkAmount != 0;
    504             if (isAwake == wasAwake) {
    505                 return;
    506             }
    507             mDarkAmount = darkAmount;
    508             setLayoutAnimationListener(isAwake ? null : mKeepAwakeListener);
    509         }
    510 
    511         @Override
    512         public boolean hasOverlappingRendering() {
    513             return false;
    514         }
    515     }
    516 
    517     /**
    518      * Representation of an item that appears under the clock on main keyguard message.
    519      */
    520     @VisibleForTesting
    521     static class KeyguardSliceButton extends Button implements
    522             ConfigurationController.ConfigurationListener {
    523 
    524         @StyleRes
    525         private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary;
    526 
    527         public KeyguardSliceButton(Context context) {
    528             super(context, null /* attrs */, 0 /* styleAttr */, sStyleId);
    529             onDensityOrFontScaleChanged();
    530             setEllipsize(TruncateAt.END);
    531         }
    532 
    533         @Override
    534         protected void onAttachedToWindow() {
    535             super.onAttachedToWindow();
    536             Dependency.get(ConfigurationController.class).addCallback(this);
    537         }
    538 
    539         @Override
    540         protected void onDetachedFromWindow() {
    541             super.onDetachedFromWindow();
    542             Dependency.get(ConfigurationController.class).removeCallback(this);
    543         }
    544 
    545         @Override
    546         public void onDensityOrFontScaleChanged() {
    547             updatePadding();
    548         }
    549 
    550         @Override
    551         public void onOverlayChanged() {
    552             setTextAppearance(sStyleId);
    553         }
    554 
    555         @Override
    556         public void setText(CharSequence text, BufferType type) {
    557             super.setText(text, type);
    558             updatePadding();
    559         }
    560 
    561         private void updatePadding() {
    562             boolean hasText = !TextUtils.isEmpty(getText());
    563             int horizontalPadding = (int) getContext().getResources()
    564                     .getDimension(R.dimen.widget_horizontal_padding) / 2;
    565             setPadding(horizontalPadding, 0, horizontalPadding * (hasText ? 1 : -1), 0);
    566             setCompoundDrawablePadding((int) mContext.getResources()
    567                     .getDimension(R.dimen.widget_icon_padding));
    568         }
    569 
    570         @Override
    571         public void setTextColor(int color) {
    572             super.setTextColor(color);
    573             updateDrawableColors();
    574         }
    575 
    576         @Override
    577         public void setCompoundDrawables(Drawable left, Drawable top, Drawable right,
    578                 Drawable bottom) {
    579             super.setCompoundDrawables(left, top, right, bottom);
    580             updateDrawableColors();
    581             updatePadding();
    582         }
    583 
    584         private void updateDrawableColors() {
    585             final int color = getCurrentTextColor();
    586             for (Drawable drawable : getCompoundDrawables()) {
    587                 if (drawable != null) {
    588                     drawable.setTint(color);
    589                 }
    590             }
    591         }
    592     }
    593 }
    594