NotificationContentView.java revision a7fe63190cc3f95af1830886edd80acef0c334e3
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 17package com.android.systemui.statusbar; 18 19import android.content.Context; 20import android.graphics.Paint; 21import android.graphics.PorterDuff; 22import android.graphics.PorterDuffXfermode; 23import android.graphics.Rect; 24import android.util.AttributeSet; 25import android.view.View; 26import android.view.animation.Interpolator; 27import android.view.animation.LinearInterpolator; 28import android.widget.FrameLayout; 29 30import com.android.systemui.R; 31 32/** 33 * A frame layout containing the actual payload of the notification, including the contracted and 34 * expanded layout. This class is responsible for clipping the content and and switching between the 35 * expanded and contracted view depending on its clipped size. 36 */ 37public class NotificationContentView extends FrameLayout { 38 39 private static final long ANIMATION_DURATION_LENGTH = 170; 40 41 private final Rect mClipBounds = new Rect(); 42 43 private View mContractedChild; 44 private View mExpandedChild; 45 46 private int mSmallHeight; 47 private int mClipTopAmount; 48 private int mActualHeight; 49 50 private final Interpolator mLinearInterpolator = new LinearInterpolator(); 51 52 private boolean mContractedVisible = true; 53 54 private final Paint mFadePaint = new Paint(); 55 56 public NotificationContentView(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); 59 reset(); 60 } 61 62 @Override 63 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 64 super.onLayout(changed, left, top, right, bottom); 65 updateClipping(); 66 } 67 68 public void reset() { 69 removeAllViews(); 70 mContractedChild = null; 71 mExpandedChild = null; 72 mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); 73 mActualHeight = mSmallHeight; 74 mContractedVisible = true; 75 } 76 77 public void setContractedChild(View child) { 78 if (mContractedChild != null) { 79 removeView(mContractedChild); 80 } 81 sanitizeContractedLayoutParams(child); 82 addView(child); 83 mContractedChild = child; 84 selectLayout(false /* animate */, true /* force */); 85 } 86 87 public void setExpandedChild(View child) { 88 if (mExpandedChild != null) { 89 removeView(mExpandedChild); 90 } 91 addView(child); 92 mExpandedChild = child; 93 selectLayout(false /* animate */, true /* force */); 94 } 95 96 public void setActualHeight(int actualHeight) { 97 mActualHeight = actualHeight; 98 selectLayout(true /* animate */, false /* force */); 99 updateClipping(); 100 } 101 102 public int getMaxHeight() { 103 104 // The maximum height is just the laid out height. 105 return getHeight(); 106 } 107 108 public int getMinHeight() { 109 return mSmallHeight; 110 } 111 112 public void setClipTopAmount(int clipTopAmount) { 113 mClipTopAmount = clipTopAmount; 114 updateClipping(); 115 } 116 117 private void updateClipping() { 118 mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight); 119 setClipBounds(mClipBounds); 120 } 121 122 private void sanitizeContractedLayoutParams(View contractedChild) { 123 LayoutParams lp = (LayoutParams) contractedChild.getLayoutParams(); 124 lp.height = mSmallHeight; 125 contractedChild.setLayoutParams(lp); 126 } 127 128 private void selectLayout(boolean animate, boolean force) { 129 if (mContractedChild == null) { 130 return; 131 } 132 boolean showContractedChild = showContractedChild(); 133 if (showContractedChild != mContractedVisible || force) { 134 if (animate && mExpandedChild != null) { 135 runSwitchAnimation(showContractedChild); 136 } else if (mExpandedChild != null) { 137 mContractedChild.setVisibility(showContractedChild ? View.VISIBLE : View.INVISIBLE); 138 mContractedChild.setAlpha(showContractedChild ? 1f : 0f); 139 mExpandedChild.setVisibility(showContractedChild ? View.INVISIBLE : View.VISIBLE); 140 mExpandedChild.setAlpha(showContractedChild ? 0f : 1f); 141 } 142 } 143 mContractedVisible = showContractedChild; 144 } 145 146 private void runSwitchAnimation(final boolean showContractedChild) { 147 mContractedChild.setVisibility(View.VISIBLE); 148 mExpandedChild.setVisibility(View.VISIBLE); 149 mContractedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); 150 mExpandedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); 151 setLayerType(LAYER_TYPE_HARDWARE, null); 152 mContractedChild.animate() 153 .alpha(showContractedChild ? 1f : 0f) 154 .setDuration(ANIMATION_DURATION_LENGTH) 155 .setInterpolator(mLinearInterpolator); 156 mExpandedChild.animate() 157 .alpha(showContractedChild ? 0f : 1f) 158 .setDuration(ANIMATION_DURATION_LENGTH) 159 .setInterpolator(mLinearInterpolator) 160 .withEndAction(new Runnable() { 161 @Override 162 public void run() { 163 mContractedChild.setLayerType(LAYER_TYPE_NONE, null); 164 mExpandedChild.setLayerType(LAYER_TYPE_NONE, null); 165 setLayerType(LAYER_TYPE_NONE, null); 166 mContractedChild.setVisibility(showContractedChild 167 ? View.VISIBLE 168 : View.INVISIBLE); 169 mExpandedChild.setVisibility(showContractedChild 170 ? View.INVISIBLE 171 : View.VISIBLE); 172 } 173 }); 174 } 175 176 private boolean showContractedChild() { 177 return mActualHeight <= mSmallHeight || mExpandedChild == null; 178 } 179 180 public void notifyContentUpdated() { 181 selectLayout(false /* animate */, true /* force */); 182 } 183 184 public boolean isContentExpandable() { 185 return mExpandedChild != null; 186 } 187} 188