eu.power_switch.gui.StatusMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for eu.power_switch.gui.StatusMessageHandler.java

Source

/*
 *     PowerSwitch by Max Rosin & Markus Ressel
 *     Copyright (C) 2015  Markus Ressel
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package eu.power_switch.gui;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;

import java.util.Date;

import eu.power_switch.R;
import eu.power_switch.gui.activity.MainActivity;
import eu.power_switch.gui.dialog.UnknownErrorDialog;
import eu.power_switch.gui.fragment.RecyclerViewFragment;
import eu.power_switch.gui.fragment.settings.SettingsTabFragment;
import eu.power_switch.shared.constants.PermissionConstants;
import eu.power_switch.shared.constants.SettingsConstants;
import eu.power_switch.shared.log.Log;

/**
 * This is a helper Class to create and show status messages depending on the app state
 * <p/>
 * Created by Markus on 17.11.2015.
 */
public class StatusMessageHandler {

    private static Toast lastToast;
    private static Snackbar lastSnackbar;

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a Snackbar if
     * it is running in the foreground
     * You can pass an actionMessage and a Runnable that will be represented as a button on the Snackbar. The Toast
     * however will not have a button, be mindful about that.
     *
     * @param view                          parent view this snackbar is shown on (used for
     *                                      the Snackbar and as a context)
     * @param messageResourceId             status message resource id
     * @param actionButtonMessageResourceId message resource id of action button
     * @param runnable                      code that should be executed when activating the action button
     * @param duration                      duration
     */
    public static void showInfoMessage(View view, @StringRes int messageResourceId,
            @StringRes int actionButtonMessageResourceId, Runnable runnable, int duration) {
        Context context = view.getContext();

        if (MainActivity.isInForeground()) {
            if (view instanceof RecyclerView) {
                RecyclerView recyclerView = (RecyclerView) view;
                showSnackbar(recyclerView, context.getString(messageResourceId),
                        context.getString(actionButtonMessageResourceId), runnable, duration);
            } else {
                showSnackbar(view, context.getString(messageResourceId),
                        context.getString(actionButtonMessageResourceId), runnable, duration);
            }
        } else {
            showInfoToast(context, context.getString(messageResourceId), duration);
        }
    }

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a Snackbar if
     * it is running in the foreground
     * You can pass an actionMessage and a Runnable that will be represented as a button on the Snackbar. The Toast
     * however will not have a button, be mindful about that.
     *
     * @param context                       any suitable context
     * @param messageResourceId             status message resource id
     * @param actionButtonMessageResourceId message resource id of action button
     * @param runnable                      code that should be executed when activating the action button
     * @param duration                      duration
     */
    public static void showInfoMessage(Context context, @StringRes int messageResourceId,
            @StringRes int actionButtonMessageResourceId, Runnable runnable, int duration) {
        if (MainActivity.isInForeground()) {
            showSnackbar(MainActivity.getMainAppView(), context.getString(messageResourceId),
                    context.getString(actionButtonMessageResourceId), runnable, duration);
        } else {
            showInfoToast(context, context.getString(messageResourceId), duration);
        }
    }

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Dismiss" Button by default.
     *
     * @param view              view this snackbar is shown on (used for
     *                          the Snackbar and as a context)
     * @param messageResourceId status message resource id
     * @param duration          duration
     */
    public static void showInfoMessage(View view, @StringRes int messageResourceId, int duration) {
        Context context = view.getContext();
        showInfoMessage(view, context.getString(messageResourceId), duration);
    }

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Dismiss" Button by default.
     *
     * @param context           any suitable context
     * @param messageResourceId status message resource id
     * @param duration          duration
     */
    public static void showInfoMessage(Context context, @StringRes int messageResourceId, int duration) {
        showInfoMessage(context, context.getString(messageResourceId), duration);
    }

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Dismiss" Button by default.
     *
     * @param view     view this snackbar is shown on (used for
     *                 the Snackbar and as a context)
     * @param message  status message
     * @param duration duration
     */
    public static void showInfoMessage(View view, String message, int duration) {
        Context context = view.getContext();

        if (MainActivity.isInForeground()) {
            if (view instanceof RecyclerView) {
                RecyclerView recyclerView = (RecyclerView) view;
                showInfoSnackbar(recyclerView, message, duration);
            } else {
                showInfoSnackbar(view, message, duration);
            }
        } else {
            showInfoToast(context, message, duration);
        }
    }

    /**
     * Shows a status message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Dismiss" Button by default.
     *
     * @param context  any suitable context
     * @param message  status message
     * @param duration duration
     */
    public static void showInfoMessage(Context context, String message, int duration) {
        if (MainActivity.isInForeground()) {
            showInfoSnackbar(MainActivity.getMainAppView(), message, duration);
        } else {
            showInfoToast(context, message, duration);
        }
    }

