//https://github.com/digicrafts/Heyzap-ANE/blob/master/android/src/com/heyzap/sdk/ClickableToast.java //https://github.com/tumbling-dice/snippets/blob/master/Java/Android/ClickableToast/src/android/widget/ClickableToast.java package nya.miku.wishmaster.lib; import java.lang.reflect.Field; import java.lang.reflect.Method; import nya.miku.wishmaster.common.Logger; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; public class ClickableToast extends FrameLayout { private static final String TAG = "ClickableToast"; private static Resources internalResources = null; private OnClickListener onClickListener = null; protected WindowManager windowManager; private static DismissToastBroadcastReceiver dismissReceiver = new DismissToastBroadcastReceiver(); private Integer windowAnimation; private View container; private boolean gravityTop; public ClickableToast(Context context) { super(context); init(); } public void setOnClickListener(OnClickListener onClickListener) { this.onClickListener = onClickListener; } public void init(){ dismissReceiver.setToast(this); this.setBackgroundColor(Color.TRANSPARENT); this.windowManager = (WindowManager) this.getContext().getSystemService(Application.WINDOW_SERVICE); } @Override public void onAttachedToWindow(){ WindowManager.LayoutParams params = getWmParams(); try{ this.windowManager.updateViewLayout(this, params); }catch(RuntimeException e){} } @Override public void onDraw(Canvas canvas){ canvas.rotate(180); super.onDraw(canvas); canvas.rotate(180); } public void show(){ WindowManager.LayoutParams params = getWmParams(); this.windowManager.addView(this, params); getContext().registerReceiver(dismissReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); } public void show(final int duration){ this.show(); this.postDelayed(new Runnable(){ public void run(){ hide(); } }, duration); } public void setGravityTop(boolean value) { this.gravityTop = value; } public WindowManager.LayoutParams getWmParams(){ WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.alpha = 1; params.format = PixelFormat.RGBA_8888; if (gravityTop) { params.gravity = Gravity.TOP; } else { params.gravity = Gravity.BOTTOM; params.verticalMargin = isNarrow() ? 0.05f : 0.07f; } params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //params.type = WindowManager.LayoutParams.LAST_SYSTEM_WINDOW + 30; try { if (internalResources == null) internalResources = Resources.getSystem(); params.windowAnimations = internalResources.getIdentifier("Animation.Toast", "style", "android"); params.y = getResources().getDimensionPixelSize(internalResources.getIdentifier("toast_y_offset", "dimen", "android")); } catch (Exception e) { Logger.e(TAG, e); } return params; } public boolean isNarrow(){ DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); return displayMetrics.heightPixels > displayMetrics.widthPixels; } @SuppressWarnings("deprecation") public boolean isVertical(){ int rotation = this.windowManager.getDefaultDisplay().getOrientation(); return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180; } public int getSlideDownAnimation(Context ctx){ if(windowAnimation != null){ return windowAnimation; } PopupWindow w = new PopupWindow(ctx); try { Field mIsDropDown = PopupWindow.class.getDeclaredField("mIsDropdown"); mIsDropDown.setAccessible(true); mIsDropDown.setBoolean(w, true); Field mAnimationStyle = PopupWindow.class.getDeclaredField("mAnimationStyle"); mAnimationStyle.setAccessible(true); mAnimationStyle.setInt(w, -1); Field mAboveAnchor = PopupWindow.class.getDeclaredField("mAboveAnchor"); mAboveAnchor.setAccessible(true); mAboveAnchor.setBoolean(w, false); Method computeAnimationResource = PopupWindow.class.getDeclaredMethod("computeAnimationResource"); computeAnimationResource.setAccessible(true); windowAnimation = (Integer) computeAnimationResource.invoke(w); } catch (Exception e){} if(windowAnimation == null){ windowAnimation = android.R.style.Animation_Toast; } return windowAnimation; } public static ClickableToast show(Context ctx, View v, int duration){ ClickableToast toast = new ClickableToast(ctx); toast.addView(v); toast.show(duration); return toast; } public static ClickableToast showText(Context ctx, CharSequence text, OnClickListener listener) { return showText(ctx, text, listener, false); } public static ClickableToast showText(Context ctx, CharSequence text, OnClickListener listener, boolean gravityTop) { try { if (internalResources == null) internalResources = Resources.getSystem(); LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflater.inflate(internalResources.getIdentifier("transient_notification", "layout", "android"), null); TextView tv = (TextView) v.findViewById(internalResources.getIdentifier("message", "id", "android")); tv.setText(text); final ClickableToast toast = new ClickableToast(ctx); if (gravityTop) toast.setGravityTop(true); toast.setOnClickListener(listener); v.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { if (toast.onClickListener != null) toast.onClickListener.onClick(); } catch (Exception e) { Logger.e(TAG, e); } try { toast.hide(); } catch (Exception e) { Logger.e(TAG, e); } } }); toast.addView(v); toast.show(3500); return toast; } catch (Exception e) { Logger.e(TAG, e); Toast fallbackToast = Toast.makeText(ctx, text, Toast.LENGTH_LONG); if (gravityTop) fallbackToast.setGravity(Gravity.TOP, 0, 0); fallbackToast.show(); return null; } } public static interface OnClickListener { void onClick(); } public void hide() { this.onClickListener = null; try{ this.windowManager.removeView(this); }catch(RuntimeException e){} // this happens when the view has already been removed try{ getContext().unregisterReceiver(dismissReceiver); }catch(RuntimeException e){} //I know of no scenario where this would happen } public static class DismissToastBroadcastReceiver extends BroadcastReceiver{ private ClickableToast toast; public void setToast(ClickableToast toast){ this.toast = toast; } @Override public void onReceive(Context context, Intent intent) { if(toast != null){ toast.hide(); } } }; public void setContentView(int layoutId) { this.removeAllViews(); LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Application.LAYOUT_INFLATER_SERVICE); container = inflater.inflate(layoutId, null); this.addView(container); } }