Scores are now saved in SQLite and can be send to the /me/games API endpoint

This commit is contained in:
Ruben 2016-09-03 18:22:18 +01:00
parent 5bdda26f30
commit f5fa4ead2f
12 changed files with 852 additions and 70 deletions

View file

@ -1,20 +1,27 @@
package com.rubenvandeven.emotionhero; package com.rubenvandeven.emotionhero;
import android.content.Context; import android.content.Context;
import android.graphics.PointF;
import android.util.Log; import android.util.Log;
import com.google.gson.Gson;
import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler; import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestHandle;
import com.loopj.android.http.RequestParams; import com.loopj.android.http.RequestParams;
import com.loopj.android.http.SyncHttpClient; import com.loopj.android.http.SyncHttpClient;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.HeaderElement; import cz.msebera.android.httpclient.HeaderElement;
import cz.msebera.android.httpclient.ParseException; import cz.msebera.android.httpclient.ParseException;
import cz.msebera.android.httpclient.entity.StringEntity;
/** /**
* Created by ruben on 01/09/16. * Created by ruben on 01/09/16.
@ -26,7 +33,7 @@ public class ApiRestClient {
private static final String BASE_URL = "http://api.emotionhero.com"; // TODO: https! private static final String BASE_URL = "http://api.emotionhero.com"; // TODO: https!
private static AsyncHttpClient client = new AsyncHttpClient(); private static AsyncHttpClient client = new AsyncHttpClient();
private static SyncHttpClient syncClient = new SyncHttpClient(); // private static SyncHttpClient syncClient = new SyncHttpClient();
private String jwt; private String jwt;
@ -38,7 +45,7 @@ public class ApiRestClient {
public void registerIfNeeded() { public void registerIfNeeded() {
if(player.getJWT() == null) { if(player.getJWT() == null) {
requestWithJWT(null, null, null, null); requestWithJWT(null, null, null, null, null);
} }
} }
@ -47,10 +54,11 @@ public class ApiRestClient {
* @todo However, custom token endpoint should be used eventually * @todo However, custom token endpoint should be used eventually
* @param method * @param method
* @param url * @param url
* @param params * @param postBody
* @param getParams
* @param responseHandler * @param responseHandler
*/ */
public void requestWithJWT(final String method, final String url, final RequestParams params, final AsyncHttpResponseHandler responseHandler) { public void requestWithJWT(final String method, final String url, final StringEntity postBody, final RequestParams getParams, final AsyncHttpResponseHandler responseHandler) {
// sync call, so we can return a value! // sync call, so we can return a value!
client.post(BASE_URL + "/api/register", null, new JsonHttpResponseHandler() { client.post(BASE_URL + "/api/register", null, new JsonHttpResponseHandler() {
@Override @Override
@ -65,7 +73,7 @@ public class ApiRestClient {
getPlayer().setRemoteId(remoteId); getPlayer().setRemoteId(remoteId);
if(method != null) { if(method != null) {
ApiRestClient.this.request( method, url, params, responseHandler); ApiRestClient.this.request( method, url, postBody, getParams, responseHandler);
} }
} catch (JSONException e) { } catch (JSONException e) {
// responseHandler.sendFailureMessage(500, null, null); // responseHandler.sendFailureMessage(500, null, null);
@ -115,35 +123,136 @@ public class ApiRestClient {
} }
} }
public void request(String method, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { public void request(String method, String url, StringEntity postBody, RequestParams getParams, AsyncHttpResponseHandler responseHandler) {
Header[] headers = new Header[]{new TokenHeader()}; Header[] headers = new Header[]{new TokenHeader()};
Log.d("API", "Do request to: " + url); Log.d("API", "Do request to: " + url);
if(method == "post") { if(method == "post") {
client.post(player.getContext(), url, headers,params,"application/json", responseHandler); client.post(player.getContext(), url, headers, postBody,"application/json", responseHandler);
} else { } else {
client.get(player.getContext(), url, headers, params, responseHandler); client.get(player.getContext(), url, headers, getParams, responseHandler);
} }
} }
public void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { public void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
String jwt = player.getJWT(); String jwt = player.getJWT();
if(jwt != null) { if(jwt != null) {
request("get", getAbsoluteUrl(url), params, responseHandler); request("get", getAbsoluteUrl(url), null, params, responseHandler);
} else { } else {
requestWithJWT("get", getAbsoluteUrl(url), params, responseHandler); requestWithJWT("get", getAbsoluteUrl(url), null, params, responseHandler);
} }
} }
public void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { public void post(String url, StringEntity postBody, AsyncHttpResponseHandler responseHandler) {
String jwt = player.getJWT(); String jwt = player.getJWT();
if(jwt != null) { if(jwt != null) {
request("post", getAbsoluteUrl(url), params, responseHandler); request("post", getAbsoluteUrl(url), postBody, null, responseHandler);
} else { } else {
requestWithJWT("post", getAbsoluteUrl(url), params, responseHandler); requestWithJWT("post", getAbsoluteUrl(url), postBody, null, responseHandler);
} }
} }
private static String getAbsoluteUrl(String relativeUrl) { private static String getAbsoluteUrl(String relativeUrl) {
return BASE_URL + relativeUrl; return BASE_URL + relativeUrl;
} }
public void syncGame(final Game game) {
if(game.remoteId != null)
return;
RequestParams params = new RequestParams();
JSONObject j = new JSONObject();
try {
j.put("lvl_id", game.scenario.id);
j.put("score", game.score);
j.put("time", game.time);
JSONArray jHits = new JSONArray();
j.put("hits", jHits);
for(Hit hit: game.hits.values()) {
JSONObject jHit = new JSONObject();
jHit.put("target_index", hit.target.index);
jHit.put("score", hit.score);
jHit.put("glasses", hit.glasses);
jHit.put("ethnicity", hit.ethnicity);
jHit.put("age", hit.age);
jHit.put("gender", hit.gender);
JSONObject jExpressions = new JSONObject();
jHit.put("expressions", jExpressions);
JSONObject jEmotions = new JSONObject();
jHit.put("emotions", jEmotions);
JSONObject jPoints = new JSONObject();
jHit.put("points", jPoints);
for(Expression e: Expression.values()) {
jExpressions.put(e.getDbName(), hit.expressions.get(e));
}
for(Emotion e: Emotion.values()) {
jEmotions.put(e.getDbName(), hit.emotions.get(e));
}
int i=0;
for(PointF p: hit.points) {
JSONObject jPoint = new JSONObject();
jPoint.put("x", p.x);
jPoint.put("y", p.y);
jPoints.put(""+i, jPoint);
i++;
}
jHits.put(jHit);
}
} catch (JSONException e) {
e.printStackTrace();
}
StringEntity postBody = null;
try {
postBody = new StringEntity(j.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
this.post("/me/games", postBody, new JsonHttpResponseHandler(){
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Log.d("API",response.toString());
GameOpenHelper gameHelper = new GameOpenHelper(player.getContext());
// set remote ids on hits and game.
try {
game.remoteId = response.getString("id");
JSONObject hits = response.getJSONObject("hits");
gameHelper.saveRemoteId(game);
for(Hit hit: game.hits.values()) {
hit.remoteId = hits.getString(Long.toString(hit.id));
gameHelper.saveRemoteId(hit);
}
} catch (JSONException e) {
Log.e("API","Invalid data: " + response.toString());
e.printStackTrace();
}
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
handleOnFailure(statusCode, headers, responseString, throwable);
}
});
}
public static void handleOnFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
Log.e("API", "FAILURE ON REQUEST!");
Log.e("API", throwable.getMessage());
Log.e("API", "Status: "+statusCode);
Log.e("API", "Headers:");
for(Header header: headers) {
Log.e("API", "\t" + header.getName() + ": " + header.getValue());
}
Log.e("API", "Response:");
Log.e("API", responseString);
}
} }

View file

@ -62,4 +62,9 @@ public enum Emotion {
return Color.BLACK; return Color.BLACK;
} }
public String getDbName() {
return this.name().toLowerCase();
}
} }