    /**
     * Shows an error message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Details" Button by default, which opens up a dialog showing more infos about the exception.
     * The exception will also be logged, so you dont have to do this in your catch{} blocks yourself.
     *
     * @param view view this snackbar is shown on (used for
     *             the Snackbar and as a context)
     * @param e    throwable
     */
    public static void showErrorMessage(final View view, final Throwable e) {
        Context context = view.getContext();

        if (MainActivity.isInForeground()) {
            if (view instanceof RecyclerView) {
                RecyclerView recyclerView = (RecyclerView) view;
                showErrorSnackbar(MainActivity.getActivity(), recyclerView, e);
            } else {
                showErrorSnackbar(MainActivity.getActivity(), view, e);
            }
        } else {
            showErrorToast(context, e);
        }
    }

    /**
     * Shows an error message on screen, either as Toast if the app is running in the background or as a snackbar if
     * it is running in the foreground.
     * The Snackbar will have a "Details" Button by default, which opens up a dialog showing more infos about the exception.
     * The exception will also be logged, so you dont have to do this in your catch{} blocks yourself.
     *
     * @param context any suitable context
     * @param e       throwable
     */
    public static void showErrorMessage(Context context, Throwable e) {
        if (MainActivity.isInForeground()) {
            showErrorSnackbar(MainActivity.getActivity(), MainActivity.getMainAppView(), e);
        } else {
            showErrorToast(context, e);
        }
    }

    /**
     * Show Error Dialog
     *
     * @param context            any suitable context
     * @param t                  Throwable
     * @param timeInMilliseconds time when the exception was thrown
     */
    public static void showErrorDialog(Context context, Throwable t, long timeInMilliseconds) {
        context.startActivity(UnknownErrorDialog.getNewInstanceIntent(t, timeInMilliseconds));
    }

    /**
     * Show Error Dialog
     *
     * @param context any suitable context
     * @param t       Throwable
     */
    public static void showErrorDialog(Context context, Throwable t) {
        showErrorDialog(context, t, new Date().getTime());
    }

