git.egatuts.nxtremotecontroller.activity.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for git.egatuts.nxtremotecontroller.activity.MainActivity.java

Source

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *  Copyright (c) 2014 EgaTuts & Esa Garca - All Rights Reserved                 *
 *                                                                                 *
 *  Open-source code licensed under the MIT License (the "License").               *
 *                                                                                 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy   *
 *  of this software and associated documentation files (the "Software"), to deal  *
 *  in the Software without restriction, including without limitation the rights   *
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      *
 *  copies of the Software, and to permit persons to whom the Software is          *
 *  furnished to do so, subject to the following conditions:                       *
 *                                                                                 *
 *  The above copyright notice and this permission notice shall be included in     *
 *  all copies or substantial portions of the Software.                            *
 *                                                                                 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     *
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       *
 *  FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 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.                                                                  *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *  You can find the entire project at:                                                                                                                        *
 *                                                                                                                                                             *
 *    https://github.com/Egatuts/nxt-remote-controller                                                                                                         *
 *                                                                                                                                                             *
 *  And the corresponding file at:                                                                                                                             *
 *                                                                                                                                                             *
 *    https://github.com/Egatuts/nxt-remote-controller/blob/master/Android%20App/app/src/main/java/git/egatuts/nxtremotecontroller/activity/MainActivity.java  *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package git.egatuts.nxtremotecontroller.activity;

import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;

import com.andexert.library.RippleView;

import git.egatuts.nxtremotecontroller.R;
import git.egatuts.nxtremotecontroller.device.PairedDevice;
import git.egatuts.nxtremotecontroller.device.PairedDeviceAdapter;
import git.egatuts.nxtremotecontroller.fragment.ActivityBaseFragment;
import git.egatuts.nxtremotecontroller.fragment.BluetoothFragment;
import git.egatuts.nxtremotecontroller.fragment.DefaultFragmentPendingTransition;
import git.egatuts.nxtremotecontroller.fragment.FragmentPendingTransition;
import git.egatuts.nxtremotecontroller.fragment.HomeFragment;
import git.egatuts.nxtremotecontroller.fragment.ScanFragment;
import git.egatuts.nxtremotecontroller.listener.AppKillerListener;
import git.egatuts.nxtremotecontroller.listener.BluetoothEnableListener;
import git.egatuts.nxtremotecontroller.navigation.NavigationDrawerCallback;
import git.egatuts.nxtremotecontroller.navigation.NavigationDrawerFragment;
import git.egatuts.nxtremotecontroller.receiver.AppKillerReceiver;
import git.egatuts.nxtremotecontroller.receiver.BluetoothEnableReceiver;
import git.egatuts.nxtremotecontroller.views.BaseIndeterminateProgressDialog;

/*
 *  Main activity created when the app is called from the android launcher.
 *  It loads a fragment based on the clicked option from the drawer menu.
 *  Keep in mind that it doesn't load by default a fragment, it relays
 *  on the NavigationDrawerCallback#onNavigationItemSelected.
 */
public class MainActivity extends BaseActivity implements NavigationDrawerCallback, ActivityPendingTransition {

    public static final String ACTION_RESTART_APP = "restart_app";
    public static final String URL_HELP = "https://github.com/Egatuts/nxt-remote-controller";
    public static final String URL_DONATE = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9VPAAPMYC2HEJ";

    public static final String PREFERENCE_BLUETOOTH_DISABLE_KEY = "preference_disable_bluetooth";
    public static final boolean PREFERENCE_BLUETOOTH_DISABLE_VALUE = false;
    public static final String PREFERENCE_START_DISCOVERY_KEY = "preference_auto_discovery";
    public static final boolean PREFERENCE_START_DISCOVERY_VALUE = true;

    private static final int NAVIGATION_HOME = 0;
    private static final int NAVIGATION_SCAN = 1;
    private static final int NAVIGATION_SETTINGS = 2;
    private static final int NAVIGATION_HELP = 3;
    private static final int NAVIGATION_DONATE = 4;

    private NavigationDrawerFragment drawerFragment;
    private PairedDeviceAdapter devicesAdapter;
    private ActivityBaseFragment selectedFragment;
    private ActivityBaseFragment activeFragment;
    private ActivityBaseFragment lastFragment;
    private Intent intent;
    private Intent controlIntent;
    private AppKillerReceiver appKillerReceiver;
    private boolean selfDestroyed = false;
    private ProgressDialog.OnDismissListener progressDialogOnDismiss;
    private RippleView rippleView;
    private RippleView.AnimationFinishListener rippleViewListener;
    private PairedDevice device;
    private BluetoothEnableReceiver bluetoothEnableReceiver;
    private long showingTime;

    /*
     *  Getter and setter for the lastFragment property.
     */
    public void setLastFragment(ActivityBaseFragment fragment) {
        this.lastFragment = fragment;
    }

    public ActivityBaseFragment getLastFragment() {
        return this.lastFragment;
    }

    /*
     *  Getter and setter for the activeFragment property.
     */
    public void setActiveFragment(ActivityBaseFragment fragment) {
        this.activeFragment = fragment;
    }

