diff --git a/.idea/misc.xml b/.idea/misc.xml index 738edfe..406ac20 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -56,7 +56,7 @@ - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index f58a768..e0915b0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.de.aldo_apps.aldo.mariokartcircuitselector" minSdkVersion 16 targetSdkVersion 25 - versionCode 3 - versionName "0.3" + versionCode 4 + versionName "0.4" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/assets/mario_kart_circuit_selector b/app/src/main/assets/mario_kart_circuit_selector new file mode 100644 index 0000000..a978ba1 Binary files /dev/null and b/app/src/main/assets/mario_kart_circuit_selector differ diff --git a/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/Constants.java b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/Constants.java index 9681f6a..f26048c 100644 --- a/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/Constants.java +++ b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/Constants.java @@ -6,6 +6,11 @@ package com.de.aldo_apps.aldo.mariokartcircuitselector; public class Constants { + /** + * The Version Code of the Database. + */ + public static final Integer DATABASE_VERSION = 1; + /** * As SQLite does not have a native boolean value, we use integers to represent true and false. * This is the value for a true statement. @@ -18,10 +23,16 @@ public class Constants { */ public final static Integer FALSE = 0; + /** + * The Path to the Database + */ + public static final String DATABASE_PATH + = "/data/data/com.de.aldo_apps.aldo.mariokartcircuitselector/databases/"; + /** * The Name of the complete database. */ - public static final String DATABASE_NAME = "mario_kart_circuit_selector.db"; + public static final String DATABASE_NAME = "mario_kart_circuit_selector"; /** * The name of the table containing all information according accessories. diff --git a/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/DatabaseHandler.java b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/DatabaseHandler.java new file mode 100644 index 0000000..0c5d2ad --- /dev/null +++ b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/DatabaseHandler.java @@ -0,0 +1,329 @@ +package com.de.aldo_apps.aldo.mariokartcircuitselector; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Accessory; +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Character; +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Kart; +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Track; +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Wheels; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.KEY_AVAILABLE; +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.KEY_GAME; +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.KEY_ID; +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.KEY_NAME; +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.TABLE_TRACK; +import static com.de.aldo_apps.aldo.mariokartcircuitselector.Constants.TABLE_WHEELS; + +/** + * The Database Handler class which opens/closes connection and handles all CRUD Operations + * on the Database. + * + * @author aldo7224 + * @version 0.1 + * @since 08.08.2017 + */ +public class DatabaseHandler extends SQLiteOpenHelper { + + /** + * Tag for debugging output. + */ + private static final String TAG = "DatabaseHandler"; + + private final Context mContext; + + private SQLiteDatabase mDatabase; + + public DatabaseHandler(final Context context) { + super(context, Constants.DATABASE_NAME, null, Constants.DATABASE_VERSION); + mContext = context; + } + + @Override + public void onCreate(final SQLiteDatabase sqLiteDatabase) { + + mDatabase = sqLiteDatabase; + + Log.d(TAG, "onCreate: Is new database opened? [" + mDatabase.isOpen() + "]"); + + if (!checkDataBase()) { + // Maybe the DB already exists but we need to upgrade. + Log.d(TAG, "onCreate: Dropping all Tables (in case they already exist)."); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_GAME); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_ACCESSORY); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_CHARACTER); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_KART); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_RULESET); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Constants.TABLE_TRACK); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_WHEELS); + + try { + Log.d(TAG, "onCreate: Copying the Database from Assets Folder to database path."); + copyDataBase(); + } catch (IOException exception) { + Log.d(TAG, "onCreate: Could not Copy Database. Exception [" + + exception.getMessage() + "]"); + } + + } + } + + @Override + public void onUpgrade(final SQLiteDatabase sqLiteDatabase, + final int oldVersion, + final int newVersion) { + // Dropping Tables and Creating them again. All handled by onCreate. + Log.d(TAG, "onUpgrade: Databse was upgraded. Performing upgrade."); + onCreate(sqLiteDatabase); + } + + /** + * Check if the database already exist to avoid re-copying the file each time you open the + * application. Also check if the Version Code of the Database changed, so maybe the data need + * to be copied again. + * @return true if it exists, false if it doesn't + */ + private boolean checkDataBase(){ + + Log.d(TAG, "checkDataBase: Checking Database availability."); + SQLiteDatabase checkDB = null; + + if (mDatabase != null && mDatabase.isOpen()) { + Log.d(TAG, "checkDataBase: Closing real database to prevent exception when " + + "opening test DB."); + checkDB = mDatabase; + } else { + try { + final String myPath = Constants.DATABASE_PATH + Constants.DATABASE_NAME; + Log.d(TAG, "checkDataBase: Opening Test-Database."); + checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); + + } catch (final SQLiteException exception) { + //database does't exist yet. + Log.d(TAG, "checkDataBase: Opening of database throws Exception [" + + exception.getMessage() + "]. Database seems to not exist yet."); + } + } + // If Database exists we need to close the Database. + if (checkDB != null) { + Log.d(TAG, "checkDataBase: Database seems to exist already."); + // If the Version Code is Lower than the predefined value, we need to upgrade the DB. + if (checkDB.getVersion() < Constants.DATABASE_VERSION) { + Log.d(TAG, "checkDataBase: Database Version code from new and old one differ."); + checkDB.close(); + return false; + } + Log.d(TAG, "checkDataBase: Closing Database."); + checkDB.close(); + } + return checkDB != null; + } + + /** + * Copies your database from your local assets-folder to the just created empty database in the + * system folder, from where it can be accessed and handled. + * This is done by transfering bytestream. + * */ + private void copyDataBase() throws IOException { + + //Open your local db as the input stream + Log.d(TAG, "copyDataBase: Opening InputStream for DB in assets folder."); + final InputStream inputStream = mContext.getAssets().open(Constants.DATABASE_NAME); + + // Path to the just created empty db + final String outFileName = Constants.DATABASE_PATH + Constants.DATABASE_NAME; + + //Open the empty db as the output stream + Log.d(TAG, "copyDataBase: Opening Outputstream for DB on hard disk [" + outFileName + "]"); + final OutputStream outputStream = new FileOutputStream(outFileName); + + //transfer bytes from the inputfile to the outputfile + final byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) > 0) { + Log.d(TAG, "copyDataBase: Writing single Chunk of DB from assets to hard disk."); + outputStream.write(buffer, 0, length); + } + + //Close the streams + Log.d(TAG, "copyDataBase: Flushing Stream."); + outputStream.flush(); + Log.d(TAG, "copyDataBase: Closing Output Stream."); + outputStream.close(); + Log.d(TAG, "copyDataBase: Closing Input Stream."); + inputStream.close(); + + } + + /** + * Helper method to update the availability status of a single track. + * + * @param track The track which should be marked as available/unavailable. + * @param isAvailable The status of availability to be set. + * + * @return The result code of the update function. + */ + public int changeTrackAvailability(final Track track, final boolean isAvailable) { + final SQLiteDatabase db = this.getWritableDatabase(); + + final ContentValues values = new ContentValues(); + values.put(Constants.KEY_GAME, track.getGame()); + values.put(KEY_NAME, track.getName()); + values.put(Constants.KEY_PACKAGE, track.getPackage()); + values.put(Constants.KEY_NUMBER, track.getmNumber()); + if (isAvailable) { + values.put(KEY_AVAILABLE, Constants.TRUE); + } else { + values.put(KEY_AVAILABLE, Constants.FALSE); + } + + return db.update(Constants.TABLE_TRACK, values, KEY_ID + " = ?", + new String[] {String.valueOf(track.getId()) }); + } + + /** + * Helper method to update the availability status of a single character. + * + * @param character The character which should be marked as available/unavailable. + * @param isAvailable The status of availability to be set. + * + * @return The result code of the update function. + */ + public int changeCharacterAvailability(final Character character, final boolean isAvailable) { + final SQLiteDatabase db = this.getWritableDatabase(); + + final ContentValues values = new ContentValues(); + values.put(Constants.KEY_GAME, character.getGame()); + values.put(KEY_NAME, character.getName()); + values.put(Constants.KEY_WEIGHT, character.getWeight()); + if (isAvailable) { + values.put(KEY_AVAILABLE, Constants.TRUE); + } else { + values.put(KEY_AVAILABLE, Constants.FALSE); + } + + return db.update(Constants.TABLE_CHARACTER, values, KEY_ID + " = ?", + new String[] {String.valueOf(character.getId()) }); + } + + /** + * Helper method to update the availability status of a single kart. + * + * @param kart The kart which should be marked as available/unavailable. + * @param isAvailable The status of availability to be set. + * + * @return The result code of the update function. + */ + public int changeKartAvailability(final Kart kart, final boolean isAvailable) { + final SQLiteDatabase db = this.getWritableDatabase(); + + final ContentValues values = new ContentValues(); + values.put(Constants.KEY_GAME, kart.getGame()); + values.put(KEY_NAME, kart.getName()); + values.put(Constants.KEY_WEIGHT, kart.getWeight()); + values.put(Constants.KEY_WHEELS, kart.getWheels()); + values.put(Constants.KEY_ACCESSORY, kart.getAccessory()); + values.put(Constants.KEY_DEDICATED_DRIVER, kart.getDedicatedDriver()); + values.put(Constants.KEY_FREE_FOR_ALL, kart.getFreeForAll()); + if (isAvailable) { + values.put(KEY_AVAILABLE, Constants.TRUE); + } else { + values.put(KEY_AVAILABLE, Constants.FALSE); + } + + return db.update(Constants.TABLE_KART, values, KEY_ID + " = ?", + new String[] {String.valueOf(kart.getId()) }); + } + + /** + * Helper method to update the availability status of a single accessory. + * + * @param accessory The accessory which should be marked as available/unavailable. + * @param isAvailable The status of availability to be set. + * + * @return The result code of the update function. + */ + public int changeAccessoryAvailability(final Accessory accessory, final boolean isAvailable) { + final SQLiteDatabase db = this.getWritableDatabase(); + + final ContentValues values = new ContentValues(); + values.put(Constants.KEY_GAME, accessory.getGame()); + values.put(KEY_NAME, accessory.getName()); + if (isAvailable) { + values.put(KEY_AVAILABLE, Constants.TRUE); + } else { + values.put(KEY_AVAILABLE, Constants.FALSE); + } + + return db.update(Constants.TABLE_ACCESSORY, values, KEY_ID + " = ?", + new String[] {String.valueOf(accessory.getId()) }); + } + + /** + * Helper method to update the availability status of a single wheels. + * + * @param wheels The wheels which should be marked as available/unavailable. + * @param isAvailable The status of availability to be set. + * + * @return The result code of the update function. + */ + public int changeWheelsAvailability(final Wheels wheels, final boolean isAvailable) { + final SQLiteDatabase db = this.getWritableDatabase(); + + final ContentValues values = new ContentValues(); + values.put(Constants.KEY_GAME, wheels.getGame()); + values.put(KEY_NAME, wheels.getGame()); + if (isAvailable) { + values.put(KEY_AVAILABLE, Constants.TRUE); + } else { + values.put(KEY_AVAILABLE, Constants.FALSE); + } + + return db.update(TABLE_WHEELS, values, KEY_ID + " = ?", + new String[] {String.valueOf(wheels.getId()) }); + } + + public Track testDBConnection(final int id) { + Log.d(TAG, "testDBConnection: Opening Readable Database."); + final SQLiteDatabase dbToUse; + if (mDatabase != null && mDatabase.isOpen()) { + dbToUse = mDatabase; + } else { + dbToUse = this.getReadableDatabase(); + } + + Log.d(TAG, "testDBConnection: Query a single track for id = [" + id + "]"); + Cursor cursor = dbToUse.query(TABLE_TRACK, new String[] { KEY_ID, + KEY_NAME, KEY_AVAILABLE }, KEY_ID + "=?", + new String[] { String.valueOf(id) }, null, null, null, null); + if (cursor != null) { + Log.d(TAG, "testDBConnection: Moving cursor to first."); + cursor.moveToFirst(); + } else { + Log.d(TAG, "testDBConnection: cursor is null"); + return null; + } + + Track track = new Track(); + track.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME))); + track.setGame(cursor.getString(cursor.getColumnIndex(KEY_GAME))); + track.setId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(KEY_ID)))); + track.setAvailable(Integer.parseInt(cursor.getString(cursor.getColumnIndex(KEY_AVAILABLE)))); + + dbToUse.close(); + + // return contact + return track; + } +} diff --git a/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/GameSelection.java b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/GameSelection.java index 2737ef5..d38be24 100644 --- a/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/GameSelection.java +++ b/app/src/main/java/com/de/aldo_apps/aldo/mariokartcircuitselector/GameSelection.java @@ -2,6 +2,12 @@ package com.de.aldo_apps.aldo.mariokartcircuitselector; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import com.de.aldo_apps.aldo.mariokartcircuitselector.database_models.Track; public class GameSelection extends AppCompatActivity { @@ -9,5 +15,24 @@ public class GameSelection extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game_selection); + + final DatabaseHandler handler = new DatabaseHandler(this); + + final EditText editText = (EditText) findViewById(R.id.id_input); + + final Button button = (Button) findViewById(R.id.ok_button); + + final TextView result = (TextView) findViewById(R.id.result_field); + + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + final int id = Integer.parseInt(editText.getText().toString()); + final Track track = handler.testDBConnection(id); + final String resultStr = track.getGame() + " - " + track.getName() + " - " + track.getAvailable() + " - "; + result.setText(resultStr); + } + }); + } } diff --git a/app/src/main/res/layout/activity_game_selection.xml b/app/src/main/res/layout/activity_game_selection.xml index d700bea..547d5ec 100644 --- a/app/src/main/res/layout/activity_game_selection.xml +++ b/app/src/main/res/layout/activity_game_selection.xml @@ -1,18 +1,30 @@ - + + +