org.cobaltians.cobalt.activities.CobaltActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.cobaltians.cobalt.activities.CobaltActivity.java

Source

/**
 *
 * CobaltActivity
 * Cobalt
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Cobaltians
 *
 * 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 org.cobaltians.cobalt.activities;

import org.cobaltians.cobalt.Cobalt;
import org.cobaltians.cobalt.R;
import org.cobaltians.cobalt.customviews.ActionViewMenuItem;
import org.cobaltians.cobalt.customviews.ActionViewMenuItemListener;
import org.cobaltians.cobalt.customviews.BottomBar;
import org.cobaltians.cobalt.font.CobaltFontManager;
import org.cobaltians.cobalt.fragments.CobaltFragment;
import org.cobaltians.cobalt.fragments.CobaltWebLayerFragment;

import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * {@link Activity} containing a {@link CobaltFragment}.
 * @author Diane
 */
public abstract class CobaltActivity extends AppCompatActivity implements ActionViewMenuItemListener {

    protected static final String TAG = CobaltActivity.class.getSimpleName();

    // NAVIGATION
    private boolean mAnimatedTransition;
    private JSONObject mDataNavigation;

    // Pop
    protected static ArrayList<Activity> sActivitiesArrayList = new ArrayList<>();

    // Modal
    private boolean mWasPushedAsModal;
    private static boolean sWasPushedFromModal = false;

    // BARS
    protected HashMap<String, ActionViewMenuItem> mMenuItemsHashMap = new HashMap<>();
    protected HashMap<Integer, String> mMenuItemsIdMap = new HashMap<>();
    protected HashMap<String, MenuItem> mMenuItemByNameMap = new HashMap<>();

    /***********************************************************************************************
     *
     * LIFECYCLE
     *
     **********************************************************************************************/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(getLayoutToInflate());
        sActivitiesArrayList.add(this);

        Bundle bundle = getIntent().getExtras();
        if (bundle == null) {
            bundle = new Bundle();
        }
        Bundle extras = bundle.getBundle(Cobalt.kExtras);
        if (extras == null) {
            extras = Cobalt.getInstance(this.getApplicationContext())
                    .getConfigurationForController(getInitController());
            extras.putString(Cobalt.kPage, getInitPage());
            bundle.putBundle(Cobalt.kExtras, extras);
        }

        if (bundle.containsKey(Cobalt.kJSData)) {
            try {
                mDataNavigation = new JSONObject(bundle.getString(Cobalt.kJSData));
            } catch (JSONException e) {
                if (Cobalt.DEBUG)
                    Log.e(Cobalt.TAG, TAG + " - onCreate: data navigation parsing failed. "
                            + extras.getString(Cobalt.kJSData));
                e.printStackTrace();
            }
        }

        if (extras.containsKey(Cobalt.kBars)) {
            try {
                JSONObject actionBar = new JSONObject(extras.getString(Cobalt.kBars));
                setupBars(actionBar);
            } catch (JSONException exception) {
                setupBars(null);
                if (Cobalt.DEBUG) {
                    Log.e(Cobalt.TAG, TAG + " - onCreate: bars configuration parsing failed. "
                            + extras.getString(Cobalt.kBars));
                }
                exception.printStackTrace();
            }
        } else {
            setupBars(null);
        }

