ActionableToastBar.java revision d243d459b64003c5171ac5ff606729e525161be6
1/** 2 * Copyright (c) 2011, Google Inc. 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 */ 16package com.android.mail.ui; 17 18import android.animation.Animator; 19import android.animation.AnimatorInflater; 20import android.content.Context; 21import android.text.Spanned; 22import android.util.AttributeSet; 23import android.view.LayoutInflater; 24import android.view.MotionEvent; 25import android.view.View; 26import android.widget.FrameLayout; 27import android.widget.ImageView; 28import android.widget.LinearLayout; 29import android.widget.TextView; 30 31import com.android.mail.R; 32import com.android.mail.ui.ViewMode.ModeChangeListener; 33 34/** 35 * A custom {@link View} that exposes an action to the user. 36 */ 37public class ActionableToastBar extends LinearLayout { 38 private boolean mHidden = false; 39 private Animator mShowAnimation; 40 private Animator mHideAnimation; 41 private final int mBottomMarginSizeInConversation; 42 private final int mBottomMarginSize; 43 44 /** Icon for the description. */ 45 private ImageView mActionDescriptionIcon; 46 /** The clickable view */ 47 private View mActionButton; 48 /** Icon for the action button. */ 49 private View mActionIcon; 50 /** The view that contains the description. */ 51 private TextView mActionDescriptionView; 52 /** The view that contains the text for the action button. */ 53 private TextView mActionText; 54 private ToastBarOperation mOperation; 55 56 public ActionableToastBar(Context context) { 57 this(context, null); 58 } 59 60 public ActionableToastBar(Context context, AttributeSet attrs) { 61 this(context, attrs, 0); 62 } 63 64 public ActionableToastBar(Context context, AttributeSet attrs, int defStyle) { 65 super(context, attrs, defStyle); 66 mBottomMarginSize = context.getResources() 67 .getDimensionPixelSize(R.dimen.toast_bar_bottom_margin); 68 mBottomMarginSizeInConversation = context.getResources().getDimensionPixelSize( 69 R.dimen.toast_bar_bottom_margin_in_conversation); 70 LayoutInflater.from(context).inflate(R.layout.actionable_toast_row, this, true); 71 } 72 73 @Override 74 protected void onFinishInflate() { 75 super.onFinishInflate(); 76 77 mActionDescriptionIcon = (ImageView) findViewById(R.id.description_icon); 78 mActionDescriptionView = (TextView) findViewById(R.id.description_text); 79 mActionButton = findViewById(R.id.action_button); 80 mActionIcon = findViewById(R.id.action_icon); 81 mActionText = (TextView) findViewById(R.id.action_text); 82 } 83 84 /** 85 * Tells the view that it will be appearing in the conversation pane 86 * and should adjust its layout parameters accordingly. 87 * @param isInConversationMode true if the view will be shown in the conversation view 88 */ 89 public void setConversationMode(boolean isInConversationMode) { 90 final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams(); 91 params.bottomMargin = isInConversationMode ? mBottomMarginSizeInConversation 92 : mBottomMarginSize; 93 setLayoutParams(params); 94 } 95 96 /** 97 * Displays the toast bar and makes it visible. Allows the setting of 98 * parameters to customize the display. 99 * @param listener performs some action when the action button is clicked 100 * @param descriptionIconResourceId resource ID for the description icon or 101 * 0 if no icon should be shown 102 * @param descriptionText a description text to show in the toast bar 103 * @param showActionIcon if true, the action button icon should be shown 104 * @param actionTextResource resource ID for the text to show in the action button 105 * @param replaceVisibleToast if true, this toast should replace any currently visible toast. 106 * Otherwise, skip showing this toast. 107 * @param op the operation that corresponds to the specific toast being shown 108 */ 109 public void show(final ActionClickedListener listener, int descriptionIconResourceId, 110 CharSequence descriptionText, boolean showActionIcon, int actionTextResource, 111 boolean replaceVisibleToast, ToastBarOperation op) { 112 113 if (!mHidden && !replaceVisibleToast) { 114 return; 115 } 116 117 mOperation = op; 118 119 mActionButton.setOnClickListener(new OnClickListener() { 120 @Override 121 public void onClick(View widget) { 122 listener.onActionClicked(); 123 hide(true); 124 } 125 }); 126 127 // Set description icon. 128 if (descriptionIconResourceId == 0) { 129 mActionDescriptionIcon.setVisibility(GONE); 130 } else { 131 mActionDescriptionIcon.setVisibility(VISIBLE); 132 mActionDescriptionIcon.setImageResource(descriptionIconResourceId); 133 } 134 135 mActionDescriptionView.setText(descriptionText); 136 mActionIcon.setVisibility(showActionIcon ? VISIBLE : GONE); 137 mActionText.setText(actionTextResource); 138 139 mHidden = false; 140 getShowAnimation().start(); 141 } 142 143 public ToastBarOperation getOperation() { 144 return mOperation; 145 } 146 147 /** 148 * Hides the view and resets the state. 149 */ 150 public void hide(boolean animate) { 151 mHidden = true; 152 if (getVisibility() == View.VISIBLE) { 153 mActionDescriptionView.setText(""); 154 mActionButton.setOnClickListener(null); 155 // Hide view once it's clicked. 156 if (animate) { 157 getHideAnimation().start(); 158 } else { 159 setAlpha(0); 160 setVisibility(View.GONE); 161 } 162 } 163 } 164 165 private Animator getShowAnimation() { 166 if (mShowAnimation == null) { 167 mShowAnimation = AnimatorInflater.loadAnimator(getContext(), 168 R.anim.fade_in); 169 mShowAnimation.addListener(new Animator.AnimatorListener() { 170 @Override 171 public void onAnimationStart(Animator animation) { 172 setVisibility(View.VISIBLE); 173 } 174 @Override 175 public void onAnimationEnd(Animator animation) { 176 } 177 @Override 178 public void onAnimationCancel(Animator animation) { 179 } 180 @Override 181 public void onAnimationRepeat(Animator animation) { 182 } 183 }); 184 mShowAnimation.setTarget(this); 185 } 186 return mShowAnimation; 187 } 188 189 private Animator getHideAnimation() { 190 if (mHideAnimation == null) { 191 mHideAnimation = AnimatorInflater.loadAnimator(getContext(), 192 R.anim.fade_out); 193 mHideAnimation.addListener(new Animator.AnimatorListener() { 194 @Override 195 public void onAnimationStart(Animator animation) { 196 } 197 @Override 198 public void onAnimationRepeat(Animator animation) { 199 } 200 @Override 201 public void onAnimationEnd(Animator animation) { 202 setVisibility(View.GONE); 203 } 204 @Override 205 public void onAnimationCancel(Animator animation) { 206 } 207 }); 208 mHideAnimation.setTarget(this); 209 } 210 return mHideAnimation; 211 } 212 213 public boolean isEventInToastBar(MotionEvent event) { 214 if (!isShown()) { 215 return false; 216 } 217 int[] xy = new int[2]; 218 float x = event.getX(); 219 float y = event.getY(); 220 getLocationOnScreen(xy); 221 return (x > xy[0] && x < (xy[0] + getWidth()) && y > xy[1] && y < xy[1] + getHeight()); 222 } 223 224 public boolean isAnimating() { 225 return mShowAnimation != null && mShowAnimation.isStarted(); 226 } 227 /** 228 * Classes that wish to perform some action when the action button is clicked 229 * should implement this interface. 230 */ 231 public interface ActionClickedListener { 232 public void onActionClicked(); 233 } 234} 235