Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /*
2 * Copyright 2012 Roman Nurik
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 */
17 package org.mozilla.gecko.widget;
19 import java.util.LinkedList;
21 import org.mozilla.gecko.R;
22 import org.mozilla.gecko.animation.PropertyAnimator;
24 import android.graphics.drawable.Drawable;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.view.View;
28 import android.widget.Button;
29 import android.widget.TextView;
31 public class ButtonToast {
32 private final static String LOGTAG = "GeckoButtonToast";
33 private final static int TOAST_DURATION = 5000;
35 private final View mView;
36 private final TextView mMessageView;
37 private final Button mButton;
38 private final Handler mHideHandler = new Handler();
40 private final ToastListener mListener;
41 private final LinkedList<Toast> mQueue = new LinkedList<Toast>();
42 private Toast mCurrentToast;
44 public enum ReasonHidden {
45 CLICKED,
46 TIMEOUT,
47 STARTUP
48 }
50 // State objects
51 private static class Toast {
52 public final CharSequence buttonMessage;
53 public Drawable buttonDrawable;
54 public final CharSequence message;
55 public ToastListener listener;
57 public Toast(CharSequence aMessage, CharSequence aButtonMessage,
58 Drawable aDrawable, ToastListener aListener) {
59 message = aMessage;
60 buttonMessage = aButtonMessage;
61 buttonDrawable = aDrawable;
62 listener = aListener;
63 }
64 }
66 public interface ToastListener {
67 void onButtonClicked();
68 void onToastHidden(ReasonHidden reason);
69 }
71 public ButtonToast(View view) {
72 mView = view;
73 mListener = null;
74 mMessageView = (TextView) mView.findViewById(R.id.toast_message);
75 mButton = (Button) mView.findViewById(R.id.toast_button);
76 mButton.setOnClickListener(new View.OnClickListener() {
77 @Override
78 public void onClick(View view) {
79 Toast t = mCurrentToast;
80 if (t == null)
81 return;
83 hide(false, ReasonHidden.CLICKED);
84 if (t.listener != null) {
85 t.listener.onButtonClicked();
86 }
87 }
88 });
90 hide(true, ReasonHidden.STARTUP);
91 }
93 public void show(boolean immediate, CharSequence message,
94 CharSequence buttonMessage, Drawable buttonDrawable,
95 ToastListener listener) {
96 show(new Toast(message, buttonMessage, buttonDrawable, listener), immediate);
97 }
99 private void show(Toast t, boolean immediate) {
100 // If we're already showing a toast, add this one to the queue to show later
101 if (mView.getVisibility() == View.VISIBLE) {
102 mQueue.offer(t);
103 return;
104 }
106 mCurrentToast = t;
107 mButton.setEnabled(true);
109 mMessageView.setText(t.message);
110 mButton.setText(t.buttonMessage);
111 mButton.setCompoundDrawablePadding(mView.getContext().getResources().getDimensionPixelSize(R.dimen.toast_button_padding));
112 mButton.setCompoundDrawablesWithIntrinsicBounds(t.buttonDrawable, null, null, null);
114 mHideHandler.removeCallbacks(mHideRunnable);
115 mHideHandler.postDelayed(mHideRunnable, TOAST_DURATION);
117 mView.setVisibility(View.VISIBLE);
118 int duration = immediate ? 0 : mView.getResources().getInteger(android.R.integer.config_longAnimTime);
120 PropertyAnimator animator = new PropertyAnimator(duration);
121 animator.attach(mView, PropertyAnimator.Property.ALPHA, 1.0f);
122 animator.start();
123 }
125 public void hide(boolean immediate, ReasonHidden reason) {
126 if (mButton.isPressed() && reason != ReasonHidden.CLICKED) {
127 mHideHandler.postDelayed(mHideRunnable, TOAST_DURATION);
128 return;
129 }
131 if (mCurrentToast != null && mCurrentToast.listener != null) {
132 mCurrentToast.listener.onToastHidden(reason);
133 }
134 mCurrentToast = null;
135 mButton.setEnabled(false);
136 mHideHandler.removeCallbacks(mHideRunnable);
137 int duration = immediate ? 0 : mView.getResources().getInteger(android.R.integer.config_longAnimTime);
139 mView.clearAnimation();
140 if (immediate) {
141 mView.setVisibility(View.GONE);
142 showNextInQueue();
143 } else {
144 // Using Android's animation frameworks will not correctly turn off clicking.
145 // See bug 885717.
146 PropertyAnimator animator = new PropertyAnimator(duration);
147 animator.attach(mView, PropertyAnimator.Property.ALPHA, 0.0f);
148 animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener () {
149 // If we are showing a toast and go in the background
150 // onAnimationEnd will be called when the app is restored
151 public void onPropertyAnimationEnd() {
152 mView.setVisibility(View.GONE);
153 showNextInQueue();
154 }
155 public void onPropertyAnimationStart() { }
156 });
157 animator.start();
158 }
159 }
161 public void onSaveInstanceState(Bundle outState) {
162 // Add whatever toast we're currently showing to the front of the queue
163 if (mCurrentToast != null) {
164 mQueue.add(0, mCurrentToast);
165 }
166 }
168 private void showNextInQueue() {
169 Toast t = mQueue.poll();
170 if (t != null) {
171 show(t, false);
172 }
173 }
175 private Runnable mHideRunnable = new Runnable() {
176 @Override
177 public void run() {
178 hide(false, ReasonHidden.TIMEOUT);
179 }
180 };
181 }