/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.linkbubble.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.graphics.PixelFormat; import android.os.Handler; import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewPropertyAnimator; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.TextView; import com.linkbubble.R; import com.linkbubble.util.CrashTracking; import com.linkbubble.util.SwipeDismissTouchListener; import com.linkbubble.util.Util; public class Prompt { public interface OnPromptEventListener { void onActionClick(); void onClose(); } public static final int LENGTH_SHORT = 3000; public static final int LENGTH_LONG = 6000; private static Prompt sPrompt; private static boolean sIsShowing; private View mRootView; private View mBarView; private TextView mMessageView; private TextView mPromptButtonTextView; private ViewPropertyAnimator mBarAnimator; private Handler mHideHandler = new Handler(); private OnPromptEventListener mListener; private WindowManager mWindowManager; private WindowManager.LayoutParams mLayoutParams; int mSnackbarHeight; public static void initModule(Context context) { Util.Assert(sPrompt == null, "non-null instance"); sPrompt = new Prompt(context); } public static void deinitModule() { Util.Assert(sPrompt != null, "null instance"); sPrompt = null; } public static boolean isShowing() { return sIsShowing; } private Prompt(Context context) { mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mSnackbarHeight = context.getResources().getDimensionPixelSize(R.dimen.snackbar_height); LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mRootView = li.inflate(R.layout.view_prompt, null); mLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, context.getResources().getDimensionPixelSize(R.dimen.snackbar_height), WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, PixelFormat.TRANSLUCENT); mLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; mLayoutParams.setTitle("LinkBubble: Prompt"); mBarView = mRootView.findViewById(R.id.prompt); mBarAnimator = mBarView.animate(); mMessageView = (TextView) mBarView.findViewById(R.id.prompt_message); mPromptButtonTextView = (TextView)mBarView.findViewById(R.id.prompt_button_text_view); mPromptButtonTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mListener != null) { mListener.onActionClick(); } hidePrompt(false); } }); hidePrompt(true); } private void showPrompt(CharSequence text, CharSequence buttonText, int duration, boolean forceSingleLine, OnPromptEventListener listener) { mMessageView.setText(text); if (forceSingleLine) { mMessageView.setSingleLine(true); mMessageView.setEllipsize(TextUtils.TruncateAt.END); } else { mMessageView.setSingleLine(false); mMessageView.setEllipsize(null); } mListener = listener; mPromptButtonTextView.setText(buttonText); mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, duration); mBarView.setVisibility(View.VISIBLE); mBarAnimator.cancel(); mBarAnimator.y(0) .setDuration(mBarView.getResources().getInteger(android.R.integer.config_shortAnimTime)) .setInterpolator(new DecelerateInterpolator()) .setListener(null); mWindowManager.addView(mRootView, mLayoutParams); sIsShowing = true; mBarView.setOnTouchListener(new SwipeDismissTouchListener(mBarView, null, new SwipeDismissTouchListener.DismissCallbacks() { @Override public boolean canDismiss(Object token) { // If the user taps, start the delay over for a long length period mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, Prompt.LENGTH_LONG); return true; } @Override public void onDismiss(View view, Object token) { hidePrompt(true); } @Override public void onReturn() { mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, 1500); } })); } private void hidePrompt(boolean immediate) { mHideHandler.removeCallbacks(mHideRunnable); mBarAnimator.cancel(); if (immediate) { mBarView.setVisibility(View.GONE); mBarView.setY(mSnackbarHeight); if (sIsShowing) { mWindowManager.removeViewImmediate(mRootView); sIsShowing = false; } if (mListener != null) { mListener.onClose(); mListener = null; } } else { mBarAnimator.y(mSnackbarHeight) .setDuration(mBarView.getResources().getInteger(android.R.integer.config_shortAnimTime)) .setInterpolator(new AccelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mBarView.setVisibility(View.GONE); if (sIsShowing) { mWindowManager.removeViewImmediate(mRootView); sIsShowing = false; } if (mListener != null) { mListener.onClose(); mListener = null; } } }); } } private Runnable mHideRunnable = new Runnable() { @Override public void run() { hidePrompt(false); } }; public static void show(CharSequence text, CharSequence buttonText, int duration, OnPromptEventListener listener) { show(text, buttonText, duration, false, listener); } public static void show(CharSequence text, CharSequence buttonText, int duration, boolean forceSingleLine, OnPromptEventListener listener) { Util.Assert(sPrompt != null, "null instance"); if (sPrompt != null) { sPrompt.hidePrompt(true); CrashTracking.log("Prompt.show() text:" + text); sPrompt.showPrompt(text, buttonText, duration, forceSingleLine, listener); } } }