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