uk.ac.hutton.ics.buntata.activity.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.hutton.ics.buntata.activity.MainActivity.java

Source

/*
 * Copyright 2016 Information & Computational Sciences, The James Hutton Institute
 *
 * 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 uk.ac.hutton.ics.buntata.activity;

import android.*;
import android.app.*;
import android.content.*;
import android.content.pm.*;
import android.os.*;
import android.support.annotation.*;
import android.support.design.widget.*;
import android.support.v4.app.*;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.*;
import android.support.v4.util.Pair;
import android.support.v4.view.*;
import android.support.v7.widget.*;
import android.util.*;
import android.view.*;

import com.google.zxing.integration.android.*;

import java.util.*;

import butterknife.*;
import jhi.buntata.resource.*;
import uk.ac.hutton.ics.buntata.R;
import uk.ac.hutton.ics.buntata.database.entity.*;
import uk.ac.hutton.ics.buntata.database.manager.*;
import uk.ac.hutton.ics.buntata.fragment.*;
import uk.ac.hutton.ics.buntata.service.*;
import uk.ac.hutton.ics.buntata.util.*;

/**
 * The {@link MainActivity} is the main view of the app. It shows the categories and let's the user navigate to the leaf nodes which then show
 * information about the item.
 *
 * @author Sebastian Raubach
 */
public class MainActivity extends DrawerActivity implements OnFragmentChangeListener {
    private static final int REQUEST_CODE_INTRO = 1;
    private static final int REQUEST_CODE_SELECT_DATASOURCE = 2;
    private static final int REQUEST_CODE_DETAILS = 3;
    private static final int REQUEST_CODE_CAMERA_SCAN_PERMISSIONS = 4;

    private int datasourceId = -1;

    public static boolean override = false;
    private static long lastUpdateCheck = 0;
    private String query = null;

    @BindView(R.id.main_view_fab)
    FloatingActionButton fab;
    private SearchView searchView;

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

        ButterKnife.bind(this);

        /* Make sure the default preferences are set */
        PreferenceUtils.setDefaults(this);
        NodeManager.clearCaches();
        DatasourceService.init(this);

        /* Initialize the internal database for track history keeping */
        new LogEntryManager(this).initializeDatabase();

