Java tutorial
/******************************************************************************* * Copyright 2014 Hyplink (solideclipse@gmail.com) * * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0 * * 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 hyplink.net.pot; import hyplink.net.general.MathUtils; import hyplink.net.pot.Grid.GridState; import hyplink.net.pot.SwipeController.SwipeDirection; import hyplink.net.pot.SwipeController.SwipeHandler; import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.pm.ActivityInfo; import android.media.AudioManager; import android.media.SoundPool; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.TextView; import android.widget.Toast; import com.startapp.android.publish.StartAppAd; import com.startapp.android.publish.StartAppSDK; /** Main game launcher activity */ public class GameActivity extends FragmentActivity implements SwipeHandler { // ========================= CONSTANTS ========================= // ========================= VARIABLES ========================= private ViewGroup gridRenderer; private CellRenderer[] cellRenderers = new CellRenderer[16]; private TextView scoreRenderer; private TextView bestScoreRenderer; private AlertDialog dialog; private Animation animation; private MenuItem soundMenuItem; private Grid grid; private GamePreferences gamePreferences; private SwipeController controller; private boolean soundEnabled; private AudioManager audioManager; private SoundPool soundPool; private int moveSoundId; private StartAppAd startAppAd = new StartAppAd(this); // ======================== CONSTRUCTORS ======================= // ==================== GETTERS AND SETTERS ==================== // ====================== OVERRIDE METHODS ===================== @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // load logic grid = new Grid(); // load controller controller = new SwipeController(this); // load data gamePreferences = new GamePreferences(this); // load sound audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0); // load view setOrientation(); StartAppSDK.init(this, "108710732", "208747074", true); StartAppAd.showSplash(this, savedInstanceState); setContentView(R.layout.game); loadView(); // load animation animation = AnimationUtils.loadAnimation(this, R.anim.cell_animation); } @Override protected void onResume() { super.onResume(); startAppAd.onResume(); // change orientation setOrientation(); // load sound setting soundEnabled = gamePreferences.loadSoundSetting(); // load sound when resume moveSoundId = soundPool.load(this, R.raw.move, 1); // Load game when resume grid.loadData(gamePreferences); // Avoid load invalid game on first run or user quit when lost. if (grid.getState() == GridState.LOSE) { resetGame(); } // show in UI updateView(); } @Override protected void onPause() { super.onPause(); startAppAd.onPause(); // unload sound soundPool.unload(moveSoundId); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu items for use in the action bar MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); soundMenuItem = menu.findItem(R.id.action_sound); // Prevent wrong icon when orientation change boolean soundEnabled = gamePreferences.loadSoundSetting(); soundMenuItem.setIcon(soundEnabled ? R.drawable.ic_action_sound_on : R.drawable.ic_action_sound_off); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle presses on the action bar items switch (item.getItemId()) { case R.id.action_new: showNewGameConfirmDialog(); return true; case R.id.action_sound: toogleSound(); return true; case R.id.action_orientation: toogleOrientation(); return true; case R.id.action_share: share(); return true; case R.id.action_rate: rate(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void handleMove(SwipeDirection direction) { // move grid if (grid.move(direction)) { // active animation cellRenderers[grid.getLastFilledPosition()].setAnimation(animation); // play sound playSound(moveSoundId); // save data grid.saveData(gamePreferences); // update best score if (gamePreferences.loadBestScore() < grid.getScore()) { gamePreferences.saveBestScore(grid.getScore()); } // show in UI updateView(); } // handle when state change if (grid.getState() != GridState.PLAY) { showEndGameDialog(grid.getState()); } } // ====================== PUBLIC METHODS ======================= // ===================== PROTECTED METHODS ===================== // ====================== DEFAULT METHODS ====================== // ====================== PRIVATE METHODS ====================== private void loadView() { gridRenderer = (ViewGroup) findViewById(R.id.grid); gridRenderer.setOnTouchListener(controller); cellRenderers[0] = (CellRenderer) findViewById(R.id.cell1); cellRenderers[1] = (CellRenderer) findViewById(R.id.cell2); cellRenderers[2] = (CellRenderer) findViewById(R.id.cell3); cellRenderers[3] = (CellRenderer) findViewById(R.id.cell4); cellRenderers[4] = (CellRenderer) findViewById(R.id.cell5); cellRenderers[5] = (CellRenderer) findViewById(R.id.cell6); cellRenderers[6] = (CellRenderer) findViewById(R.id.cell7); cellRenderers[7] = (CellRenderer) findViewById(R.id.cell8); cellRenderers[8] = (CellRenderer) findViewById(R.id.cell9); cellRenderers[9] = (CellRenderer) findViewById(R.id.cell10); cellRenderers[10] = (CellRenderer) findViewById(R.id.cell11); cellRenderers[11] = (CellRenderer) findViewById(R.id.cell12); cellRenderers[12] = (CellRenderer) findViewById(R.id.cell13); cellRenderers[13] = (CellRenderer) findViewById(R.id.cell14); cellRenderers[14] = (CellRenderer) findViewById(R.id.cell15); cellRenderers[15] = (CellRenderer) findViewById(R.id.cell16); scoreRenderer = (TextView) findViewById(R.id.score); bestScoreRenderer = (TextView) findViewById(R.id.best_score); } private void updateView() { // Display the grid for (int i = 0; i < cellRenderers.length; i++) { cellRenderers[i].setValue(grid.getValueAtIndex(i)); } // Display score scoreRenderer.setText(String.valueOf(grid.getScore())); // Display best score bestScoreRenderer.setText(String.valueOf(gamePreferences.loadBestScore())); } private void playSound(int soundId) { if (soundEnabled) { float curVol = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); float maxVol = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); float vol = curVol / maxVol; soundPool.play(soundId, vol, vol, 0, 0, 1); } } private void toogleSound() { soundEnabled = !soundEnabled; gamePreferences.saveSoundSetting(soundEnabled); soundMenuItem.setIcon(soundEnabled ? R.drawable.ic_action_sound_on : R.drawable.ic_action_sound_off); } private void showEndGameDialog(GridState state) { dialog = new AlertDialog.Builder(this).create(); // Disable BACK key switch (state) { case WIN: dialog.setTitle(R.string.win_title); dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.expand), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { grid.expandingMode(); dialog.dismiss(); } }); break; case LOSE: dialog.setTitle(R.string.lose_title); dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.rate), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { rate(); } }); break; default: break; } Object param; StringBuilder message = new StringBuilder(); if (grid.getScore() == gamePreferences.loadBestScore()) { message.append(getString(R.string.best_score_reach_message)); message.append("\n"); param = Integer.valueOf(grid.getScore()); String format = getString(R.string.player_score_message); message.append(String.format(format, param)); } else { param = Integer.valueOf(grid.getScore()); String format = getString(R.string.player_score_message); message.append(String.format(format, param)); message.append("\n"); param = Integer.valueOf(gamePreferences.loadBestScore()); format = getString(R.string.best_score_message); message.append(String.format(format, param)); } dialog.setMessage(message); dialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.new_game), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { resetGame(); dialog.dismiss(); } }); dialog.setButton(DialogInterface.BUTTON_NEUTRAL, getString(R.string.share), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { share(); } }); dialog.setCanceledOnTouchOutside(false); dialog.setCancelable(false); dialog.show(); } private void showNewGameConfirmDialog() { dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.confirm_title); dialog.setMessage(getString(R.string.confirm_new_game_message)); dialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.text_yes), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { resetGame(); dialog.dismiss(); } }); dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.text_no), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dialog.show(); } private void resetGame() { grid = new Grid(); grid.saveData(gamePreferences); updateView(); // 50% showAds(0.5f); } private void rate() { Intent intent = new Intent("android.intent.action.VIEW"); intent.setData(Uri.parse(getString(R.string.app_market))); try { startActivity(intent); } catch (ActivityNotFoundException e) { try { intent.setData(Uri.parse(getString(R.string.app_url))); startActivity(intent); } catch (ActivityNotFoundException ex) { Toast.makeText(this, getString(R.string.rate_error), Toast.LENGTH_SHORT).show(); } } } private void share() { Intent intent = new Intent("android.intent.action.SEND"); Object[] args = new Object[3]; args[0] = Integer.valueOf(grid.getScore()); args[1] = getString(R.string.app_market); args[2] = getString(R.string.app_url); String message = getString(R.string.share_message, args); intent.putExtra("android.intent.extra.TEXT", message); intent.setType("text/plain"); startActivity(intent); } private void setOrientation() { int orientation = gamePreferences.loadOrientationSetting(); if (getRequestedOrientation() == orientation) { return; } setRequestedOrientation(orientation); } @TargetApi(Build.VERSION_CODES.GINGERBREAD) private void toogleOrientation() { int orientation = getRequestedOrientation(); switch (orientation) { case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; break; case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; break; default: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; } gamePreferences.saveOrientationSetting(orientation); setRequestedOrientation(orientation); } private void showAds(float chance) { if (MathUtils.randomBoolean(chance)) { startAppAd.showAd(); // show the ad startAppAd.loadAd(); // load the next ad } } // ====================== INNER INTERFACES ===================== // ======================= INNER CLASSES ======================= }