org.ligi.gobandroid_hd.ui.GoActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.ligi.gobandroid_hd.ui.GoActivity.java

Source

/**
 * gobandroid 
 * by Marcus -Ligi- Bueschleb 
 * http://ligi.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as 
 * published by the Free Software Foundation; 
 *
 * 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 org.ligi.gobandroid_hd.ui;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Toast;

import org.ligi.axt.AXT;
import org.ligi.axt.listeners.DialogDiscardingOnClickListener;
import org.ligi.gobandroid_hd.App;
import org.ligi.gobandroid_hd.InteractionScope;
import org.ligi.gobandroid_hd.R;
import org.ligi.gobandroid_hd.logic.BoardCell;
import org.ligi.gobandroid_hd.logic.Cell;
import org.ligi.gobandroid_hd.logic.GoGame;
import org.ligi.gobandroid_hd.logic.sgf.SGFWriter;
import org.ligi.gobandroid_hd.ui.alerts.GameInfoDialog;
import org.ligi.gobandroid_hd.ui.application.GobandroidFragmentActivity;
import org.ligi.gobandroid_hd.ui.fragments.DefaultGameExtrasFragment;
import org.ligi.gobandroid_hd.ui.recording.SaveSGFDialog;
import org.ligi.gobandroid_hd.ui.review.BookmarkDialog;
import org.ligi.gobandroid_hd.ui.scoring.GameScoringActivity;
import org.ligi.gobandroid_hd.ui.share.ShareAsAttachmentDialog;
import org.ligi.tracedroid.logging.Log;
import org.ligi.tracedroid.sending.TraceDroidEmailSender;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import butterknife.ButterKnife;
import butterknife.InjectView;
import fr.nicolaspomepuy.discreetapprate.AppRate;
import fr.nicolaspomepuy.discreetapprate.RetryPolicy;

/**
 * Activity for a Go Game
 */