View file

@ -0,0 +1,89 @@
package com.rubenvandeven.emotionhero;
import com.affectiva.android.affdex.sdk.detector.Face;
/**
* Created by ruben on 02/09/16.
*
* Strictly not all expression variables, but they all are floats...
*/
public enum Expression {
ROLL,
PITCH,
YAW,
INTER_OCULAR_DISTANCE,
MOUTH_OPEN,
LIP_PRESS,
BROW_RAISE,
NOSE_WRINKLER,
LIP_DEPRESSOR,
BROW_FURROW,
ATTENTION,
SMILE,
INNER_BROW_RAISER,
CHIN_RAISER,
SMIRK,
LIP_SUCK,
UPPER_LIP_RAISER,
LIP_PUCKER,
EYE_CLOSURE,
ENGAGEMENT,
VALENCE;
public float getValueFromFace(Face face)
{
if(face == null)
return 0f;
switch (this) {
case ROLL:
return face.measurements.orientation.getRoll();
case PITCH:
return face.measurements.orientation.getPitch();
case YAW:
return face.measurements.orientation.getYaw();
case INTER_OCULAR_DISTANCE:
return face.measurements.getInterocularDistance();
case MOUTH_OPEN:
return face.expressions.getMouthOpen();
case LIP_PRESS:
return face.expressions.getLipPress();
case BROW_RAISE:
return face.expressions.getBrowRaise();
case NOSE_WRINKLER:
return face.expressions.getNoseWrinkle();
case LIP_DEPRESSOR:
return face.expressions.getLipCornerDepressor();
case BROW_FURROW:
return face.expressions.getBrowFurrow();
case ATTENTION:
return face.expressions.getAttention();
case SMILE:
return face.expressions.getSmile();
case INNER_BROW_RAISER:
return face.expressions.getBrowRaise();
case CHIN_RAISER:
return face.expressions.getChinRaise();
case SMIRK:
return face.expressions.getSmirk();
case LIP_SUCK:
return face.expressions.getLipSuck();
case UPPER_LIP_RAISER:
return face.expressions.getUpperLipRaise();
case LIP_PUCKER:
return face.expressions.getLipPucker();
case EYE_CLOSURE:
return face.expressions.getEyeClosure();
case ENGAGEMENT:
return face.emotions.getEngagement();
case VALENCE:
return face.emotions.getValence();
}
return 0;
}
public String getDbName() {
return this.name().toLowerCase();
}
}

View file

