comingle.dragracing.TrackActivity.java Source code

Java tutorial

Introduction

Here is the source code for comingle.dragracing.TrackActivity.java

Source

/**
This file is part of CoMingle.
    
CoMingle 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.
    
CoMingle 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 CoMingle. If not, see <http://www.gnu.org/licenses/>.
    
CoMingle Version 1.0, Beta Prototype
    
Authors:
Edmund S. L. Lam      sllam@qatar.cmu.edu
Nabeeha Fatima        nhaque@andrew.cmu.edu
    
* This implementation was made possible by an JSREP grant (JSREP 4-003-2-001, Effective Distributed 
Programming via Join Patterns with Guards, Propagation and More) from the Qatar National Research Fund 
(a member of the Qatar Foundation). The statements made herein are solely the responsibility of the authors.
**/

package comingle.dragracing;

import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import comingle.actuation.ActuatorAction;
import comingle.android.directory.ui.dialogsequences.DirectoryChosenListener;
import comingle.comms.directory.BaseDirectory;
import comingle.comms.directory.NodeInfo;
import comingle.comms.listeners.DirectoryChangedListener;
import comingle.comms.listeners.LocalNodeInfoAvailableListener;
import comingle.comms.listeners.NetworkStatusChangedListener;
import comingle.comms.message.Message;
import comingle.dragracing.R;
import comingle.runtime.CoMingleAndroidRuntime;
import comingle.tuple.*;

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.widget.LinearLayout;

import android.widget.Toast;

import dragracing.Dragracing;

public class TrackActivity extends FragmentActivity {

    class Car {
        private Rect sprite;
        private Paint paint;
        private boolean throttle;
        private int owner;
        private int impulse_time;

        public Car(int owner) {
            this.owner = owner;
            paint = new Paint();
            paint.setColor(CAR_COLORS[owner]);
            throttle = false;
            int left;

            //adjusting movt. of car from one phone to the next
            if (getLocation() > 0) {
                left = 0;
            } else {
                left = 90;
            }

            int right = left + TRACK_WIDTH;
            int top = TOP_MARGIN + TRACK_WIDTH * owner - 12;
            int bottom = TOP_MARGIN + TRACK_WIDTH * (owner + 1) - 15;
            sprite = new Rect(left, top, right, bottom);
            impulse_time = 0;
        }

        public void setSprite(Rect new_sprite) {
            sprite = new_sprite;
        }

        public Rect getSprite() {
            return sprite;
        }

        public Paint getPaint() {
            return paint;
        }

        public boolean getThrottle() {
            return throttle;
        }

        public int getIdx() {
            return owner;
        }

        public int getOwner() {
            return owner;
        }

        public void toggle(boolean tog) {
            throttle = tog;
        }

        public void move(int new_pos) {
            int left = new_pos;
            int right = new_pos + TRACK_WIDTH;
            int top = TOP_MARGIN + TRACK_WIDTH * owner - 12;
            int bottom = TOP_MARGIN + TRACK_WIDTH * (owner + 1) - 15;
            sprite = new Rect(left, top, right, bottom);
            //rendering doubletrack after car has moved on the sprite
            Paint paint = new Paint();
            for (int i = 0; i <= lanes; i++) {
                paint.setColor(CAR_COLORS[i]);
                float top_track_y = TOP_MARGIN + TRACK_WIDTH * i;
                //adjusting movt. of car from one phone to the next
                if (getLocation() > 0) {
                    track_canvas.drawLine(0, top_track_y, 780, top_track_y, paint);
                    track_canvas.drawLine(0, top_track_y + 7, 780, top_track_y + 7, paint);
                } else {
                    track_canvas.drawLine(75, top_track_y, 800, top_track_y, paint);
                    track_canvas.drawLine(75, top_track_y + 7, 800, top_track_y + 7, paint);
                }
            }
        }

        public void impulse() {
            impulse_time = (int) System.currentTimeMillis();
        }

        public boolean checkImpulse(int refresh_time) {
            if (impulse_time == 0) {
                return false;
            }
            return refresh_time - impulse_time <= IMPULSE_LENGTH;
        }

    }