        DatasourceService.getAllAdvanced(this, false, false,
                new RemoteCallback<List<BuntataDatasourceAdvanced>>(this) {
                    @Override
                    public void onSuccess(List<BuntataDatasourceAdvanced> result) {
                        boolean updateAvailable = false;

                        for (BuntataDatasourceAdvanced adv : result) {
                            updateAvailable = adv
                                    .getState() == BuntataDatasourceAdvanced.InstallState.INSTALLED_HAS_UPDATE;

                            if (updateAvailable)
                                break;
                        }

                        long timeSince = System.currentTimeMillis() - lastUpdateCheck;

                        /* Only check for updates if it has been at least 2 hours */
                        if (updateAvailable && timeSince > 1000 * 60 * 60 * 2) {
                            /* Show a Snackbar with a button to open the datasource activity */
                            int textColor = ContextCompat.getColor(MainActivity.this,
                                    android.R.color.primary_text_dark);
                            SnackbarUtils.create(getSnackbarParentView(), R.string.snackbar_updates_available,
                                    textColor, ContextCompat.getColor(MainActivity.this, R.color.colorPrimaryDark),
                                    5000).setAction(R.string.generic_show, new View.OnClickListener() {
                                        @Override
                                        public void onClick(View v) {
                                            startActivityForResult(
                                                    new Intent(getApplicationContext(), DatasourceActivity.class),
                                                    REQUEST_DATA_SOURCE);
                                        }
                                    }).setActionTextColor(textColor).show();

                            lastUpdateCheck = System.currentTimeMillis();
                        }
                    }
                });
    }

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

        //      if (PreferenceUtils.getPreferenceAsBoolean(this, PreferenceUtils.PREFS_SHOW_DATASOURCE_SELECTION_HELP, true))
        //      {
        //         drawerLayout.openDrawer(Gravity.START);
        //
        //         navigationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
        //         {
        //            @Override
        //            public void onGlobalLayout()
        //            {
        //               navigationView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        //
        //               /* Show a Snackbar with a button to open the datasource activity */
        //               int textColor = ContextCompat.getColor(MainActivity.this, android.R.color.primary_text_dark);
        //               SnackbarUtils.create(getSnackbarParentView(), R.string.snackbar_updates_available, textColor, ContextCompat.getColor(MainActivity.this, R.color.colorPrimaryDark), 5000)
        //                         .setActionTextColor(textColor)
        //                         .show();
        //
        //               PreferenceUtils.setPreferenceAsBoolean(MainActivity.this, PreferenceUtils.PREFS_SHOW_DATASOURCE_SELECTION_HELP, false);
        //            }
        //         });
        //      }
    }

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

        init();
    }

    private void init() {
        boolean showIntro = !PreferenceUtils.getPreferenceAsBoolean(this, PreferenceUtils.PREFS_EULA_ACCEPTED,
                false);

        if (showIntro) {
            /* Show the intro */
            startActivityForResult(new Intent(getApplicationContext(), IntroductionActivity.class),
                    REQUEST_CODE_INTRO);
        } else {
            /* Get the selected data source */
            int datasourceId = PreferenceUtils.getPreferenceAsInt(this,
                    PreferenceUtils.PREFS_SELECTED_DATASOURCE_ID, -1);

            /* If no valid source is selected, open the data source activity */
            if (datasourceId == -1) {
                startActivityForResult(new Intent(getApplicationContext(), DatasourceActivity.class),
                        REQUEST_CODE_SELECT_DATASOURCE);
            } else {
                /* Else check if this is an override call. If so, recreate the activity */
                if (override) {
                    Intent intent = getIntent();
                    finish();
                    startActivity(intent);
                }
                /* Else if the data source changed, update the content */
                else if (datasourceId != this.datasourceId) {
                    updateContent(null, null, datasourceId, -1, -1);
                }
            }

            /* Remember the new data source and disable override */
            this.datasourceId = datasourceId;
            override = false;
        }

        showWhatsNew();
    }

    protected void showWhatsNew() {
        try {
            /* Get the versionCode of the Package, which must be different (incremented) in each release on the market in the AndroidManifest.xml */
            final PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(),
                    PackageManager.GET_ACTIVITIES);

            int lastVersionCode = PreferenceUtils.getPreferenceAsInt(this, PreferenceUtils.PREFS_LAST_VERSION, -1);

            /* If this is the first start, show nothing just remember the version number */
            if (lastVersionCode == -1) {
                PreferenceUtils.setPreferenceAsInt(this, PreferenceUtils.PREFS_LAST_VERSION,
                        packageInfo.versionCode);
            }
            /* Else show what's new if version numbers differ */
            else {
                if (packageInfo.versionCode > lastVersionCode) {
                    startActivity(new Intent(getApplicationContext(), ChangelogActivity.class));
                }
            }

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * Updates the main view's content
     *
     * @param transitionRoot The view to use as the transition root in case we're navigating to a leaf node
     * @param datasourceId   The current data source id
     * @param parentId       The id of the parent node
     */
    private void updateContent(View transitionRoot, final View title, int datasourceId, int parentId,
            int mediumId) {
        if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            fab.hide();
        else
            fab.show();

        /* Check if this node has children */
        List<BuntataNodeAdvanced> children = new NodeManager(this, datasourceId).getForParent(parentId);
        boolean hasChildren = parentId == -1 || children.size() > 0;

        BuntataDatasource datasource = new DatasourceManager(this, datasourceId).getById(datasourceId);
        boolean skipSingleChild = children.size() == 1 && !datasource.isShowSingleChild();

        /* If it doesn't */
        if (!hasChildren || skipSingleChild) {
            /* If it's only got one child, jump straight to it */
            if (skipSingleChild)
                parentId = children.get(0).getId();

            /* If it's a leaf node, open the details activity */
            Intent intent = new Intent(getApplicationContext(), NodeDetailsActivity.class);

            /* Pass parameters */
            Bundle args = new Bundle();
            args.putInt(NodeDetailsActivity.PARAM_NODE_ID, parentId);
            args.putInt(NodeDetailsActivity.PARAM_DATASOURCE_ID, datasourceId);
            args.putInt(NodeDetailsActivity.PARAM_PREFERED_FIRST_MEDIUM, mediumId);
            intent.putExtras(args);

            /* Depending on the android version, transition views or just slide */
            List<Pair<View, String>> pairs = new ArrayList<>();
            pairs.add(Pair.create(transitionRoot, getString(R.string.transition_node_view)));
            pairs.add(Pair.create(transitionRoot, getString(R.string.transition_node_details_view)));

            if (title.getVisibility() == View.VISIBLE)
                pairs.add(Pair.create(title, "t_node_title"));

            pairs.add(Pair.create((View) toolbar, "t_toolbar"));

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                View decor = getWindow().getDecorView();

                View navigationBar = decor.findViewById(android.R.id.navigationBarBackground);
                if (navigationBar != null)
                    pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));

                View statusBar = decor.findViewById(android.R.id.statusBarBackground);
                if (statusBar != null)
                    pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
            }

            ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this,
                    pairs.toArray(new Pair[pairs.size()]));

            startActivityForResult(intent, REQUEST_CODE_DETAILS, options.toBundle());
        } else {
            /* Add a new fragment */
            Fragment fragment = new NodeFragment();

            /* Pass parameters */
            Bundle args = new Bundle();
            args.putInt(NodeFragment.PARAM_PARENT_ID, parentId);
            args.putInt(NodeFragment.PARAM_DATASOURCE_ID, datasourceId);
            fragment.setArguments(args);

            /* Add a slide transition */
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);
            ft.addToBackStack(fragment.toString());
            ft.replace(R.id.fragment_holder, fragment, fragment.toString()).commit();
        }
    }

    @OnClick(R.id.main_view_fab)
    public void onFabClicked() {
        while (getSupportFragmentManager().getBackStackEntryCount() > 1)
            onBackPressed();
    }

    @Override
    public void onBackPressed() {
        if (getSupportFragmentManager().getBackStackEntryCount() > 2)
            fab.show();
        else
            fab.hide();

        /* If there's only one item left on the stack, finish as there's nothing to go back to */
        if (getSupportFragmentManager().getBackStackEntryCount() == 1)
            finish();
        /* Else, just let the parent handle things */
        else
            super.onBackPressed();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        switch (requestCode) {
        case REQUEST_CODE_CAMERA_SCAN_PERMISSIONS: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                /* Permission granted */
                scanBarcode();
            } else {
                int foreground = ContextCompat.getColor(this, android.R.color.white);
                int background = ContextCompat.getColor(this, R.color.snackbar_red);
                SnackbarUtils.show(getSnackbarParentView(), getString(R.string.snackbar_permission_missing_camera),
                        foreground, background, Snackbar.LENGTH_LONG);
            }

            break;
        }

        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private void scanBarcode() {
        /* Add the third-party barcode scanner */
        IntentIntegrator integrator = new IntentIntegrator(this);
        integrator.initiateScan();
        GoogleAnalyticsUtils.trackEvent(this, getTracker(TrackerName.APP_TRACKER),
                getString(R.string.ga_event_category_scan), getString(R.string.ga_event_action_scan_camera));
    }

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

        IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        /* See if it's the camera barcode scanner */
        if (scanResult != null && resultCode == Activity.RESULT_OK) {
            if (searchView != null)
                searchView.setQuery(scanResult.getContents(), true);
        } else {
            switch (requestCode) {
            case REQUEST_CODE_INTRO:
                if (resultCode == RESULT_OK) {
                    //               PreferenceUtils.setPreferenceAsBoolean(this, PreferenceUtils.PREFS_AT_LEAST_ONE_DATASOURCE, true);
                } else {
                    PreferenceUtils.setPreferenceAsBoolean(this, PreferenceUtils.PREFS_AT_LEAST_ONE_DATASOURCE,
                            false);
                    /* User cancelled the intro so we'll finish this activity too. */
                    finish();
                }
                break;
            case REQUEST_CODE_SELECT_DATASOURCE:
            case REQUEST_DATA_SOURCE:
                if (resultCode != RESULT_OK) {
                    startActivityForResult(new Intent(getApplicationContext(), DatasourceActivity.class),
                            REQUEST_CODE_SELECT_DATASOURCE);
                } else {
                    override = true;
                }
                break;
            case REQUEST_CODE_DETAILS:
                /* We're coming back from the details view, so don't add anything */
                break;
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        /* Inflate the menu */
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.main_menu, menu);

        /* Find the search menu item */
        final MenuItem searchItem = menu.findItem(R.id.action_search);

        /* Get the search manager */
        SearchManager searchManager = (SearchManager) MainActivity.this.getSystemService(Context.SEARCH_SERVICE);

        /* Get the actual search view */
        searchView = (SearchView) MenuItemCompat.getActionView(searchItem);

        if (searchView != null) {
            DisplayMetrics displayMetrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

            final MenuItem barcodeItem = menu.findItem(R.id.action_scan_barcode);

            searchView.setMaxWidth(displayMetrics.widthPixels / 2);
            searchView.setSearchableInfo(searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
            searchView.setQueryHint(getString(R.string.search_query_hint));
            /* Listen to submit events */
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    /* Trim leading and trailing spaces that some keyboards will add */
                    query = query.trim();

                    MainActivity.this.query = query;
                    filter(query);

                    searchView.clearFocus();

                    return false;
                }

                @Override
                public boolean onQueryTextChange(String s) {
                    /* Close the search field when the search string is empty */
                    if (StringUtils.isEmpty(s)) {
                        searchView.setIconified(true);
                        searchView.clearFocus();
                    }
                    return false;
                }
            });
            searchView.setOnCloseListener(new SearchView.OnCloseListener() {
                @Override
                public boolean onClose() {
                    MainActivity.this.query = null;
                    filter("");
                    barcodeItem.setVisible(false);

                    return false;
                }
            });

            searchView.setOnSearchClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    barcodeItem.setVisible(true);
                }
            });
        }

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_scan_barcode:
            scanBarcodePrePermission();

            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void scanBarcodePrePermission() {
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            /* Request the permission */
            if (!deniedPermissions.contains(Manifest.permission.CAMERA))
                ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA },
                        REQUEST_CODE_CAMERA_SCAN_PERMISSIONS);

            return;
        }

        scanBarcode();
    }

    public String getFilter() {
        return query;
    }

    private void filter(String query) {
        /* Get the current fragment with this horrible construct */
        String tag = getSupportFragmentManager()
                .getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
        NodeFragment fragment = (NodeFragment) getSupportFragmentManager().findFragmentByTag(tag);

        /* Then filter it */
        fragment.filter(query);

        if (!StringUtils.isEmpty(query)) {
            GoogleAnalyticsUtils.trackEvent(this, getTracker(BaseActivity.TrackerName.APP_TRACKER),
                    getString(R.string.ga_event_category_node_search), "Datasource: " + datasourceId, query);
        }
    }

    @Override
    protected Integer getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected Integer getToolbarId() {
        return R.id.toolbar;
    }

    @Override
    public void onFragmentChange(View transitionRoot, View title, int datasourceId, int parentId, int mediumId) {
        updateContent(transitionRoot, title, datasourceId, parentId, mediumId);
    }
}