    public ActivityBaseFragment getActiveFragment() {
        return this.activeFragment;
    }

    /*
     *  Saves the adapter.
     */
    public void saveAdapter(PairedDeviceAdapter adapter) {
        this.devicesAdapter = adapter;
    }

    /*
     *  Replaces a fragment with a new one using optional transitions.
     */
    public void replaceFragmentWith(int id, ActivityBaseFragment fragment,
            FragmentPendingTransition transitionInterface) {
        FragmentPendingTransition transition = transitionInterface != null ? transitionInterface
                : new DefaultFragmentPendingTransition();
        int[] transitions = transition.onForward(fragment);
        this.activeFragment = fragment;
        this.fragmentManager.beginTransaction().setCustomAnimations(transitions[0], transitions[1])
                .replace(id, fragment).commit();
    }

    public void replaceFragmentWith(ActivityBaseFragment fragment, FragmentPendingTransition transitionInterface) {
        this.replaceFragmentWith(R.id.main_container, fragment, transitionInterface);
    }

    /*
     *  Starts the controller activity resetting all the variables used to work with the listeners :(.
     */
    private void startControlDevice(Intent intent) {
        this.device = null;
        this.rippleView = null;
        this.controlIntent = null;
        super.startActivity(intent, this);
    }

    /*
     *  Checks if the RippleView is running the ripple animation
     */
    public void controlDevice(final RippleView view, final PairedDevice device) {
        final MainActivity self = this;
        final Intent intent = new Intent(this, ControllerActivity.class);
        intent.putExtra("device", device);
        this.controlIntent = intent;
        if (!view.isRunning()) {
            self.startControlDevice(intent);
        } else {
            view.setAnimationFinishListener(self.rippleViewListener);
        }
    }

    /*
     *  We set the forward transition depending of which activity we are going to start.
     */
    @Override
    public int[] onForward(Intent intent) {
        /*
         *  Here we check which activity is starting comparing the full class names (including package).
         *  If we are generating an intent adding a category the defClass statement
         *  will generate and propagate a NullPointerException. FUCK IT!
         */
        try {
            String defClass = intent.getComponent().getClassName();
            if (defClass.equals(SettingsActivity.class.getName())) {
                return new int[] { R.anim.settings_transition_in, R.anim.settings_transition_out };
            } else if (defClass.equals(ControllerActivity.class.getName())) {
                return new int[] { R.anim.controller_transition_in, R.anim.controller_transition_out };
            }
        } catch (NullPointerException e) {
            //e.printStackTrace();
        }
        return new int[] {};
    }

    @Override
    public int[] onBackward() {
        return new int[] {};
    }

    /*
     *  When the configuration has changed (orientation) we
     *  should communicate that to the drawer fragment.
     */
    @Override
    public void onConfigurationChanged(Configuration configuration) {
        super.onConfigurationChanged(configuration);
        this.drawerFragment.getActionBarDrawerToggle().onConfigurationChanged(configuration);
    }

    /*
     *  We enable drawer opening/closing with the physical button available in some devices.
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            if (this.drawerFragment.isDrawerOpened()) {
                this.drawerFragment.closeDrawer();
            } else {
                this.drawerFragment.openDrawer();
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /*
     *  We also enable closing drawer with the back button.
     */
    @Override
    public void onBackPressed() {
        if (this.drawerFragment.isDrawerOpened()) {
            this.drawerFragment.closeDrawer();
        }
        super.onBackPressed();
    }

    /*
     *  When the creation process has finished we sync the state of the drawer toggle.
     */
    @Override
    public void onPostCreate(Bundle savedInstanceState) {
        this.drawerFragment.getActionBarDrawerToggle().syncState();
        this.appKillerReceiver.registerReceiver();
        super.onPostCreate(savedInstanceState);
    }

    /*
     *  When the drawer is opened. Take in mind that this method
     *  will execute only when the opening animation has finished.
     */
    @Override
    public void onOpenDrawer() {
    }

    /*
     *  When the drawer is closed. Take in mind that this method
     *  will execute only when the closing animation has finished.
     */
    @Override
    public void onCloseDrawer() {
        if (this.intent == null)
            return;
        super.startActivity(this.intent, this);
        this.selfDestroyed = true;
        if (this.intent.getAction() == "")
            super.finish();
        this.intent = null;
    }

