1a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang/*
2a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Copyright (C) 2014 The Android Open Source Project
3a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *
4a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Licensed under the Apache License, Version 2.0 (the "License");
5a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * you may not use this file except in compliance with the License.
6a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * You may obtain a copy of the License at
7a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *
8a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *      http://www.apache.org/licenses/LICENSE-2.0
9a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *
10a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Unless required by applicable law or agreed to in writing, software
11a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * distributed under the License is distributed on an "AS IS" BASIS,
12a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * See the License for the specific language governing permissions and
14a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * limitations under the License.
15a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */
16a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
17a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangpackage com.android.fmradio.views;
18a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
19a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.content.Context;
20a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.graphics.PixelFormat;
21a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.os.Handler;
22a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.util.Log;
23a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.Gravity;
24a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.View;
25a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.view.WindowManager;
26a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.Button;
27a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.RelativeLayout;
28a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport android.widget.TextView;
29a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
30a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangimport com.android.fmradio.R;
31a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
32a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang/**
33a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * The view used to display the customized toast
34a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *
35a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * Usage:
36a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang *
37a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * FmSnackBar snackBar = FmSnackBar.make(context, title, action,
38a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * listener,FmSnackBar.DEFAULT_DURATION);
39a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * snackBar.show();
40a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang * snackBar.dismiss();
41a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang */
42a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huangpublic final class FmSnackBar extends View {
43a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
44a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private static final String TAG = "FmSnackBar";
45a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private static final Object LOCK = new Object();
46a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public static final int DEFAULT_DURATION = 3000;
47a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public static final int MIN_DURATION = 1000;
48a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private Context mContext = null;
49a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private WindowManager.LayoutParams mWindowParams = null;
50a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private RelativeLayout mLayout = null;
51a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private boolean mIsDisplayed = false;
52a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private Button mButton = null;
53a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private TextView mTextView = null;
54a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private OnActionTriggerListener mActionListener = null;
55a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private Handler mHandler = null;
56a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private int mDuration = DEFAULT_DURATION;
57a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
58a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private final Runnable mDismissionRunnable = new Runnable() {
59a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        @Override
60a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        public void run() {
61a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            FmSnackBar.this.dismiss();
62a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
63a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    };
64a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
65a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    /**
66a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * The callback listener, it will called while the action button
67a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * was set and the action button was clicked
68a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     */
69a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public interface OnActionTriggerListener {
70a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        /**
71a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang         * Action button callback
72a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang         */
73a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        void onActionTriggered();
74a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
75a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
76a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    /**
77a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * To make a FmSnackBar instance
78a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     *
79a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @param context The context instance
80a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @param title The notification text
81a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @param actionName The action name displayed to end user
82a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @param listener The callback listener
83a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @param duration The displaying duration
84a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * @return The FmSnackBar instance
85a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     */
86a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public static synchronized FmSnackBar make(Context context, String title, String actionName,
87a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            OnActionTriggerListener listener, int duration) {
88a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        FmSnackBar instance = new FmSnackBar(context);
89a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        if (title == null) {
90a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mTextView.setText("");
91a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        } else {
92a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mTextView.setText(title);
93a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
94a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        if (actionName != null & listener != null) {
95a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mButton.setText(actionName);
96a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mActionListener = listener;
97a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mButton.setVisibility(View.VISIBLE);
98a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        } else {
99a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mButton.setVisibility(View.GONE);
100a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
101a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        if (duration < MIN_DURATION) {
102a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mDuration = MIN_DURATION;
103a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        } else {
104a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            instance.mDuration = duration;
105a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
106a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        return instance;
107a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
108a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
109a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private FmSnackBar(Context context) {
110a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        super(context);
111a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        init(context);
112a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
113a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
114a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    private void init(Context context) {
115a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mContext = context;
116a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mHandler = new Handler();
117a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mLayout = (RelativeLayout) RelativeLayout.inflate(context, R.layout.snackbar, null);
118a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams = new WindowManager.LayoutParams();
119a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
120a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.format = PixelFormat.RGBA_8888;
121a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
122a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
123a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.x = 0;
124a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.y = 0;
125a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.width = WindowManager.LayoutParams.MATCH_PARENT;
126a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
127a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
128a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mButton = (Button) mLayout.findViewById(R.id.snackbar_action);
129a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mButton.setOnClickListener(new OnClickListener() {
130a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            @Override
131a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            public void onClick(View arg0) {
132a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                if (mActionListener != null) {
133a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                    mActionListener.onActionTriggered();
134a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                }
135a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            }
136a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        });
137a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mButton.setVisibility(View.GONE);
138a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
139a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        mTextView = (TextView) mLayout.findViewById(R.id.snackbar_text);
140a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
141a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
142a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    /**
143a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * To display the view of FmSnackBar
144a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     */
145a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public void show() {
146a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        synchronized (LOCK) {
147a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            WindowManager manager = (WindowManager) mContext
148a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                    .getSystemService(Context.WINDOW_SERVICE);
149a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            if (mIsDisplayed) {
150a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                manager.removeViewImmediate(mLayout);
151a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            }
152a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            manager.addView(mLayout, mWindowParams);
153a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            mIsDisplayed = true;
154a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            mHandler.postDelayed(mDismissionRunnable, mDuration);
155a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
156a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
157a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang
158a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    /**
159a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     * To dismiss the view of Snackbar
160a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang     */
161a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    public void dismiss() {
162a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        synchronized (LOCK) {
163a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            WindowManager manager = (WindowManager) mContext
164a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                    .getSystemService(Context.WINDOW_SERVICE);
165a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            if (mIsDisplayed) {
166a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                try {
167a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                    manager.removeViewImmediate(mLayout);
168a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                } catch (IllegalArgumentException e) {
169a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                    Log.d(TAG, "dismiss, " + e.toString());
170a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang                }
171a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            }
172a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang            mIsDisplayed = false;
173a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang        }
174a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang    }
175a8b6afca0e187c008ba8fdeb670d5f2c13116bedBenson Huang}
176