uk.ac.horizon.artcodes.activity.NavigationActivity.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.horizon.artcodes.activity.NavigationActivity.java

Source

/*
 * Artcodes recognises a different marker scheme that allows the
 * creation of aesthetically pleasing, even beautiful, codes.
 * Copyright (C) 2013-2016  The University of Nottingham
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published
 *     by the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package uk.ac.horizon.artcodes.activity;

import android.accounts.AccountManager;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.HeaderViewListAdapter;
import android.widget.ListView;

import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;

import java.util.List;

import uk.ac.horizon.artcodes.Feature;
import uk.ac.horizon.artcodes.GoogleAnalytics;
import uk.ac.horizon.artcodes.R;
import uk.ac.horizon.artcodes.account.Account;
import uk.ac.horizon.artcodes.databinding.NavigationBinding;
import uk.ac.horizon.artcodes.fragment.ExperienceLibraryFragment;
import uk.ac.horizon.artcodes.fragment.ExperienceRecentFragment;
import uk.ac.horizon.artcodes.fragment.ExperienceRecommendFragment;
import uk.ac.horizon.artcodes.fragment.ExperienceSearchFragment;
import uk.ac.horizon.artcodes.fragment.ExperienceStarFragment;
import uk.ac.horizon.artcodes.fragment.FeatureListFragment;
import uk.ac.horizon.artcodes.server.LoadCallback;

public class NavigationActivity extends ArtcodeActivityBase
        implements NavigationView.OnNavigationItemSelectedListener {
    private static final int REQUEST_CODE_SIGN_IN = 63;
    private static final int REQUEST_CODE_PICK_ACCOUNT = 67;
    private static final long DRAWER_CLOSE_DELAY_MS = 250;
    private static final String NAV_ITEM_ID = "navItemId";

    private final Handler drawerActionHandler = new Handler();
    private NavigationBinding binding;
    private ActionBarDrawerToggle drawerToggle;
    private MenuItem selected;

    private static final String FRAGMENT_TAG = "fragment";
    private static final Handler searchHandler = new Handler();

    private GoogleApiClient apiClient;

    @Override
    public void onBackPressed() {
        if (binding.drawer.isDrawerOpen(GravityCompat.START)) {
            binding.drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public void onConfigurationChanged(final Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onNavigationItemSelected(final MenuItem menuItem) {
        if (menuItem != null) {
            if (menuItem.isCheckable()) {
                if (selected != null) {
                    selected.setChecked(false);
                }

                selected = menuItem;
                menuItem.setChecked(true);
            }
            drawerActionHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    navigate(menuItem, true);
                }
            }, DRAWER_CLOSE_DELAY_MS);
        }

        binding.drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        if (item.getItemId() == android.support.v7.appcompat.R.id.home) {
            return drawerToggle.onOptionsItemSelected(item);
        }
        return super.onOptionsItemSelected(item);
    }

    private void updateAccounts() {
        final Menu menu = binding.navigation.getMenu();
        final MenuItem libraries = menu.findItem(R.id.nav_libraries);
        final SubMenu subMenu = libraries.getSubMenu();

        while (subMenu.size() > 0) {
            subMenu.removeItem(subMenu.getItem(0).getItemId());
        }

        final List<Account> accounts = getServer().getAccounts();
        for (int index = 0; index < accounts.size(); index++) {
            final Account account = accounts.get(index);
            final MenuItem menuItem = subMenu.add(R.id.navigation, index, Menu.NONE, account.getDisplayName());
            if (account.getId().equals("local")) {
                menuItem.setIcon(R.drawable.ic_folder_24dp);
            } else {
                menuItem.setIcon(R.drawable.ic_cloud_24dp);
            }
            menuItem.setCheckable(true);
        }

        final MenuItem menuItem = subMenu.add(R.id.navigation, R.id.nav_addaccount, Menu.NONE,
                R.string.nav_addaccount);
        menuItem.setIcon(R.drawable.ic_add_24dp);

        for (int i = 0, count = binding.navigation.getChildCount(); i < count; i++) {
            final View child = binding.navigation.getChildAt(i);
            if (child != null && child instanceof ListView) {
                final ListView menuView = (ListView) child;
                final HeaderViewListAdapter adapter = (HeaderViewListAdapter) menuView.getAdapter();
                final BaseAdapter wrapped = (BaseAdapter) adapter.getWrappedAdapter();
                wrapped.notifyDataSetChanged();
            }
        }

        getServer().loadRecent(new LoadCallback<List<String>>() {
            @Override
            public void loaded(List<String> item) {
                final MenuItem recent = menu.findItem(R.id.nav_recent);
                if (recent != null) {
                    recent.setVisible(!item.isEmpty());
                }
            }

            @Override
            public void error(Throwable e) {
                GoogleAnalytics.trackException(e);
            }
        });
        getServer().loadStarred(new LoadCallback<List<String>>() {
            @Override
            public void loaded(List<String> item) {
                final MenuItem starred = menu.findItem(R.id.nav_starred);
                if (starred != null) {
                    starred.setVisible(!item.isEmpty());
                }
            }

            @Override
            public void error(Throwable e) {
                GoogleAnalytics.trackException(e);
            }
        });
    }

    @Override
    protected void onNewIntent(Intent intent) {
        Log.i("a", "New intent " + intent);
        super.onNewIntent(intent);
    }

    public void navigate(Fragment fragment, boolean addToBackStack) {
        if (addToBackStack) {
            getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment, FRAGMENT_TAG)
                    .addToBackStack(null).commit();
        } else {
            getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment, FRAGMENT_TAG).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        final MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.search_menu, menu);

        final MenuItem searchItem = menu.findItem(R.id.search);
        final SearchView searchView = (SearchView) searchItem.getActionView();
        final SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            private Runnable delayedAction = null;

            @Override
            public boolean onQueryTextSubmit(String query) {
                search(query);
                return true;
            }

            @Override
            public boolean onQueryTextChange(final String newText) {
                if (delayedAction != null) {
                    searchHandler.removeCallbacks(delayedAction);
                    delayedAction = null;
                }

                if (newText.trim().length() > 3) {
                    delayedAction = new Runnable() {
                        @Override
                        public void run() {
                            search(newText);
                        }
                    };

                    searchHandler.postDelayed(delayedAction, 1000);
                }
                return true;
            }
        });
        MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionExpand(final MenuItem item) {
                return true;
            }

            @Override
            public boolean onMenuItemActionCollapse(final MenuItem item) {
                Log.i("a", "Closed");
                Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
                if (fragment instanceof ExperienceSearchFragment) {
                    getSupportFragmentManager().popBackStack();
                }
                return true;
            }
        });

        return true;

    }

    private void search(String query) {
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
        if (fragment instanceof ExperienceSearchFragment) {
            ((ExperienceSearchFragment) fragment).search(query);
        } else {
            ExperienceSearchFragment experienceSearchFragment = new ExperienceSearchFragment();
            experienceSearchFragment.setArguments(new Bundle());
            experienceSearchFragment.getArguments().putString("query", query);
            navigate(experienceSearchFragment, true);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
            if (resultCode == RESULT_OK) {
                if (data != null) {
                    if (data.hasExtra(AccountManager.KEY_ACCOUNT_NAME)) {
                        String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);

                        if (accountName != null) {
                            tryGoogleAccount(accountName, null);
                        }
                    }
                }
            }
        } else if (requestCode == REQUEST_CODE_SIGN_IN) {
            final GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.getSignInAccount() != null) {
                tryGoogleAccount(result.getSignInAccount().getEmail(), result.getSignInAccount().getDisplayName());
            }
        }
    }

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Feature.get(this, R.bool.feature_show_welcome).isEnabled()) {
            startActivity(new Intent(this, AboutArtcodesActivity.class));
            return;
        }

        binding = DataBindingUtil.setContentView(this, R.layout.navigation);

        setSupportActionBar(binding.toolbar);

        binding.navigation.setNavigationItemSelectedListener(this);

        final View headerView = binding.navigation.inflateHeaderView(R.layout.navigation_header);

        final MenuItem featureItem = binding.navigation.getMenu().findItem(R.id.nav_features);
        if (Feature.get(this, R.bool.feature_edit_features).isEnabled()) {
            featureItem.setVisible(true);
        } else {
            headerView.setLongClickable(true);
            headerView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    featureItem.setVisible(true);
                    Feature.get(getBaseContext(), R.bool.feature_edit_features).setEnabled(true);
                    return false;
                }
            });
        }

        updateAccounts();

        drawerToggle = new ActionBarDrawerToggle(this, binding.drawer, binding.toolbar, R.string.open,
                R.string.close) {
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                updateAccounts();
            }
        };
        binding.drawer.addDrawerListener(drawerToggle);

        drawerToggle.syncState();

        int navigationIndex = R.id.nav_home;
        if (savedInstanceState != null) {
            navigationIndex = savedInstanceState.getInt(NAV_ITEM_ID, R.id.nav_home);
        }
        MenuItem item = binding.navigation.getMenu().findItem(navigationIndex);
        if (item == null) {
            item = binding.navigation.getMenu().findItem(R.id.nav_home);
        }

        navigate(item, false);

        final GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.oauth_client_id)).requestEmail().requestProfile().build();

        apiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(@NonNull final ConnectionResult connectionResult) {
                        Log.i("Signin", "Failed " + connectionResult);
                    }
                }).addApi(Auth.GOOGLE_SIGN_IN_API, gso).build();
        apiClient.connect();

    }

    @Override
    protected void onSaveInstanceState(final Bundle outState) {
        super.onSaveInstanceState(outState);
        if (selected != null) {
            outState.putInt(NAV_ITEM_ID, selected.getItemId());
        }
    }

    private void tryGoogleAccount(final String name, final String displayName) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    final Account account = getServer().createAccount("google:" + name);
                    if (account.validates()) {
                        account.setDisplayName(displayName);
                        getServer().add(account);
                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                updateAccounts();
                                final Bundle bundle = new Bundle();
                                bundle.putString("account", account.getId());
                                final Fragment fragment = new ExperienceLibraryFragment();
                                fragment.setArguments(bundle);
                                navigate(fragment, true);
                            }
                        });
                    }
                } catch (UserRecoverableAuthException userRecoverableException) {
                    Log.i("intent", "Intent = " + userRecoverableException.getIntent());
                    startActivityForResult(userRecoverableException.getIntent(), REQUEST_CODE_PICK_ACCOUNT);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void selectAccount() {
        apiClient.clearDefaultAccountAndReconnect();
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(apiClient);
        startActivityForResult(signInIntent, REQUEST_CODE_SIGN_IN);
    }

    private void navigate(MenuItem item, boolean addToBackStack) {
        switch (item.getItemId()) {
        case R.id.nav_home:
            navigate(new ExperienceRecommendFragment(), addToBackStack);
            break;

        case R.id.nav_starred:
            navigate(new ExperienceStarFragment(), addToBackStack);
            break;

        case R.id.nav_features:
            navigate(new FeatureListFragment(), addToBackStack);
            break;

        case R.id.nav_recent:
            navigate(new ExperienceRecentFragment(), addToBackStack);
            break;

        case R.id.nav_about_artcodes:
            startActivity(new Intent(this, AboutArtcodesActivity.class));
            break;

        case R.id.nav_addaccount:
            selectAccount();
            break;

        default:
            final List<Account> accounts = getServer().getAccounts();
            if (item.getItemId() < accounts.size()) {
                final Account account = accounts.get(item.getItemId());
                Bundle bundle = new Bundle();
                bundle.putString("account", account.getId());
                final Fragment fragment = new ExperienceLibraryFragment();
                fragment.setArguments(bundle);
                navigate(fragment, addToBackStack);
            }
            break;
        }
    }
}