    private static final String TAG = "DragRacingTrackActivity";

    private static final int LEGEND_MARGIN = 50;

    private static final int TOP_MARGIN = 300;
    private static final int TRACK_WIDTH = 30;
    private static final int TRACK_LENGTH = 800;
    private static final int TRACK_CENTER = 500;
    private static final int CAR_DISPLACEMENT = 10;

    private static final int FPS = 32;
    private static final int FPS_RATE = 1000 / FPS;

    private static final int IMPULSE_LENGTH = 30;

    private static final int BG_COLOR = Color.parseColor("#FFf3f3f3");
    private static final int[] CAR_COLORS = { Color.CYAN, Color.parseColor("#FF58b866"),
            Color.parseColor("#FFEE9C00"), Color.RED, Color.MAGENTA, Color.BLUE, Color.BLACK, Color.LTGRAY };

    private static final String[] INTERVAL_MARKERS = { "A", "B", "C", "D", "E", "F", "G", "H" };

    private static final String DR_REQ_CODE = "DRAGRACING_COMINGLE";
    private static final int DR_ADMIN_PORT = 8181;
    private static final int DR_FACT_PORT = 8819;

    private static final int RET_WIFI_SETTINGS = 203;

    private CoMingleAndroidRuntime<Dragracing> dragracingRuntime;

    private boolean gameStarted = false;
    private boolean postedWifiComplaint = false;

    private Canvas track_canvas;
    private LinkedList<Car> cars;
    private LinearLayout track;

    boolean timerStarted = false;
    Timer timer;
    TimerTask refreshTrackTask;

    int time_pressed;
    int time_released;

    int prev_refresh_time;

    boolean brakes = true;

    private Menu options_menu;

    //to keep track of number of lanes while moving
    public int lanes = 0;

    public void recordTimePressed() {
        time_pressed = (int) System.currentTimeMillis();
    }

    public void reportTimeReleased() {
        time_released = (int) System.currentTimeMillis();
        Toast.makeText(this, String.format("Duration: %s", time_released - time_pressed), Toast.LENGTH_SHORT)
                .show();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track);
        Bitmap bg = Bitmap.createBitmap(TRACK_LENGTH, 800, Bitmap.Config.ARGB_8888);
        track_canvas = new Canvas(bg);

        dragracingRuntime = new CoMingleAndroidRuntime<Dragracing>(this, Dragracing.class, DR_ADMIN_PORT,
                DR_FACT_PORT, DR_REQ_CODE);

        DirectoryChosenListener<Message> postDirChoiceListener = new DirectoryChosenListener<Message>() {
            @Override
            public void doDirectoryChosenAction(BaseDirectory<Message> directory) {
                setupDirectory();
            }
        };

        dragracingRuntime.initStandardDirectorySetup(R.layout.peer_list_row, R.id.peer_name, R.id.peer_loc,
                R.id.peer_ip, postDirChoiceListener);

        cars = new LinkedList<Car>();

        track = (LinearLayout) findViewById(R.id.track);
        track.setBackground(new BitmapDrawable(getResources(), bg));

