package com.rubenvandeven.emotionhero; import android.Manifest; import android.annotation.SuppressLint; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.support.v4.app.ActivityCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; 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.List; /** * 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 { final static String LOG_TAG = "EmotionHero"; final int PERMISSIONS_REQUEST_CAMERA = 1; /** * Whether or not the system UI should be auto-hidden after * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds. */ private static final boolean AUTO_HIDE = true; /** * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after * user interaction before hiding the system UI. */ private static final int AUTO_HIDE_DELAY_MILLIS = 3000; /** * Some older devices needs a small delay between UI widget updates * and a change of the status and navigation bar. */ private static final int UI_ANIMATION_DELAY = 300; private final Handler mHideHandler = new Handler(); private TextView mContentView; private final Runnable mHidePart2Runnable = new Runnable() { @SuppressLint("InlinedApi") @Override public void run() { // Delayed removal of status and navigation bar // Note that some of these constants are new as of API 16 (Jelly Bean) // and API 19 (KitKat). It is safe to use them, as they are inlined // at compile-time and do nothing on earlier devices. mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); } }; private View mControlsView; private final Runnable mShowPart2Runnable = new Runnable() { @Override public void run() { // Delayed display of UI elements ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.show(); } mControlsView.setVisibility(View.VISIBLE); } }; private boolean mVisible; private final Runnable mHideRunnable = new Runnable() { @Override public void run() { hide(); } }; /** * Touch listener to use for in-layout UI controls to delay hiding the * system UI. This is to prevent the jarring behavior of controls going away * while interacting with activity UI. */ private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (AUTO_HIDE) { delayedHide(AUTO_HIDE_DELAY_MILLIS); } return false; } }; private CameraDetector detector; SurfaceView cameraPreview; int previewWidth = 0; int previewHeight = 0; Scenario currentScenario; ScenarioView scenarioView; boolean has_camera_permission = false; Button restartButton; TextView paramText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gaming); mVisible = true; mControlsView = findViewById(R.id.fullscreen_content_controls); mContentView = (TextView) findViewById(R.id.fullscreen_content); RelativeLayout videoLayout = (RelativeLayout) findViewById(R.id.video_layout); // paramText = (TextView) findViewById(R.id.paramText); restartButton = (Button) findViewById(R.id.restartButton); restartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); startActivity(getIntent()); } }); // Set up the user interaction to manually show or hide the system UI. mContentView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { toggle(); } }); // Upon interacting with UI controls, delay any scheduled hide() // operations to prevent the jarring behavior of controls going away // while interacting with the UI. findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener); //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 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; } } setMeasuredDimension(width,height); } }; 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); cameraPreview.setLayoutParams(params); videoLayout.addView(cameraPreview,0); currentScenario = new ScenarioAnger(); scenarioView = new ScenarioView(this, currentScenario); RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); videoLayout.addView(scenarioView, 1, scenarioViewParams); // new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT) // videoLayout.addView(scenarioView, 200, 100); // startDetector(); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Trigger the initial hide() shortly after the activity has been // created, to briefly hint to the user that UI controls // are available. delayedHide(100); } private void toggle() { if (mVisible) { hide(); } else { show(); } } @Override protected void onResume() { super.onResume(); startDetector(); } @Override protected void onPause() { super.onPause(); stopDetector(); } 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.e(LOG_TAG, "HAS PERM"); has_camera_permission = true; } else { Log.e(LOG_TAG, "NO PERM"); 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); detector.setLicensePath("emotionhero_dev.license"); detector.setMaxProcessRate(10); detector.setDetectAllEmotions(true); detector.setDetectAllAppearances(false); detector.setDetectAllEmojis(false); detector.setDetectAllExpressions(false); detector.setMaxProcessRate(12); detector.setImageListener(this); detector.setOnCameraEventListener(this); detector.setFaceListener(this); } detector.start(); mContentView.setText("STARTING..."); Log.d(LOG_TAG, Boolean.toString(detector.isRunning())); } } } void stopDetector() { if (detector != null && detector.isRunning()) { detector.stop(); } } private void hide() { // Hide UI first ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.hide(); } mControlsView.setVisibility(View.GONE); mVisible = false; // Schedule a runnable to remove the status and navigation bar after a delay mHideHandler.removeCallbacks(mShowPart2Runnable); mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY); } @SuppressLint("InlinedApi") private void show() { // Show the system bar mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); mVisible = true; // Schedule a runnable to display UI elements after a delay mHideHandler.removeCallbacks(mHidePart2Runnable); mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY); } /** * Schedules a call to hide() in [delay] milliseconds, canceling any * previously scheduled calls. */ private void delayedHide(int delayMillis) { mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, delayMillis); } @Override /** * Detector callback gives the faces found so we can match their scores to the given scenario. */ public void onImageResults(List list, Frame frame, float timestamp) { // Log.e(LOG_TAG, "RESULT! faces: " + Integer.toString(list.size()) + " t: " + Float.toString(timestamp) + "s" ); if(!currentScenario.isWithinTime(timestamp)) { mContentView.setText(String.format("LEVEL ENDED\nScore: %.2f", currentScenario.getTotalScore())); stopDetector(); restartButton.setVisibility(View.VISIBLE); return; } if (list == null) return; if (list.size() == 0) { mContentView.setText("NO FACE FOUND"); } else { Face face = list.get(0); currentScenario.validateFaceOnTime(face, timestamp); scenarioView.setCurrentAttributeScoresForFace(face); mContentView.setText(String.format("SCORE \n%.2f",currentScenario.getTotalScore())); // String paramString = ""; // paramString += "Anger " + String.format("%02.2f", face.emotions.getAnger()) + "%\n"; // paramString += "Contempt " + String.format("%02.2f", face.emotions.getContempt()) + "%\n"; // paramString += "Disgust " + String.format("%02.2f", face.emotions.getDisgust()) + "%\n"; // paramString += "Fear " + String.format("%02.2f", face.emotions.getFear()) + "%\n"; // paramString += "Joy " + String.format("%02.2f", face.emotions.getJoy()) + "%\n"; // paramString += "Sadness " + String.format("%02.2f", face.emotions.getSadness()) + "%\n"; // paramString += "Surprise " + String.format("%02.2f", face.emotions.getSurprise()) + "%\n"; // // paramText.setText(paramString); } } @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() { mContentView.setText("START!"); currentScenario.start(); } @Override public void onFaceDetectionStopped() { mContentView.setText("No face found..."); // paramText.setText("No face found"); } }