ua.boberproduction.bbr.BaseActivity.java Source code

Java tutorial

Introduction

Here is the source code for ua.boberproduction.bbr.BaseActivity.java

Source

/*
* Copyright 2015 Kostiantyn Aloshychev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ua.boberproduction.bbr;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.GridView;
import android.widget.Toast;

import com.google.android.gms.ads.AdView;
import com.google.firebase.analytics.FirebaseAnalytics;

import java.util.LinkedList;
import java.util.List;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import ua.boberproduction.bbr.billing.Billing;
import ua.boberproduction.bbr.feedback.FeedbackFragment;
import ua.boberproduction.bbr.navigation.AnimatedExpandableListAdapter;
import ua.boberproduction.bbr.navigation.AnimatedExpandableListView;
import ua.boberproduction.bbr.navigation.AnimatedExpandableListView.ChildItem;
import ua.boberproduction.bbr.navigation.AnimatedExpandableListView.GroupItem;
import ua.boberproduction.bbr.navigation.ListMenuFragment;
import ua.boberproduction.bbr.navigation.MainMenuFragment;
import ua.boberproduction.bbr.navigation.RootMenuManager;
import ua.boberproduction.bbr.notes.NoteViewerFragment;
import ua.boberproduction.bbr.sqlite.DBInstallTaskFragment;
import ua.boberproduction.bbr.sqlite.DBInstaller;
import ua.boberproduction.bbr.sqlite.SQLiteStructureRepository;
import ua.boberproduction.bbr.textcontent.TextContentFragment;
import ua.boberproduction.bbr.util.Utils;

/**
 * Base Activity class implementing common UI elements and behaviour.
 */
public abstract class BaseActivity extends AppCompatActivity {
    // load NDK SQLite library containing ICU to support cyrillic FTS search.
    static {
        System.loadLibrary("android_sqlite");
    }