@ -0,0 +1,49 @@
package com.rubenvandeven.emotionhero;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ruben on 02/09/16.
*
* A play of a level by current user at a specific time
*/
public class Game {
public Long id;
public Scenario scenario;
public float score;
public Date time;
public String remoteId;
public Map<Integer, Hit> hits = new HashMap<>();
public Game(Long id, int lvl_id, float score, Date time, String remoteId) {
this(id, new Scenario(lvl_id, null), score, time, remoteId);
}
public Game(Long id, Scenario scenario, float score, Date time, String remoteId) {
this.id = id;
this.scenario= scenario;
this.score = score;
this.time = time == null ? new Date() : time;
this.remoteId = remoteId;
}
public void addHit(Hit hit) {
hits.put(hit.target.index, hit);
score = calculateScore();
}
private float calculateScore() {
float s = 0;
for(Hit hit: hits.values()) {
s += hit.score;
}
return s;
}
}

View file

@ -0,0 +1,401 @@
package com.rubenvandeven.emotionhero;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.PointF;
import java.util.ArrayList;
import java.util.Date;
/**
* Created by ruben on 02/09/16.
*
* To test data:
* adb -d shell "run-as com.rubenvandeven.emotionhero ls /data/data/com.rubenvandeven.emotionhero/databases/"
* adb -d shell "run-as com.rubenvandeven.emotionhero cp /data/data/com.rubenvandeven.emotionhero/databases/emotionhero.db /sdcard/emotionhero.db"
* adb pull /sdcard/emotionhero.db
*/
public class GameOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String GAME_TABLE_NAME = "games";
private static final String GAME_TABLE_CREATE =
"CREATE TABLE " + GAME_TABLE_NAME + " (" +
"id INTEGER NOT NULL," +
"lvl_id INTEGER NOT NULL," +
"score VARCHAR(255) NOT NULL," +
"time INTEGER NOT NULL," +
"remoteId VARCHAR(255) DEFAULT NULL, " +
"PRIMARY KEY(id));";
private static final String[] GAME_PROJECTION = {
"id",
"lvl_id",
"score",
"time",
"remoteId"
};
private static final String HIT_TABLE_NAME = "hits";
public static final String HIT_TABLE_CREATE =
"CREATE TABLE hits (" +
"id INTEGER NOT NULL," +
"game_id INTEGER NOT NULL," +
"target_index INTEGER NOT_NULL," +
"score VARCHAR(20)," +
"remoteId VARCHAR(20)," +
"glasses VARCHAR(20)," +
"ethnicity VARCHAR(20)," +
"age VARCHAR(20)," +
"gender VARCHAR(1)," +
"anger VARCHAR(20)," +
"contempt VARCHAR(20)," +
"disgust VARCHAR(20)," +
"fear VARCHAR(20)," +
"joy VARCHAR(20)," +
"sadness VARCHAR(20)," +
"surprise VARCHAR(20)," +
"roll VARCHAR(20)," +
"pitch VARCHAR(20)," +
"yaw VARCHAR(20)," +
"inter_ocular_distance VARCHAR(20)," +
"mouth_open VARCHAR(20)," +
"lip_press VARCHAR(20)," +
"brow_raise VARCHAR(20)," +
"nose_wrinkler VARCHAR(20)," +
"lip_depressor VARCHAR(20)," +
"brow_furrow VARCHAR(20)," +
"attention VARCHAR(20)," +
"smile VARCHAR(20)," +
"inner_brow_raiser VARCHAR(20)," +
"chin_raiser VARCHAR(20)," +
"smirk VARCHAR(20)," +
"lip_suck VARCHAR(20)," +
"upper_lip_raiser VARCHAR(20)," +
"lip_pucker VARCHAR(20)," +
"eye_closure VARCHAR(20)," +
"engagement VARCHAR(20)," +
"valence VARCHAR(20)," +
"point_0x VARCHAR(20)," +
"point_0y VARCHAR(20)," +
"point_1x VARCHAR(20)," +
"point_1y VARCHAR(20)," +
"point_2x VARCHAR(20)," +
"point_2y VARCHAR(20)," +
"point_3x VARCHAR(20)," +
"point_3y VARCHAR(20)," +
"point_4x VARCHAR(20)," +
"point_4y VARCHAR(20)," +
"point_5x VARCHAR(20)," +
"point_5y VARCHAR(20)," +
"point_6x VARCHAR(20)," +
"point_6y VARCHAR(20)," +
"point_7x VARCHAR(20)," +
"point_7y VARCHAR(20)," +
"point_8x VARCHAR(20)," +
"point_8y VARCHAR(20)," +
"point_9x VARCHAR(20)," +
"point_9y VARCHAR(20)," +
"point_10x VARCHAR(20)," +
"point_10y VARCHAR(20)," +
"point_11x VARCHAR(20)," +
"point_11y VARCHAR(20)," +
"point_12x VARCHAR(20)," +
"point_12y VARCHAR(20)," +
"point_13x VARCHAR(20)," +
"point_13y VARCHAR(20)," +
"point_14x VARCHAR(20)," +
"point_14y VARCHAR(20)," +
"point_15x VARCHAR(20)," +
"point_15y VARCHAR(20)," +
"point_16x VARCHAR(20)," +
"point_16y VARCHAR(20)," +
"point_17x VARCHAR(20)," +
"point_17y VARCHAR(20)," +
"point_18x VARCHAR(20)," +
"point_18y VARCHAR(20)," +
"point_19x VARCHAR(20)," +
"point_19y VARCHAR(20)," +
"point_20x VARCHAR(20)," +
"point_20y VARCHAR(20)," +
"point_21x VARCHAR(20)," +
"point_21y VARCHAR(20)," +
"point_22x VARCHAR(20)," +
"point_22y VARCHAR(20)," +
"point_23x VARCHAR(20)," +
"point_23y VARCHAR(20)," +
"point_24x VARCHAR(20)," +
"point_24y VARCHAR(20)," +
"point_25x VARCHAR(20)," +
"point_25y VARCHAR(20)," +
"point_26x VARCHAR(20)," +
"point_26y VARCHAR(20)," +
"point_27x VARCHAR(20)," +
"point_27y VARCHAR(20)," +
"point_28x VARCHAR(20)," +
"point_28y VARCHAR(20)," +
"point_29x VARCHAR(20)," +
"point_29y VARCHAR(20)," +
"point_30x VARCHAR(20)," +
"point_30y VARCHAR(20)," +
"point_31x VARCHAR(20)," +
"point_31y VARCHAR(20)," +
"point_32x VARCHAR(20)," +
"point_32y VARCHAR(20)," +
"point_33x VARCHAR(20)," +
"point_33y VARCHAR(20)," +
"PRIMARY KEY (id));" ;
private static final String[] HIT_PROJECTION = {
"id","game_id", "target_index","score","remoteId","glasses","ethnicity","age","gender","anger","contempt","disgust","fear","joy","sadness","surprise","roll","pitch","yaw","inter_ocular_distance","mouth_open","lip_press","brow_raise","nose_wrinkler","lip_depressor","brow_furrow","attention","smile","inner_brow_raiser","chin_raiser","smirk","lip_suck","upper_lip_raiser","lip_pucker","eye_closure","engagement","valence","point_0x","point_0y","point_1x","point_1y","point_2x","point_2y","point_3x","point_3y","point_4x","point_4y","point_5x","point_5y","point_6x","point_6y","point_7x","point_7y","point_8x","point_8y","point_9x","point_9y","point_10x","point_10y","point_11x","point_11y","point_12x","point_12y","point_13x","point_13y","point_14x","point_14y","point_15x","point_15y","point_16x","point_16y","point_17x","point_17y","point_18x","point_18y","point_19x","point_19y","point_20x","point_20y","point_21x","point_21y","point_22x","point_22y","point_23x","point_23y","point_24x","point_24y","point_25x","point_25y","point_26x","point_26y","point_27x","point_27y","point_28x","point_28y","point_29x","point_29y","point_30x","point_30y","point_31x","point_31y","point_32x","point_32y","point_33x","point_33y"
};
private Context context;
GameOpenHelper(Context context) {
super(context, "emotionhero.db", null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(GAME_TABLE_CREATE);
db.execSQL(HIT_TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// until now there is only 1 database version.. so no alter table statements
if(oldVersion == 1 && newVersion == 2) {
// run alter statements
db.execSQL("DROP TABLE hits");
db.execSQL("DROP TABLE games");
db.execSQL(GAME_TABLE_CREATE);
db.execSQL(HIT_TABLE_CREATE);
}
}
public void insertGame(Game game) {
// Gets the data repository in write mode
SQLiteDatabase db = getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put("lvl_id", game.scenario.id);
values.put("score", game.score);
values.put("time", game.time.getTime());
if(game.remoteId == null) {
values.putNull("remoteId");
} else {
values.put("remoteId", game.remoteId);
}
// Insert the new row, returning the primary key value of the new row
long newRowId = db.insert(GAME_TABLE_NAME, null, values);
game.id = newRowId;
for(Hit hit: game.hits.values()) {
insertHit(hit);
}
}
public Game[] getGamesForLevel(int lvl_id) {
SQLiteDatabase db = getReadableDatabase();
String selection = "lvl_id = ?";
String[] selectionArgs = { Integer.toString(lvl_id) };
String sortOrder = "score DESC";
Cursor c = db.query(
GAME_TABLE_NAME, // The table to query
GAME_PROJECTION, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder, // The sort order
null // no limit!
);
return cursorToGames(c, null);
}
public Game[] getGamesForScenario(Scenario s) {
SQLiteDatabase db = getReadableDatabase();
String selection = "lvl_id = ?";
String[] selectionArgs = { Integer.toString(s.id) };
String sortOrder = "score DESC";
Cursor c = db.query(
GAME_TABLE_NAME, // The table to query
GAME_PROJECTION, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder, // The sort order
null // no limit!
);
return cursorToGames(c, s);
}
public Game[] cursorToGames(Cursor c, Scenario s) {
Game[] games = new Game[c.getCount()];
int i = 0;
c.moveToFirst();
while (!c.isAfterLast()) {
Scenario scenario = s == null ? new Scenario(c.getInt(1), null) : s;
Game game = new Game(c.getLong(0), scenario, c.getFloat(2), new Date(c.getInt(3)), c.getString(4));
games[i] = game;
this.getHitsForGame(game); // hits are appended to game object
i++;
c.moveToNext();
}
return games;
}
public void saveRemoteId(Game game) {
SQLiteDatabase db = getWritableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put("remoteId", game.remoteId);
// Which row to update, based on the title
String selection = "id = ?";
String[] selectionArgs = { Long.toString(game.id) };
int count = db.update(
GAME_TABLE_NAME,
values,
selection,
selectionArgs);
}
public void insertHit(Hit hit) {
// Gets the data repository in write mode
SQLiteDatabase db = getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put("game_id", hit.game.id);
values.put("target_index", hit.target.index);
values.put("score", hit.score);
values.put("glasses", hit.glasses);
values.put("ethnicity", hit.ethnicity);
values.put("age", hit.age);
values.put("gender", hit.gender);
for(Emotion emotion: Emotion.values()) {
values.put(emotion.name().toLowerCase(), hit.emotions.get(emotion));
}
for(Expression exp: Expression.values()) {
values.put(exp.getDbName(), hit.expressions.get(exp));
}
int i=0;
for(PointF point: hit.points) {
values.put("point_"+i+"x", point.x);
values.put("point_"+i+"y", point.y);
i++;
}
if(hit.remoteId == null) {
values.putNull("remoteId");
} else {
values.put("remoteId", hit.remoteId);
}
// Insert the new row, returning the primary key value of the new row
long newRowId = db.insert(HIT_TABLE_NAME, null, values);
hit.id = newRowId;
}
public ArrayList<Hit> getHitsForGame(Game game) {
SQLiteDatabase db = getReadableDatabase();
String selection = "game_id = ?";
String[] selectionArgs = { Long.toString(game.id) };
String sortOrder = "target_index ASC";
Cursor c = db.query(
HIT_TABLE_NAME, // The table to query
HIT_PROJECTION, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder, // The sort order
null // no limit!
);
return cursorToHits(game, c);
}
public ArrayList<Hit> cursorToHits(Game game, Cursor c) {
ArrayList<Hit> hits = new ArrayList<Hit>(c.getCount());
c.moveToFirst();
while (!c.isAfterLast()) {
hits.add(new Hit(game, c));
c.moveToNext();
}
return hits;
}
public void saveRemoteId(Hit hit) {
SQLiteDatabase db = getWritableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put("remoteId", hit.remoteId);
// Which row to update, based on the title
String selection = "id = ?";
String[] selectionArgs = { Long.toString(hit.id) };
int count = db.update(
HIT_TABLE_NAME,
values,
selection,
selectionArgs);
}
public Game getGameByid(long id) {
SQLiteDatabase db = getReadableDatabase();
String selection = "id = ?";
String[] selectionArgs = { Long.toString(id) };
Cursor c = db.query(
GAME_TABLE_NAME, // The table to query
GAME_PROJECTION, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null, // The sort order
null // no limit!
);
Game[] games = cursorToGames(c, null);
return games[0];
}
public int getLocalRankOfGame(Game game) {
String[] params = { Long.toString(game.scenario.id), Float.toString(game.score) };
Cursor c = getReadableDatabase().rawQuery("SELECT COUNT(id)+1 FROM games WHERE lvl_id = ? AND score > ?", params);
c.moveToFirst();
return c.getInt(0);
}
}

View file

@ -205,7 +205,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
detector.setDetectAllEmotions(true); detector.setDetectAllEmotions(true);
detector.setDetectAllAppearances(false); detector.setDetectAllAppearances(false);
detector.setDetectAllEmojis(false); detector.setDetectAllEmojis(false);
detector.setDetectAllExpressions(false); detector.setDetectAllExpressions(true);
detector.setMaxProcessRate(20); detector.setMaxProcessRate(20);
detector.setImageListener(this); detector.setImageListener(this);
@ -393,8 +393,12 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
// highscoreView.setVisibility(View.VISIBLE); // highscoreView.setVisibility(View.VISIBLE);
finish(); finish();
GameOpenHelper gameHelper = new GameOpenHelper(getApplicationContext());
gameHelper.insertGame(currentScenario.game);
Intent intent = new Intent(this, HighscoreActivity.class); Intent intent = new Intent(this, HighscoreActivity.class);
intent.putExtra(HighscoreActivity.INTENT_EXTRA_SCORE_ID, score.id.toString()); intent.putExtra(HighscoreActivity.INTENT_EXTRA_SCORE_ID, score.id.toString());
intent.putExtra(HighscoreActivity.INTENT_EXTRA_GAME_ID, currentScenario.game.id.toString());
startActivity(intent); startActivity(intent);
} }
} }

