com.chrulri.droidoflife.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.chrulri.droidoflife.MainActivity.java

Source

/******************************************************************************
 *  Droid of Life, an open source Android game based on Conway's Game of Life *
 *  Copyright (C) 2012  Christian Ulrich <chrulri@gmail.com>                  *
 *                                                                            *
 *  This program is free software: you can redistribute it and/or modify      *
 *  it under the terms of the GNU 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 General Public License for more details.                              *
 *                                                                            *
 *  You should have received a copy of the GNU General Public License         *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
 ******************************************************************************/
package com.chrulri.droidoflife;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.Menu;
import android.support.v4.view.MenuItem;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;

import com.chrulri.droidoflife.LifeRuntime.LifeRuntimeException;

public class MainActivity extends FragmentActivity {
    static final String TAG = MainActivity.class.getSimpleName();

    static final int RESULT_SETTINGS = 0xF0;

    static final long ITERATION_DELAY_MS = 100;

    private IterationTask iterationTask;
    private SurfaceHolder surface;
    private Bitmap bitmap;
    private int settingsCache;

    private void refreshTitle() {
        String title = "" + getText(R.string.app_name);
        // append iteration
        int iteration = LifeRuntime.getIteration();
        if (iteration > 0) {
            title += " (#" + iteration + ")";
        }
        // append automatic mode
        if (iterationTask != null) {
            title += " - " + getText(R.string.auto_short);
        }
        setTitle(title);
    }

    private void restartRuntime() {
        if (bitmap != null) {
            LifeRuntime.destroy();
        }

        // TODO ask for width/height
        final int width = 200;
        final int height = 100;

        try {
            LifeRuntime.create(width, height);
        } catch (LifeRuntimeException e) {
            e.printStackTrace();
            // TODO show error

            // emergency exit
            finish();
            return;
        }

        bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        refreshTitle();
    }

    private boolean doIteration() {
        try {
            LifeRuntime.iterate();
            doRender();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "error on iteration", e);
            return false;
        }
        return true;
    }

    private void doRender() {
        if (bitmap == null) {
            // bitmap not ready yet, wtf?!
            Log.w(TAG, "bitmap is null");
            return;
        }

        Canvas canvas = surface.lockCanvas();
        if (canvas == null) {
            // surface not ready yet, nothing to do!
            return;
        }

        LifeRuntime.render(bitmap, settingsCache);

        Rect dst = surface.getSurfaceFrame();
        canvas.drawBitmap(bitmap, null, dst, null);

        surface.unlockCanvasAndPost(canvas);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        getSupportActionBar().setDisplayShowHomeEnabled(false);

        settingsCache = SettingsActivity.loadSettings(this);

        SurfaceView view = (SurfaceView) findViewById(R.id.main_surfaceView);
        surface = view.getHolder();

        restartRuntime();

        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // disable iteration task for manual mode
                if (iterationTask != null) {
                    iterationTask.cancel(false);
                    iterationTask = null;
                } else {
                    doIteration();
                }
                refreshTitle();
            }
        });
        surface.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                doRender();
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                doRender();
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // ignore
            }

        });

        refreshTitle();

        // Manual
        // TODO show manual
    }

    @Override
    protected void onResume() {
        super.onResume();
        // restart iteration
        if (iterationTask != null) {
            iterationTask = new IterationTask();
            iterationTask.execute();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // pause iteration
        if (iterationTask != null) {
            iterationTask.cancel(false);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // remove iteration task
        iterationTask = null;
        surface = null;
        bitmap = null;
        // destroy life with a nuclear bomb (!!)
        LifeRuntime.destroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.mi_automatic:
            // toggle automatic mode
            if (iterationTask == null) {
                iterationTask = new IterationTask();
                iterationTask.execute();
            } else {
                iterationTask.cancel(false);
                iterationTask = null;
            }
            refreshTitle();
            return true;
        case R.id.mi_restart:
            // restart game of life
            restartRuntime();
            doRender();
            return true;
        case R.id.mi_settings:
            // open settings activity
            startActivityForResult(new Intent(this, SettingsActivity.class), RESULT_SETTINGS);
            return true;
        case R.id.mi_help:
            // open help dialog
            DialogFragment help = new HelpDialogFragment();
            help.show(getSupportFragmentManager(), null);
            return true;
        case R.id.mi_about:
            // open about dialog
            DialogFragment about = new AboutDialogFragment();
            about.show(getSupportFragmentManager(), null);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case RESULT_SETTINGS:
            settingsCache = SettingsActivity.loadSettings(this);
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    class IterationTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onProgressUpdate(Void... values) {
            refreshTitle();
        }

        @Override
        protected Void doInBackground(Void... params) {
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
            wakeLock.acquire();
            try {
                while (!isCancelled()) {
                    // new generation ready, hurray!
                    if (!doIteration()) {
                        // exit on error
                        return null;
                    }
                    // tell everyone
                    publishProgress();
                    // sleep for next generation
                    try {
                        Thread.sleep(ITERATION_DELAY_MS);
                    } catch (InterruptedException e) {
                        // ignore
                    }
                }
                return null;
            } finally {
                wakeLock.release();
            }
        }

        @Override
        protected void onPostExecute(Void result) {
            // clean exit on error
            iterationTask = null;
        }
    }
}