tkj.android.homecontrol.mythmote.MythMote.java Source code

Java tutorial

Introduction

Here is the source code for tkj.android.homecontrol.mythmote.MythMote.java

Source

/*
 * Copyright (C) 2010 Thomas G. Kenny Jr
 *
 * Licensed under the GNU General Public 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.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * 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 tkj.android.homecontrol.mythmote;

import java.util.ArrayList;
import java.util.List;

import tkj.android.homecontrol.mythmote.LocationChangedEventListener;
import tkj.android.homecontrol.mythmote.db.MythMoteDbHelper;
import tkj.android.homecontrol.mythmote.db.MythMoteDbManager;
import tkj.android.homecontrol.mythmote.keymanager.KeyBindingManager;
import tkj.android.homecontrol.mythmote.ui.AutoRepeatButton;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;

public class MythMote extends AbstractMythmoteFragmentActivity
        implements LocationChangedEventListener, MythCom.StatusChangedEventListener {

    public static final int SETTINGS_ID = Menu.FIRST;
    public static final int RECONNECT_ID = Menu.FIRST + 1;
    public static final int SELECTLOCATION_ID = Menu.FIRST + 2;
    public static final int DONATE_ID = Menu.FIRST + 3;
    public static final int SENDWOL_ID = Menu.FIRST + 4;
    public static final int KEYBOARD_INPUT_ID = Menu.FIRST + 5;
    public static final String LOG_TAG = "MythMote";
    public static final String EXTRA_LOCATION_NAME = "EXTRA_LOCATION_NAME";
    public static final String EXTRA_LOCATION_ADDRESS = "EXTRA_LOCATION_ADDRESS";
    public static final String EXTRA_LOCATION_PORT = "EXTRA_LOCATION_PORT";
    public static final String EXTRA_LOCATION_MAC = "EXTRA_LOCATION_MAC";

    private static final String KEY_VOLUME_DOWN = "[";
    private static final String KEY_VOLUME_UP = "]";
    private static final String DONATE_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TX7RH2TX6NJ2N&lc=US&item_name=mythmote%2ddonation&item_number=mythmote%2dgooglecodepage&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";

    private static FrontendLocation sLocation = new FrontendLocation();
    private static int sSelected = -1;
    private static boolean sIsScreenLarge = false;
    private static boolean sShowDonateMenuItem = true;
    //   private static PowerManager powerManager;
    //   private static PowerManager.WakeLock wakeLock;
    private static List<Fragment> sFragmentArrayList;
    private static List<String> sHeaderArrayList;
    private static Intent sIntent = null;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //get intent that started this activity
        sIntent = getIntent();

        //allow mythmote to be shown ontop of lock screen
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

        // determine if large screen layouts are being used
        sIsScreenLarge = this.getResources().getString(R.string.screensize).equals("large");
    }

    /**
     * Called when the activity is resumed
     */
    @Override
    public void onResume() {
        super.onResume();

        //set mythcom status handler
        MythCom mythCom = MythCom.GetMythCom(this);
        mythCom.SetOnStatusChangeHandler(this);

        //load and configure user interface
        this.setupContentView();

        // If intent is not null attempt to process it's data
        if (sIntent != null && sIntent.getAction() == "tkj.android.homecontrol.mythmote.CONNECT_TO_FRONTEND") {
            Log.d(MythMote.LOG_TAG, "Intent Action: " + sIntent.getAction());

            FrontendLocation intentFe = new FrontendLocation();
            intentFe.Name = sIntent.getStringExtra(EXTRA_LOCATION_NAME);
            intentFe.Address = sIntent.getStringExtra(EXTRA_LOCATION_ADDRESS);
            intentFe.Port = sIntent.getIntExtra(EXTRA_LOCATION_PORT, MythCom.DEFAULT_MYTH_PORT);
            intentFe.MAC = sIntent.getStringExtra(EXTRA_LOCATION_MAC);

            MythMoteDbManager dbAdapter = new MythMoteDbManager(this);
            dbAdapter.open();

            Cursor dbCursor = dbAdapter.fetchFrontendLocation(intentFe.Address, intentFe.Port);
            if (dbCursor != null && dbCursor.getCount() > 0) {
                //select found frontend
                sSelected = dbCursor.getInt(dbCursor.getColumnIndex(MythMoteDbHelper.KEY_ROWID));
                Log.d(MythMote.LOG_TAG, "Selecting existing frontend from Intent: " + intentFe.Address);
            } else {
                //add and selected provided frontend
                sSelected = (int) dbAdapter.createFrontendLocation(intentFe);
                Log.d(MythMote.LOG_TAG, "Created new frontend from Intent: " + intentFe.Address);
            }

            //save to preferences (required because setSelectedLocation() will overwrite sSelected)
            if (sSelected != -1) {
                this.getSharedPreferences(MythMotePreferences.MYTHMOTE_SHARED_PREFERENCES_ID, MODE_PRIVATE).edit()
                        .putInt(MythMotePreferences.PREF_SELECTED_LOCATION, sSelected).commit();
            }
        }

        // Here we disconnect if connected because the selected location
        // may have changed from the preference activity. setSelectedLocation()
        // will also trigger
        // loading any other changed preferences

        // disconnect if connected
        if (mythCom != null && (mythCom.IsConnected() || mythCom.IsConnecting())) {
            // force disconnected state
            mythCom.Disconnect();
        }

        // set selected location and connect
        if (this.setSelectedLocation())
            mythCom.Connect(sLocation);
    }

    /**
     * Called when the activity is paused
     */
    @Override
    public void onPause() {
        super.onPause();

        //clear intent
        sIntent = null;

        MythCom mythCom = MythCom.GetMythCom(this);

        if (mythCom != null && mythCom.IsConnected())
            mythCom.Disconnect();
    }

    /**
     * Called when the activity is being destroyed
     */
    @Override
    public void onDestroy() {
        super.onDestroy();

        MythCom mythCom = MythCom.GetMythCom(this);

        if (mythCom != null) {
            mythCom.ActivityOnDestroy();
        }

    }

    /**
     * Called when device configuration changes occur. Configuration changes
     * that cause this function to be called must be registered in
     * AndroidManifest.xml
     */
    public void onConfigurationChanged(Configuration config) {
        super.onConfigurationChanged(config);

        this.setupContentView();
    }

    /**
     * Overridden to allow the hardware volume controls to influence the Myth
     * front end volume control
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            MythCom.GetMythCom(this).SendKey(KEY_VOLUME_DOWN);
            return true;
        case KeyEvent.KEYCODE_VOLUME_UP:
            MythCom.GetMythCom(this).SendKey(KEY_VOLUME_UP);
            return true;
        default:
            return super.onKeyDown(keyCode, event);

        }
    }

    /**
     * Called to create the options menu once.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        boolean result = super.onCreateOptionsMenu(menu);

        // create reconnect menu item
        MenuItem menuItem = menu.add(0, RECONNECT_ID, 0, R.string.reconnect_str)
                .setIcon(R.drawable.ic_menu_refresh);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        }

        // create settings menu item
        menuItem = menu.add(0, SETTINGS_ID, 0, R.string.settings_menu_str)
                .setIcon(android.R.drawable.ic_menu_preferences);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        }

        // create keyboard input menu item
        menuItem = menu.add(0, KEYBOARD_INPUT_ID, 0, R.string.keyboard_input_str)
                .setIcon(R.drawable.ic_notification_ime_default);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        }

        // create select location menu item
        menuItem = menu.add(0, SELECTLOCATION_ID, 0, R.string.selected_location_str)
                .setIcon(R.drawable.ic_menu_home);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        }

        //create wake on lan menu item
        menuItem = menu.add(0, SENDWOL_ID, 0, R.string.send_wol_str).setIcon(R.drawable.ic_menu_sun);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

        }
        //menu.add(0, SENDWOL_RE_ID, 0, R.string.send_wol_re_str);
        //menu.add(0, SENDWOL_PJ_ID, 0, R.string.send_wol_pj_str);

        //add donate button if enabled
        if (sShowDonateMenuItem) {

        }

        // return results
        return result;
    }

    /**
     * Called when the menu is opened.
     */
    @Override
    public boolean onMenuOpened(int featureId, Menu menu) {

        if (null != menu) {

            //get donate menu item
            MenuItem menuItem = menu.findItem(DONATE_ID);

            //if donate menu item exists and the user wants it gone remove it
            if (null != menuItem && !sShowDonateMenuItem)
                menu.removeItem(DONATE_ID);

            //if the donate button is missing and the user wants it add it back
            if (null == menuItem && sShowDonateMenuItem)
                menu.add(0, DONATE_ID, 0, R.string.donate_menu_item_str).setIcon(R.drawable.paypal);
        }
        return super.onMenuOpened(featureId, menu);
    }

    /**
     * Called when a menu item is selected
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        try {
            // Check which menu item was selected
            switch (item.getItemId()) {
            case SETTINGS_ID:
                // Create mythmote preferences intent and start the activity
                Intent settingsIntent = new Intent(this,
                        tkj.android.homecontrol.mythmote.MythMotePreferences.class);
                this.startActivity(settingsIntent);
                break;

            case RECONNECT_ID:
                MythCom mythCom = MythCom.GetMythCom(this);
                if (mythCom.IsConnected() || mythCom.IsConnecting())
                    mythCom.Disconnect();

                // set selected location and connect
                if (this.setSelectedLocation())
                    mythCom.Connect(sLocation);
                break;

            case SELECTLOCATION_ID:
                // Displays the list of configured frontend locations.
                // Fires the locationChanged event when the user selects a
                // location
                // even if the user selects the same location already selected.
                MythMotePreferences.SelectLocation(this, this);
                break;

            case SENDWOL_ID:
                WOLPowerManager.sendWOL(this, sLocation.MAC, 5);
                break;
            case DONATE_ID:
                this.startDonateIntent();
                break;

            case KEYBOARD_INPUT_ID:
                DialogFragment newFragment = new MythmoteKeyboardInputFragment();
                newFragment.show(getSupportFragmentManager(), "keyboard_input");
                break;

            }
            ;
        } catch (android.content.ActivityNotFoundException ex) {
            // Show error when activity is not found
            AlertDialog.Builder diag = new AlertDialog.Builder(this);
            diag.setMessage(ex.getMessage());
            diag.setTitle("Error");
            diag.setNeutralButton("OK", null);
            diag.show();
        }
        return false;
    }

    private void setupContentView() {
        //load main layout
        this.setContentView(R.layout.main);

        // try to setup view pager
        if (this.setupViewPager())
            return;

        // if viewpager wasn't found try to setup large layout
        if (this.setupLargeLayout())
            return;
    }

    /**
     * Setups up the viewpager and MythmotePagerAdapter if
     * the current layout contains the mythmote_pager view pager.
     */
    private boolean setupViewPager() {

        // get viewpager from layout
        ViewPager pager = (ViewPager) findViewById(R.id.mythmote_pager);

        // if there is a viewpager set it up
        if (null == pager)
            return false;

        //get current view pager page
        int cItem = pager.getCurrentItem();
        cItem = cItem >= 0 ? cItem : 0;

        // create fragment and header arrays
        sFragmentArrayList = new ArrayList<Fragment>();
        sHeaderArrayList = new ArrayList<String>();

        // mythmote navigation page fragment
        Fragment nav = Fragment.instantiate(this, MythmoteNavigationFragment.class.getName());
        sFragmentArrayList.add(nav);
        sHeaderArrayList.add(this.getString(R.string.navigation_str));

        // mythmote interactive tv page fragment
        Fragment itv = Fragment.instantiate(this, MythmoteInteractiveTVFragment.class.getName());
        sFragmentArrayList.add(itv);
        sHeaderArrayList.add(this.getString(R.string.interactive_tv));

        // mythmote numbers page fragment
        Fragment num = Fragment.instantiate(this, MythmoteNumberPadFragment.class.getName());
        sFragmentArrayList.add(num);
        sHeaderArrayList.add(this.getString(R.string.numpad_str));

        // mythmote numbers page fragment
        Fragment jump = Fragment.instantiate(this, MythmoteQuickJumpFragment.class.getName());
        sFragmentArrayList.add(jump);
        sHeaderArrayList.add(this.getString(R.string.quickjump_str));

        //      // mythmote keyboard input page fragment
        //      Fragment keyboard = Fragment.instantiate(this,
        //            MythmoteKeyboardInputFragment.class.getName());
        //      sFragmentArrayList.add(keyboard);
        //      sHeaderArrayList.add(this.getString(R.string.keyboard_input_str));

        // set pager adapter and initial item
        pager.setAdapter(new MythmotePagerAdapter(this.getSupportFragmentManager()));
        pager.setCurrentItem(cItem);

        return true;
    }

    /**
     * Setups up the large layout that does not
     * use the ViewPager
     */
    private boolean setupLargeLayout() {

        //get framgment manager and start a transaction
        FragmentManager fragMgr = this.getSupportFragmentManager();
        FragmentTransaction fTran = fragMgr.beginTransaction();

        //Setup nav fragment
        Fragment nav = fragMgr.findFragmentById(R.layout.fragment_mythmote_navigation);
        if (null == nav) {
            nav = Fragment.instantiate(this, MythmoteNavigationFragment.class.getName());
            fTran.add(R.id.framelayout_navigation_fragment, nav);
        } else {
            fTran.replace(R.id.framelayout_navigation_fragment, nav);
        }

        //Setup interactive tv fragment
        Fragment itv = fragMgr.findFragmentById(R.layout.fragment_mythmote_interactivetv);
        if (null == itv) {
            itv = Fragment.instantiate(this, MythmoteInteractiveTVFragment.class.getName());
            fTran.add(R.id.framelayout_interactivetv_fragment, itv);
        } else {
            fTran.replace(R.id.framelayout_interactivetv_fragment, itv);
        }

        //setup number pad
        Fragment num = fragMgr.findFragmentById(R.layout.fragment_mythmote_numbers);
        if (null == num) {
            num = Fragment.instantiate(this, MythmoteNumberPadFragment.class.getName());
            fTran.add(R.id.framelayout_numberpad_fragment, num);
        } else {
            fTran.replace(R.id.framelayout_numberpad_fragment, num);
        }

        //setup quick jump
        Fragment jump = fragMgr.findFragmentById(R.layout.fragment_mythmote_quickjump);
        if (null == jump) {
            jump = Fragment.instantiate(this, MythmoteQuickJumpFragment.class.getName());
            fTran.add(R.id.framelayout_quickjump_fragment, jump);
        } else {
            fTran.replace(R.id.framelayout_quickjump_fragment, jump);
        }

        //finalize fragment transaction
        //fTran.commit();
        //this fixes an exception reported via google play caused by a bug in support library.
        fTran.commitAllowingStateLoss();

        return true;
    }

    /**
     * Called when the frontend location is changed
     */
    public void LocationChanged() {
        MythCom mythCom = MythCom.GetMythCom(this);
        if (mythCom.IsConnected() || mythCom.IsConnecting())
            mythCom.Disconnect();

        // set selected location and connect
        if (this.setSelectedLocation())
            mythCom.Connect(sLocation);
    }

    /**
     * Called when MythCom status changes
     */
    public void StatusChanged(String StatusMsg, int statusCode) {

        final String msg = StatusMsg;
        final int code = statusCode;

        this.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                // set titleJUMPPOINT_guidegrid
                setTitle(msg);

                // change color based on status code
                if (code == MythCom.STATUS_ERROR) {
                    setTitleColor(Color.RED);
                } else if (code == MythCom.STATUS_DISCONNECTED) {
                    setTitleColor(Color.RED);
                } else if (code == MythCom.STATUS_CONNECTED) {
                    setTitleColor(Color.GREEN);
                } else if (code == MythCom.STATUS_CONNECTING) {
                    setTitleColor(Color.YELLOW);
                }
            }

        });
    }

    /**
     * Reads the selected frontend from preferences and sets sLocation values.
     */
    private boolean setSelectedLocation() {

        // load shared preferences
        this.loadSharedPreferences();

        // _location should be initialized
        if (sLocation == null) {
            Log.e(LOG_TAG, "Cannot set location. Location object not initialized.");
        }

        // create location database adapter
        MythMoteDbManager dbManager = new MythMoteDbManager(this);

        // open connect
        dbManager.open();

        // get the selected location information by it's ID
        Cursor cursor = dbManager.fetchFrontendLocation(sSelected);

        // make sure returned cursor is valid
        if (cursor == null || cursor.getCount() <= 0)
            return false;
        // set selected location from Cursor
        sLocation.ID = cursor.getInt(cursor.getColumnIndex(MythMoteDbHelper.KEY_ROWID));
        sLocation.Name = cursor.getString(cursor.getColumnIndex(MythMoteDbHelper.KEY_NAME));
        sLocation.Address = cursor.getString(cursor.getColumnIndex(MythMoteDbHelper.KEY_ADDRESS));
        sLocation.Port = cursor.getInt(cursor.getColumnIndex(MythMoteDbHelper.KEY_PORT));
        sLocation.MAC = cursor.getString(cursor.getColumnIndex(MythMoteDbHelper.KEY_MAC));
        sLocation.WifiOnly = cursor.getInt(cursor.getColumnIndex(MythMoteDbHelper.KEY_WIFIONLY));

        // close cursor and db adapter
        cursor.close();
        dbManager.close();

        return true;
    }

    /**
     * Reads the mythmote shared preferences and sets local members accordingly.
     */
    private void loadSharedPreferences() {
        // get shared preferences reference
        SharedPreferences pref = this.getSharedPreferences(MythMotePreferences.MYTHMOTE_SHARED_PREFERENCES_ID,
                MODE_PRIVATE);

        // get selected frontend id
        sSelected = pref.getInt(MythMotePreferences.PREF_SELECTED_LOCATION, -1);

        // get if donate button should be visibl
        sShowDonateMenuItem = pref.getBoolean(MythMotePreferences.PREF_SHOW_DONATE_MENU_ITEM, true);

        //read long press action
        if (pref.getInt(MythMotePreferences.PREF_LONGPRESS_ACTION, 0) == 0) {
            //auto repeat action

            //enable auto repeat
            AutoRepeatButton.SetAutoRepeatEnalbed(true);

            //disable editable
            KeyBindingManager.EditingEnabled = false;
        } else {
            //edit key-bindings action

            //disable auto repeat
            AutoRepeatButton.SetAutoRepeatEnalbed(false);

            //set editable
            KeyBindingManager.EditingEnabled = true;
        }

        // set the hapticfeedback setting in keymanager
        KeyBindingManager.HapticFeedbackEnabled = pref.getBoolean(MythMotePreferences.PREF_HAPTIC_FEEDBACK_ENABLED,
                false);

        //set autorepeat interval
        AutoRepeatButton.SetRepeatInterval(pref.getInt(MythMotePreferences.PREF_KEY_REPEAT_INTERVAL,
                AutoRepeatButton.DEFAULT_REPEAT_INTERVAL));

        // done with pref ref
        pref = null;
    }

    private void startDonateIntent() {
        AlertDialog.Builder dBuilder = new AlertDialog.Builder(this);
        dBuilder.setMessage(R.string.donate_intent_alert_str);
        dBuilder.setTitle("Donate Beer Money?");
        dBuilder.setNegativeButton("Cancel", null);
        dBuilder.setNeutralButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //open browser at our paypal donation page.
                Uri uri = Uri.parse(DONATE_URL);
                Intent webIntent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(webIntent);
            }
        });
        dBuilder.show();
    }

    class MythmotePagerAdapter extends FragmentStatePagerAdapter {

        public MythmotePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return sFragmentArrayList.size();
        }

        @Override
        public Fragment getItem(int position) {
            return sFragmentArrayList.get(position);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return sHeaderArrayList.get(position);
        }

    }

}