View file

@ -33,6 +33,7 @@ public class HighscoreActivity extends AppCompatActivity {
public final static String INTENT_EXTRA_SCORE_ID = "com.rubenvandeven.emotionhero.SCORE_ID"; public final static String INTENT_EXTRA_SCORE_ID = "com.rubenvandeven.emotionhero.SCORE_ID";
public final static String INTENT_EXTRA_GAME_ID = "com.rubenvandeven.emotionhero.GAME_ID";
/** /**
* The {@link android.support.v4.view.PagerAdapter} that will provide * The {@link android.support.v4.view.PagerAdapter} that will provide
@ -67,6 +68,7 @@ public class HighscoreActivity extends AppCompatActivity {
player = Player.getInstance(getApplicationContext()); player = Player.getInstance(getApplicationContext());
String scoreIdString = getIntent().getStringExtra(INTENT_EXTRA_SCORE_ID); String scoreIdString = getIntent().getStringExtra(INTENT_EXTRA_SCORE_ID);
String gameIdString = getIntent().getStringExtra(INTENT_EXTRA_GAME_ID);
if(scoreIdString != null) { if(scoreIdString != null) {
UUID score_id = UUID.fromString(scoreIdString); UUID score_id = UUID.fromString(scoreIdString);
score = player.getPlayerInfo().getScore(score_id); score = player.getPlayerInfo().getScore(score_id);
@ -74,10 +76,20 @@ public class HighscoreActivity extends AppCompatActivity {
Log.e("Highscore", "CANNOT FIND SCORE!! " + scoreIdString); Log.e("Highscore", "CANNOT FIND SCORE!! " + scoreIdString);
} }
} }
if(gameIdString != null) {
long gameId = Long.valueOf(gameIdString);
Game game = player.getGameOpenHelper().getGameByid(gameId);
if(game == null) {
Log.e("Highscore", "CANNOT FIND GAME!! " + gameIdString);
} else {
Log.i("Highscore", "FOUND GAME" + game.id + " " + game.score);
Log.i("Highscore", "RANK " + player.getGameOpenHelper().getLocalRankOfGame(game));
player.api.syncGame(game);
}
}
Log.i("Highscore", ""+player.getPlayerInfo().reachedLevelId); Log.i("Highscore", ""+player.getPlayerInfo().reachedLevelId);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);

View file

@ -0,0 +1,130 @@
package com.rubenvandeven.emotionhero;
import android.database.Cursor;
import android.graphics.PointF;
import com.affectiva.android.affdex.sdk.detector.Face;
import com.google.gson.annotations.Expose;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ruben on 02/09/16.
*/
public class Hit {
public long id;
public Scenario.Target target;
@Expose(serialize = false, deserialize = false)
public Game game;
public float score;
public Map<Emotion, Float> emotions = new HashMap<>(7);
public boolean glasses;
public String ethnicity;
public String age;
public String gender;
public Map<Expression, Float> expressions = new HashMap<>(21); // also includes measurements
public PointF[] points = new PointF[34];
public String remoteId;
/**
* Constructor for game moment
*/
public Hit(Scenario.Target target, Game game, Face face, float score) {
this.score = score;
this.target = target;
this.game = game;
for(Emotion emotion: Emotion.values()) {
emotions.put(emotion,emotion.getValueFromFace(face));
}
this.gender = face.appearance.getGender() == Face.GENDER.UNKNOWN ? "U" : (face.appearance.getGender() == Face.GENDER.MALE ? "M" : "F");
this.glasses = face.appearance.getGlasses() == Face.GLASSES.YES ? true : false;
this.ethnicity = face.appearance.getEthnicity().name();
this.age = face.appearance.getAge().name();
for(Expression exp: Expression.values()) {
this.expressions.put(exp, exp.getValueFromFace(face));
}
this.points = face.getFacePoints().clone();
game.addHit(this);
}
/**
* Constructor from database entity
*/
public Hit(Game game, Cursor c) {
this.id = c.getLong(c.getColumnIndex("id"));
this.score = c.getFloat(c.getColumnIndex("score"));
String rId = c.getString(c.getColumnIndex("remoteId"));
this.remoteId = (rId == null || rId.length() == 0) ? null : c.getString(c.getColumnIndex("remoteId"));
this.target = game.scenario.getTargetByIndex(c.getInt(c.getColumnIndex("target_index")));
this.glasses = c.getInt(c.getColumnIndex("glasses")) == 1;
this.ethnicity = c.getString(c.getColumnIndex("ethnicity"));
this.age = c.getString(c.getColumnIndex("age"));
this.gender = c.getString(c.getColumnIndex("gender"));
this.emotions.put(Emotion.ANGER, c.getFloat(c.getColumnIndex("anger")));
this.emotions.put(Emotion.CONTEMPT, c.getFloat(c.getColumnIndex("contempt")));
this.emotions.put(Emotion.DISGUST, c.getFloat(c.getColumnIndex("disgust")));
this.emotions.put(Emotion.FEAR, c.getFloat(c.getColumnIndex("fear")));
this.emotions.put(Emotion.JOY, c.getFloat(c.getColumnIndex("joy")));
this.emotions.put(Emotion.SADNESS, c.getFloat(c.getColumnIndex("sadness")));
this.emotions.put(Emotion.SURPRISE, c.getFloat(c.getColumnIndex("surprise")));
for(Expression exp: Expression.values()) {
this.expressions.put(exp, c.getFloat( c.getColumnIndex( exp.getDbName() )));
}
this.points[0] = new PointF(c.getFloat(c.getColumnIndex("point_0x")), c.getFloat(c.getColumnIndex("point_0y")));
this.points[1] = new PointF(c.getFloat(c.getColumnIndex("point_1x")), c.getFloat(c.getColumnIndex("point_1y")));
this.points[2] = new PointF(c.getFloat(c.getColumnIndex("point_2x")), c.getFloat(c.getColumnIndex("point_2y")));
this.points[3] = new PointF(c.getFloat(c.getColumnIndex("point_3x")), c.getFloat(c.getColumnIndex("point_3y")));
this.points[4] = new PointF(c.getFloat(c.getColumnIndex("point_4x")), c.getFloat(c.getColumnIndex("point_4y")));
this.points[5] = new PointF(c.getFloat(c.getColumnIndex("point_5x")), c.getFloat(c.getColumnIndex("point_5y")));
this.points[6] = new PointF(c.getFloat(c.getColumnIndex("point_6x")), c.getFloat(c.getColumnIndex("point_6y")));
this.points[7] = new PointF(c.getFloat(c.getColumnIndex("point_7x")), c.getFloat(c.getColumnIndex("point_7y")));
this.points[8] = new PointF(c.getFloat(c.getColumnIndex("point_8x")), c.getFloat(c.getColumnIndex("point_8y")));
this.points[9] = new PointF(c.getFloat(c.getColumnIndex("point_9x")), c.getFloat(c.getColumnIndex("point_9y")));
this.points[10] = new PointF(c.getFloat(c.getColumnIndex("point_10x")), c.getFloat(c.getColumnIndex("point_10y")));
this.points[11] = new PointF(c.getFloat(c.getColumnIndex("point_11x")), c.getFloat(c.getColumnIndex("point_11y")));
this.points[12] = new PointF(c.getFloat(c.getColumnIndex("point_12x")), c.getFloat(c.getColumnIndex("point_12y")));
this.points[13] = new PointF(c.getFloat(c.getColumnIndex("point_13x")), c.getFloat(c.getColumnIndex("point_13y")));
this.points[14] = new PointF(c.getFloat(c.getColumnIndex("point_14x")), c.getFloat(c.getColumnIndex("point_14y")));
this.points[15] = new PointF(c.getFloat(c.getColumnIndex("point_15x")), c.getFloat(c.getColumnIndex("point_15y")));
this.points[16] = new PointF(c.getFloat(c.getColumnIndex("point_16x")), c.getFloat(c.getColumnIndex("point_16y")));
this.points[17] = new PointF(c.getFloat(c.getColumnIndex("point_17x")), c.getFloat(c.getColumnIndex("point_17y")));
this.points[18] = new PointF(c.getFloat(c.getColumnIndex("point_18x")), c.getFloat(c.getColumnIndex("point_18y")));
this.points[19] = new PointF(c.getFloat(c.getColumnIndex("point_19x")), c.getFloat(c.getColumnIndex("point_19y")));
this.points[20] = new PointF(c.getFloat(c.getColumnIndex("point_20x")), c.getFloat(c.getColumnIndex("point_20y")));
this.points[21] = new PointF(c.getFloat(c.getColumnIndex("point_21x")), c.getFloat(c.getColumnIndex("point_21y")));
this.points[22] = new PointF(c.getFloat(c.getColumnIndex("point_22x")), c.getFloat(c.getColumnIndex("point_22y")));
this.points[23] = new PointF(c.getFloat(c.getColumnIndex("point_23x")), c.getFloat(c.getColumnIndex("point_23y")));
this.points[24] = new PointF(c.getFloat(c.getColumnIndex("point_24x")), c.getFloat(c.getColumnIndex("point_24y")));
this.points[25] = new PointF(c.getFloat(c.getColumnIndex("point_25x")), c.getFloat(c.getColumnIndex("point_25y")));
this.points[26] = new PointF(c.getFloat(c.getColumnIndex("point_26x")), c.getFloat(c.getColumnIndex("point_26y")));
this.points[27] = new PointF(c.getFloat(c.getColumnIndex("point_27x")), c.getFloat(c.getColumnIndex("point_27y")));
this.points[28] = new PointF(c.getFloat(c.getColumnIndex("point_28x")), c.getFloat(c.getColumnIndex("point_28y")));
this.points[29] = new PointF(c.getFloat(c.getColumnIndex("point_29x")), c.getFloat(c.getColumnIndex("point_29y")));
this.points[30] = new PointF(c.getFloat(c.getColumnIndex("point_30x")), c.getFloat(c.getColumnIndex("point_30y")));
this.points[31] = new PointF(c.getFloat(c.getColumnIndex("point_31x")), c.getFloat(c.getColumnIndex("point_31y")));
this.points[32] = new PointF(c.getFloat(c.getColumnIndex("point_32x")), c.getFloat(c.getColumnIndex("point_32y")));
this.points[33] = new PointF(c.getFloat(c.getColumnIndex("point_33x")), c.getFloat(c.getColumnIndex("point_33y")));
game.addHit(this);
}
}

View file

@ -91,6 +91,7 @@ public class Player {
while((ch = fis.read()) != -1){ while((ch = fis.read()) != -1){
builder.append((char)ch); builder.append((char)ch);
} }
Log.d("PLAYER", builder.toString());
return PlayerInfo.fromJson(builder.toString()); return PlayerInfo.fromJson(builder.toString());
} catch (IOException e) { } catch (IOException e) {
return new PlayerInfo(); return new PlayerInfo();
@ -120,4 +121,12 @@ public class Player {
Log.e("PlayerInfo", "Could not save player information!"); Log.e("PlayerInfo", "Could not save player information!");
} }
} }
private GameOpenHelper gameOpenHelper;
public GameOpenHelper getGameOpenHelper() {
if(gameOpenHelper == null) {
gameOpenHelper = new GameOpenHelper(getContext());
}
return gameOpenHelper;
}
} }

