Home | History | Annotate | Download | only in notification
      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 
     17 package com.android.systemui.statusbar.notification;
     18 
     19 import android.animation.ValueAnimator;
     20 import android.content.Context;
     21 import android.graphics.Color;
     22 import android.service.notification.StatusBarNotification;
     23 import android.view.View;
     24 import android.widget.ImageView;
     25 import android.widget.ProgressBar;
     26 import android.widget.TextView;
     27 
     28 import com.android.systemui.statusbar.CrossFadeHelper;
     29 import com.android.systemui.statusbar.ExpandableNotificationRow;
     30 import com.android.systemui.statusbar.TransformableView;
     31 import com.android.systemui.statusbar.ViewTransformationHelper;
     32 
     33 /**
     34  * Wraps a notification view inflated from a template.
     35  */
     36 public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
     37 
     38     private static final int mDarkProgressTint = 0xffffffff;
     39 
     40     protected ImageView mPicture;
     41     private ProgressBar mProgressBar;
     42     private TextView mTitle;
     43     private TextView mText;
     44     private View mActionsContainer;
     45 
     46     private int mContentHeight;
     47     private int mMinHeightHint;
     48 
     49     protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
     50         super(ctx, view, row);
     51         mTransformationHelper.setCustomTransformation(
     52                 new ViewTransformationHelper.CustomTransformation() {
     53                     @Override
     54                     public boolean transformTo(TransformState ownState,
     55                             TransformableView notification, final float transformationAmount) {
     56                         if (!(notification instanceof HybridNotificationView)) {
     57                             return false;
     58                         }
     59                         TransformState otherState = notification.getCurrentState(
     60                                 TRANSFORMING_VIEW_TITLE);
     61                         final View text = ownState.getTransformedView();
     62                         CrossFadeHelper.fadeOut(text, transformationAmount);
     63                         if (otherState != null) {
     64                             ownState.transformViewVerticalTo(otherState, this,
     65                                     transformationAmount);
     66                             otherState.recycle();
     67                         }
     68                         return true;
     69                     }
     70 
     71                     @Override
     72                     public boolean customTransformTarget(TransformState ownState,
     73                             TransformState otherState) {
     74                         float endY = getTransformationY(ownState, otherState);
     75                         ownState.setTransformationEndY(endY);
     76                         return true;
     77                     }
     78 
     79                     @Override
     80                     public boolean transformFrom(TransformState ownState,
     81                             TransformableView notification, float transformationAmount) {
     82                         if (!(notification instanceof HybridNotificationView)) {
     83                             return false;
     84                         }
     85                         TransformState otherState = notification.getCurrentState(
     86                                 TRANSFORMING_VIEW_TITLE);
     87                         final View text = ownState.getTransformedView();
     88                         CrossFadeHelper.fadeIn(text, transformationAmount);
     89                         if (otherState != null) {
     90                             ownState.transformViewVerticalFrom(otherState, this,
     91                                     transformationAmount);
     92                             otherState.recycle();
     93                         }
     94                         return true;
     95                     }
     96 
     97                     @Override
     98                     public boolean initTransformation(TransformState ownState,
     99                             TransformState otherState) {
    100                         float startY = getTransformationY(ownState, otherState);
    101                         ownState.setTransformationStartY(startY);
    102                         return true;
    103                     }
    104 
    105                     private float getTransformationY(TransformState ownState,
    106                             TransformState otherState) {
    107                         int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
    108                         int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
    109                         return (otherStablePosition[1]
    110                                 + otherState.getTransformedView().getHeight()
    111                                 - ownStablePosition[1]) * 0.33f;
    112                     }
    113 
    114                 }, TRANSFORMING_VIEW_TEXT);
    115     }
    116 
    117     private void resolveTemplateViews(StatusBarNotification notification) {
    118         mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
    119         mPicture.setTag(ImageTransformState.ICON_TAG,
    120                 notification.getNotification().getLargeIcon());
    121         mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
    122         mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
    123         final View progress = mView.findViewById(com.android.internal.R.id.progress);
    124         if (progress instanceof ProgressBar) {
    125             mProgressBar = (ProgressBar) progress;
    126         } else {
    127             // It's still a viewstub
    128             mProgressBar = null;
    129         }
    130         mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
    131     }
    132 
    133     @Override
    134     public void notifyContentUpdated(StatusBarNotification notification) {
    135         // Reinspect the notification. Before the super call, because the super call also updates
    136         // the transformation types and we need to have our values set by then.
    137         resolveTemplateViews(notification);
    138         super.notifyContentUpdated(notification);
    139     }
    140 
    141     @Override
    142     protected void updateInvertHelper() {
    143         super.updateInvertHelper();
    144         View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
    145         if (mainColumn != null) {
    146             mInvertHelper.addTarget(mainColumn);
    147         }
    148     }
    149 
    150     @Override
    151     protected void updateTransformedTypes() {
    152         // This also clears the existing types
    153         super.updateTransformedTypes();
    154         if (mTitle != null) {
    155             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, mTitle);
    156         }
    157         if (mText != null) {
    158             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT, mText);
    159         }
    160         if (mPicture != null) {
    161             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE, mPicture);
    162         }
    163         if (mProgressBar != null) {
    164             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS, mProgressBar);
    165         }
    166     }
    167 
    168     @Override
    169     public void setDark(boolean dark, boolean fade, long delay) {
    170         if (dark == mDark && mDarkInitialized) {
    171             return;
    172         }
    173         super.setDark(dark, fade, delay);
    174         setPictureGrayscale(dark, fade, delay);
    175         setProgressBarDark(dark, fade, delay);
    176     }
    177 
    178     private void setProgressBarDark(boolean dark, boolean fade, long delay) {
    179         if (mProgressBar != null) {
    180             if (fade) {
    181                 fadeProgressDark(mProgressBar, dark, delay);
    182             } else {
    183                 updateProgressDark(mProgressBar, dark);
    184             }
    185         }
    186     }
    187 
    188     private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
    189         startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
    190             @Override
    191             public void onAnimationUpdate(ValueAnimator animation) {
    192                 float t = (float) animation.getAnimatedValue();
    193                 updateProgressDark(target, t);
    194             }
    195         }, dark, delay, null /* listener */);
    196     }
    197 
    198     private void updateProgressDark(ProgressBar target, float intensity) {
    199         int color = interpolateColor(mColor, mDarkProgressTint, intensity);
    200         target.getIndeterminateDrawable().mutate().setTint(color);
    201         target.getProgressDrawable().mutate().setTint(color);
    202     }
    203 
    204     private void updateProgressDark(ProgressBar target, boolean dark) {
    205         updateProgressDark(target, dark ? 1f : 0f);
    206     }
    207 
    208     protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
    209         if (mPicture != null) {
    210             if (fade) {
    211                 fadeGrayscale(mPicture, grayscale, delay);
    212             } else {
    213                 updateGrayscale(mPicture, grayscale);
    214             }
    215         }
    216     }
    217 
    218     private static int interpolateColor(int source, int target, float t) {
    219         int aSource = Color.alpha(source);
    220         int rSource = Color.red(source);
    221         int gSource = Color.green(source);
    222         int bSource = Color.blue(source);
    223         int aTarget = Color.alpha(target);
    224         int rTarget = Color.red(target);
    225         int gTarget = Color.green(target);
    226         int bTarget = Color.blue(target);
    227         return Color.argb(
    228                 (int) (aSource * (1f - t) + aTarget * t),
    229                 (int) (rSource * (1f - t) + rTarget * t),
    230                 (int) (gSource * (1f - t) + gTarget * t),
    231                 (int) (bSource * (1f - t) + bTarget * t));
    232     }
    233 
    234     @Override
    235     public void setContentHeight(int contentHeight, int minHeightHint) {
    236         super.setContentHeight(contentHeight, minHeightHint);
    237 
    238         mContentHeight = contentHeight;
    239         mMinHeightHint = minHeightHint;
    240         updateActionOffset();
    241     }
    242 
    243     private void updateActionOffset() {
    244         if (mActionsContainer != null) {
    245             // We should never push the actions higher than they are in the headsup view.
    246             int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
    247             mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight());
    248         }
    249     }
    250 }
    251