    private final int NAV_MENU_HIDE_DELAY = 200;
    //private IabHelper iabHelper;
    private FirebaseAnalytics firebaseAnalytics;
    private SearchView searchView;
    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;
    private Ad adBanner;
    private Toolbar toolbar;
    private Billing billing;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main_bbr);

        super.onCreate(savedInstanceState);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        // check if external storage is available for read and write. If not, quit application and show toast message.
        if (!Utils.isExternalStorageWritable()) {
            try {
                throw new Error("External memory not available. Quitting app.");
            } catch (Error error) {
                Toast.makeText(getApplicationContext(), getString(R.string.error_storage_read_unavailable),
                        Toast.LENGTH_LONG).show();
                finish();
                System.exit(0);
            }
        }

        // if there is no savedInstanceState (initial activity load),
        // create a dummy retainable fragment to hold AsyncTask which is copying database from assets to the system storage.
        // It is made in order to pass the task to a recreated activity after configuration change.
        // When completed, it loads content.
        if (!DBInstaller.isLatestContentDBInstalled(this)) {
            Fragment mTaskFragment = getFragmentManager()
                    .findFragmentByTag(DBInstallTaskFragment.TAG_TASK_FRAGMENT);
            // If the Fragment is non-null, then it is currently being retained across a configuration change.
            if (mTaskFragment == null) {
                mTaskFragment = new DBInstallTaskFragment();
                getFragmentManager().beginTransaction().add(mTaskFragment, DBInstallTaskFragment.TAG_TASK_FRAGMENT)
                        .commit();
            }
        } else {
            setupUI();
        }

        firebaseAnalytics = FirebaseAnalytics.getInstance(this);

        // initialize in-app billing, if premium mode is not active and Google services are available
        if (!Ad.getGodModeStatus(this)) {

            // Showing status
            if (isGoogleServicesAvailable()) {
                billing = new Billing(this);
                billing.onCreate();
            }
        }
    }

    private boolean isGoogleServicesAvailable() {
        /*        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
                return googleAPI.isGooglePlayServicesAvailable(this) == SUCCESS;*/
        return true;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (billing != null)
            billing.onActivityResult(requestCode, resultCode, data);
    }

    public FirebaseAnalytics getFirebaseAnalytics() {
        if (firebaseAnalytics == null)
            firebaseAnalytics = FirebaseAnalytics.getInstance(this);
        return firebaseAnalytics;
    }

    public Ad getAdBanner() {
        return adBanner;
    }

    public void setupUI() {
        Observable.fromCallable(() -> {
            if (RootMenuManager.listIsNull())
                RootMenuManager.getList();
            return null;
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).doOnError((e) -> {
            Log.e(BBRApplication.TAG_BBR, "Error getting root menu list", e);
            Utils.toastError(this, getString(R.string.error_loading_menu_list), Toast.LENGTH_SHORT);
        }).subscribe((r) -> {
            setupToolbar();
            setupNavigationDrawer();
            showContent();
        });
    }

    public void setupToolbar() {
        // Customize toolbar
        String apptitle = getString(R.string.app_name);
        toolbar.setTitle(apptitle);
        setSupportActionBar(toolbar);
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setDisplayShowHomeEnabled(true);
        }
    }

    /**
     * Show the activity content. Called after all preparation (db checking and installing etc) is finished.
     */
    public abstract void showContent();

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        MenuItem searchItem = menu.findItem(R.id.action_search);

        SearchManager searchManager = (SearchManager) this.getSystemService(Context.SEARCH_SERVICE);

        searchView = null;
        if (searchItem != null) {
            searchView = (SearchView) searchItem.getActionView();
        }
        if (searchView != null) {
            searchView.setSearchableInfo(searchManager.getSearchableInfo(this.getComponentName()));

            searchView.setIconified(true);
            searchView.clearFocus();
            searchView.onActionViewCollapsed();
        }

        // if user activated God Mode, hide the 'remove ads' menu option..
        if (Ad.getGodModeStatus(this)) {
            MenuItem item = menu.findItem(R.id.action_remove_ads);
            item.setVisible(false);
        }

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        boolean godMode = prefs.getBoolean(getString(R.string.pref_god_mode), false);

        if (!godMode) {
            AdView adView = (AdView) findViewById(R.id.adView);
            if (adBanner == null)
                adBanner = new Ad(adView);

            if (!(fragment instanceof MainMenuFragment)) {
                adBanner.showBanner();
            } else
                adBanner.hideBanner();
        }
    }

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

        if (id == R.id.action_settings) {
            startActivity(new Intent(this, EditPreferencesActivity.class));
            return true;

        } else if (id == R.id.action_rate_app) {
            final String appPackageName = getPackageName(); // getPackageName() from Context or Activity object
            try {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
            } catch (android.content.ActivityNotFoundException anfe) {
                startActivity(new Intent(Intent.ACTION_VIEW,
                        Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
            }
        } else if (id == R.id.action_feedback) {
            FragmentTransaction ft = this.getFragmentManager().beginTransaction();
            FeedbackFragment fragment = new FeedbackFragment();
            ft.setCustomAnimations(R.animator.slide_in_right, R.animator.slide_out_left, R.animator.slide_in_left,
                    R.animator.slide_out_right);
            ft.replace(R.id.main_frame, fragment).addToBackStack(null).commit();
        } else if (id == R.id.action_remove_ads) {
            // if Google Services are available, launch the billing. If not, show error message.
            // Showing status
            if (isGoogleServicesAvailable())
                billing.purchaseRemoveAds();
            else
                Toast.makeText(this, getString(R.string.toast_error_google_services_unavailable),
                        Toast.LENGTH_SHORT).show();
        }

        return drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // collapse the search line (if it's activated)

        if (searchView != null && !searchView.isIconified()) {
            searchView.clearFocus();
            searchView.setIconified(true);
            searchView.onActionViewCollapsed();
        }

        // Load fullscreen Ads into memory
        Ad.requestNewInterstitial(this);
    }

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

        if (adBanner != null)
            adBanner.close();
    }

    private List<GroupItem> getGroupItems() {
        List<Chapter> rootCategories = RootMenuManager.getList();
        List<GroupItem> groupItems = new LinkedList<>();
        groupItems.add(new GroupItem(getString(R.string.menu_homepage)));
        GroupItem group;
        // Populate our GroupItem List by parent and child items
        for (Chapter rootCategory : rootCategories) {
            group = new GroupItem(rootCategory.getTitle(), rootCategory.getId());
            List<Chapter> children = SQLiteStructureRepository.getInstance().getChapters(rootCategory.getId());
            if (children.size() > 0) {
                for (Chapter child : children) {
                    ChildItem childItem = new ChildItem(child.getTitle(), child.getId());
                    group.getItems().add(childItem);
                }
            }
            groupItems.add(group);
        }
        // add 'Favorites', 'Notebook', etc. menu entries
        groupItems.add(new GroupItem(getString(R.string.menu_favorites), 1000));
        groupItems.add(new GroupItem(getString(R.string.menu_notepad), 1001));

        return groupItems;
    }

    // TODO: Delegate to drawer (AnimatedExpandableListView) class
    public void setupNavigationDrawer() {
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open,
                R.string.drawer_close);
        drawerToggle.setDrawerIndicatorEnabled(true);

        // next, add the categories from the DB
        Observable.fromCallable(this::getGroupItems).observeOn(AndroidSchedulers.mainThread())
                .doOnError((e) -> Log.e(BBRApplication.TAG_BBR, "Error generating navigation drawer menu.", e))
                .subscribeOn(Schedulers.newThread()).subscribe((groupItems) -> {
                    AnimatedExpandableListAdapter adapter = new AnimatedExpandableListAdapter(this, groupItems);
                    AnimatedExpandableListView listView = (AnimatedExpandableListView) findViewById(
                            R.id.nav_drawer_animated_listview);
                    listView.setAdapter(adapter);

                    listView.setOnGroupClickListener((parent, v, groupPosition, id) -> {
                        // If the selected group has any children,
                        // we call collapseGroupWithAnimation(int) and
                        // expandGroupWithAnimation(int) to animate group
                        // expansion/collapse.
                        if (groupItems.get(groupPosition).getItems().size() > 0) {
                            if (listView.isGroupExpanded(groupPosition)) {
                                listView.collapseGroupWithAnimation(groupPosition);
                            } else {
                                for (int i = 0; i < listView.getCount(); i++) {
                                    if (listView.isGroupExpanded(i) && groupPosition != i) {
                                        listView.collapseGroupWithAnimation(i);
                                    }
                                }
                                listView.expandGroupWithAnimation(groupPosition);
                            }
                            // if there are no children, make appropriate action
                        } else {
                            Chapter selectedChapter = new Chapter(groupItems.get(groupPosition).getId(),
                                    groupItems.get(groupPosition).getTitle(), 0);
                            closeNavigationDrawer();

                            new Handler().postDelayed(
                                    () -> RootMenuManager.performOnClickAction(selectedChapter, this),
                                    NAV_MENU_HIDE_DELAY);
                        }
                        return true;
                    });

                    listView.setOnChildClickListener(
                            (expandableListView, view, groupPosition, childPosition, id) -> {
                                drawerLayout.closeDrawer(GravityCompat.START);
                                listView.collapseGroup(groupPosition);
                                ChildItem childItem = groupItems.get(groupPosition).getItems().get(childPosition);

                                Chapter selectedChapter = new Chapter(childItem.getId(), childItem.getTitle(),
                                        groupItems.get(groupPosition).getId());
                                closeNavigationDrawer();

                                new Handler().postDelayed(() -> RootMenuManager
                                        .performOnClickAction(selectedChapter, BaseActivity.this),
                                        NAV_MENU_HIDE_DELAY);
                                return false;
                            });
                });

        drawerLayout.addDrawerListener(drawerToggle);
    }

    // close navigation drawer, if it's open. Return true if drawer was open on method launch.
    private boolean closeNavigationDrawer() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
            drawerLayout.closeDrawer(GravityCompat.START);
            Fragment fragment = getFragmentManager().findFragmentById(R.id.main_frame);
            if (fragment instanceof MainMenuFragment) {
                GridView gridLayout = (GridView) findViewById(R.id.grid_menu);
                if (null != gridLayout) {
                    gridLayout.invalidate();
                    gridLayout.requestLayout();
                }
            }
            return true;
        }
        return false;
    }

    @Override
    public void onBackPressed() {
        // close navigation drawer, if it's open
        if (closeNavigationDrawer())
            return;

        Fragment fragment = getFragmentManager().findFragmentById(R.id.main_frame);
        if (fragment instanceof TextContentFragment && ((TextContentFragment) fragment).isShowingPopup()) {
            ((TextContentFragment) fragment).hidePopupImage();
            return;
        } else if (fragment instanceof MainMenuFragment) {
            this.finishAffinity();
            // from NoteViewer, ensure that back press returns directly to NotebookFragment, avoiding NoteEditor even if it was saved in backstack.
        } else if (fragment instanceof NoteViewerFragment) {
            if (!getFragmentManager().popBackStackImmediate(getString(R.string.tag_fragment_notebook),
                    FragmentManager.POP_BACK_STACK_INCLUSIVE)) {
                super.onBackPressed();
            }
        }

        // Navigate through the fragments using the "back" button.
        // Check if there are fragments in the backstack, and pop them out.
        if (getFragmentManager().getBackStackEntryCount() > 0) {
            getFragmentManager().popBackStack();
            return;
        }

        super.onBackPressed();
    }

    public void openCategory(int id, String category) {
        // Check if there are any subcategories for the chosen category.
        Observable.fromCallable(() -> SQLiteStructureRepository.getInstance().getChapters(id))
                .subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).doOnError((e) -> {
                    Log.e(BBRApplication.TAG_BBR, "Error getting category list.", e);
                    Utils.toastError(this, getString(R.string.error_loading_categories), Toast.LENGTH_SHORT);
                }).subscribe((categories) -> {
                    Fragment fragment;
                    Bundle bundle = new Bundle();
                    // If there are, load another ListMenuFragment.
                    // Also, it will need the 'parent' category to put it into the actionBar's subtitle, so we're putting it into the bundle.
                    if (categories.size() > 0) {
                        fragment = new ListMenuFragment();
                    } else
                        // If not, load content.
                        fragment = new TextContentFragment();

                    // put the clicked category name into a bundle, and put the bundle into the fragment
                    bundle.putInt(getString(R.string.tag_category_id), id);
                    bundle.putString(getString(R.string.tag_category), category);
                    FragmentTransaction ft = this.getFragmentManager().beginTransaction();
                    fragment.setArguments(bundle);
                    //set sliding animations
                    ft.setCustomAnimations(R.animator.slide_in_right, R.animator.slide_out_left,
                            R.animator.slide_in_left, R.animator.slide_out_right);
                    ft.replace(R.id.main_frame, fragment).addToBackStack(null).commit();
                    this.getFragmentManager().executePendingTransactions();
                });
    }

    @Override
    protected void onDestroy() {
        AdView adView = (AdView) findViewById(R.id.adView);
        if (adView != null) {
            adView.destroy();
        }

        if (billing != null)
            billing.onDestroy();

        super.onDestroy();
    }

    public void setActiveChapterId(int activeChapterId) {
        AnimatedExpandableListView listView = (AnimatedExpandableListView) findViewById(
                R.id.nav_drawer_animated_listview);
        AnimatedExpandableListAdapter adapter = (AnimatedExpandableListAdapter) listView.getExpandableListAdapter();
        if (adapter != null) {
            adapter.setCurrentChapterId(activeChapterId);
            adapter.notifyDataSetChanged();
        }
    }
}