        if (savedInstanceState == null) {
            CobaltFragment fragment = getFragment();

            if (fragment != null) {
                fragment.setArguments(extras);
                mAnimatedTransition = bundle.getBoolean(Cobalt.kJSAnimated, true);

                if (mAnimatedTransition) {
                    mWasPushedAsModal = bundle.getBoolean(Cobalt.kPushAsModal, false);
                    if (mWasPushedAsModal) {
                        sWasPushedFromModal = true;
                        overridePendingTransition(R.anim.modal_open_enter, android.R.anim.fade_out);
                    } else if (bundle.getBoolean(Cobalt.kPopAsModal, false)) {
                        sWasPushedFromModal = false;
                        overridePendingTransition(android.R.anim.fade_in, R.anim.modal_close_exit);
                    } else if (sWasPushedFromModal)
                        overridePendingTransition(R.anim.modal_push_enter, R.anim.modal_push_exit);
                } else
                    overridePendingTransition(0, 0);
            }

            if (findViewById(getFragmentContainerId()) != null) {
                getSupportFragmentManager().beginTransaction().replace(getFragmentContainerId(), fragment).commit();
            } else if (Cobalt.DEBUG)
                Log.e(Cobalt.TAG, TAG + " - onCreate: fragment container not found");
        } else if (Cobalt.DEBUG)
            Log.e(Cobalt.TAG, TAG + " - onCreate: getFragment() returned null");
    }

    @Override
    protected void onStart() {
        super.onStart();

        Cobalt.getInstance(getApplicationContext()).onActivityStarted(this);
    }

    public void onAppStarted() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainerId());
        if (fragment != null && CobaltFragment.class.isAssignableFrom(fragment.getClass())) {
            ((CobaltFragment) fragment).sendEvent(Cobalt.JSEventOnAppStarted, null, null);
        } else if (Cobalt.DEBUG)
            Log.i(Cobalt.TAG, TAG + " - onAppStarted: no fragment container found \n"
                    + " or fragment found is not an instance of CobaltFragment. \n" + "Drop onAppStarted event.");
    }

    public void onAppForeground() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainerId());
        if (fragment != null && CobaltFragment.class.isAssignableFrom(fragment.getClass())) {
            ((CobaltFragment) fragment).sendEvent(Cobalt.JSEventOnAppForeground, null, null);
        } else if (Cobalt.DEBUG)
            Log.i(Cobalt.TAG,
                    TAG + " - onAppForeground: no fragment container found \n"
                            + " or fragment found is not an instance of CobaltFragment. \n"
                            + "Drop onAppForeground event.");
    }

    @Override
    public void finish() {
        super.finish();

        if (mAnimatedTransition) {
            if (mWasPushedAsModal) {
                sWasPushedFromModal = false;
                overridePendingTransition(android.R.anim.fade_in, R.anim.modal_close_exit);
            } else if (sWasPushedFromModal)
                overridePendingTransition(R.anim.modal_pop_enter, R.anim.modal_pop_exit);
        } else
            overridePendingTransition(0, 0);
    }

    @Override
    protected void onStop() {
        super.onStop();

        Cobalt.getInstance(getApplicationContext()).onActivityStopped(this);
    }

    public void onAppBackground() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainerId());
        if (fragment != null && CobaltFragment.class.isAssignableFrom(fragment.getClass())) {
            ((CobaltFragment) fragment).sendEvent(Cobalt.JSEventOnAppBackground, null, null);
        } else if (Cobalt.DEBUG)
            Log.i(Cobalt.TAG,
                    TAG + " - onAppBackground: no fragment container found \n"
                            + " or fragment found is not an instance of CobaltFragment. \n"
                            + "Drop onAppBackground event.");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        sActivitiesArrayList.remove(this);
    }

    public String getInitController() {
        return null;
    }

    public String getInitPage() {
        return null;
    }

    /***********************************************************************************************
     *
     * MENU
     *
     **********************************************************************************************/

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        Bundle bundle = getIntent().getExtras();
        if (bundle == null) {
            bundle = new Bundle();
        }
        Bundle extras = bundle.getBundle(Cobalt.kExtras);
        if (extras == null) {
            extras = Cobalt.getInstance(getApplicationContext()).getConfigurationForController(getInitController());
        }
        if (extras.containsKey(Cobalt.kBars)) {
            try {
                JSONObject actionBar = new JSONObject(extras.getString(Cobalt.kBars));
                String color = actionBar.optString(Cobalt.kBarsColor, null);
                if (color == null) {
                    color = getDefaultActionBarTextColor();
                }
                JSONArray actions = actionBar.optJSONArray(Cobalt.kBarsActions);
                if (actions != null)
                    setupOptionsMenu(menu, color, actions);
            } catch (JSONException exception) {
                if (Cobalt.DEBUG) {
                    Log.e(Cobalt.TAG, TAG + " - onCreate: action bar configuration parsing failed. "
                            + extras.getString(Cobalt.kBars));
                }
                exception.printStackTrace();
            }
        }

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemId = item.getItemId();

        if (itemId == android.R.id.home) {
            onBackPressed();
            return true;
        }
        if (mMenuItemsIdMap.containsKey(itemId)) {
            onPressed(mMenuItemsIdMap.get(itemId));
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /***********************************************************************************************
     *
     * COBALT
     *
     **********************************************************************************************/

    /***********************************************************************************************
     *
     * UI
     *
     **********************************************************************************************/

    /**
     * Returns a new instance of the contained fragment. 
     * This method should be overridden in subclasses.
     * @return a new instance of the fragment contained.
     */
    protected abstract CobaltFragment getFragment();

    protected int getLayoutToInflate() {
        return R.layout.activity_cobalt;
    }

    public int getFragmentContainerId() {
        return R.id.fragment_container;
    }

    public int getTopBarId() {
        return R.id.top_bar;
    }

    public int getBottomBarId() {
        return R.id.bottom_bar;
    }

    public String getDefaultActionBarBackgroundColor() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar == null) {
            return null;
        }

        TypedValue colorPrimary = new TypedValue();
        if (!actionBar.getThemedContext().getTheme().resolveAttribute(android.R.attr.colorPrimary, colorPrimary,
                true)) {
            return null;
        }

        // TODO: handle all data types
        String hexColor = String.format("%08x", colorPrimary.data);
        return hexColor.substring(2, 8) + hexColor.substring(0, 2);
    }

    public String getDefaultActionBarTextColor() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar == null) {
            return null;
        }

        TypedValue textColorPrimary = new TypedValue();
        if (!actionBar.getThemedContext().getTheme().resolveAttribute(android.R.attr.textColorPrimary,
                textColorPrimary, true)) {
            return null;
        }

        // TODO: handle all data types
        String hexColor = String.format("%08x", textColorPrimary.data);
        return hexColor.substring(2, 8) + hexColor.substring(0, 2);
    }

    public void setupBars(JSONObject configuration) {
        Toolbar topBar = (Toolbar) findViewById(getTopBarId());
        // TODO: use LinearLayout for bottomBar instead to handle groups
        //LinearLayout bottomBar = (LinearLayout) findViewById(getBottomBarId());
        BottomBar bottomBar = (BottomBar) findViewById(getBottomBarId());

        // TODO: make bars more flexible
        if (topBar == null || bottomBar == null) {
            if (Cobalt.DEBUG)
                Log.w(Cobalt.TAG, TAG
                        + " - setupBars: activity does not have an action bar and/or does not contain a bottom bar.");
            return;
        }

        setSupportActionBar(topBar);
        ActionBar actionBar = getSupportActionBar();

        // Default
        if (actionBar != null) {
            actionBar.setTitle(null);
            if (sActivitiesArrayList.size() == 1) {
                actionBar.setDisplayHomeAsUpEnabled(false);
            } else {
                actionBar.setDisplayHomeAsUpEnabled(true);
            }
        }

        if (configuration != null) {
            // Background color
            // TODO: apply on overflow popup
            String backgroundColor = configuration.optString(Cobalt.kBarsBackgroundColor, null);
            if (backgroundColor == null) {
                backgroundColor = getDefaultActionBarBackgroundColor();
            }
            try {
                int backgroundColorInt = Cobalt.parseColor(backgroundColor);
                if (actionBar != null)
                    actionBar.setBackgroundDrawable(new ColorDrawable(backgroundColorInt));
                bottomBar.setBackgroundColor(backgroundColorInt);
            } catch (IllegalArgumentException exception) {
                if (Cobalt.DEBUG) {
                    Log.w(Cobalt.TAG, TAG + " - setupBars: backgroundColor " + backgroundColor
                            + " format not supported, use (#)RGB or (#)RRGGBB(AA).");
                }
                exception.printStackTrace();
            }

            // Color (default: system)
            int colorInt = CobaltFontManager.DEFAULT_COLOR;
            boolean applyColor = false;
            String color = configuration.optString(Cobalt.kBarsColor, null);
            if (color == null)
                color = getDefaultActionBarTextColor();
            try {
                colorInt = Cobalt.parseColor(color);
                applyColor = true;
            } catch (IllegalArgumentException exception) {
                if (Cobalt.DEBUG) {
                    Log.w(Cobalt.TAG, TAG + " - setupBars: color " + color
                            + " format not supported, use (#)RGB or (#)RRGGBB(AA).");
                }
                exception.printStackTrace();
            }

            // Logo
            String logo = configuration.optString(Cobalt.kBarsIcon, null);
            if (logo != null) {
                Drawable logoDrawable = null;

                int logoResId = getResourceIdentifier(logo);
                if (logoResId != 0) {
                    try {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            logoDrawable = getResources().getDrawable(logoResId, null);
                        } else {
                            logoDrawable = getResources().getDrawable(logoResId);
                        }

                        if (applyColor && logoDrawable != null) {
                            logoDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
                        }
                    } catch (Resources.NotFoundException exception) {
                        Log.w(Cobalt.TAG, TAG + " - setupBars: " + logo + " resource not found.");
                        exception.printStackTrace();
                    }
                } else {
                    logoDrawable = CobaltFontManager.getCobaltFontDrawable(this, logo, colorInt);
                }
                topBar.setLogo(logoDrawable);
                if (actionBar != null)
                    actionBar.setDisplayShowHomeEnabled(true);
            } else {
                if (actionBar != null)
                    actionBar.setDisplayShowHomeEnabled(false);
            }

            // Title
            String title = configuration.optString(Cobalt.kBarsTitle, null);
            if (title != null) {
                if (actionBar != null)
                    actionBar.setTitle(title);
            } else {
                if (actionBar != null)
                    actionBar.setDisplayShowTitleEnabled(false);
            }

            // Visible
            JSONObject visible = configuration.optJSONObject(Cobalt.kBarsVisible);
            if (visible != null)
                setActionBarVisible(visible);

            // Up
            JSONObject navigationIcon = configuration.optJSONObject(Cobalt.kBarsNavigationIcon);
            if (navigationIcon != null) {
                boolean enabled = navigationIcon.optBoolean(Cobalt.kNavigationIconEnabled, true);
                if (actionBar != null)
                    actionBar.setDisplayHomeAsUpEnabled(enabled);
                Drawable navigationIconDrawable = null;

                String icon = navigationIcon.optString(Cobalt.kNavigationIconIcon, null);
                if (icon != null) {
                    int iconResId = getResourceIdentifier(icon);
                    if (iconResId != 0) {
                        try {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                navigationIconDrawable = getResources().getDrawable(iconResId, null);
                            } else {
                                navigationIconDrawable = getResources().getDrawable(iconResId);
                            }
                        } catch (Resources.NotFoundException exception) {
                            Log.w(Cobalt.TAG, TAG + " - setupBars: " + logo + " resource not found.");
                            exception.printStackTrace();
                        }
                    } else {
                        navigationIconDrawable = CobaltFontManager.getCobaltFontDrawable(this, icon, colorInt);
                    }
                    topBar.setNavigationIcon(navigationIconDrawable);
                }
            }

            if (applyColor) {
                topBar.setTitleTextColor(colorInt);

                Drawable overflowIconDrawable = topBar.getOverflowIcon();
                // should never be null but sometimes....
                if (overflowIconDrawable != null)
                    overflowIconDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);

                Drawable navigationIconDrawable = topBar.getNavigationIcon();
                // should never be null but sometimes....
                if (navigationIconDrawable != null)
                    navigationIconDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
            }
        }
    }

    private void setupOptionsMenu(Menu menu, String color, JSONArray actions) {
        ActionBar actionBar = getSupportActionBar();
        // TODO: use LinearLayout for bottomBar instead to handle groups
        //LinearLayout bottomBar = (LinearLayout) findViewById(getBottomBarId());
        BottomBar bottomBar = (BottomBar) findViewById(getBottomBarId());

        // TODO: make bars more flexible
        if (actionBar == null || bottomBar == null) {
            if (Cobalt.DEBUG) {
                Log.w(Cobalt.TAG, TAG
                        + " - setupOptionsMenu: activity does not have an action bar and/or does not contain a bottom bar.");
            }
            return;
        }

        Menu bottomMenu = bottomBar.getMenu();

        menu.clear();
        bottomMenu.clear();

        int actionId = 0;
        int menuItemsAddedToTop = 0;
        int menuItemsAddedToOverflow = 0;
        int menuItemsAddedToBottom = 0;

        int length = actions.length();
        for (int i = 0; i < length; i++) {
            try {
                JSONObject action = actions.getJSONObject(i);
                String position = action.getString(Cobalt.kActionPosition); // must be "top", "bottom", "overflow"
                JSONArray groupActions = action.optJSONArray(Cobalt.kActionActions);

                Menu addToMenu = menu;
                int order;

                switch (position) {
                case Cobalt.kPositionTop:
                    order = menuItemsAddedToTop++;
                    break;
                case Cobalt.kPositionOverflow:
                    order = menuItemsAddedToOverflow++;
                    break;
                case Cobalt.kPositionBottom:
                    order = menuItemsAddedToBottom++;
                    addToMenu = bottomMenu;
                    // TODO find a way to add same space between each actionViewItem
                    /*MenuItem spaceMenuItem = addToMenu.add(Menu.NONE, Menu.NONE, order++, "");
                    MenuItemCompat.setShowAsAction(spaceMenuItem, MenuItem.SHOW_AS_ACTION_ALWAYS);
                    spaceMenuItem.setVisible(true);
                    spaceMenuItem.setEnabled(false);*/
                    break;
                default:
                    throw new JSONException("androidPosition attribute must be top, overflow or bottom.");
                }

                if (groupActions != null) {
                    addGroup(addToMenu, order, groupActions, actionId, position, color);
                } else {
                    addMenuItem(addToMenu, order, action, actionId++, position, color);
                }
            } catch (JSONException exception) {
                if (Cobalt.DEBUG) {
                    Log.w(Cobalt.TAG, TAG + " - setupOptionsMenu: action " + i
                            + " of actions array below is not an object, does not contain a position field or its value is not top, overflow or bottom.\n"
                            + actions.toString());
                }

                exception.printStackTrace();
            }
        }
    }

    protected void addGroup(Menu menu, int order, JSONArray actions, int actionId, String position, String color) {
        int length = actions.length();
        for (int i = 0; i < length; i++) {
            try {
                JSONObject action = actions.getJSONObject(i);
                addMenuItem(menu, order++, action, actionId++, position, color);
            } catch (JSONException exception) {
                if (Cobalt.DEBUG) {
                    Log.w(Cobalt.TAG, TAG + " - addGroup: action " + i
                            + " of actions array below is not an object.\n" + actions.toString());
                }
                exception.printStackTrace();
            }
        }
    }

    public void setBadgeMenuItem(String name, String badgeText) {
        if (mMenuItemsHashMap.containsKey(name)) {
            ActionViewMenuItem item = mMenuItemsHashMap.get(name);
            item.setActionBadge(badgeText);
        }
    }

    public void setContentMenuItem(String name, JSONObject content) {
        if (mMenuItemsHashMap.containsKey(name)) {
            ActionViewMenuItem item = mMenuItemsHashMap.get(name);
            item.setActionContent(content);
        }
    }

    public void setActionBarVisible(JSONObject visible) {
        ActionBar actionBar = getSupportActionBar();
        BottomBar bottomBar = (BottomBar) findViewById(getBottomBarId());
        if (visible.has(Cobalt.kVisibleTop) && actionBar != null) {
            boolean top = visible.optBoolean(Cobalt.kVisibleTop);

            if (!top && actionBar.isShowing()) {
                actionBar.hide();
            } else if (top && !actionBar.isShowing()) {
                actionBar.show();
            }
        }

        if (visible.has(Cobalt.kVisibleBottom)) {
            boolean bottom = visible.optBoolean(Cobalt.kVisibleBottom);
            if (bottom) {
                bottomBar.setVisibility(View.VISIBLE);
            } else
                bottomBar.setVisibility(View.GONE);
        }
    }

    public void setBarContent(JSONObject content) {
        Toolbar topBar = (Toolbar) findViewById(getTopBarId());
        ActionBar actionBar = getSupportActionBar();
        BottomBar bottomBar = (BottomBar) findViewById(getBottomBarId());
        int colorInt = CobaltFontManager.DEFAULT_COLOR;
        boolean applyColor = false;

        try {
            String backgroundColor = content.optString(Cobalt.kBarsBackgroundColor, null);
            // TODO: apply on overflow popup
            if (backgroundColor != null) {
                int backgroundColorInt = Cobalt.parseColor(backgroundColor);
                if (actionBar != null)
                    actionBar.setBackgroundDrawable(new ColorDrawable(backgroundColorInt));
                bottomBar.setBackgroundColor(backgroundColorInt);
            }
        } catch (IllegalArgumentException exception) {
            if (Cobalt.DEBUG) {
                Log.w(Cobalt.TAG, TAG
                        + " - setBarContent: backgroundColor format not supported, use (#)RGB or (#)RRGGBB(AA).");
            }
            exception.printStackTrace();
        }

        try {
            String color = content.optString(Cobalt.kBarsColor, null);
            if (color != null) {
                colorInt = Cobalt.parseColor(color);
                applyColor = true;
                topBar.setTitleTextColor(colorInt);

                Drawable overflowIconDrawable = topBar.getOverflowIcon();
                // should never be null but sometimes....
                if (overflowIconDrawable != null) {
                    overflowIconDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
                }

                Drawable navigationIconDrawable = topBar.getNavigationIcon();
                // should never be null but sometimes....
                if (navigationIconDrawable != null) {
                    navigationIconDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
                }
            }
        } catch (IllegalArgumentException exception) {
            if (Cobalt.DEBUG) {
                Log.w(Cobalt.TAG, TAG + " - setupBars: color format not supported, use (#)RGB or (#)RRGGBB(AA).");
            }
            exception.printStackTrace();
        }

        String logo = content.optString(Cobalt.kBarsIcon, null);
        if (logo != null && !logo.equals("")) {
            Drawable logoDrawable = null;

            int logoResId = getResourceIdentifier(logo);
            if (logoResId != 0) {
                try {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        logoDrawable = getResources().getDrawable(logoResId, null);
                    } else {
                        logoDrawable = getResources().getDrawable(logoResId);
                    }

                    if (applyColor && logoDrawable != null) {
                        logoDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
                    }
                } catch (Resources.NotFoundException exception) {
                    Log.w(Cobalt.TAG, TAG + " - setupBars: " + logo + " resource not found.");
                    exception.printStackTrace();
                }
            } else {
                logoDrawable = CobaltFontManager.getCobaltFontDrawable(getApplicationContext(), logo, colorInt);
            }
            topBar.setLogo(logoDrawable);
            if (actionBar != null)
                actionBar.setDisplayShowHomeEnabled(true);
        } else {
            if (actionBar != null)
                actionBar.setDisplayShowHomeEnabled(false);
        }

        if (content.has(Cobalt.kBarsNavigationIcon)) {
            try {
                JSONObject navigationIcon = content.getJSONObject(Cobalt.kBarsNavigationIcon);
                if (navigationIcon == null)
                    navigationIcon = new JSONObject();
                boolean enabled = navigationIcon.optBoolean(Cobalt.kNavigationIconEnabled, true);
                if (actionBar != null)
                    actionBar.setDisplayHomeAsUpEnabled(enabled);
                Drawable navigationIconDrawable = null;

                String icon = navigationIcon.optString(Cobalt.kNavigationIconIcon);
                if (icon != null) {
                    int iconResId = getResourceIdentifier(icon);
                    if (iconResId != 0) {
                        try {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                navigationIconDrawable = getResources().getDrawable(iconResId, null);
                            } else {
                                navigationIconDrawable = getResources().getDrawable(iconResId);
                            }
                            if (applyColor && navigationIconDrawable != null) {
                                navigationIconDrawable.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP);
                            }
                        } catch (Resources.NotFoundException exception) {
                            Log.w(Cobalt.TAG, TAG + " - setupBars: " + icon + " resource not found.");
                            exception.printStackTrace();
                        }
                    } else {
                        navigationIconDrawable = CobaltFontManager.getCobaltFontDrawable(getApplicationContext(),
                                icon, colorInt);
                    }
                    topBar.setNavigationIcon(navigationIconDrawable);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        if (content.has(Cobalt.kBarsTitle) && actionBar != null) {
            try {
                String title = content.getString(Cobalt.kBarsTitle);
                if (title != null) {
                    actionBar.setTitle(title);
                } else {
                    actionBar.setDisplayShowTitleEnabled(false);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    public void setActionItemVisible(String actionName, boolean visible) {
        MenuItem menuItem = mMenuItemByNameMap.get(actionName);
        if (menuItem != null) {
            menuItem.setVisible(visible);
        }
    }

    public void setActionItemEnabled(String actionName, boolean enabled) {
        MenuItem menuItem = mMenuItemByNameMap.get(actionName);
        if (menuItem != null) {
            menuItem.setEnabled(enabled);
        }

        if (mMenuItemsHashMap.containsKey(actionName)) {
            ActionViewMenuItem actionViewMenuItem = mMenuItemsHashMap.get(actionName);
            actionViewMenuItem.setEnabled(enabled);
        }
    }

    protected void addMenuItem(Menu menu, int order, JSONObject action, final int id, String position,
            String barsColor) {
        try {
            final String name = action.getString(Cobalt.kActionName);
            String title = action.getString(Cobalt.kActionTitle);
            boolean visible = action.optBoolean(Cobalt.kActionVisible, true);
            boolean enabled = action.optBoolean(Cobalt.kActionEnabled, true);

            final MenuItem menuItem = menu.add(Menu.NONE, id, order, title);

            int showAsAction = MenuItemCompat.SHOW_AS_ACTION_IF_ROOM;
            switch (position) {
            case Cobalt.kPositionBottom:
                showAsAction = MenuItemCompat.SHOW_AS_ACTION_ALWAYS;
                break;
            case Cobalt.kPositionOverflow:
                showAsAction = MenuItemCompat.SHOW_AS_ACTION_NEVER;
                break;
            }
            MenuItemCompat.setShowAsAction(menuItem, showAsAction);

            ActionViewMenuItem actionView = new ActionViewMenuItem(this, action, barsColor);
            actionView.setActionViewMenuItemListener(new WeakReference<>(this));

            MenuItemCompat.setActionView(menuItem, actionView);
            menuItem.setVisible(visible);
            menuItem.setEnabled(enabled);
            mMenuItemsHashMap.put(name, actionView);
            //need this next hashmap to send onPressed when item is on overflow
            mMenuItemsIdMap.put(id, name);
            //need this next hashmap to set menuItem
            mMenuItemByNameMap.put(name, menuItem);
        } catch (JSONException exception) {
            if (Cobalt.DEBUG) {
                Log.w(Cobalt.TAG,
                        TAG + "addMenuItem: action " + action.toString() + " format not supported, use at least {\n"
                                + "\tname: \"name\",\n" + "\ttitle: \"title\",\n" + "}");
            }

            exception.printStackTrace();
        }
    }

    public int getResourceIdentifier(String resource) {
        int resId = 0;

        try {
            if (resource == null || resource.length() == 0) {
                throw new IllegalArgumentException();
            }

            String[] resourceSplit = resource.split(":");
            String packageName, resourceName;
            switch (resourceSplit.length) {
            case 1:
                packageName = getPackageName();
                resourceName = resourceSplit[0];
                break;
            case 2:
                packageName = resourceSplit[0].length() != 0 ? resourceSplit[0] : getPackageName();
                resourceName = resourceSplit[1];
                break;
            default:
                throw new IllegalArgumentException();
            }
            resId = getResources().getIdentifier(resourceName, "drawable", packageName);
            if (resId == 0) {
                Log.w(Cobalt.TAG, TAG + "getResourceIdentifier: resource " + resource + " not found.");
            }
        } catch (IllegalArgumentException exception) {
            if (Cobalt.DEBUG) {
                Log.w(Cobalt.TAG, TAG + "getResourceIdentifier: resource " + resource
                        + " format not supported, use resource, :resource or package:resource.");
            }
            exception.printStackTrace();
        }

        return resId;
    }

    /***********************************************************************************************
     *
     * BACK
     *
     **********************************************************************************************/

    /**
     * Called when back button is pressed. 
     * This method should NOT be overridden in subclasses.
     */
    @Override
    public void onBackPressed() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainerId());
        if (fragment != null && CobaltFragment.class.isAssignableFrom(fragment.getClass())) {
            ((CobaltFragment) fragment).askWebViewForBackPermission();
        } else {
            super.onBackPressed();
            if (Cobalt.DEBUG)
                Log.i(Cobalt.TAG,
                        TAG + " - onBackPressed: no fragment container found \n"
                                + " or fragment found is not an instance of CobaltFragment. \n"
                                + "Call super.onBackPressed()");
        }
    }

    /**
     * Called from the contained {@link CobaltFragment} when the Web view has authorized the back event.
     * This method should NOT be overridden in subclasses.
     */
    public void back() {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                backWithSuper();
            }
        });
    }

    private void backWithSuper() {

        try {
            super.onBackPressed();
        } catch (IllegalStateException exc) {
            if (Cobalt.DEBUG)
                Log.i(Cobalt.TAG, TAG + " onBackPressed: catch illegalStateException for fix crash on API > 11");
        }
    }

    /***********************************************************************************************
     *
     * WEB LAYER DISMISS
     *
     **********************************************************************************************/

    /**
     * Called when a {@link CobaltWebLayerFragment} has been dismissed.
     * This method may be overridden in subclasses.
     */
    public void onWebLayerDismiss(String page, JSONObject data) {
        CobaltFragment fragment = (CobaltFragment) getSupportFragmentManager()
                .findFragmentById(getFragmentContainerId());
        if (fragment != null) {
            fragment.onWebLayerDismiss(page, data);
        } else if (Cobalt.DEBUG)
            Log.e(Cobalt.TAG, TAG + " - onWebLayerDismiss: no fragment container found");
    }

    public void popTo(String controller, String page, JSONObject data) {
        Intent popToIntent = Cobalt.getInstance(this).getIntentForController(controller, page);

        if (popToIntent != null) {
            Bundle popToExtras = popToIntent.getBundleExtra(Cobalt.kExtras);
            String popToActivityClassName = popToExtras.getString(Cobalt.kActivity);

            try {
                Class<?> popToActivityClass = Class.forName(popToActivityClassName);

                boolean popToControllerFound = false;
                int popToControllerIndex = -1;

                for (int i = sActivitiesArrayList.size() - 1; i >= 0; i--) {
                    Activity oldActivity = sActivitiesArrayList.get(i);
                    Class<?> oldActivityClass = oldActivity.getClass();

                    Bundle oldBundle = oldActivity.getIntent().getExtras();
                    Bundle oldExtras = (oldBundle != null) ? oldBundle.getBundle(Cobalt.kExtras) : null;
                    String oldPage = (oldExtras != null) ? oldExtras.getString(Cobalt.kPage) : null;

                    if (oldPage == null && CobaltActivity.class.isAssignableFrom(oldActivityClass)) {
                        Fragment fragment = ((CobaltActivity) oldActivity).getSupportFragmentManager()
                                .findFragmentById(((CobaltActivity) oldActivity).getFragmentContainerId());
                        if (fragment != null) {
                            oldExtras = fragment.getArguments();
                            oldPage = (oldExtras != null) ? oldExtras.getString(Cobalt.kPage) : null;
                        }
                    }

                    if (popToActivityClass.equals(oldActivityClass) && (!CobaltActivity.class
                            .isAssignableFrom(oldActivityClass)
                            || (CobaltActivity.class.isAssignableFrom(oldActivityClass) && page.equals(oldPage)))) {
                        popToControllerFound = true;
                        popToControllerIndex = i;
                        ((CobaltActivity) oldActivity).setDataNavigation(data);
                        break;
                    }
                }

                if (popToControllerFound) {
                    while (popToControllerIndex + 1 < sActivitiesArrayList.size()) {
                        sActivitiesArrayList.get(popToControllerIndex + 1).finish();
                    }
                } else if (Cobalt.DEBUG)
                    Log.w(Cobalt.TAG, TAG + " - popTo: controller " + controller
                            + (page == null ? "" : " with page " + page) + " not found in history. Abort.");
            } catch (ClassNotFoundException exception) {
                exception.printStackTrace();
            }
        } else if (Cobalt.DEBUG)
            Log.e(Cobalt.TAG, TAG + " - popTo: unable to pop to null controller");
    }

    public void dataForPop(JSONObject data) {
        if (sActivitiesArrayList.size() >= 2) {
            boolean cobaltActivityFound = false;
            int index = sActivitiesArrayList.size() - 2;
            while (!cobaltActivityFound && index >= 0) {
                Activity activity = sActivitiesArrayList.get(index);
                if (CobaltActivity.class.isAssignableFrom(activity.getClass())) {
                    ((CobaltActivity) activity).setDataNavigation(data);
                    cobaltActivityFound = true;
                }
                index--;
            }
            if (!cobaltActivityFound && Cobalt.DEBUG)
                Log.e(Cobalt.TAG, TAG + " - dataForPop: CobaltActivity not found");
        }
    }

    public JSONObject getDataNavigation() {
        return mDataNavigation;
    }

    public void setDataNavigation(JSONObject data) {
        this.mDataNavigation = data;
    }

    /***********************************************************************************************
     *
     * ACTION VIEW MENU ITEM
     *
     **********************************************************************************************/

    @Override
    public void onPressed(String name) {
        CobaltFragment fragment = (CobaltFragment) getSupportFragmentManager()
                .findFragmentById(getFragmentContainerId());
        JSONObject message = new JSONObject();
        JSONObject data = new JSONObject();
        try {
            message.put(Cobalt.kJSType, Cobalt.JSTypeUI);
            message.put(Cobalt.kJSUIControl, Cobalt.JSControlBars);
            data.put(Cobalt.kJSAction, Cobalt.JSActionActionPressed);
            data.put(Cobalt.kJSActionName, name);
            message.put(Cobalt.kJSData, data);
            fragment.sendMessage(message);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}