com.vinexs.eeb.BaseActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.vinexs.eeb.BaseActivity.java

Source

/*
 * Copyright (c) 2015. Vin @ vinexs.com (MIT License)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.vinexs.eeb;

import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentManager.BackStackEntry;
import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDialog;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.ViewConfiguration;
import android.widget.Toast;

import com.vinexs.BuildConfig;
import com.vinexs.R;
import com.vinexs.eeb.misc.BaseExceptionHandler;
import com.vinexs.tool.Utility;

import java.lang.reflect.Field;
import java.util.Calendar;
import java.util.Locale;

@SuppressWarnings("unused")
public abstract class BaseActivity extends AppCompatActivity {

    protected String TAG = getClass().getSimpleName();
    protected static long appInitTime = Calendar.getInstance().getTimeInMillis();
    protected static BaseExceptionHandler exceptionHandler = null;

    protected boolean closeByDialog = true;
    protected boolean allowBack = true;
    protected boolean pressBackToClose = false;

    // Navigation Drawer
    protected DrawerLayout drawerLayout = null;
    protected ActionBarDrawerToggle drawerToggle = null;
    protected Boolean hasLeftDrawer = false;
    protected Boolean hasRightDrawer = false;

    // Theme Res
    protected int currentTheme = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setOverflowMenuAvailable();
        setCustomSetting();
        setContentFrame();
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawerLayout != null) {
            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START);
            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END);
        }
        setDefaultBackStackListener();
    }

    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        if (hasLeftDrawer || hasRightDrawer) {
            drawerToggle.syncState();
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        BackStackSyncStatus();
        if (!BuildConfig.DEBUG && exceptionHandler != null) {
            Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (currentTheme != PreferenceManager.getDefaultSharedPreferences(this).getInt("theme",
                getBaseContext().getApplicationInfo().theme)) {
            restart();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        invalidateOptionsMenu();
        if (hasLeftDrawer || hasRightDrawer) {
            drawerToggle.onConfigurationChanged(newConfig);
        }
    }

    @Override
    public abstract void onNewIntent(Intent intent);

    public void restart() {
        final Bundle outState = new Bundle();
        onSaveInstanceState(outState);
        final Intent intent = new Intent(this, getClass());
        finish();
        overridePendingTransition(0, 0);
        startActivity(intent);
    }

    // ================  Default layout frame  =========================

    public void setContentFrame() {
        setContentView(getContentFrame());
    }

    public abstract int getContentFrame();

    protected void setToolbar(int resId) {
        Toolbar toolbar = (Toolbar) findViewById(resId);
        if (toolbar != null) {
            setToolbar(toolbar);
        }
    }

    protected void setToolbar(Toolbar toolbar) {
        if (toolbar == null) {
            return;
        }
        setSupportActionBar(toolbar);
        if ((hasLeftDrawer || hasRightDrawer) && getSupportActionBar() != null) {
            getSupportActionBar().setHomeButtonEnabled(true);
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
        if (drawerToggle != null) {
            drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, 0, 0);
            drawerToggle.syncState();
            drawerLayout.addDrawerListener(drawerToggle);
        }
    }

    // ================  Handle back and fragment  =========================

    /**
     * To add system default back stack, put this method to onCreate().
     */
    public void setDefaultBackStackListener() {
        getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {
            @Override
            public void onBackStackChanged() {
                BackStackSyncStatus();
            }
        });
    }

    @Override
    public void onBackPressed() {
        Utility.hideKeyBroad(this);
        try {
            if (allowBack) {
                FragmentManager fragmentMgr = getSupportFragmentManager();
                if (fragmentMgr.getBackStackEntryCount() > 0) {
                    fragmentMgr.popBackStack();
                } else if (drawerLayout != null && (drawerLayout.isDrawerOpen(GravityCompat.START)
                        || drawerLayout.isDrawerOpen(GravityCompat.END))) {
                    closeLeftDrawer();
                    closeRightDrawer();
                } else {
                    closeAppsConfirmation();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void lockBackPress() {
        allowBack = false;
    }

    public void unlockBackPress() {
        allowBack = true;
    }

    public void closeAppsConfirmation() {
        if (closeByDialog) {
            // Close application by asking in dialog.
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage(
                    getResources().getString(R.string.app_close).replace("app_name", Utility.getAppName(this)));
            builder.setPositiveButton(R.string.confirm, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    setResult(AppCompatActivity.RESULT_CANCELED);
                    finish();
                }
            });
            builder.setNegativeButton(R.string.cancel, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            AppCompatDialog dialog = builder.create();
            dialog.show();
        } else {
            // Close application by double-tap back button.
            if (!pressBackToClose) {
                pressBackToClose = true;
                Toast.makeText(this,
                        getResources().getString(R.string.app_close).replace("app_name", Utility.getAppName(this)),
                        Toast.LENGTH_SHORT).show();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        pressBackToClose = false;
                    }
                }, 2000);
                return;
            }
            setResult(AppCompatActivity.RESULT_CANCELED);
            finish();
        }
    }

    /**
     * Require setDefaultBackStackListener() ran in onCreate
     */
    protected void BackStackSyncStatus() {
        try {
            FragmentManager fragMgr = getSupportFragmentManager();
            int count = fragMgr.getBackStackEntryCount();
            if (count - 1 >= 0) {
                Log.d("TEST", "BackStackSyncStatus::(count - 1 >= 0) == true");
                BackStackEntry entry = fragMgr.getBackStackEntryAt(count - 1);
                String title = (String) entry.getBreadCrumbTitle();
                if (getSupportActionBar() != null) {
                    setBackStackTitle(title);
                    getSupportActionBar().setHomeButtonEnabled(true);
                    if (!hasLeftDrawer && !hasRightDrawer) {
                        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                    }
                }
                if (drawerLayout != null) {
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START);
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END);
                }
                if (drawerToggle != null) {
                    drawerToggle.setDrawerIndicatorEnabled(false);
                }
                onBaseBackStackChanged(false, count);
            } else {
                if (getSupportActionBar() != null) {
                    setBackStackTitle(Utility.getAppName(this));
                    getSupportActionBar().setHomeButtonEnabled(false);
                    if (!hasLeftDrawer && !hasRightDrawer) {
                        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                    }
                }
                if (hasLeftDrawer) {
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START);
                    if (drawerToggle != null) {
                        drawerToggle.setDrawerIndicatorEnabled(true);
                    }
                }
                if (hasRightDrawer) {
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END);
                }
                onBaseBackStackChanged(true, count);
            }
            if (drawerToggle != null) {
                drawerToggle.syncState();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setBackStackTitle(String title) {
        ActionBar actionbar = getSupportActionBar();
        if (actionbar == null) {
            return;
        }
        actionbar.setTitle(title);
    }

    public abstract void onBaseBackStackChanged(boolean noTurnBack, int entryCount);

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            switch (item.getItemId()) {
            case android.R.id.home: // Home as up
                onBackPressed();
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
        return drawerToggle.onOptionsItemSelected(item);
    }

    // ================  Fragments Control =========================

    public void addLeftDrawer(Fragment frag) {
        addLeftDrawer(frag, "LEFT_DRAWER");
    }

    public void addLeftDrawer(Fragment frag, String tag) {
        if (hasLeftDrawer) {
            return;
        }
        hasLeftDrawer = true;
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.add(R.id.frame_drawer_left, frag, tag).commitAllowingStateLoss();
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START);
        setDrawerToggleEnable();
    }

    public void addRightDrawer(Fragment frag) {
        if (hasRightDrawer) {
            return;
        }
        hasRightDrawer = true;
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.add(R.id.frame_drawer_right, frag, "RIGHT_DRAWER").commitAllowingStateLoss();
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END);
        setDrawerToggleEnable();
    }

    public void closeLeftDrawer() {
        drawerLayout.closeDrawer(GravityCompat.START);
    }

    public void closeRightDrawer() {
        drawerLayout.closeDrawer(GravityCompat.END);
    }

    private void setDrawerToggleEnable() {
        if (drawerToggle != null) {
            return;
        }
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, 0, 0);
        drawerToggle.syncState();
        drawerLayout.addDrawerListener(drawerToggle);
        drawerToggle.setDrawerIndicatorEnabled(true);
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
    }

    /**
     * <p>The user should be pointed(through an intent) to the system settings to change it manually.
     * The application should handle its localization on its own just like described.</p>
     * <p>It should run in onCreate() method and before setContentView().</p>
     * <p><font color="red">Don't forget to add android:configChanges="layoutDirection|locale" to
     * every activity at AndroidManifest.</font></p>
     */
    public void setCustomSetting() {
        SharedPreferences sharePref = PreferenceManager.getDefaultSharedPreferences(this);

        // Override application original locale.
        String defaultLocale = Locale.getDefault().toString();
        String appLocale = sharePref.getString("locale", defaultLocale);
        if (!appLocale.isEmpty() && !defaultLocale.equals(appLocale)) {
            Locale locale;
            if (appLocale.contains("_")) {
                String[] localePart = appLocale.split("_");
                locale = new Locale(localePart[0], localePart[1]);
            } else {
                locale = new Locale(appLocale);
            }
            Locale.setDefault(locale);
            Configuration config = getBaseContext().getResources().getConfiguration();
            config.locale = locale;
            getBaseContext().getResources().updateConfiguration(config,
                    getBaseContext().getResources().getDisplayMetrics());
        }

        // Override application original Theme.
        Integer appTheme = sharePref.getInt("theme", getBaseContext().getApplicationInfo().theme);
        currentTheme = appTheme;
        setTheme(appTheme);
    }

    // ================  Fragments Control =========================

    public Fragment getExistFragment(String fragName) {
        return getSupportFragmentManager().findFragmentByTag(fragName);
    }

    public Fragment getTopFragment() {
        FragmentManager fragMgr = getSupportFragmentManager();
        FragmentManager.BackStackEntry backEntry = fragMgr
                .getBackStackEntryAt(fragMgr.getBackStackEntryCount() - 1);
        String backEntryName = backEntry.getName();
        return fragMgr.findFragmentByTag(backEntryName);
    }

    public void addFragment(Fragment fragment) {
        addFragment(R.id.frame_content, fragment);
    }

    public void addFragment(int viewId, Fragment fragment) {
        if (fragment.isAdded()) {
            return;
        }
        FragmentManager fragMgr = getSupportFragmentManager();
        FragmentTransaction transaction = fragMgr.beginTransaction();
        BackStackEntry lastEntry = fragMgr.getBackStackEntryCount() == 0 ? null
                : fragMgr.getBackStackEntryAt(fragMgr.getBackStackEntryCount() - 1);
        // Transaction options
        String fragName = fragment.getClass().getSimpleName();
        String breadCrumbTitle;
        String breadCrumbShortTitle;
        Boolean addToBackStack = false;
        int animationEnter = 0;
        int animationExit = 0;
        // Fill options
        Bundle args = fragment.getArguments();
        if (args != null) {
            if (args.containsKey("animationEnter") && args.containsKey("animationExit")) {
                animationEnter = args.getInt("animationEnter");
                animationExit = args.getInt("animationExit");
            }
            if (args.containsKey("breadCrumbTitle")) {
                breadCrumbTitle = args.getString("breadCrumbTitle");
            } else {
                breadCrumbTitle = (lastEntry != null) ? lastEntry.getBreadCrumbTitle().toString()
                        : Utility.getAppName(this);
            }
            if (args.containsKey("breadCrumbShortTitle")) {
                breadCrumbShortTitle = args.getString("breadCrumbShortTitle");
            } else {
                breadCrumbShortTitle = (lastEntry != null) ? lastEntry.getBreadCrumbShortTitle().toString()
                        : Utility.getAppName(this);
            }
            if (args.containsKey("fragmentName")) {
                fragName = args.getString("fragmentName");
            }
            if (args.containsKey("addToBackStack")) {
                addToBackStack = args.getBoolean("addToBackStack");
            }
        } else {
            breadCrumbTitle = (lastEntry != null) ? lastEntry.getBreadCrumbTitle().toString()
                    : Utility.getAppName(this);
            breadCrumbShortTitle = (lastEntry != null) ? lastEntry.getBreadCrumbShortTitle().toString()
                    : Utility.getAppName(this);
        }
        // Set option to fragment manager
        if (animationEnter != 0 && animationExit != 0) {
            transaction.setCustomAnimations(animationEnter, animationExit);
        }
        if (breadCrumbTitle != null && !breadCrumbTitle.isEmpty()) {
            transaction.setBreadCrumbTitle(breadCrumbTitle);
        }
        if (breadCrumbShortTitle != null && !breadCrumbShortTitle.isEmpty()) {
            transaction.setBreadCrumbShortTitle(breadCrumbShortTitle);
        }
        if (transaction.isAddToBackStackAllowed() && addToBackStack) {
            transaction.addToBackStack(fragName);
        }
        // Add fragment
        transaction.add(viewId, fragment, fragName).commitAllowingStateLoss();
    }

    public void replaceFragment(Fragment fragment) {
        replaceFragment(R.id.frame_content, fragment);
    }

    public void replaceFragment(int viewId, Fragment fragment) {
        if (fragment.isAdded()) {
            return;
        }
        FragmentManager fragMgr = getSupportFragmentManager();
        FragmentTransaction transaction = fragMgr.beginTransaction();
        BackStackEntry lastEntry = fragMgr.getBackStackEntryCount() == 0 ? null
                : fragMgr.getBackStackEntryAt(fragMgr.getBackStackEntryCount() - 1);
        // Transaction options
        String fragName = fragment.getClass().getSimpleName();
        String breadCrumbTitle;
        String breadCrumbShortTitle;
        Boolean addToBackStack = true;
        int animationEnter = 0;
        int animationExit = 0;
        // Fill options
        Bundle args = fragment.getArguments();
        if (args != null) {
            if (args.containsKey("animationEnter") && args.containsKey("animationExit")) {
                animationEnter = args.getInt("animationEnter");
                animationExit = args.getInt("animationExit");
            }
            if (args.containsKey("breadCrumbTitle")) {
                breadCrumbTitle = args.getString("breadCrumbTitle");
            } else {
                breadCrumbTitle = (lastEntry != null) ? lastEntry.getBreadCrumbTitle().toString()
                        : Utility.getAppName(this);
            }
            if (args.containsKey("breadCrumbShortTitle")) {
                breadCrumbShortTitle = args.getString("breadCrumbShortTitle");
            } else {
                breadCrumbShortTitle = (lastEntry != null) ? lastEntry.getBreadCrumbShortTitle().toString()
                        : Utility.getAppName(this);
            }
            if (args.containsKey("fragmentName")) {
                fragName = args.getString("fragmentName");
            }
            if (args.containsKey("addToBackStack")) {
                addToBackStack = args.getBoolean("addToBackStack");
            }
        } else {
            breadCrumbTitle = (lastEntry != null) ? lastEntry.getBreadCrumbTitle().toString()
                    : Utility.getAppName(this);
            breadCrumbShortTitle = (lastEntry != null) ? lastEntry.getBreadCrumbShortTitle().toString()
                    : Utility.getAppName(this);
        }
        // Set option to fragment manager
        if (animationEnter != 0 && animationExit != 0) {
            transaction.setCustomAnimations(animationEnter, animationExit);
        }
        if (breadCrumbTitle != null && !breadCrumbTitle.isEmpty()) {
            transaction.setBreadCrumbTitle(breadCrumbTitle);
        }
        if (breadCrumbShortTitle != null && !breadCrumbShortTitle.isEmpty()) {
            transaction.setBreadCrumbShortTitle(breadCrumbShortTitle);
        }
        if (transaction.isAddToBackStackAllowed() && addToBackStack) {
            transaction.addToBackStack(fragName);
        }
        // Replace fragment
        transaction.replace(viewId, fragment, fragName).commitAllowingStateLoss();
    }

    public void showFragment(Fragment fragment) {
        if (!fragment.isHidden()) {
            return;
        }
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.show(fragment).commitAllowingStateLoss();
    }

    public void hideFragment(Fragment fragment) {
        if (!fragment.isAdded()) {
            return;
        }
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.hide(fragment).commitAllowingStateLoss();
    }

    public void removeFragment(Fragment fragment) {
        if (!fragment.isAdded()) {
            return;
        }
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.remove(fragment).commitAllowingStateLoss();
        Bundle args = fragment.getArguments();
        if (args != null && args.containsKey("breadCrumbTitle")) {
            manager.popBackStack();
        }
    }

    // ================  Hack =========================

    /**
     * <p>This hack used to add overflow menu button if device has physical menu button.
     * Phones with a physical menu button don't have an overflow menu in the ActionBar. </p>
     * <p>This avoids ambiguity for the user, essentially having two buttons available to open the exact same menu.</p>
     * <p>It should run in onCreate() method and before setContentView().</p>
     */
    public void setOverflowMenuAvailable() {
        try {
            ViewConfiguration config = ViewConfiguration.get(this);
            Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
            if (menuKeyField != null) {
                menuKeyField.setAccessible(true);
                menuKeyField.setBoolean(config, false);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}