How to have activity touch passthrough except with snackbar

So in my tasker plugin the user can have tasker make my plugin run. When my plugin runs it creates a transparent activity that shows a snackbar then terminates when done. The only problem is that when the activity shows, the user can not interact with the screen they are currently looking at. I know the app link bubble allows pass through while showing a snackbar so it is possible. All help is much appreciated thanks.

Here is the SnackbarActivity.java:

public class SnackbarActivity extends AppCompatActivity {

    public String message = "Not Set";
    public String button = "Not Set";
    public String length = "Short";
    public String color = "#5F9691";
    public String command = "Button";
    public Intent messageIntent;
    public String result = "";

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.invisible_activity);
        messageIntent = getIntent();
        message = messageIntent.getStringExtra("message");
        button = messageIntent.getStringExtra("button");
        length = messageIntent.getStringExtra("length");
        command = messageIntent.getStringExtra("command");
        switch (length) {
            case "Short":
                Snackbar.make(findViewById(R.id.toolbar), message, Snackbar.LENGTH_SHORT)
                        .setAction(button, new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                result = command;
                            }
                        }).setCallback(new Snackbar.Callback() {
                    @Override
                    public void onDismissed(Snackbar snackbar, int event) {
                        super.onDismissed(snackbar, event);
                        finish();
                        switch (event) {
                            case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                                result = "Timeout";
                                break;
                            case Snackbar.Callback.DISMISS_EVENT_SWIPE:
                                result = "Swipe";
                                break;
                        }
                    }
                }).show();
                break;
            case "Long":
                Snackbar.make(findViewById(R.id.toolbar), message, Snackbar.LENGTH_LONG)
                        .setAction(button, new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                result = command;
                            }
                        }).setCallback(new Snackbar.Callback() {
                    @Override
                    public void onDismissed(Snackbar snackbar, int event) {
                        super.onDismissed(snackbar, event);
                        finish();
                        switch (event) {
                            case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                                result = "Timeout";
                                break;
                            case Snackbar.Callback.DISMISS_EVENT_SWIPE:
                                result = "Swipe";
                                break;
                        }
                    }
                }).show();
                break;
            case "Forever":
                Snackbar.make(findViewById(R.id.toolbar), message, Snackbar.LENGTH_INDEFINITE)
                        .setAction(button, new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                result = command;
                            }
                        }).setCallback(new Snackbar.Callback() {
                    @Override
                    public void onDismissed(Snackbar snackbar, int event) {
                        super.onDismissed(snackbar, event);
                        finish();
                        switch (event) {
                            case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                                result = "Timeout";
                                break;
                            case Snackbar.Callback.DISMISS_EVENT_SWIPE:
                                result = "Swipe";
                                break;
                        }
                    }
                }).show();
                break;
        }
    }

    @Override
    protected void onStop() {
        if ( TaskerPlugin.Setting.hostSupportsVariableReturn(messageIntent.getExtras())) {
            Bundle vars = new Bundle();
            vars.putString("%sb_command", result);
            TaskerPlugin.Setting.signalFinish(getApplicationContext(), messageIntent, TaskerPlugin.Setting.RESULT_CODE_OK, vars);
        }
        super.onStop();
    }
}

Here is styles.xml:

<style name="Theme.AppCompat.Translucent">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="colorPrimaryDark">@android:color/transparent</item>
        <item name="android:windowAnimationStyle">@android:style/Animation</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

Answer

You could use WindowManager to show the snackbar even when your app is not running and also making the background screen clickable.

private static final int mLayoutParamFlags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        //| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

public void onCreate() {
    super.onCreate();

    LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    mSnackbarView = layoutInflater.inflate(R.layout.activity_snackbar, null);

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_PARENT,
            WindowManager.LayoutParams.WRAP_PARENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            mLayoutParamFlags,
            PixelFormat.TRANSLUCENT);

    WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    windowManager.addView(mSnackbarView, params);
}

In the above code mSnackbar is a View and activity_snackbar is the view you wan tot show in WindowManager.

You can show the WindowManager using Service. Create a class and extend it with Service. Given above is the code for Service’s onCreate() method.

EDIT

Here is how you customize the snackbar

Initialize mSnackbarView as Snackbar and not just View

private Snackbar mSnackbarView;

Cast mSnackbarView with Snackbar class

mSnackbarView = (Snackbar) layoutInflater.inflate(R.layout.activity_snackbar, null);

Now mSnackbarView is a normal Snackbar View, you can customize it the way you customize an actual Snackbar View.

// Changing action button text color
View sbView = mSnackbarView.getView();
TextView textView = (TextView)     sbView.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(Color.YELLOW);

EDIT 2

To make both the Snackbar and background screen clickable I commented third layout params for WindowManager WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE.

And add onClickListener on mSnackbarView.

mSnackbarView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            System.out.println("Snackbar clicked");
        }
    });

Now both the snackbar as well as background screen is clickable.

EDIT 3

This is how you start a Service

Intent snackbarIntent = new Intent(context, snackbarService.class);
context.startService(snackbarIntent);

This is how you stop a service

Intent snackbarIntent = new Intent(context, snackbarService.class);
context.stopService(snackbarIntent);

Leave a Reply

Your email address will not be published. Required fields are marked *