    /**
     * Shows "No active Gateway" Message
     *
     * @param recyclerViewFragment
     */
    public static void showNoActiveGatewayMessage(final RecyclerViewFragment recyclerViewFragment) {
        showInfoMessage(recyclerViewFragment.getRecyclerView(), R.string.no_active_gateway, R.string.open_settings,
                new Runnable() {
                    @Override
                    public void run() {
                        MainActivity.addToBackstack(MainActivity.IDENTIFIER_SETTINGS, SettingsTabFragment.class,
                                recyclerViewFragment.getActivity().getString(R.string.menu_settings));

                        SettingsTabFragment settingsTabFragment = SettingsTabFragment
                                .newInstance(SettingsConstants.GATEWAYS_TAB_INDEX);
                        recyclerViewFragment.getActivity().getSupportFragmentManager().beginTransaction()
                                .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
                                        android.R.anim.slide_in_left, android.R.anim.slide_out_right)
                                .replace(R.id.mainContentFrameLayout, settingsTabFragment).addToBackStack(null)
                                .commit();
                    }
                }, Snackbar.LENGTH_LONG);
    }

    /**
     * Shows "No active Gateway" Message
     *
     * @param fragmentActivity
     */
    public static void showNoActiveGatewayMessage(final FragmentActivity fragmentActivity) {
        showInfoMessage(fragmentActivity, R.string.no_active_gateway, R.string.open_settings, new Runnable() {
            @Override
            public void run() {
                MainActivity.addToBackstack(MainActivity.IDENTIFIER_SETTINGS, SettingsTabFragment.class,
                        fragmentActivity.getString(R.string.menu_settings));
                SettingsTabFragment settingsTabFragment = SettingsTabFragment
                        .newInstance(SettingsConstants.GATEWAYS_TAB_INDEX);
                fragmentActivity.getSupportFragmentManager().beginTransaction()
                        .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
                                android.R.anim.slide_in_left, android.R.anim.slide_out_right)
                        .replace(R.id.mainContentFrameLayout, settingsTabFragment).addToBackStack(null).commit();
            }
        }, Snackbar.LENGTH_LONG);
    }

    /**
     * Show missing permission message with "Grant" button to trigger permission request dialog
     *
     * @param activity     activity used for permission changed callbacks
     * @param recyclerView recyclerview to show snackbar on
     * @param permissions  permission constant(s)
     */
    public static void showPermissionMissingMessage(final Activity activity, final RecyclerView recyclerView,
            final String... permissions) {

        if (permissions.length == 0) {
            throw new IllegalArgumentException("Missing permission constant(s)");
        }

        int messageResource;
        final int requestCode;

        switch (permissions[0]) {
        case Manifest.permission.WRITE_EXTERNAL_STORAGE:
            messageResource = R.string.missing_external_storage_permission;
            requestCode = PermissionConstants.REQUEST_CODE_STORAGE_PERMISSION;
            break;
        case Manifest.permission.ACCESS_FINE_LOCATION:
            messageResource = R.string.missing_location_permission;
            requestCode = PermissionConstants.REQUEST_CODE_LOCATION_PERMISSION;
            break;
        case Manifest.permission.READ_PHONE_STATE:
            messageResource = R.string.missing_phone_permission;
            requestCode = PermissionConstants.REQUEST_CODE_PHONE_PERMISSION;
            break;
        default:
            messageResource = R.string.missing_permission;
            requestCode = -1;
        }

        if (permissions.length > 1) {
            //            messageResource = R.string.missing_multiple_permissions;
        }

        Snackbar snackbar = Snackbar.make(recyclerView, messageResource, Snackbar.LENGTH_INDEFINITE);
        if (requestCode != -1) {
            snackbar.setAction(R.string.grant, new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ActivityCompat.requestPermissions(activity, permissions, requestCode);
                }
            });
        } else {
            snackbar.setAction(R.string.dismiss, new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // do nothing, just dismiss the snackbar
                }
            });
        }
        snackbar.show();
    }

    /**
     * Show Snackbar with default "Dismiss" action button
     *
     * @param parent   parent view
     * @param message  message
     * @param duration duration
     */
    private static void showInfoSnackbar(View parent, String message, int duration) {
        Log.d("Status Snackbar: " + message);
        final Snackbar snackbar = Snackbar.make(parent, message, duration);

        snackbar.setAction(R.string.dismiss, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do nothing, just dismiss the snackbar
            }
        });

        snackbar.show();
        lastSnackbar = snackbar;
    }

    /**
     * Show Snackbar with default "Details" action button, which opens a dialog
     * containing the full Exception message
     *
     * @param activity activity used to generate dialog transition
     * @param parent   parent view
     * @param e        throwable
     */
    private static void showErrorSnackbar(final FragmentActivity activity, View parent, final Throwable e) {
        Log.e("Error Snackbar", e);

        // remember the time when the exception was raised
        final Date timeRaised = new Date();
        showSnackbar(parent, activity.getString(R.string.unknown_error), activity.getString(R.string.details),
                new Runnable() {
                    @Override
                    public void run() {
                        StatusMessageHandler.showErrorDialog(activity, e, timeRaised.getTime());
                    }
                }, 15000);
    }

    /**
     * Show Snackbar with custom action button
     *
     * @param parent              parent view
     * @param message             message
     * @param actionButtonMessage action button message
     * @param runnable            action code
     * @param duration            duration
     */
    private static void showSnackbar(View parent, String message, String actionButtonMessage,
            final Runnable runnable, int duration) {
        Log.d("Snackbar: [" + message + "] with action: [" + actionButtonMessage + "]");

        if (parent == null) {
            parent = MainActivity.getMainAppView();
        }

        final Snackbar snackbar = Snackbar.make(parent, message, duration);
        snackbar.setAction(actionButtonMessage, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runnable.run();
            }
        });

        snackbar.show();
        lastSnackbar = snackbar;
    }

    /**
     * Show Status Toast above all other views
     *
     * @param context  any suitable context
     * @param message  toast message
     * @param duration duration of toast
     */
    private static void showInfoToast(final Context context, final String message, final int duration) {
        Log.d("Status Toast: " + message);

        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                // cancel last toast
                if (lastToast != null) {
                    lastToast.cancel();
                }

                // create and show new toast
                Toast toast = Toast.makeText(context.getApplicationContext(), message, duration);
                toast.show();

                // save toast reference
                lastToast = toast;
            }
        });
    }

    /**
     * Show Error Toast above all other views
     *
     * @param context any suitable context
     * @param e       throwable
     */
    private static void showErrorToast(final Context context, final Throwable e) {
        Log.e("Error Toast: ", e);

        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                // cancel last toast
                if (lastToast != null) {
                    lastToast.cancel();
                }

                // create and show new toast
                Toast toast = Toast.makeText(context.getApplicationContext(), e.getClass().toString(),
                        Toast.LENGTH_LONG);
                toast.show();

                // save toast reference
                lastToast = toast;
            }
        });
    }
}