mobile/android/base/widget/ButtonToast.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/widget/ButtonToast.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,181 @@
     1.4 +/*
     1.5 + * Copyright 2012 Roman Nurik
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * Unless required by applicable law or agreed to in writing, software
    1.14 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.16 + * See the License for the specific language governing permissions and
    1.17 + * limitations under the License.
    1.18 + */
    1.19 +
    1.20 +package org.mozilla.gecko.widget;
    1.21 +
    1.22 +import java.util.LinkedList;
    1.23 +
    1.24 +import org.mozilla.gecko.R;
    1.25 +import org.mozilla.gecko.animation.PropertyAnimator;
    1.26 +
    1.27 +import android.graphics.drawable.Drawable;
    1.28 +import android.os.Bundle;
    1.29 +import android.os.Handler;
    1.30 +import android.view.View;
    1.31 +import android.widget.Button;
    1.32 +import android.widget.TextView;
    1.33 +
    1.34 +public class ButtonToast {
    1.35 +    private final static String LOGTAG = "GeckoButtonToast";
    1.36 +    private final static int TOAST_DURATION = 5000;
    1.37 +
    1.38 +    private final View mView;
    1.39 +    private final TextView mMessageView;
    1.40 +    private final Button mButton;
    1.41 +    private final Handler mHideHandler = new Handler();
    1.42 +
    1.43 +    private final ToastListener mListener;
    1.44 +    private final LinkedList<Toast> mQueue = new LinkedList<Toast>();
    1.45 +    private Toast mCurrentToast;
    1.46 +
    1.47 +    public enum ReasonHidden {
    1.48 +        CLICKED,
    1.49 +        TIMEOUT,
    1.50 +        STARTUP
    1.51 +    }
    1.52 +
    1.53 +    // State objects
    1.54 +    private static class Toast {
    1.55 +        public final CharSequence buttonMessage;
    1.56 +        public Drawable buttonDrawable;
    1.57 +        public final CharSequence message;
    1.58 +        public ToastListener listener;
    1.59 +
    1.60 +        public Toast(CharSequence aMessage, CharSequence aButtonMessage,
    1.61 +                     Drawable aDrawable, ToastListener aListener) {
    1.62 +            message = aMessage;
    1.63 +            buttonMessage = aButtonMessage;
    1.64 +            buttonDrawable = aDrawable;
    1.65 +            listener = aListener;
    1.66 +        }
    1.67 +    }
    1.68 +
    1.69 +    public interface ToastListener {
    1.70 +        void onButtonClicked();
    1.71 +        void onToastHidden(ReasonHidden reason);
    1.72 +    }
    1.73 +
    1.74 +    public ButtonToast(View view) {
    1.75 +        mView = view;
    1.76 +        mListener = null;
    1.77 +        mMessageView = (TextView) mView.findViewById(R.id.toast_message);
    1.78 +        mButton = (Button) mView.findViewById(R.id.toast_button);
    1.79 +        mButton.setOnClickListener(new View.OnClickListener() {
    1.80 +                    @Override
    1.81 +                    public void onClick(View view) {
    1.82 +                        Toast t = mCurrentToast;
    1.83 +                        if (t == null)
    1.84 +                            return;
    1.85 +
    1.86 +                        hide(false, ReasonHidden.CLICKED);
    1.87 +                        if (t.listener != null) {
    1.88 +                            t.listener.onButtonClicked();
    1.89 +                        }
    1.90 +                    }
    1.91 +                });
    1.92 +
    1.93 +        hide(true, ReasonHidden.STARTUP);
    1.94 +    }
    1.95 +
    1.96 +    public void show(boolean immediate, CharSequence message,
    1.97 +                     CharSequence buttonMessage, Drawable buttonDrawable,
    1.98 +                     ToastListener listener) {
    1.99 +        show(new Toast(message, buttonMessage, buttonDrawable, listener), immediate);
   1.100 +    }
   1.101 +
   1.102 +    private void show(Toast t, boolean immediate) {
   1.103 +        // If we're already showing a toast, add this one to the queue to show later
   1.104 +        if (mView.getVisibility() == View.VISIBLE) {
   1.105 +            mQueue.offer(t);
   1.106 +            return;
   1.107 +        }
   1.108 +
   1.109 +        mCurrentToast = t;
   1.110 +        mButton.setEnabled(true);
   1.111 +
   1.112 +        mMessageView.setText(t.message);
   1.113 +        mButton.setText(t.buttonMessage);
   1.114 +        mButton.setCompoundDrawablePadding(mView.getContext().getResources().getDimensionPixelSize(R.dimen.toast_button_padding));
   1.115 +        mButton.setCompoundDrawablesWithIntrinsicBounds(t.buttonDrawable, null, null, null);
   1.116 +
   1.117 +        mHideHandler.removeCallbacks(mHideRunnable);
   1.118 +        mHideHandler.postDelayed(mHideRunnable, TOAST_DURATION);
   1.119 +
   1.120 +        mView.setVisibility(View.VISIBLE);
   1.121 +        int duration = immediate ? 0 : mView.getResources().getInteger(android.R.integer.config_longAnimTime);
   1.122 +
   1.123 +        PropertyAnimator animator = new PropertyAnimator(duration);
   1.124 +        animator.attach(mView, PropertyAnimator.Property.ALPHA, 1.0f);
   1.125 +        animator.start();
   1.126 +    }
   1.127 +
   1.128 +    public void hide(boolean immediate, ReasonHidden reason) {
   1.129 +        if (mButton.isPressed() && reason != ReasonHidden.CLICKED) {
   1.130 +            mHideHandler.postDelayed(mHideRunnable, TOAST_DURATION);
   1.131 +            return;
   1.132 +        }
   1.133 +
   1.134 +        if (mCurrentToast != null && mCurrentToast.listener != null) {
   1.135 +            mCurrentToast.listener.onToastHidden(reason);
   1.136 +        }
   1.137 +        mCurrentToast = null;
   1.138 +        mButton.setEnabled(false);
   1.139 +        mHideHandler.removeCallbacks(mHideRunnable);
   1.140 +        int duration = immediate ? 0 : mView.getResources().getInteger(android.R.integer.config_longAnimTime);
   1.141 +
   1.142 +        mView.clearAnimation();
   1.143 +        if (immediate) {
   1.144 +            mView.setVisibility(View.GONE);
   1.145 +            showNextInQueue();
   1.146 +        } else {
   1.147 +            // Using Android's animation frameworks will not correctly turn off clicking.
   1.148 +            // See bug 885717.
   1.149 +            PropertyAnimator animator = new PropertyAnimator(duration);
   1.150 +            animator.attach(mView, PropertyAnimator.Property.ALPHA, 0.0f);
   1.151 +            animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener () {
   1.152 +                // If we are showing a toast and go in the background
   1.153 +                // onAnimationEnd will be called when the app is restored
   1.154 +                public void onPropertyAnimationEnd() {
   1.155 +                    mView.setVisibility(View.GONE);
   1.156 +                    showNextInQueue();
   1.157 +                }
   1.158 +                public void onPropertyAnimationStart() { }
   1.159 +            });
   1.160 +            animator.start();
   1.161 +        }
   1.162 +    }
   1.163 +
   1.164 +    public void onSaveInstanceState(Bundle outState) {
   1.165 +        // Add whatever toast we're currently showing to the front of the queue
   1.166 +        if (mCurrentToast != null) {
   1.167 +            mQueue.add(0, mCurrentToast);
   1.168 +        }
   1.169 +    }
   1.170 +
   1.171 +    private void showNextInQueue() {
   1.172 +        Toast t = mQueue.poll();
   1.173 +        if (t != null) {
   1.174 +            show(t, false);
   1.175 +        }
   1.176 +    }
   1.177 +
   1.178 +    private Runnable mHideRunnable = new Runnable() {
   1.179 +        @Override
   1.180 +        public void run() {
   1.181 +            hide(false, ReasonHidden.TIMEOUT);
   1.182 +        }
   1.183 +    };
   1.184 +}

mercurial