View file

@ -1,19 +1,13 @@
package com.rubenvandeven.emotionhero; package com.rubenvandeven.emotionhero;
import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.util.SparseArray;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import static com.google.gson.internal.bind.TypeAdapters.UUID;
/** /**
* Created by ruben on 20/08/16. * Created by ruben on 20/08/16.
*/ */

View file

@ -6,6 +6,7 @@ import android.util.Log;
import com.affectiva.android.affdex.sdk.detector.Face; import com.affectiva.android.affdex.sdk.detector.Face;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Timer; import java.util.Timer;
@ -39,6 +40,11 @@ public class Scenario {
float duration = 0; float duration = 0;
/**
* If a game is beign played.
*/
Game game;
/** /**
* @deprecated * @deprecated
*/ */
@ -68,22 +74,11 @@ public class Scenario {
ArrayList<Target> targets = new ArrayList<>(); ArrayList<Target> targets = new ArrayList<>();
class Target { class Target {
public int index;
public Emotion emotion; public Emotion emotion;
public float value; public float value;
public float timestamp; public float timestamp;
public Hit hit; public boolean isHit = false;
}
ArrayList<Hit> hits = new ArrayList<>();
class Hit {
public float value;
/**
* Extra bonus given
*/
public boolean isSpotOn = false;
// public Bitmap image; //image at time of hit
public Face face; // face at time of hit
} }
/** /**
@ -115,7 +110,7 @@ public class Scenario {
} }
}; };
timer.schedule(tickTask, 0, 1000/DESIRED_FPS); timer.schedule(tickTask, 0, 1000/DESIRED_FPS);
this.game = new Game(null, this, 0, new Date(), null);
} }
/** /**
@ -133,30 +128,30 @@ public class Scenario {
return; return;
} }
for (int i = targets.size() - 1; i >= 0; i--) { for(Target target: targets) {
Target target = targets.get(i);
// skip targets that are already scored // skip targets that are already scored
if(target.hit != null) { if(target.isHit == true) {
continue; continue;
} }
if(target.timestamp <= runningTime) { if(target.timestamp <= runningTime) {
float scored_value = target.emotion.getValueFromFace(currentFace); float scored_value = target.emotion.getValueFromFace(currentFace);
float required_value = target.value; float required_value = target.value;
Hit hit = new Hit(); float score = Math.round(100 - Math.abs(scored_value-required_value));
hit.value = Math.round(100 - Math.abs(scored_value-required_value)); Hit hit = new Hit(target, game, currentFace, score);
hit.face = currentFace;
hits.add(hit);
// //
_activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1, _activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1,
1,0, hit.value / 200f + 0.5f ); // play back the sound slower 1,0, hit.score / 200f + 0.5f ); // play back the sound slower
// depending on hit value // depending on hit value
target.hit = hit; target.isHit = true;
} }
} }
} }
public Target getTargetByIndex(int target_index) {
return targets.get(target_index-1);
}
/** /**
* Add a target on given timestamp * Add a target on given timestamp
@ -175,6 +170,7 @@ public class Scenario {
target.timestamp = timestamp; target.timestamp = timestamp;
target.value = value; target.value = value;
target.emotion = emotion; target.emotion = emotion;
target.index = targets.size() + 1;
targets.add(target); targets.add(target);
} }
@ -195,32 +191,11 @@ public class Scenario {
setTarget(emotion, value, timestamp); setTarget(emotion, value, timestamp);
} }
/**
* @deprecated use @see tick()
* @param face
* @param timestamp
*/
public void validateFaceOnTime(Face face, float timestamp)
{
// TODO: interpolation of time
for (int i = targets.size() - 1; i >= 0; i--) {
Target target = targets.get(i);
if(target.timestamp > timestamp - 0.2 && target.timestamp < timestamp + 0.2) {
float scored_value = target.emotion.getValueFromFace(face);
float required_value = target.value;
Hit hit = new Hit();
hit.value = 100 - Math.abs(scored_value-required_value);
target.hit = hit;
hits.add(hit);
}
}
}
public float getHitTotalValue() public float getHitTotalValue()
{ {
float value = 0; float value = 0;
for (Hit hit : hits) { for (Hit hit : game.hits.values()) {
value += hit.value; value += hit.score;
} }
return value; return value;
} }
@ -385,4 +360,8 @@ public class Scenario {
return "..."; return "...";
} }
public Hit getHitForTarget(Target target) {
return game.hits.get(target.index);
}
} }

View file

@ -196,9 +196,10 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaints.get(target.emotion)); canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaints.get(target.emotion));
if(target.hit != null) { if(target.isHit) {
canvas.drawText(Float.toString(target.hit.value), cx, cy, emoPaints.get(target.emotion)); Hit hit = _scenario.getHitForTarget(target);
canvas.drawCircle(cx, cy, max_ball_radius * target.hit.value/100, emoScoredPaints.get(target.emotion)); canvas.drawText(Float.toString(hit.score), cx, cy, emoPaints.get(target.emotion));
canvas.drawCircle(cx, cy, max_ball_radius * hit.score/100, emoScoredPaints.get(target.emotion));
// TODO: Use target.hit.face to set Rect src. // TODO: Use target.hit.face to set Rect src.
// if(target.hit.image != null) { // if(target.hit.image != null) {