        track.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!released()) {
                        dragracingRuntime.getRewriteMachine().addSendTap();
                    }
                    return true;
                }
                return true;
            }
        });
    }

    private void setupDirectory() {
        final TrackActivity self = this;
        /*
        dragracingRuntime.getDirectory().addNetworkStatusChangedListener(new NetworkStatusChangedListener() {
          @Override
          public void doWifiAdapterStatusChangedAction(boolean enabled) {            
          }
          @Override
          public void doWifiConnectionStatusChangedAction(boolean connected) {
        if(!postedWifiComplaint && dragracingRuntime.getDirectory().isWifiEnabled() && !dragracingRuntime.getDirectory().isWifiConnected()) {
           postConfigWifiConnection("Please form a wifi-direct group!");
        }
          }
        }); */
        dragracingRuntime.getDirectory().addLocalNodeInfoAvailableListener(new LocalNodeInfoAvailableListener() {
            @Override
            public void doLocalNodeInfoAvailableAction(NodeInfo local, final int role) {
                self.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        self.initSelfInfo();
                        self.startDragRacingRewriteMachine();
                    }
                });
            }
        });
        dragracingRuntime.getDirectory().addDirectoryChangedListener(new DirectoryChangedListener() {
            @Override
            public void doDirectoryChangedAction(final List<NodeInfo> new_peers, List<NodeInfo> added_nodes,
                    final List<NodeInfo> dropped_nodes, int role) {
                self.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        self.initOpponentsInfo(new_peers);
                        if (dropped_nodes.size() > 0) {
                            self.postAlert("Player Dropped", "A player has dropped out! Please restart the app!");
                        }
                    }
                });
            }
        });
    }

    private void startDragRacingRewriteMachine() {

        dragracingRuntime.initRewriteMachine();

        ActuatorAction<LinkedList<Integer>> renderTrackAction = new ActuatorAction<LinkedList<Integer>>() {
            @Override
            public void doAction(LinkedList<Integer> locs) {
                renderTrack(locs);
            }
        };
        dragracingRuntime.getRewriteMachine().setRenderTrackActuator(renderTrackAction);

        ActuatorAction<Unit> releaseAction = new ActuatorAction<Unit>() {
            @Override
            public void doAction(Unit arg0) {
                release();
            }
        };
        dragracingRuntime.getRewriteMachine().setReleaseActuator(releaseAction);

        ActuatorAction<Integer> recvTapAction = new ActuatorAction<Integer>() {
            @Override
            public void doAction(Integer car_idx) {
                tap(car_idx);
            }
        };
        dragracingRuntime.getRewriteMachine().setRecvTapActuator(recvTapAction);

        ActuatorAction<Integer> hasAction = new ActuatorAction<Integer>() {
            @Override
            public void doAction(Integer player_idx) {
                addPlayer(player_idx, true);
            }
        };
        dragracingRuntime.getRewriteMachine().setHasActuator(hasAction);

        ActuatorAction<Integer> decWinnerAction = new ActuatorAction<Integer>() {
            @Override
            public void doAction(Integer winner) {
                declareWinner(winner);
            }
        };
        dragracingRuntime.getRewriteMachine().setDecWinnerActuator(decWinnerAction);

        dragracingRuntime.startRewriteMachine();

        if (dragracingRuntime.isRewriteReady() && dragracingRuntime.isOwner()) {
            this.setMenuItemVisibility(R.id.action_start, true);
        }
    }

    public int getLocation() {
        return dragracingRuntime.getLocation();
    }

    @Override
    protected void onResume() {
        super.onResume();
        startTimerIfNeeded();
        dragracingRuntime.resumeNetworkNotifications();
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopTimerIfNeeded();
        dragracingRuntime.pauseNetworkNotifications();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopTimerIfNeeded();
        dragracingRuntime.close();
        // p2p_dir.close();
    }

    public void startTimerIfNeeded() {
        if (!timerStarted) {
            prev_refresh_time = (int) System.currentTimeMillis();
            timer = new Timer();
            final TrackActivity self = this;
            refreshTrackTask = new TimerTask() {
                @Override
                public void run() {
                    self.refreshTrack();
                }
            };
            timer.schedule(refreshTrackTask, 0, FPS_RATE);
            timerStarted = true;
        }
    }

    public void stopTimerIfNeeded() {
        if (timerStarted) {
            timer.cancel();
            timer.purge();
            timer = null;
            timerStarted = false;
        }
    }

    public int getPrevRefreshTime() {
        return prev_refresh_time;
    }

    public void setPrevRefreshTime(int new_refresh_time) {
        prev_refresh_time = new_refresh_time;
    }

    public void renderTrack(LinkedList<Integer> locs) {

        //decide phone_order for rendering tracks
        for (int x = 0; x < locs.size(); x++) {
            if (locs.get(x) == this.getLocation()) {
                if (x > 0) {
                    initTrack(locs.size() - 1, 1);
                }
                if (x < locs.size() - 1) {
                    initTrack(locs.size() - 1, 0);

                    break;
                }
            }
        }

        initMarkers(locs);
    }

    private void initTrack(int num_of_lanes, int phone_order) {
        Paint paint = new Paint();
        lanes = num_of_lanes;
        for (int i = 0; i <= num_of_lanes; i++) {
            paint.setColor(CAR_COLORS[i]);
            float top_track_y = TOP_MARGIN + TRACK_WIDTH * i;
            // float bot_track_y = TOP_MARGIN + TRACK_CENTER + TRACK_WIDTH*i;

            //rendering double track instead of single
            if (phone_order == 0) {
                track_canvas.drawLine(75, top_track_y, 800, top_track_y, paint);
                track_canvas.drawLine(75, top_track_y + 7, 800, top_track_y + 7, paint);
            } else {
                track_canvas.drawLine(0, top_track_y, 800, top_track_y, paint);
                track_canvas.drawLine(0, top_track_y + 7, 800, top_track_y + 7, paint);
            }
            // track_canvas.drawLine(0, bot_track_y, 800, bot_track_y, paint);

        }
    }

    private void initMarkers(LinkedList<Integer> locs) {
        Paint text_paint = new Paint();
        text_paint.setColor(Color.BLACK);
        text_paint.setTextSize(20);

        String prev = "Start";
        String next = "End";
        int x = locs.indexOf(getLocation());

        if (x == locs.size() - 1) {
            initEndFlag();
        }

        if (x == 0) {
            initStartFlag();
        }

        if (x > 0) {
            prev = String.format("<< %s", INTERVAL_MARKERS[x - 1]);
        }

        if (x < locs.size() - 1) {
            next = String.format("%s >>", INTERVAL_MARKERS[x]);
        }

        //adjusted placement of markers
        track_canvas.drawText(prev, 20, TOP_MARGIN - 70, text_paint);
        track_canvas.drawText(next, 800 - 50, TOP_MARGIN - 70, text_paint);

    }

    private void initStartFlag() {
        Paint text_paint = new Paint();
        text_paint.setColor(Color.BLACK);
        text_paint.setTextSize(20);

        switch (lanes) {
        case 1:
        case 2:
        case 3:
            for (int j = 0; j <= 50; j = j + 50) {
                for (int i = 250; i <= 380; i = i + 40) {
                    track_canvas.drawRect(j, i, j + 25, i + 20, text_paint);
                }
            }
            for (int k = 270; k <= 400; k = k + 40) {
                track_canvas.drawRect(25, k, 50, k + 20, text_paint);
            }
            break;
        case 4:
            for (int j = 0; j <= 50; j = j + 50) {
                for (int i = 250; i <= 420; i = i + 40) {
                    track_canvas.drawRect(j, i, j + 25, i + 20, text_paint);
                }
            }
            for (int k = 270; k <= 440; k = k + 40) {
                track_canvas.drawRect(25, k, 50, k + 20, text_paint);
            }
            ;
            break;
        case 5:
            for (int j = 0; j <= 50; j = j + 50) {
                for (int i = 250; i <= 460; i = i + 40) {
                    track_canvas.drawRect(j, i, j + 25, i + 20, text_paint);
                }
            }
            for (int k = 270; k <= 480; k = k + 40) {
                track_canvas.drawRect(25, k, 50, k + 20, text_paint);
            }
            ;
            break;
        case 6:
            for (int j = 0; j <= 50; j = j + 50) {
                for (int i = 250; i <= 500; i = i + 40) {
                    track_canvas.drawRect(j, i, j + 25, i + 20, text_paint);
                }
            }
            for (int k = 270; k <= 520; k = k + 40) {
                track_canvas.drawRect(25, k, 50, k + 20, text_paint);
            }
            ;
            break;
        }
    }

    private void initEndFlag() {
        Paint text_paint = new Paint();
        text_paint.setColor(Color.BLACK);
        text_paint.setTextSize(20);
        switch (lanes) {
        case 1:
        case 2:
        case 3:

            track_canvas.drawRect(780, 250, 800, 380, text_paint);
            break;
        case 4:
            track_canvas.drawRect(780, 250, 800, 420, text_paint);
            break;
        case 5:
            track_canvas.drawRect(780, 250, 800, 460, text_paint);
            break;
        case 6:
            track_canvas.drawRect(780, 250, 800, 500, text_paint);
            break;
        }
    }

    public void moveCar(Car car, int time_prev, int time_curr) {
        Paint bg_paint = new Paint();
        bg_paint.setColor(BG_COLOR);
        track_canvas.drawRect(car.getSprite(), bg_paint);
        int new_pos = RacerLib.newPos(car.getSprite().left, time_prev, time_curr);

        if (new_pos < TRACK_LENGTH) {
            car.move(new_pos);
            track_canvas.drawRect(car.getSprite(), car.getPaint());
        } else {
            removeCar(car.getOwner());
            dragracingRuntime.getRewriteMachine().addExiting(car.getOwner());
        }
    }

    public void refreshTrack() {
        final TrackActivity self = this;
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                int curr_refresh_time = (int) System.currentTimeMillis();
                int prev_refresh_time = self.getPrevRefreshTime();
                for (int i = 0; i < cars.size(); i++) {
                    Car car = cars.get(i);
                    if (car.checkImpulse(curr_refresh_time)) {
                        self.moveCar(car, prev_refresh_time, curr_refresh_time);
                    }
                }
                self.setPrevRefreshTime(curr_refresh_time);
                track.invalidate();
            }
        });
    }

    private int myLocation() {
        return dragracingRuntime.getLocation();
    }

    private void placeCarAvailable(int car_idx, int left_margin, int pos_idx) {
        if (car_idx >= CAR_COLORS.length) {
            return;
        }

        Paint car_paint = new Paint();
        if (car_idx >= 0) {
            car_paint.setColor(CAR_COLORS[car_idx]);
        } else {
            car_paint.setColor(BG_COLOR);
        }

        int left = left_margin + TRACK_WIDTH * pos_idx + 20;
        int right = left_margin + TRACK_WIDTH * (pos_idx + 1) + 20;
        int top = LEGEND_MARGIN + 2;
        int bottom = LEGEND_MARGIN + TRACK_WIDTH - 2;
        Rect sprite = new Rect(left, top, right, bottom);

        track_canvas.drawRect(sprite, car_paint);

    }

    private void initSelfInfo() {
        Paint text_paint = new Paint();
        text_paint.setColor(Color.BLACK);
        text_paint.setTextSize(20);

        track_canvas.drawText("YOU:", 20, LEGEND_MARGIN - 20, text_paint);
        track_canvas.drawText("THE BAD & UGLY:", 520, LEGEND_MARGIN - 20, text_paint);

        placeCarAvailable(myLocation(), 0, 0);
    }

    private void initOpponentsInfo(List<NodeInfo> new_nodes) {
        if (!dragracingRuntime.isRewriteReady()) {
            return;
        }
        for (int x = 0; x < CAR_COLORS.length - 1; x++) {
            placeCarAvailable(-1, 500, x);
        }
        int opp_count = 0;
        for (NodeInfo opp : new_nodes) {
            if (opp.location != myLocation()) {
                placeCarAvailable(opp.location, 500, opp_count);
                opp_count++;
            }
        }
    }

    public void beginRace() {
        this.gameStarted = true;
        // int myLoc = dragracingRuntime.getLocation();
        LinkedList<Integer> locs = (LinkedList<Integer>) dragracingRuntime.getDirectory().getLocations();
        dragracingRuntime.getRewriteMachine().addInitRace(locs);
        this.setMenuItemVisibility(R.id.action_go, true);
        this.setMenuItemVisibility(R.id.action_start, false);
    }

    public void restartGame() {

        setBrakes(true);

        cars = new LinkedList<Car>();

        track_canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        startDragRacingRewriteMachine();

        if (dragracingRuntime.isOwner()) {
            beginRace();
        }

    }

    public void declareWinner(final int car_idx) {

        final TrackActivity self = this;

        self.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String msg;
                if (self.getLocation() == car_idx) {
                    msg = "YOU WIN!";
                } else {
                    msg = "YOU LOSE!";
                }
                self.restartGame();
                self.postAlert("Game Over", msg);
            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.track, menu);
        options_menu = menu;
        if (dragracingRuntime.isRewriteReady() && dragracingRuntime.isOwner()) {
            this.setMenuItemVisibility(R.id.action_start, true);
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        int myLoc = getLocation();
        switch (id) {
        case R.id.action_settings:
            return true;
        case R.id.action_start:
            if (myLoc == 0) {
                beginRace();
            }
            return true;
        case R.id.action_go:
            if (myLoc == 0) {
                dragracingRuntime.getRewriteMachine().addGo();
            }
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public void setMenuItemVisibility(int id, boolean visible) {
        if (options_menu == null) {
            String msg = "Option menu is null";
            Log.e(TAG, msg);
            // postToast(msg);
            return;
        }
        MenuItem item = options_menu.findItem(id);
        if (item != null) {
            item.setVisible(visible);
        } else {
            String msg = "Failed to find item " + id;
            Log.e(TAG, msg);
            // postToast(msg);
        }
    }

    public void postAlert(final String title, final String msg) {
        final TrackActivity self = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder alert = new AlertDialog.Builder(self);
                alert.setTitle(title);
                alert.setMessage(msg);
                alert.setPositiveButton("Ok", new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                alert.show();
            }
        });
    }

    public void postConfigWifiConnection(final String msg) {
        if (postedWifiComplaint) {
            return;
        }
        postedWifiComplaint = true;
        final TrackActivity self = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                AlertDialog.Builder alert = new AlertDialog.Builder(self);
                alert.setTitle("No Wifi-Direct Connection");
                alert.setMessage(msg);
                alert.setPositiveButton("Settings", new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        self.startActivityForResult(new Intent(Settings.ACTION_WIFI_SETTINGS), RET_WIFI_SETTINGS);
                        dialog.dismiss();
                    }
                });
                alert.setNegativeButton("Close", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        self.finish();
                    }
                });
                alert.show();
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        /* if (requestCode == RET_WIFI_SETTINGS){
           postedWifiComplaint = false;
        } */
        this.dragracingRuntime.handleOnActivityResults(requestCode);
    }

    public void postToast(final String msg) {
        final TrackActivity self = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(self, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }

    // Car Methods
    public void addPlayer(int loc) {
        Car car = new Car(loc);
        cars.addLast(car);
        track_canvas.drawRect(car.getSprite(), car.getPaint());
    }

    public void addPlayer(int loc, boolean acc) {
        Car car = new Car(loc);
        car.toggle(acc);
        cars.addLast(car);
        track_canvas.drawRect(car.getSprite(), car.getPaint());
    }

    public void removeCar(int loc) {
        for (int x = 0; x < cars.size(); x++) {
            Car car = cars.get(x);
            if (car.getOwner() == loc) {
                Paint bg_paint = new Paint();
                bg_paint.setColor(BG_COLOR);
                track_canvas.drawRect(car.getSprite(), bg_paint);
                cars.remove(x);
                return;
            }
        }
    }

    public void tap(int loc) {
        for (Car car : cars) {
            if (loc == car.getOwner()) {
                car.impulse();
                return;
            }
        }
    }

    public void countDown(final int count) {
        final TrackActivity self = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    int cnt = count;
                    while (cnt > 0) {
                        Toast.makeText(self, String.format("Get Ready: %s", cnt), Toast.LENGTH_SHORT).show();
                        Thread.sleep(1000);
                        cnt--;
                    }
                    Toast.makeText(self, "GO!!!", Toast.LENGTH_SHORT).show();
                    self.setBrakes(false);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
    }

    public void release() {
        countDown(0);
    }

    public void setBrakes(boolean br) {
        brakes = br;
    }

    public boolean released() {
        return brakes;
    }

}