NotificationContentView.java revision 0d9f35d1d86b1022d3ebd5fc988750bf062828c0
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 if (mContractedChild != null) { 70 mContractedChild.animate().cancel(); 71 } 72 if (mExpandedChild != null) { 73 mExpandedChild.animate().cancel(); 74 } 75 removeAllViews(); 76 mContractedChild = null; 77 mExpandedChild = null; 78 mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); 79 mActualHeight = mSmallHeight; 80 mContractedVisible = true; 81 } 82 83 public void setContractedChild(View child) { 84 if (mContractedChild != null) { 85 mContractedChild.animate().cancel(); 86 removeView(mContractedChild); 87 } 88 sanitizeContractedLayoutParams(child); 89 addView(child); 90 mContractedChild = child; 91 selectLayout(false /* animate */, true /* force */); 92 } 93 94 public void setExpandedChild(View child) { 95 if (mExpandedChild != null) { 96 mExpandedChild.animate().cancel(); 97 removeView(mExpandedChild); 98 } 99 addView(child); 100 mExpandedChild = child; 101 selectLayout(false /* animate */, true /* force */); 102 } 103 104 public void setActualHeight(int actualHeight) { 105 mActualHeight = actualHeight; 106 selectLayout(true /* animate */, false /* force */); 107 updateClipping(); 108 } 109 110 public int getMaxHeight() { 111 112 // The maximum height is just the laid out height. 113 return getHeight(); 114 } 115 116 public int getMinHeight() { 117 return mSmallHeight; 118 } 119 120 public void setClipTopAmount(int clipTopAmount) { 121 mClipTopAmount = clipTopAmount; 122 updateClipping(); 123 } 124 125 private void updateClipping() { 126 mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight); 127 setClipBounds(mClipBounds); 128 } 129 130 private void sanitizeContractedLayoutParams(View contractedChild) { 131 LayoutParams lp = (LayoutParams) contractedChild.getLayoutParams(); 132 lp.height = mSmallHeight; 133 contractedChild.setLayoutParams(lp); 134 } 135 136 private void selectLayout(boolean animate, boolean force) { 137 if (mContractedChild == null) { 138 return; 139 } 140 boolean showContractedChild = showContractedChild(); 141 if (showContractedChild != mContractedVisible || force) { 142 if (animate && mExpandedChild != null) { 143 runSwitchAnimation(showContractedChild); 144 } else if (mExpandedChild != null) { 145 mContractedChild.setVisibility(showContractedChild ? View.VISIBLE : View.INVISIBLE); 146 mContractedChild.setAlpha(showContractedChild ? 1f : 0f); 147 mExpandedChild.setVisibility(showContractedChild ? View.INVISIBLE : View.VISIBLE); 148 mExpandedChild.setAlpha(showContractedChild ? 0f : 1f); 149 } 150 } 151 mContractedVisible = showContractedChild; 152 } 153 154 private void runSwitchAnimation(final boolean showContractedChild) { 155 mContractedChild.setVisibility(View.VISIBLE); 156 mExpandedChild.setVisibility(View.VISIBLE); 157 mContractedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); 158 mExpandedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); 159 setLayerType(LAYER_TYPE_HARDWARE, null); 160 mContractedChild.animate() 161 .alpha(showContractedChild ? 1f : 0f) 162 .setDuration(ANIMATION_DURATION_LENGTH) 163 .setInterpolator(mLinearInterpolator); 164 mExpandedChild.animate() 165 .alpha(showContractedChild ? 0f : 1f) 166 .setDuration(ANIMATION_DURATION_LENGTH) 167 .setInterpolator(mLinearInterpolator) 168 .withEndAction(new Runnable() { 169 @Override 170 public void run() { 171 mContractedChild.setLayerType(LAYER_TYPE_NONE, null); 172 mExpandedChild.setLayerType(LAYER_TYPE_NONE, null); 173 setLayerType(LAYER_TYPE_NONE, null); 174 mContractedChild.setVisibility(showContractedChild 175 ? View.VISIBLE 176 : View.INVISIBLE); 177 mExpandedChild.setVisibility(showContractedChild 178 ? View.INVISIBLE 179 : View.VISIBLE); 180 } 181 }); 182 } 183 184 private boolean showContractedChild() { 185 return mActualHeight <= mSmallHeight || mExpandedChild == null; 186 } 187 188 public void notifyContentUpdated() { 189 selectLayout(false /* animate */, true /* force */); 190 } 191 192 public boolean isContentExpandable() { 193 return mExpandedChild != null; 194 } 195} 196