edu.berkeley.boinc.BOINCActivity.java Source code

Java tutorial

Introduction

Here is the source code for edu.berkeley.boinc.BOINCActivity.java

Source

/*******************************************************************************
 * This file is part of BOINC.
 * http://boinc.berkeley.edu
 * Copyright (C) 2012 University of California
 * 
 * BOINC is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 * 
 * BOINC 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package edu.berkeley.boinc;

import android.app.Dialog;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import edu.berkeley.boinc.adapter.NavDrawerListAdapter;
import edu.berkeley.boinc.adapter.NavDrawerListAdapter.NavDrawerItem;
import edu.berkeley.boinc.attach.SelectionListActivity;
import edu.berkeley.boinc.client.ClientStatus;
import edu.berkeley.boinc.client.Monitor;
import edu.berkeley.boinc.client.IMonitor;
import edu.berkeley.boinc.rpc.Project;
import edu.berkeley.boinc.utils.BOINCDefs;
import edu.berkeley.boinc.utils.Logging;
import java.util.ArrayList;

public class BOINCActivity extends ActionBarActivity {

    public static IMonitor monitor;
    private Integer clientComputingStatus = -1;
    private Integer numberProjectsInNavList = 0;
    static Boolean mIsBound = false;

    // app title (changes with nav bar selection)
    private CharSequence mTitle;
    // nav drawer title
    private CharSequence mDrawerTitle;

    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private NavDrawerListAdapter mDrawerListAdapter;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been established, getService returns 
            // the Monitor object that is needed to call functions.
            monitor = IMonitor.Stub.asInterface(service);
            mIsBound = true;
            determineStatus();
        }

        public void onServiceDisconnected(ComponentName className) {
            // This should not happen
            monitor = null;
            mIsBound = false;

            Log.e(Logging.TAG, "BOINCActivity onServiceDisconnected");
        }
    };

    private BroadcastReceiver mClientStatusChangeRec = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Logging.VERBOSE)
                Log.d(Logging.TAG, "BOINCActivity ClientStatusChange - onReceive()");
            determineStatus();
        }
    };
    private IntentFilter ifcsc = new IntentFilter("edu.berkeley.boinc.clientstatuschange");

    @Override
    public void onCreate(Bundle savedInstanceState) {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // setup navigation bar
        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
        mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // display view for selected nav drawer item
                dispatchNavBarOnClick(mDrawerListAdapter.getItem(position), false);
            }
        });
        mDrawerListAdapter = new NavDrawerListAdapter(getApplicationContext());
        mDrawerList.setAdapter(mDrawerListAdapter);
        // enabling action bar app icon and behaving it as toggle button
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, //nav menu toggle icon
                R.string.app_name, // nav drawer open - description for accessibility
                R.string.app_name // nav drawer close - description for accessibility
        ) {
            public void onDrawerClosed(View view) {
                getSupportActionBar().setTitle(mTitle);
                // calling onPrepareOptionsMenu() to show action bar icons
                supportInvalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView) {
                getSupportActionBar().setTitle(mDrawerTitle);
                mDrawerListAdapter.notifyDataSetChanged(); // force redraw of all items (adapter.getView()) in order to adapt changing icons or number of tasks/notices
                // calling onPrepareOptionsMenu() to hide action bar icons
                supportInvalidateOptionsMenu();
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        // pre-select fragment
        // 1. check if explicitly requested fragment present
        // e.g. after initial project attach.
        int targetFragId = getIntent().getIntExtra("targetFragment", -1);

        // 2. if no explicit request, try to restore previous selection
        if (targetFragId < 0 && savedInstanceState != null)
            targetFragId = savedInstanceState.getInt("navBarSelectionId");

        NavDrawerItem item = null;
        if (targetFragId < 0) {
            // if non of the above, go to default
            item = mDrawerListAdapter.getItem(0);
        } else
            item = mDrawerListAdapter.getItemForId(targetFragId);

        if (item != null)
            dispatchNavBarOnClick(item, true);
        else if (Logging.WARNING)
            Log.w(Logging.TAG, "onCreate: fragment selection returned null");

        //bind monitor service
        doBindService();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("navBarSelectionId", mDrawerListAdapter.selectedMenuId);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onDestroy()");
        doUnbindService();
        super.onDestroy();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onNewIntent()");
        // onNewIntent gets called if activity is brought to front via intent, but was still alive, so onCreate is not called again
        // getIntent always returns the intent activity was created of, so this method is the only hook to receive an updated intent
        // e.g. after (not initial) project attach
        super.onNewIntent(intent);
        // navigate to explicitly requested fragment (e.g. after project attach)
        int id = intent.getIntExtra("targetFragment", -1);
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onNewIntent() for target fragment: " + id);
        NavDrawerItem item = mDrawerListAdapter.getItemForId(id);
        if (item != null)
            dispatchNavBarOnClick(item, false);
        else if (Logging.WARNING)
            Log.w(Logging.TAG, "onNewIntent: requested target fragment is null, for id: " + id);
    }

    @Override
    protected void onResume() { // gets called by system every time activity comes to front. after onCreate upon first creation
        super.onResume();
        registerReceiver(mClientStatusChangeRec, ifcsc);
        determineStatus();
    }

    @Override
    protected void onPause() { // gets called by system every time activity loses focus.
        if (Logging.VERBOSE)
            Log.v(Logging.TAG, "BOINCActivity onPause()");
        super.onPause();
        unregisterReceiver(mClientStatusChangeRec);
    }

    private void doBindService() {
        // start service to allow setForeground later on...
        startService(new Intent(this, Monitor.class));
        // Establish a connection with the service, onServiceConnected gets called when
        bindService(new Intent(this, Monitor.class), mConnection, Service.BIND_AUTO_CREATE);
    }

    private void doUnbindService() {
        if (mIsBound) {
            // Detach existing connection.
            unbindService(mConnection);
            mIsBound = false;
        }
    }
    /*
    public IMonitor getMonitorService() {
       if(!mIsBound) if(Logging.WARNING) Log.w(Logging.TAG, "Fragment trying to obtain serive reference, but Monitor not bound in BOINCActivity");
       return monitor;
    }*/

    public void startAttachProjectListActivity() {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity attempt to start ");
        startActivity(new Intent(this, SelectionListActivity.class));
    }

    /**
     * React to selection of nav bar item
     * @param item
     * @param position
     * @param init
     */
    private void dispatchNavBarOnClick(NavDrawerItem item, boolean init) {
        // update the main content by replacing fragments
        if (item == null) {
            if (Logging.WARNING)
                Log.w(Logging.TAG, "dispatchNavBarOnClick returns, item null.");
            return;
        }
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "dispatchNavBarOnClick for item with id: " + item.getId() + " title: "
                    + item.getTitle() + " is project? " + item.isProjectItem());

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        Boolean fragmentChanges = false;
        if (init) {
            // if init, setup status fragment
            ft.replace(R.id.status_container, new StatusFragment());
        }
        if (!item.isProjectItem()) {
            switch (item.getId()) {
            case R.string.tab_tasks:
                ft.replace(R.id.frame_container, new TasksFragment());
                fragmentChanges = true;
                break;
            case R.string.tab_notices:
                ft.replace(R.id.frame_container, new NoticesFragment());
                fragmentChanges = true;
                break;
            case R.string.tab_projects:
                ft.replace(R.id.frame_container, new ProjectsFragment());
                fragmentChanges = true;
                break;
            case R.string.menu_help:
                Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://boinc.berkeley.edu/wiki/BOINC_Help"));
                startActivity(i);
                break;
            case R.string.menu_about:
                final Dialog dialog = new Dialog(this);
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                dialog.setContentView(R.layout.dialog_about);
                Button returnB = (Button) dialog.findViewById(R.id.returnB);
                TextView tvVersion = (TextView) dialog.findViewById(R.id.version);
                try {
                    tvVersion.setText(getString(R.string.about_version) + " "
                            + getPackageManager().getPackageInfo(getPackageName(), 0).versionName);
                } catch (NameNotFoundException e) {
                    if (Logging.WARNING)
                        Log.w(Logging.TAG, "version name not found.");
                }

                returnB.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog.dismiss();
                    }
                });
                dialog.show();
                break;
            case R.string.menu_eventlog:
                startActivity(new Intent(this, EventLogActivity.class));
                break;
            case R.string.projects_add:
                startActivity(new Intent(this, SelectionListActivity.class));
                break;
            case R.string.tab_preferences:
                ft.replace(R.id.frame_container, new PrefsFragment());
                fragmentChanges = true;
                break;

            default:
                if (Logging.ERROR)
                    Log.d(Logging.TAG,
                            "dispatchNavBarOnClick() could not find corresponding fragment for " + item.getTitle());
                break;
            }

        } else {
            // ProjectDetailsFragment. Data shown based on given master URL
            Bundle args = new Bundle();
            args.putString("url", item.getProjectMasterUrl());
            Fragment frag = new ProjectDetailsFragment();
            frag.setArguments(args);
            ft.replace(R.id.frame_container, frag);
            fragmentChanges = true;
        }

        mDrawerLayout.closeDrawer(mDrawerList);

        if (fragmentChanges) {
            ft.commit();
            setTitle(item.getTitle());
            mDrawerListAdapter.selectedMenuId = item.getId(); //highlight item persistently
            mDrawerListAdapter.notifyDataSetChanged(); // force redraw
        }

        if (Logging.DEBUG)
            Log.d(Logging.TAG, "displayFragmentForNavDrawer() " + item.getTitle());
    }

    // tests whether status is available and whether it changed since the last event.
    private void determineStatus() {
        try {
            if (mIsBound) {
                Integer newComputingStatus = monitor.getComputingStatus();
                if (newComputingStatus != clientComputingStatus) {
                    // computing status has changed, update and invalidate to force adaption of action items
                    clientComputingStatus = newComputingStatus;
                    supportInvalidateOptionsMenu();
                }
                if (numberProjectsInNavList != monitor.getProjects().size())
                    numberProjectsInNavList = mDrawerListAdapter
                            .compareAndAddProjects((ArrayList<Project>) monitor.getProjects());
                //setAppTitle();
            }
        } catch (Exception e) {
        }
    }

    public final boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            if (this.mDrawerLayout.isDrawerOpen(this.mDrawerList)) {
                this.mDrawerLayout.closeDrawer(this.mDrawerList);
            } else {
                this.mDrawerLayout.openDrawer(this.mDrawerList);
            }
            return true;
        }
        return super.onKeyDown(keyCode, keyEvent);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onCreateOptionsMenu()");

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onPrepareOptionsMenu()");

        // run mode, set title and icon based on status
        MenuItem runMode = menu.findItem(R.id.run_mode);
        if (clientComputingStatus == ClientStatus.COMPUTING_STATUS_NEVER) {
            // display play button
            runMode.setTitle(R.string.menu_run_mode_enable);
            runMode.setIcon(R.drawable.playw);
        } else {
            // display stop button
            runMode.setTitle(R.string.menu_run_mode_disable);
            runMode.setIcon(R.drawable.pausew);
        }

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (Logging.DEBUG)
            Log.d(Logging.TAG, "BOINCActivity onOptionsItemSelected()");

        // toggle drawer
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

        switch (item.getItemId()) {
        case R.id.run_mode:
            if (item.getTitle().equals(getApplication().getString(R.string.menu_run_mode_disable))) {
                if (Logging.DEBUG)
                    Log.d(Logging.TAG, "run mode: disable");
                new WriteClientModeAsync().execute(BOINCDefs.RUN_MODE_NEVER);
            } else if (item.getTitle().equals(getApplication().getString(R.string.menu_run_mode_enable))) {
                if (Logging.DEBUG)
                    Log.d(Logging.TAG, "run mode: enable");
                new WriteClientModeAsync().execute(BOINCDefs.RUN_MODE_AUTO);
            } else if (Logging.DEBUG)
                Log.d(Logging.TAG, "run mode: unrecognized command");
            return true;
        case R.id.projects_add:
            startActivity(new Intent(this, SelectionListActivity.class));
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getSupportActionBar().setTitle(mTitle);
    }

    private final class WriteClientModeAsync extends AsyncTask<Integer, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Integer... params) {
            // setting provided mode for both, CPU computation and network.
            Boolean runMode;
            try {
                runMode = monitor.setRunMode(params[0]);
            } catch (RemoteException e) {
                runMode = false;
            }
            Boolean networkMode;
            try {
                networkMode = monitor.setNetworkMode(params[0]);
            } catch (RemoteException e) {
                networkMode = false;
            }
            return runMode && networkMode;
        }

        @Override
        protected void onPostExecute(Boolean success) {
            if (success)
                try {
                    monitor.forceRefresh();
                } catch (RemoteException e) {
                }
            else if (Logging.WARNING)
                Log.w(Logging.TAG, "setting run and network mode failed");
        }
    }
}