public class GoActivity extends GobandroidFragmentActivity
        implements OnTouchListener, OnKeyListener, GoGame.GoGameChangeListener {

    public GoSoundManager sound_man;

    @InjectView(R.id.go_board)
    GoBoardViewHD go_board = null;

    @InjectView(R.id.zoom_board)
    GoBoardViewHD zoom_board = null;

    @InjectView(R.id.game_extra_container)
    View gameExtrasContainer;

    private Toast info_toast = null;
    private Fragment actFragment;
    private InteractionScope interaction_scope;
    private int last_processed_move_change_num = 0;

    public Fragment getGameExtraFragment() {

        return new DefaultGameExtrasFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        GoPrefs.init(this); // TODO remove legacy

        setContentView(R.layout.game);

        ButterKnife.inject(this);

        if (!App.isTesting) {
            // if there where stacktraces collected -> give the user the option to send them
            if (!TraceDroidEmailSender.sendStackTraces("ligi@ligi.de", this) && Build.VERSION.SDK_INT < 21) {
                AppRate.with(this).retryPolicy(RetryPolicy.EXPONENTIAL).initialLaunchCount(5).checkAndShow();
            }
        }

        interaction_scope = App.getInteractionScope();
        getSupportActionBar().setHomeButtonEnabled(true);

        AXT.at(this).disableRotation();

        if (getSettings().isWakeLockEnabled()) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }

        if (getGame() == null) { // cannot do anything without a game
            Log.w("finish()ing " + this + " cuz getGame()==null");
            finish();
            return;
        }

        if (sound_man == null) {
            sound_man = new GoSoundManager(this);
        }

        final View customNav = new CustomActionBar(this);

        final FragmentTransaction fragmentTransAction = getSupportFragmentManager().beginTransaction();
        fragmentTransAction.add(R.id.game_extra_container, getGameExtraFragment()).commit();
        getSupportFragmentManager().executePendingTransactions();

        getSupportActionBar().setCustomView(customNav);
        getSupportActionBar().setDisplayShowCustomEnabled(true);
        customNav.setFocusable(false);

        createInfoToast();

        setupBoard();

        game2ui();
    }

    @SuppressLint("ShowToast")
    // this is correct - we do not want to show the toast at this stage
    private void createInfoToast() {
        info_toast = Toast.makeText(this.getBaseContext(), "", Toast.LENGTH_LONG);
    }

    /**
     * find the go board widget and set up some properties
     */
    private void setupBoard() {
        go_board.setOnTouchListener(this);
        go_board.setOnKeyListener(this);
        go_board.move_stone_mode = false;
    }

    @Override
    public void onGoGameChange() {
        Log.i("onGoGameChange in GoActivity");
        if (getGame().getActMove().getMovePos() > last_processed_move_change_num) {
            if (getGame().isBlackToMove()) {
                sound_man.playSound(GoSoundManager.SOUND_PLACE1);
            } else {
                sound_man.playSound(GoSoundManager.SOUND_PLACE2);
            }
        }
        last_processed_move_change_num = getGame().getActMove().getMovePos();

        game2ui();
    }

    /**
     * set some preferences on the go board - intended to be called in onResume
     */
    private void setBoardPreferences() {
        if (go_board == null) {
            Log.w("setBoardPreferences() called with go_board==null - means setupBoard() was propably not called - skipping to not FC");
            return;
        }

        go_board.do_legend = getSettings().isLegendEnabled();
        go_board.legend_sgf_mode = getSettings().isSGFLegendEnabled();
        go_board.setGridEmboss(getSettings().isGridEmbossEnabled());
    }

    public boolean isBoardFocusWanted() {
        return true;
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (isBoardFocusWanted()) {
            go_board.setFocusableInTouchMode(true);
            go_board.setFocusable(true);
            go_board.requestFocus();
        } else {
            go_board.setFocusableInTouchMode(false);
            go_board.setFocusable(false);
        }
        setBoardPreferences();

        if (getGame() == null) {
            Log.w("we do not have a game in onStart of a GoGame activity - thats crazy!");
        } else {
            getGame().addGoGameChangeListener(this);
        }
    }

    @Override
    public boolean doFullScreen() {
        return getSettings().isFullscreenEnabled() | getResources().getBoolean(R.bool.force_fullscreen);
    }

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

    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {

        case R.id.menu_game_info:
            new GameInfoDialog(this, getGame()).show();
            return true;

        case R.id.menu_game_undo:
            if (!getGame().canUndo()) {
                break;
            }

            requestUndo();
            return true;

        case R.id.menu_game_pass:
            getGame().pass();
            getGame().notifyGameChange();

            return true;

        case R.id.menu_write_sgf:
            new SaveSGFDialog(this).show();
            return true;

        case R.id.menu_bookmark:
            new BookmarkDialog(this).show();
            return true;

        case R.id.menu_game_share:
            new ShareAsAttachmentDialog(this).show();
            //new ShareSGFDialog(this).show();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void switchToCounting() {

        App.getInteractionScope().setMode(InteractionScope.MODE_COUNT);
        startActivity(new Intent(this, GameScoringActivity.class));
        finish();

    }

    /**
     * @return true if we want to ask the user - different in modes
     */
    public boolean isAsk4QuitEnabled() {
        return true;
    }

    private void shutdown() {
        // sound_man.playSound(GoSoundManager.SOUND_END);
        getGame().getGoMover().stop();
        finish();
    }

    public void quit(final boolean toHome) {
        if (!isAsk4QuitEnabled()) {
            shutdown();
        } else {
            new AlertDialog.Builder(this).setTitle(R.string.end_game_quesstion_title)
                    .setMessage(R.string.quit_confirm)
                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            shutdown();
                        }
                    }).setCancelable(true).setNegativeButton(R.string.no, new DialogDiscardingOnClickListener())
                    .show();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            quit(false);
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    /**
     * show a the info toast with a specified text from a resource ID
     */
    protected void showInfoToast(@StringRes int resId) {
        info_toast.setText(resId);
        info_toast.show();
    }

    protected byte doMoveWithUIFeedback(Cell cell) {
        if (cell == null) {
            return GoGame.MOVE_INVALID_NOT_ON_BOARD;
        }

        final byte res = getGame().do_move(cell);

        switch (res) {
        case GoGame.MOVE_INVALID_IS_KO:
        case GoGame.MOVE_INVALID_CELL_NO_LIBERTIES:
            showInfoToast(getToastForResult(res));
        }

        return res;
    }

    private int getToastForResult(byte res) {
        switch (res) {
        case GoGame.MOVE_INVALID_IS_KO:
            return R.string.invalid_move_ko;

        case GoGame.MOVE_INVALID_CELL_NO_LIBERTIES:
            return R.string.invalid_move_no_liberties;
        }

        throw (new RuntimeException("Illegal game result " + res));
    }

    public void game2ui() {
        go_board.postInvalidate();
        refreshZoomFragment();
    }

    public void setFragment(Fragment newFragment) {

        if (actFragment == newFragment) {
            // GoFrag same same no need to do a thing here
            return;
        }

        final FragmentTransaction fragmentTransAction = getSupportFragmentManager().beginTransaction();

        if (actFragment != null) {
            fragmentTransAction.remove(actFragment);
        }

        fragmentTransAction.replace(R.id.game_extra_container, newFragment);

        fragmentTransAction.commit();

        actFragment = newFragment;
    }

    protected void eventForZoomBoard(MotionEvent event) {
        App.getInteractionScope().setTouchPosition(getBoard().pixel2cell(event.getX(), event.getY()));

        if (event.getAction() == MotionEvent.ACTION_UP) {
            gameExtrasContainer.setVisibility(View.VISIBLE);
            zoom_board.setVisibility(View.GONE);
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            gameExtrasContainer.setVisibility(View.GONE);
            zoom_board.setVisibility(View.VISIBLE);
        }
        refreshZoomFragment();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        eventForZoomBoard(event);

        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (getResources().getBoolean(R.bool.small)) {
                getSupportActionBar().show();
            }

        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {

            // for very small devices we want to hide the ActionBar to actually
            // see something in the Zoom-Fragment
            if (getResources().getBoolean(R.bool.small)) {
                getSupportActionBar().hide();
            }

            if (getGame().isBlackToMove()) {
                sound_man.playSound(GoSoundManager.SOUND_PICKUP1);
            } else {
                sound_man.playSound(GoSoundManager.SOUND_PICKUP2);
            }
        }

        if (!getGame().getGoMover().isReady()) {
            showInfoToast(R.string.wait_gnugo);
        } else if (getGame().getGoMover().isMoversMove()) {
            showInfoToast(R.string.not_your_turn);
        } else {
            doTouch(event);
        }

        return true;
    }

    @Override
    public void onPause() {

        go_board.move_stone_mode = false;

        if (getGame() == null) {
            Log.w("we do not have a game (anymore) in onStop of a GoGame activity - that's crazy!");
        } else {
            getGame().removeGoGameChangeListener(this);
        }

        if (doAutoSave()) {
            try {
                File f = new File(getSettings().getSGFSavePath() + "/autosave.sgf");
                f.createNewFile();

                FileWriter sgf_writer = new FileWriter(f);

                BufferedWriter out = new BufferedWriter(sgf_writer);

                out.write(SGFWriter.game2sgf(getGame()));
                out.close();
                sgf_writer.close();

            } catch (IOException e) {
                Log.i("" + e);
            }
        }
        super.onPause();
    }

    public boolean doAutoSave() {
        return false;
    }

    public void doTouch(MotionEvent event) {

        // calculate position on the field by position on the touchscreen

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            interaction_scope.setTouchPosition(getBoard().pixel2cell(event.getX(), event.getY()));
            break;

        case MotionEvent.ACTION_OUTSIDE:
            interaction_scope.setTouchPosition(null);
            break;

        case MotionEvent.ACTION_UP:

            if (go_board.move_stone_mode) {
                // TODO check if this is an illegal move ( e.g. in variants )

                if (getGame().getVisualBoard().isCellFree(interaction_scope.getTouchCell())) {
                    getGame().getActMove().setCell(interaction_scope.getTouchCell());
                    getGame().getActMove().setDidCaptures(true); // TODO check if we harm sth with that
                    getGame().refreshBoards();
                }
                go_board.move_stone_mode = false; // moving of stone done
            } else if ((getGame().getActMove().isOnCell(interaction_scope.getTouchCell()))) {
                initializeStoneMove();
            } else {
                doMoveWithUIFeedback(interaction_scope.getTouchCell());
            }

            interaction_scope.setTouchPosition(null);
            break;
        }

        getGame().notifyGameChange();
    }

    public void initializeStoneMove() {

        if (getGame().getGoMover().isPlayingInThisGame()) { // don't allow with a mover
            return;
        }

        if (go_board.move_stone_mode) { // already in the mode
            return; // -> do nothing
        }

        go_board.move_stone_mode = true;

        // TODO check if we only want this in certain modes
        if (GoPrefs.isAnnounceMoveActive()) {

            new AlertDialog.Builder(this).setMessage(R.string.hint_stone_move).setPositiveButton(R.string.ok,

                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            GoPrefs.setAnnounceMoveActive(false);
                        }
                    }).show();
        }
    }

    public boolean doAskToKeepVariant() {
        return GoPrefs.isAskVariantEnabled() && App.getInteractionScope().ask_variant_session;
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            final Cell ensuredTouchPosition = interaction_scope.getEnsuredTouchPosition();
            final BoardCell boardCell = getGame().getCalcBoard().getCell(ensuredTouchPosition);

            switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_UP:
                if (boardCell.up != null) {
                    interaction_scope.touch_position = boardCell.up;
                } else {
                    return false;
                }
                break;

            case KeyEvent.KEYCODE_DPAD_LEFT:
                if (boardCell.left != null) {
                    interaction_scope.touch_position = boardCell.left;
                } else {
                    return false;
                }
                break;

            case KeyEvent.KEYCODE_DPAD_DOWN:
                if (boardCell.down != null) {
                    interaction_scope.touch_position = boardCell.down;
                } else {
                    return false;
                }
                break;

            case KeyEvent.KEYCODE_DPAD_RIGHT:
                if (boardCell.right != null) {
                    interaction_scope.touch_position = boardCell.right;
                } else {
                    return false;
                }
                break;

            case KeyEvent.KEYCODE_DPAD_CENTER:
                doMoveWithUIFeedback(boardCell);
                break;

            default:

                return false;

            }

            go_board.postInvalidate();
            refreshZoomFragment();
            return true;
        }
        return false;
    }

    public void refreshZoomFragment() {
        zoom_board.postInvalidate();
    }

    public GoBoardViewHD getBoard() {
        if (go_board == null) {
            setupBoard();
        }
        return go_board;
    }

    public void requestUndo() {

        go_board.move_stone_mode = false;
        if (doAskToKeepVariant()) {
            new UndoWithVariationDialog(this).show();
        } else {
            getGame().undo(GoPrefs.isKeepVariantEnabled());
        }
    }

}