package com.rubenvandeven.emotionhero; import android.Manifest; import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Typeface; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.SoundPool; import android.os.Build; import android.support.v4.app.ActivityCompat; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Button; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.affectiva.android.affdex.sdk.Frame; import com.affectiva.android.affdex.sdk.detector.CameraDetector; import com.affectiva.android.affdex.sdk.detector.Detector; import com.affectiva.android.affdex.sdk.detector.Face; import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; /** * An example full-screen activity that shows and hides the system UI (i.e. * status bar and navigation/system bar) with user interaction. */ public class GamingActivity extends AppCompatActivity implements Detector.ImageListener, CameraDetector.CameraEventListener, Detector.FaceListener { public final static String INTENT_EXTRA_SCENARIO = "com.rubenvandeven.emotionhero.LEVEL"; final static String LOG_TAG = "EmotionHero"; final int PERMISSIONS_REQUEST_CAMERA = 1; private TextView mContentView; private CameraDetector detector; SurfaceView cameraPreview; int previewWidth = 0; int previewHeight = 0; Scenario currentScenario; ScenarioView scenarioView; boolean has_camera_permission = false; public SoundPool sound; public HashMap soundIds = new HashMap<>(); final static int SOUND_SCORE = 1; final static int SOUND_BONUS = 2; protected Player player; protected boolean isStarted = false; protected Timer timeoutTimer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // kiosk mode if(getSupportActionBar() != null) { getSupportActionBar().hide(); } setContentView(R.layout.activity_gaming); player = Player.getInstance(getApplicationContext()); Intent intent = getIntent(); // first level is the default to load, if none is given to intent int scenarioLvlId = intent.getIntExtra(INTENT_EXTRA_SCENARIO, Scenario.SCENARIOS.get(0)); mContentView = (TextView) findViewById(R.id.fullscreen_content); RelativeLayout videoLayout = (RelativeLayout) findViewById(R.id.video_layout); TextView titleText = (TextView) findViewById(R.id.titleText); //We create a custom SurfaceView that resizes itself to match the aspect ratio of the incoming camera frames cameraPreview = new SurfaceView(this) { @Override public void onMeasure(int widthSpec, int heightSpec) { int measureWidth = MeasureSpec.getSize(widthSpec); int measureHeight = MeasureSpec.getSize(heightSpec); int maxWidth = GamingActivity.this.getWindow().getDecorView().getWidth(); int maxHeight = GamingActivity.this.getWindow().getDecorView().getHeight(); int width; int height; if (previewHeight == 0 || previewWidth == 0) { width = measureWidth; height = measureHeight; } else { float viewAspectRatio = (float)measureWidth/measureHeight; float cameraPreviewAspectRatio = (float) previewWidth/previewHeight; if (cameraPreviewAspectRatio > viewAspectRatio) { width = measureWidth; height =(int) (measureWidth / cameraPreviewAspectRatio); } else { width = (int) (measureHeight * cameraPreviewAspectRatio); height = measureHeight; } } // make sure we fill the screen! if(width < maxWidth) { float ratio = (float)maxWidth/width; width = maxWidth; height = (int) (ratio * height); } if(height < maxHeight) { float ratio = (float)maxHeight/height; width = (int) (ratio * width); height = maxHeight; } setMeasuredDimension(width,height); // setMeasuredDimension(1,1); // this DOES increase performance.... } }; RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); // RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(1,1); params.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE); // 10% margin: // params.leftMargin = (int) 120; // params.rightMargin = params.leftMargin; cameraPreview.setLayoutParams(params); videoLayout.addView(cameraPreview,0); // currentScenario = new ScenarioAnger(this); currentScenario = new Scenario(scenarioLvlId, this); currentScenario.init(); // "start the clock"... scenarioView = new ScenarioView(this, currentScenario); scenarioView.drawOverlay = true; RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); videoLayout.addView(scenarioView, 1, scenarioViewParams); createSoundPool(); // instantiate SoundPool in sound soundIds.put(SOUND_SCORE, sound.load(this, R.raw.score2, 1)); soundIds.put(SOUND_BONUS, sound.load(this, R.raw.scorebonus, 1)); // StoryDialogFragment storyDialog = new StoryDialogFragment(); // storyDialog.show(getSupportFragmentManager(), "StoryDialog"); Typeface font = Typeface.createFromAsset(getAssets(), "unifont-9.0.02.ttf"); mContentView.setTypeface(font); titleText.setText(currentScenario.toString()); titleText.setTypeface(font); startGame(); } public void startGame() { isStarted = true; startDetector(); } @Override protected void onResume() { super.onResume(); if(isStarted) startDetector(); // should resume 'on face detection started' } @Override protected void onPause() { super.onPause(); stopDetector(); currentScenario.pause(); ActivityManager activityManager = (ActivityManager) getApplicationContext() .getSystemService(Context.ACTIVITY_SERVICE); activityManager.moveTaskToFront(getTaskId(), 0); } void startDetector() { if (detector == null || !detector.isRunning()) { // check permission String permission = "android.permission.CAMERA"; int res = getApplicationContext().checkCallingOrSelfPermission(permission); if (res == PackageManager.PERMISSION_GRANTED) { Log.i(LOG_TAG, "Has camera permission"); has_camera_permission = true; } else { Log.i(LOG_TAG, "No camera permission"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSIONS_REQUEST_CAMERA); } if(has_camera_permission) { if(detector == null) { // SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView); detector = new CameraDetector(this, CameraDetector.CameraType.CAMERA_FRONT, cameraPreview, 1, Detector.FaceDetectorMode.LARGE_FACES); detector.setDetectAllEmotions(true); detector.setDetectAllAppearances(true); detector.setDetectAllEmojis(false); detector.setDetectAllExpressions(true); detector.setMaxProcessRate(12); detector.setImageListener(this); detector.setOnCameraEventListener(this); detector.setFaceListener(this); } detector.start(); setText("STARTING..."); Log.d(LOG_TAG, Boolean.toString(detector.isRunning())); } } } void stopDetector() { if (detector != null && detector.isRunning()) { detector.stop(); } } @Override /** * Detector callback gives the faces found so we can match their hits to the given scenario. */ public void onImageResults(List list, Frame frame, float timestamp) { // frame.getOriginalBitmapFrame() // Log.e(LOG_TAG, "RESULT! faces: " + Integer.toString(list.size()) + " t: " + Float.toString(timestamp) + "s" ); // if(!currentScenario.isWithinTime(timestamp)) if(currentScenario.isFinished()) { finishLevel(); return; } if (list == null) return; if (list.size() == 0) { setText("No face found..."); // mContentView.setText("NO FACE FOUND"); // this happens in onFaceDetectionStopped } else { hideText(); // hide textView as we want as few elements as possible. Face face = list.get(0); currentScenario.setCurrentFaceAndFrame(face, (Frame.ByteArrayFrame) frame); scenarioView.setCurrentAttributeScoresForFace(face); } } @Override /** * For CameraDetector.CameraEventListener * Used to scale video preview output */ public void onCameraSizeSelected(int width, int height, Frame.ROTATE rotate) { if (rotate == Frame.ROTATE.BY_90_CCW || rotate == Frame.ROTATE.BY_90_CW) { previewWidth = height; previewHeight = width; } else { previewHeight = height; previewWidth = width; } cameraPreview.requestLayout(); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case PERMISSIONS_REQUEST_CAMERA: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { has_camera_permission = true; startDetector(); } else { has_camera_permission = false; Toast errorMsg = Toast.makeText(this, R.string.camera_required, Toast.LENGTH_LONG); errorMsg.show(); } return; } // other 'case' lines to check for other // permissions this app might request } } @Override public void onFaceDetectionStarted() { setText("START!"); currentScenario.lostFace = false; // in kioskmode, if no face is found for 60s return to main screen if(timeoutTimer != null) { timeoutTimer.cancel(); } if(isStarted) currentScenario.start(); } @Override public void onFaceDetectionStopped() { currentScenario.pause(); currentScenario.lostFace = true; // in kioskmode, if no face is found for 60s return to main screen timeoutTimer = new Timer(); TimerTask timeoutTimerTask = new TimerTask() { @Override public void run() { Intent intent = new Intent(GamingActivity.this, MirrorMenuActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); } }; timeoutTimer.schedule(timeoutTimerTask, 60*1000); } public void setText(String text) { mContentView.setVisibility(View.VISIBLE); mContentView.setText(text); } public void hideText() { mContentView.setVisibility(View.GONE); } // http://stackoverflow.com/a/27552576 protected void createSoundPool() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { createNewSoundPool(); } else { createOldSoundPool(); } } // http://stackoverflow.com/a/27552576 @TargetApi(Build.VERSION_CODES.LOLLIPOP) protected void createNewSoundPool(){ AudioAttributes attributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .build(); sound = new SoundPool.Builder() .setMaxStreams(6) // allow sounds to ring while another is started .setAudioAttributes(attributes) .build(); } // http://stackoverflow.com/a/27552576 @SuppressWarnings("deprecation") protected void createOldSoundPool(){ sound = new SoundPool(5, AudioManager.STREAM_MUSIC,0); } public void finishLevel() { stopDetector(); PlayerInfo playerInfo = player.getPlayerInfo(); // ScoreList scores = playerInfo.getScoresForLevel(currentScenario.id); // Score score = currentScenario.getScore(); // // if(score.score == currentScenario.getMaxScore()) { // // Maximum SCORE!! // // You nailed it! // } if(scores.isEmpty()) { // // First play! Nice :-) // } // else if(scores.isHighest(score)) { // // HIGHSCORE!!!!! // } else { // // Better luck next time // } // check whether this is the highest reached level by the player // ... used by 'continue' button in main menu currentScenario.game.checkAchievements(player); if(currentScenario.minimumScore < currentScenario.game.score + currentScenario.game.bonus) { if(currentScenario.isFinalLevel()) { playerInfo.completedAll = true; } else { Scenario nextScenario = new Scenario(currentScenario.getNextLevelId(), this); if(nextScenario.isHigherThen(playerInfo.reachedLevelId)) { // allow player to continue to next level :-) playerInfo.reachedLevelId = nextScenario.id; } } } // scores.add(score); player.savePlayerInfo(playerInfo); finish(); GameOpenHelper gameHelper = new GameOpenHelper(getApplicationContext()); gameHelper.insertGame(currentScenario.game); Intent intent = new Intent(this, ReviewActivity.class); intent.putExtra(ReviewActivity.INTENT_EXTRA_GAME_ID, currentScenario.game.id); intent.putExtra(ReviewActivity.INTENT_EXTRA_FROM_GAME, true); startActivity(intent); } /** * For kioskmode * @param hasFocus */ @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(!hasFocus) { // Close every kind of system dialog Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); sendBroadcast(closeDialog); } } }