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