Toast does not need to declare any permissions in the manifest file

Keywords: Android github

Preface

Because of the need of the project, Toast can still pop up after users forbid notifying permission. After testing three methods on the internet, we found that they did not meet the needs of the company and did not use them. Among them, model adaptation (named millet MIUI8) accounts for a large part of the reasons. And the requirement is that no permission can be added!!!

Look at the picture below.
(Source code at the end of the article)

  • The method is very simple, no secondary encapsulation is done.
public void showToast(View view){
        if(CustomToast.isNotificationEnabled(this)){
            //Notification is available using native Toast
            Toast.makeText(getApplicationContext(), "system Toast", Toast.LENGTH_SHORT).show();
        }else{
            CustomToast.makeText(getApplicationContext(),"custom Toast", CustomToast.LENGTH_SHORT).show();
        }
    }

First, determine whether the user has forbidden notifications (sometimes the user just wants to block push notifications), if not forbid the direct use of the system's native Toast, otherwise use our custom
The code that judges whether there are permissions is not pasted, which has little to do with this article. It should be noted that the permissions can be judged only when API19 or above, so a judgement can be added.

public static boolean isNotificationEnabled(Context context) {
        //Direct use of custom Toast below API 19
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
            //Here I use Custom Toast directly below 19
            return false;
        }
        AppOpsManager mAppOps = null;
        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        //N lines of code are omitted here
        ************;
}
 public static CustomToast makeText(Context context, CharSequence text, int duration) {
        Toast toast = Toast.makeText(context, text, duration);
        CustomToast exToast = new CustomToast(context);
        exToast.toast = toast;
        exToast.setDuration(duration);
        exToast.setText(text);
        //Add to the collection and maintain the queue yourself
        equeue.add(exToast);
        return exToast;
    }

makeText returns an instance object and adds it to the equeue collection. In order to imitate the system playing Toast, one display is finished and the second pops up. Let's look at the show method.

 public void show() {
        //The view being displayed or to be displayed is null
        if (isShow || mView == null) {
            return;
        }
        isShow = true;
        toast.setView(mView);
        //Here we get the TN object of toast by reflection.
        initTN();
        try {
            //Display toast
            show.invoke(mTN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //Toast to Time Hiding
        handler.postDelayed(hideRunnable, mDuration == LENGTH_SHORT ? LENGTH_SHORT : LENGTH_LONG);
    }

hideRunnable just tunes a hide method

private void hide() {
        if (!isShow) return;
        try {
            hide.invoke(mTN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        isShow = false;
        equeue.remove(0);
        //If there are messages in the queue, continue to show
        if (equeue.size() > 0) {
            equeue.get(0).show();
        }
    }

This method comes from Breakthrough Millet Suspension Window Authority Control - Suspension Window without Authority

private void initTN() {
        try {
            Field tnField = toast.getClass().getDeclaredField("mTN");
            tnField.setAccessible(true);
            mTN = tnField.get(toast);
            show = mTN.getClass().getMethod("show");
            hide = mTN.getClass().getMethod("hide");

            Field tnParamsField = mTN.getClass().getDeclaredField("mParams");
            tnParamsField.setAccessible(true);

            WindowManager.LayoutParams params = (WindowManager.LayoutParams) tnParamsField.get(mTN);
            params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

            /**Make sure to set mNextView before calling tn.show()*/
            Field tnNextViewField = mTN.getClass().getDeclaredField("mNextView");
            tnNextViewField.setAccessible(true);
            tnNextViewField.set(mTN, toast.getView());
        } catch (Exception e) {
            e.printStackTrace();
        }
        //Set the toast location here
        toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 200);
    }

Here's a brief introduction. Welcome to the exchange.
Reference article: http://www.codexiu.cn/android/blog/25708/

Source address: https://github.com/jackyZuo/CustomToastDemo

Posted by rushenas on Wed, 03 Apr 2019 16:18:29 -0700