    /*
     *  Executed when a new item has been selected from the navigation drawer.
     */
    @Override
    public void onNavigationDrawerItemSelected(int position) {
        this.selectedFragment = null;
        this.intent = null;

        /*
         *  We try to know which option has been clicked. there is two possible actions.
         *  Change the fragment or change the activity.
         */
        switch (position) {
        case MainActivity.NAVIGATION_HOME:
            this.selectedFragment = new HomeFragment();
            break;
        case MainActivity.NAVIGATION_SCAN:
            boolean autoStart = this.getPreferencesEditor().getBoolean(MainActivity.PREFERENCE_START_DISCOVERY_KEY,
                    MainActivity.PREFERENCE_START_DISCOVERY_VALUE);
            this.selectedFragment = ScanFragment.newInstance(this.devicesAdapter, autoStart);
            break;
        case MainActivity.NAVIGATION_SETTINGS:
            this.intent = new Intent(this, SettingsActivity.class);
            break;
        case MainActivity.NAVIGATION_HELP:
            this.intent = new Intent(Intent.ACTION_VIEW);
            this.intent.setData(Uri.parse(MainActivity.URL_HELP));
            break;
        case MainActivity.NAVIGATION_DONATE:
            this.intent = new Intent(Intent.ACTION_VIEW);
            this.intent.setData(Uri.parse(MainActivity.URL_DONATE));
            break;
        default:
            break;
        }

        /*
         *  We check which of the two actions we should execute.
         */
        if (this.activeFragment != null && this.selectedFragment != null && !this.bluetoothUtils.isEnabled()) {
            return;
        }
        if (this.selectedFragment != null) {
            if (this.activeFragment != null) {
                this.activeFragment.replaceFragmentWith(this.selectedFragment);
            } else {
                this.replaceFragmentWith(this.selectedFragment, null);
            }
        }
    }

    /*
     *  We listen for changes when the activity is visible.
     */
    @Override
    public void onResume() {
        super.onResume();
        this.bluetoothEnableReceiver.registerReceiver();
    }

    /*
     *  We stop listening for bluetooth changes when the activity is no longer visible.
     */
    @Override
    public void onStop() {
        this.bluetoothEnableReceiver.unregisterReceiver();
        super.onStop();
    }

    /*
     *  When the activity is destroyed we unregister the receiver.
     */
    @Override
    public void onDestroy() {
        this.appKillerReceiver.unregisterReceiver();
        super.onDestroy();
        boolean autoDisable = this.getPreferencesEditor().getBoolean(MainActivity.PREFERENCE_BLUETOOTH_DISABLE_KEY,
                MainActivity.PREFERENCE_BLUETOOTH_DISABLE_VALUE);
        if (!this.selfDestroyed && autoDisable)
            this.getBluetoothUtils().disable();
    }

    /*
     *  When the activity is created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        final MainActivity self = this;
        super.onCreate(savedInstanceState);
        super.setActiveTheme(super.getPreferenceTheme());
        super.setContentView(R.layout.main_layout);
        toolbar = (Toolbar) super.findViewById(R.id.toolbar);
        this.setSupportToolbar();
        this.drawerFragment = (NavigationDrawerFragment) fragmentManager.findFragmentById(R.id.drawer_fragment);
        this.drawerFragment.setup(R.id.drawer_fragment, (DrawerLayout) super.findViewById(R.id.drawer_element),
                this.toolbar);
        this.appKillerReceiver = new AppKillerReceiver(this, new AppKillerListener() {
            @Override
            public void onAppNeedsRestart(Context context, Intent intent) {
                self.selfDestroyed = true;
                self.finish();
            }
        });
        this.progressDialogOnDismiss = new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                self.getShortProgressDialog().setOnDismissListener(null);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        self.replaceFragmentWith(self.selectedFragment, self.activeFragment);
                    }
                }, 200);
            }
        };
        this.bluetoothEnableReceiver = new BluetoothEnableReceiver(this, new BluetoothEnableListener() {
            @Override
            public void onStateChange(Context context, Intent intent) {
                int state = (int) self.bluetoothEnableReceiver.getIntentData(intent);
                final BaseIndeterminateProgressDialog progress = self.getShortProgressDialog();
                Integer text = null;
                int hasToChange = 0;
                boolean hasToShow = false;

                /*
                 *  We define if we have to change the fragment or we have to show a progress dialog.
                 */
                switch (state) {
                case BluetoothAdapter.STATE_OFF:
                    hasToChange = 2;
                    break;
                case BluetoothAdapter.STATE_ON:
                    hasToChange = 1;
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    hasToShow = true;
                    text = R.string.bluetooth_disabling;
                    break;
                case BluetoothAdapter.STATE_TURNING_ON:
                    hasToShow = true;
                    text = R.string.bluetooth_enabling;
                    break;
                }

                /*
                 *  Here we have to show a progress dialog indicating that the bluetooth state is changing.
                 */
                if (hasToShow && text != null) {
                    self.showingTime = System.currentTimeMillis();
                    progress.show();
                    progress.setText(text);
                } else if (hasToChange != 0) {
                    if (hasToChange == 1)
                        self.selectedFragment = self.lastFragment;
                    if (hasToChange == 2)
                        self.selectedFragment = new BluetoothFragment();
                    if (!hasToShow && progress.isShowing()) {
                        progress.setOnDismissListener(self.progressDialogOnDismiss);
                        if (System.currentTimeMillis() - self.showingTime < 500) {
                            new Handler().postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    progress.dismiss();
                                }
                            }, 750);
                        } else {
                            progress.dismiss();
                        }
                    }
                }
            }
        });
        this.rippleViewListener = new RippleView.AnimationFinishListener() {
            @Override
            public void onFinish() {
                self.startControlDevice(self.controlIntent);
            }
        };
    }

}