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