Made changes for AffdexMe to work with SDK v2.01
|
@ -14,6 +14,7 @@
|
||||||
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
|
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name="com.affectiva.errorreporting.CustomApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
@ -38,6 +39,16 @@
|
||||||
android:value="com.affectiva.affdexme.MainActivity" />
|
android:value="com.affectiva.affdexme.MainActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.affectiva.errorreporting.ErrorReporter"
|
||||||
|
android:theme="@android:style/Theme.DeviceDefault"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.Large">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.affectiva.REPORT_ERROR" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -25,13 +25,17 @@ import com.affectiva.android.affdex.sdk.detector.Face;
|
||||||
*/
|
*/
|
||||||
public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
|
class PointFArraySharer {
|
||||||
|
PointF[] nextPointsToDraw = null;
|
||||||
|
}
|
||||||
|
|
||||||
//Inner Thread class
|
//Inner Thread class
|
||||||
class DrawingThread extends Thread{
|
class DrawingThread extends Thread{
|
||||||
private SurfaceHolder mSurfaceHolder;
|
private SurfaceHolder mSurfaceHolder;
|
||||||
private Paint circlePaint;
|
private Paint circlePaint;
|
||||||
private Paint boxPaint;
|
private Paint boxPaint;
|
||||||
private boolean stopFlag = false; //boolean to indicate when thread has been told to stop
|
private volatile boolean stopFlag = false; //boolean to indicate when thread has been told to stop
|
||||||
private PointF[] nextPointsToDraw = null; //holds a reference to the most recent set of points returned by CameraDetector, passed in by main thread
|
private final PointFArraySharer sharer;
|
||||||
private DrawingViewConfig config;
|
private DrawingViewConfig config;
|
||||||
private final long drawPeriod = 33; //draw at 30 fps
|
private final long drawPeriod = 33; //draw at 30 fps
|
||||||
|
|
||||||
|
@ -52,6 +56,7 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
boxPaint.setStyle(Paint.Style.STROKE);
|
boxPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
|
||||||
config = con;
|
config = con;
|
||||||
|
sharer = new PointFArraySharer();
|
||||||
|
|
||||||
setThickness(config.drawThickness);
|
setThickness(config.drawThickness);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +89,9 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
//Updates thread with latest points returned by the onImageResults() event.
|
//Updates thread with latest points returned by the onImageResults() event.
|
||||||
public void updatePoints(PointF[] pointList) {
|
public void updatePoints(PointF[] pointList) {
|
||||||
nextPointsToDraw = pointList;
|
synchronized (sharer) {
|
||||||
|
sharer.nextPointsToDraw = pointList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setThickness(int thickness) {
|
void setThickness(int thickness) {
|
||||||
|
@ -93,7 +100,9 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
//Inform thread face detection has stopped, so array of points is no longer valid.
|
//Inform thread face detection has stopped, so array of points is no longer valid.
|
||||||
public void invalidatePoints() {
|
public void invalidatePoints() {
|
||||||
nextPointsToDraw = null;
|
synchronized (sharer) {
|
||||||
|
sharer.nextPointsToDraw = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,7 +110,6 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
|
||||||
while(!stopFlag) {
|
while(!stopFlag) {
|
||||||
long startTime = SystemClock.elapsedRealtime(); //get time at the start of thread loop
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use SurfaceHolder.lockCanvas() to get the canvas that draws to the SurfaceView.
|
* We use SurfaceHolder.lockCanvas() to get the canvas that draws to the SurfaceView.
|
||||||
|
@ -114,35 +122,28 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
if (c!= null) {
|
if (c!= null) {
|
||||||
synchronized (mSurfaceHolder) {
|
synchronized (mSurfaceHolder) {
|
||||||
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //clear previous dots
|
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //clear previous dots
|
||||||
if ((nextPointsToDraw != null) ) {
|
|
||||||
draw(c);
|
draw(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally {
|
finally {
|
||||||
if (c!= null) {
|
if (c!= null) {
|
||||||
mSurfaceHolder.unlockCanvasAndPost(c);
|
mSurfaceHolder.unlockCanvasAndPost(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//send thread to sleep so we don't draw faster than the requested 'drawPeriod'.
|
|
||||||
long sleepTime = drawPeriod - (SystemClock.elapsedRealtime() - startTime);
|
|
||||||
try {
|
|
||||||
if(sleepTime>0){
|
|
||||||
this.sleep(sleepTime);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Log.e(LOG_TAG,ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config = null; //nullify object to avoid memory leak
|
config = null; //nullify object to avoid memory leak
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas c) {
|
void draw(Canvas c) {
|
||||||
//Save our own reference to the list of points, in case the previous reference is overwritten by the main thread.
|
PointF[] points;
|
||||||
PointF[] points = nextPointsToDraw;
|
synchronized (sharer) {
|
||||||
|
if (sharer.nextPointsToDraw == null)
|
||||||
|
return;
|
||||||
|
points = sharer.nextPointsToDraw;
|
||||||
|
}
|
||||||
|
|
||||||
//Coordinates around which to draw bounding box.
|
//Coordinates around which to draw bounding box.
|
||||||
float leftBx = config.surfaceViewWidth;
|
float leftBx = config.surfaceViewWidth;
|
||||||
|
@ -218,10 +219,9 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
private int surfaceViewHeight = 0;
|
private int surfaceViewHeight = 0;
|
||||||
private float screenToImageRatio = 0;
|
private float screenToImageRatio = 0;
|
||||||
private int drawThickness = 0;
|
private int drawThickness = 0;
|
||||||
private boolean isImageDimensionsNeeded = true;
|
|
||||||
private boolean isSurfaceViewDimensionsNeeded = true;
|
|
||||||
private boolean isDrawPointsEnabled = true; //by default, have the drawing thread draw tracking dots
|
private boolean isDrawPointsEnabled = true; //by default, have the drawing thread draw tracking dots
|
||||||
private boolean isDrawMeasurementsEnabled = false;
|
private boolean isDrawMeasurementsEnabled = false;
|
||||||
|
private boolean isDimensionsNeeded = true;
|
||||||
|
|
||||||
private Paint textPaint;
|
private Paint textPaint;
|
||||||
private int textSize;
|
private int textSize;
|
||||||
|
@ -235,32 +235,16 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
this.upperTextSpacing = upperTextSpacing;
|
this.upperTextSpacing = upperTextSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateImageDimensions(int w, int h) {
|
public void updateViewDimensions(int surfaceViewWidth, int surfaceViewHeight, int imageWidth, int imageHeight) {
|
||||||
|
if (surfaceViewWidth <= 0 || surfaceViewHeight <= 0 || imageWidth <= 0 || imageHeight <= 0) {
|
||||||
if ( (w <= 0) || (h <= 0)) {
|
throw new IllegalArgumentException("All dimensions submitted to updateViewDimensions() must be positive");
|
||||||
throw new IllegalArgumentException("Image Dimensions must be positive.");
|
|
||||||
}
|
}
|
||||||
|
this.imageWidth = imageWidth;
|
||||||
imageWidth = w;
|
this.imageHeight = imageHeight;
|
||||||
imageHeight = h;
|
this.surfaceViewWidth = surfaceViewWidth;
|
||||||
if (!isSurfaceViewDimensionsNeeded) {
|
this.surfaceViewHeight = surfaceViewHeight;
|
||||||
screenToImageRatio = (float)surfaceViewWidth / (float)imageWidth;
|
screenToImageRatio = (float)surfaceViewWidth / imageWidth;
|
||||||
}
|
isDimensionsNeeded = false;
|
||||||
isImageDimensionsNeeded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateSurfaceViewDimensions(int w, int h) {
|
|
||||||
|
|
||||||
if ( (w <= 0) || (h <= 0)) {
|
|
||||||
throw new IllegalArgumentException("SurfaceView Dimensions must be positive.");
|
|
||||||
}
|
|
||||||
|
|
||||||
surfaceViewWidth = w;
|
|
||||||
surfaceViewHeight = h;
|
|
||||||
if (!isImageDimensionsNeeded) {
|
|
||||||
screenToImageRatio = (float)surfaceViewWidth / (float)imageWidth;
|
|
||||||
}
|
|
||||||
isSurfaceViewDimensionsNeeded = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDrawThickness(int t) {
|
public void setDrawThickness(int t) {
|
||||||
|
@ -365,29 +349,17 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isImageDimensionsNeeded() {
|
public boolean isDimensionsNeeded() {
|
||||||
return drawingViewConfig.isImageDimensionsNeeded;
|
return drawingViewConfig.isDimensionsNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSurfaceDimensionsNeeded() {
|
public void invalidateDimensions() {
|
||||||
return drawingViewConfig.isSurfaceViewDimensionsNeeded;
|
drawingViewConfig.isDimensionsNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateImageDimensions() {
|
public void updateViewDimensions(int surfaceViewWidth, int surfaceViewHeight, int imageWidth, int imageHeight) {
|
||||||
drawingViewConfig.isImageDimensionsNeeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateImageDimensions(int w, int h) {
|
|
||||||
try {
|
try {
|
||||||
drawingViewConfig.updateImageDimensions(w, h);
|
drawingViewConfig.updateViewDimensions(surfaceViewWidth,surfaceViewHeight,imageWidth,imageHeight);
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(LOG_TAG,e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateSurfaceViewDimensions(int w, int h) {
|
|
||||||
try {
|
|
||||||
drawingViewConfig.updateSurfaceViewDimensions(w, h);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOG_TAG,e.getMessage());
|
Log.e(LOG_TAG,e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,13 +67,15 @@ import com.affectiva.android.affdex.sdk.detector.Face;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MainActivity extends Activity
|
public class MainActivity extends Activity
|
||||||
implements Detector.FaceListener, Detector.ImageListener, View.OnTouchListener, CameraDetector.CameraSurfaceViewListener {
|
implements Detector.FaceListener, Detector.ImageListener, View.OnTouchListener, CameraDetector.OnCameraEventListener {
|
||||||
|
|
||||||
private static final String LOG_TAG = "Affectiva";
|
private static final String LOG_TAG = "Affectiva";
|
||||||
public static final int NUM_METRICS_DISPLAYED = 6;
|
public static final int NUM_METRICS_DISPLAYED = 6;
|
||||||
|
|
||||||
//Affectiva SDK Object
|
//Affectiva SDK Object
|
||||||
private CameraDetector detector = null;
|
private CameraDetector detector = null;
|
||||||
|
//TODO: License file in byte form. Should NOT be included in released sample code.
|
||||||
|
private byte[] licenseBytes = {123,34,116,111,107,101,110,34,58,32,34,102,98,51,51,101,102,57,98,102,98,49,57,53,100,97,99,55,97,53,99,48,98,50,56,54,54,51,51,48,56,52,100,102,56,48,57,55,52,101,99,99,57,98,51,54,97,97,101,51,57,99,97,51,98,97,53,54,57,50,49,102,56,49,53,34,44,34,108,105,99,101,110,115,111,114,34,58,32,34,65,102,102,101,99,116,105,118,97,32,73,110,99,46,34,44,34,101,120,112,105,114,101,115,34,58,32,34,50,48,57,57,45,48,49,45,48,49,34,44,34,100,101,118,101,108,111,112,101,114,73,100,34,58,32,34,65,102,102,101,99,116,105,118,97,45,105,110,116,101,114,110,97,108,34,44,34,115,111,102,116,119,97,114,101,34,58,32,34,65,102,102,100,101,120,32,83,68,75,34,125};
|
||||||
|
|
||||||
//MetricsManager View UI Objects
|
//MetricsManager View UI Objects
|
||||||
private RelativeLayout metricViewLayout;
|
private RelativeLayout metricViewLayout;
|
||||||
|
@ -93,6 +95,7 @@ public class MainActivity extends Activity
|
||||||
private SurfaceView cameraView; //SurfaceView used to display camera images
|
private SurfaceView cameraView; //SurfaceView used to display camera images
|
||||||
private DrawingView drawingView; //SurfaceView containing its own thread, used to draw facial tracking dots
|
private DrawingView drawingView; //SurfaceView containing its own thread, used to draw facial tracking dots
|
||||||
private ImageButton settingsButton;
|
private ImageButton settingsButton;
|
||||||
|
private ImageButton cameraButton;
|
||||||
|
|
||||||
//Application settings variables
|
//Application settings variables
|
||||||
private int detectorProcessRate;
|
private int detectorProcessRate;
|
||||||
|
@ -105,7 +108,12 @@ public class MainActivity extends Activity
|
||||||
private float numberOfFrames = 0;
|
private float numberOfFrames = 0;
|
||||||
private long timeToUpdate = 0;
|
private long timeToUpdate = 0;
|
||||||
|
|
||||||
|
//Camera-related variables
|
||||||
private boolean isFrontFacingCameraDetected = true;
|
private boolean isFrontFacingCameraDetected = true;
|
||||||
|
private boolean isBackFacingCameraDetected = true;
|
||||||
|
int cameraPreviewWidth = 0;
|
||||||
|
int cameraPreviewHeight = 0;
|
||||||
|
CameraDetector.CameraType cameraType;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -115,20 +123,33 @@ public class MainActivity extends Activity
|
||||||
|
|
||||||
initializeUI();
|
initializeUI();
|
||||||
|
|
||||||
|
determineCameraAvailability();
|
||||||
|
|
||||||
|
initializeCameraDetector();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We check to make sure the device has a front-facing camera.
|
* We check to make sure the device has a front-facing camera.
|
||||||
* If it does not, we obscure the app with a notice informing the user they cannot
|
* If it does not, we obscure the app with a notice informing the user they cannot
|
||||||
* use the app.
|
* use the app.
|
||||||
*/
|
*/
|
||||||
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
|
void determineCameraAvailability() {
|
||||||
isFrontFacingCameraDetected = false;
|
PackageManager manager = getPackageManager();
|
||||||
|
isFrontFacingCameraDetected = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
|
||||||
|
isBackFacingCameraDetected = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA);
|
||||||
|
|
||||||
|
if (!isFrontFacingCameraDetected && !isBackFacingCameraDetected) {
|
||||||
progressBar.setVisibility(View.INVISIBLE);
|
progressBar.setVisibility(View.INVISIBLE);
|
||||||
pleaseWaitTextView.setVisibility(View.INVISIBLE);
|
pleaseWaitTextView.setVisibility(View.INVISIBLE);
|
||||||
TextView notFoundTextView = (TextView) findViewById(R.id.not_found_textview);
|
TextView notFoundTextView = (TextView) findViewById(R.id.not_found_textview);
|
||||||
notFoundTextView.setVisibility(View.VISIBLE);
|
notFoundTextView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCameraDetector();
|
//TODO: change this to be taken from settings
|
||||||
|
if (isBackFacingCameraDetected)
|
||||||
|
cameraType = CameraDetector.CameraType.CAMERA_BACK;
|
||||||
|
if (isFrontFacingCameraDetected)
|
||||||
|
cameraType = CameraDetector.CameraType.CAMERA_FRONT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeUI() {
|
void initializeUI() {
|
||||||
|
@ -145,6 +166,7 @@ public class MainActivity extends Activity
|
||||||
cameraView = (SurfaceView) findViewById(R.id.camera_preview);
|
cameraView = (SurfaceView) findViewById(R.id.camera_preview);
|
||||||
drawingView = (DrawingView) findViewById(R.id.drawing_view);
|
drawingView = (DrawingView) findViewById(R.id.drawing_view);
|
||||||
settingsButton = (ImageButton) findViewById(R.id.settings_button);
|
settingsButton = (ImageButton) findViewById(R.id.settings_button);
|
||||||
|
cameraButton = (ImageButton) findViewById(R.id.camera_button);
|
||||||
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
|
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
|
||||||
pleaseWaitTextView = (TextView) findViewById(R.id.please_wait_textview);
|
pleaseWaitTextView = (TextView) findViewById(R.id.please_wait_textview);
|
||||||
|
|
||||||
|
@ -216,12 +238,14 @@ public class MainActivity extends Activity
|
||||||
* the camera. If a SurfaceView is passed in as the last argument to the constructor,
|
* the camera. If a SurfaceView is passed in as the last argument to the constructor,
|
||||||
* that view will be painted with what the camera sees.
|
* that view will be painted with what the camera sees.
|
||||||
*/
|
*/
|
||||||
detector = new CameraDetector(this, CameraDetector.CameraType.CAMERA_FRONT, cameraView);
|
detector = new CameraDetector(this, cameraType, cameraView);
|
||||||
|
//TODO: this method SHOULD NOT be included in sample code release (customer should enter their own license file).
|
||||||
|
detector.setLicenseStream(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(licenseBytes))));
|
||||||
// NOTE: uncomment the line below and replace "YourLicenseFile" with your license file, which should be stored in /assets/Affdex/
|
// NOTE: uncomment the line below and replace "YourLicenseFile" with your license file, which should be stored in /assets/Affdex/
|
||||||
//detector.setLicensePath("YourLicenseFile");
|
//detector.setLicensePath("YourLicenseFile");
|
||||||
detector.setImageListener(this);
|
detector.setImageListener(this);
|
||||||
detector.setFaceListener(this);
|
detector.setFaceListener(this);
|
||||||
detector.setCameraDetectorDimensionsListener(this);
|
detector.setOnCameraEventListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -329,8 +353,10 @@ public class MainActivity extends Activity
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainWindowResumedTasks() {
|
void mainWindowResumedTasks() {
|
||||||
startCamera();
|
|
||||||
if (!drawingView.isSurfaceDimensionsNeeded()) {
|
startDetector();
|
||||||
|
|
||||||
|
if (!drawingView.isDimensionsNeeded()) {
|
||||||
progressBarLayout.setVisibility(View.GONE);
|
progressBarLayout.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
resetFPSCalculations();
|
resetFPSCalculations();
|
||||||
|
@ -344,11 +370,11 @@ public class MainActivity extends Activity
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startCamera() {
|
void startDetector() {
|
||||||
|
if (!isBackFacingCameraDetected && !isFrontFacingCameraDetected)
|
||||||
//this app will always detect valence (it will also always detect measurements, but measurement don't need to be enabled)
|
return; //without any cameras detected, we cannot proceed
|
||||||
detector.setDetectValence(true);
|
|
||||||
|
|
||||||
|
detector.setDetectValence(true); //this app will always detect valence
|
||||||
if (!detector.isRunning()) {
|
if (!detector.isRunning()) {
|
||||||
try {
|
try {
|
||||||
detector.start();
|
detector.start();
|
||||||
|
@ -356,9 +382,10 @@ public class MainActivity extends Activity
|
||||||
Log.e(LOG_TAG, e.getMessage());
|
Log.e(LOG_TAG, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFaceDetectionStarted() {
|
public void onFaceDetectionStarted() {
|
||||||
leftMetricsLayout.animate().alpha(1); //make left and right metrics appear
|
leftMetricsLayout.animate().alpha(1); //make left and right metrics appear
|
||||||
|
@ -375,8 +402,7 @@ public class MainActivity extends Activity
|
||||||
void performFaceDetectionStoppedTasks() {
|
void performFaceDetectionStoppedTasks() {
|
||||||
leftMetricsLayout.animate().alpha(0); //make left and right metrics disappear
|
leftMetricsLayout.animate().alpha(0); //make left and right metrics disappear
|
||||||
rightMetricsLayout.animate().alpha(0);
|
rightMetricsLayout.animate().alpha(0);
|
||||||
|
drawingView.updatePoints(null);
|
||||||
drawingView.invalidatePoints(); //inform the drawing thread that the latest facial tracking points are now invalid
|
|
||||||
resetFPSCalculations(); //Since the FPS may be different whether a face is being tracked or not, reset variables.
|
resetFPSCalculations(); //Since the FPS may be different whether a face is being tracked or not, reset variables.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,14 +411,6 @@ public class MainActivity extends Activity
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onImageResults(List<Face> faces, Frame image, float timeStamp) {
|
public void onImageResults(List<Face> faces, Frame image, float timeStamp) {
|
||||||
/**
|
|
||||||
* If the flag indicating that we still need to know the size of the camera frames, call calculateImageDimensions().
|
|
||||||
* The flag is a boolean stored in our drawingView object, retrieved through DrawingView.isImageDimensionsNeeded().
|
|
||||||
*/
|
|
||||||
if (drawingView.isImageDimensionsNeeded() ) {
|
|
||||||
calculateImageDimensions(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
//If the faces object is null, we received an unprocessed frame
|
//If the faces object is null, we received an unprocessed frame
|
||||||
if (faces == null) {
|
if (faces == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -403,6 +421,7 @@ public class MainActivity extends Activity
|
||||||
|
|
||||||
//If faces.size() is 0, we received a frame in which no face was detected
|
//If faces.size() is 0, we received a frame in which no face was detected
|
||||||
if (faces.size() == 0) {
|
if (faces.size() == 0) {
|
||||||
|
drawingView.updatePoints(null); //the drawingView takes null points to mean it doesn't have to draw anything
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,54 +467,6 @@ public class MainActivity extends Activity
|
||||||
metricDisplay.setScore(score);
|
metricDisplay.setScore(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* In this method, we inform our drawingView of the size of the incoming camera images.
|
|
||||||
* We also set the thickness (which controls the size of the dots and bounding box) based on a reference thickness, which
|
|
||||||
* should be the same whether the device is landscape or portrait.
|
|
||||||
*/
|
|
||||||
void calculateImageDimensions(Frame image){
|
|
||||||
///referenceDimension will be used to determine the size of the facial tracking dots
|
|
||||||
float referenceDimension = activityLayout.getHeight();
|
|
||||||
|
|
||||||
//get size of frames being passed by camera
|
|
||||||
int imageWidth = image.getWidth();
|
|
||||||
int imageHeight = image.getHeight();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If device is rotated vertically, reverse the width and height returned by the Frame object,
|
|
||||||
* and switch the dimension we consider to be the reference dimension.
|
|
||||||
*/
|
|
||||||
if ((ROTATE.BY_90_CW == image.getTargetRotation()) || (ROTATE.BY_90_CCW == image.getTargetRotation())) {
|
|
||||||
int temp = imageWidth;
|
|
||||||
imageWidth = imageHeight;
|
|
||||||
imageHeight = temp;
|
|
||||||
|
|
||||||
referenceDimension = activityLayout.getWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawingView.updateImageDimensions(imageWidth, imageHeight);
|
|
||||||
drawingView.setThickness((int) (referenceDimension / 160f));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called when the SDK has corrected the aspect ratio of the SurfaceView. We use this information to resize
|
|
||||||
* our mainLayout ViewGroup so the UI fits snugly around the SurfaceView. We also update our drawingView object, so the tracking dots
|
|
||||||
* are drawn in the correct coordinates.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onSurfaceViewAspectRatioChanged(int width, int height) {
|
|
||||||
drawingView.updateSurfaceViewDimensions(width,height);
|
|
||||||
|
|
||||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mainLayout.getLayoutParams();
|
|
||||||
params.height = height;
|
|
||||||
params.width = width;
|
|
||||||
mainLayout.setLayoutParams(params);
|
|
||||||
|
|
||||||
//Now that our main layout has been resized, we can remove the progress bar that was obscuring the screen (its purpose was to obscure the resizing of the SurfaceView)
|
|
||||||
progressBarLayout.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FPS measurement simply uses SystemClock to measure how many frames were processed since
|
* FPS measurement simply uses SystemClock to measure how many frames were processed since
|
||||||
* the FPS variables were last reset.
|
* the FPS variables were last reset.
|
||||||
|
@ -522,15 +493,14 @@ public class MainActivity extends Activity
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
progressBarLayout.setVisibility(View.VISIBLE);
|
progressBarLayout.setVisibility(View.VISIBLE);
|
||||||
stopCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopCamera() {
|
|
||||||
performFaceDetectionStoppedTasks();
|
performFaceDetectionStoppedTasks();
|
||||||
|
|
||||||
detector.setDetectAllEmotions(false);
|
stopDetector();
|
||||||
detector.setDetectAllExpressions(false);
|
}
|
||||||
|
|
||||||
|
void stopDetector() {
|
||||||
|
if (detector.isRunning()) {
|
||||||
try {
|
try {
|
||||||
detector.stop();
|
detector.stop();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -538,6 +508,11 @@ public class MainActivity extends Activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detector.setDetectAllEmotions(false);
|
||||||
|
detector.setDetectAllExpressions(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the user taps the screen, hide the menu if it is visible and show it if it is hidden.
|
* When the user taps the screen, hide the menu if it is visible and show it if it is hidden.
|
||||||
|
@ -547,6 +522,7 @@ public class MainActivity extends Activity
|
||||||
isMenuVisible = b;
|
isMenuVisible = b;
|
||||||
if (b) {
|
if (b) {
|
||||||
settingsButton.setVisibility(View.VISIBLE);
|
settingsButton.setVisibility(View.VISIBLE);
|
||||||
|
cameraButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
//We display the navigation bar again
|
//We display the navigation bar again
|
||||||
getWindow().getDecorView().setSystemUiVisibility(
|
getWindow().getDecorView().setSystemUiVisibility(
|
||||||
|
@ -567,6 +543,7 @@ public class MainActivity extends Activity
|
||||||
|
|
||||||
|
|
||||||
settingsButton.setVisibility(View.INVISIBLE);
|
settingsButton.setVisibility(View.INVISIBLE);
|
||||||
|
cameraButton.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +591,86 @@ public class MainActivity extends Activity
|
||||||
public void settings_button_click(View view) {
|
public void settings_button_click(View view) {
|
||||||
startActivity(new Intent(this,SettingsActivity.class));
|
startActivity(new Intent(this,SettingsActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCameraStarted(boolean b, Throwable throwable) {
|
||||||
|
if (throwable != null) {
|
||||||
|
Toast.makeText(this,"Failed to start camera.",Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCameraSizeSelected(int cameraWidth, int cameraHeight, ROTATE rotation) {
|
||||||
|
if (rotation == ROTATE.BY_90_CCW || rotation == ROTATE.BY_90_CW) {
|
||||||
|
cameraPreviewWidth = cameraHeight;
|
||||||
|
cameraPreviewHeight = cameraWidth;
|
||||||
|
} else {
|
||||||
|
cameraPreviewWidth = cameraWidth;
|
||||||
|
cameraPreviewHeight = cameraHeight;
|
||||||
|
}
|
||||||
|
drawingView.setThickness((int)(cameraWidth/100f));
|
||||||
|
|
||||||
|
mainLayout.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int layoutWidth = mainLayout.getWidth();
|
||||||
|
int layoutHeight = mainLayout.getHeight();
|
||||||
|
|
||||||
|
if (cameraPreviewWidth == 0 || cameraPreviewHeight == 0 || layoutWidth == 0 || layoutHeight == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float layoutAspectRatio = (float)layoutWidth/layoutHeight;
|
||||||
|
float cameraPreviewAspectRatio = (float)cameraPreviewWidth/cameraPreviewHeight;
|
||||||
|
|
||||||
|
int newWidth;
|
||||||
|
int newHeight;
|
||||||
|
|
||||||
|
if (cameraPreviewAspectRatio > layoutAspectRatio) {
|
||||||
|
newWidth = layoutWidth;
|
||||||
|
newHeight =(int) (layoutWidth / cameraPreviewAspectRatio);
|
||||||
|
} else {
|
||||||
|
newWidth = (int) (layoutHeight * cameraPreviewAspectRatio);
|
||||||
|
newHeight = layoutHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawingView.updateViewDimensions(newWidth,newHeight,cameraPreviewWidth,cameraPreviewHeight);
|
||||||
|
|
||||||
|
ViewGroup.LayoutParams params = mainLayout.getLayoutParams();
|
||||||
|
params.height = newHeight;
|
||||||
|
params.width = newWidth;
|
||||||
|
mainLayout.setLayoutParams(params);
|
||||||
|
|
||||||
|
//Now that our main layout has been resized, we can remove the progress bar that was obscuring the screen (its purpose was to obscure the resizing of the SurfaceView)
|
||||||
|
progressBarLayout.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void camera_button_click(View view) {
|
||||||
|
if (cameraType == CameraDetector.CameraType.CAMERA_FRONT) {
|
||||||
|
if (isBackFacingCameraDetected) {
|
||||||
|
cameraType = CameraDetector.CameraType.CAMERA_BACK;
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this,"No back-facing camera found",Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
} else if (cameraType == CameraDetector.CameraType.CAMERA_BACK) {
|
||||||
|
if (isFrontFacingCameraDetected) {
|
||||||
|
cameraType = CameraDetector.CameraType.CAMERA_FRONT;
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this,"No front-facing camera found",Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performFaceDetectionStoppedTasks();
|
||||||
|
|
||||||
|
try {
|
||||||
|
detector.setCameraType(cameraType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOG_TAG,e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.affectiva.errorreporting;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Alan on 8/21/2015.
|
||||||
|
*/
|
||||||
|
public class CustomApplication extends Application {
|
||||||
|
|
||||||
|
static volatile boolean wasErrorActivityStarted = false;
|
||||||
|
static final boolean enableCustomErrorMessage = false;
|
||||||
|
Thread.UncaughtExceptionHandler exceptionHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate ()
|
||||||
|
{
|
||||||
|
super.onCreate();
|
||||||
|
exceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
|
// Setup handler for uncaught exceptions.
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void uncaughtException (Thread thread, Throwable e)
|
||||||
|
{
|
||||||
|
handleUncaughtException (thread, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleUncaughtException (Thread thread, Throwable e)
|
||||||
|
{
|
||||||
|
if (!wasErrorActivityStarted && enableCustomErrorMessage) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction("com.affectiva.REPORT_ERROR"); // see step 5.
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
|
||||||
|
intent.putExtra("affdexme_error", e);
|
||||||
|
startActivity(intent);
|
||||||
|
wasErrorActivityStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
exceptionHandler.uncaughtException(thread,e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.affectiva.errorreporting;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import com.affectiva.affdexme.R;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Alan on 8/21/2015.
|
||||||
|
*/
|
||||||
|
public class ErrorReporter extends Activity implements View.OnClickListener {
|
||||||
|
|
||||||
|
String errorMessage;
|
||||||
|
Button sendButton;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE); // make a dialog without a titlebar
|
||||||
|
setContentView(R.layout.error_reporter);
|
||||||
|
|
||||||
|
Throwable error = (Throwable) getIntent().getSerializableExtra("affdexme_error");
|
||||||
|
if (error != null) {
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("AffdexMe Error Report:");
|
||||||
|
builder.append(DateFormat.getDateTimeInstance().format(new Date()));
|
||||||
|
builder.append("\n");
|
||||||
|
builder.append(error.getMessage());
|
||||||
|
builder.append(("\n"));
|
||||||
|
|
||||||
|
StackTraceElement[] stackTraceElements = error.getStackTrace();
|
||||||
|
for (StackTraceElement element : stackTraceElements) {
|
||||||
|
builder.append("\n");
|
||||||
|
builder.append(element.toString());
|
||||||
|
}
|
||||||
|
errorMessage = builder.toString();
|
||||||
|
} else {
|
||||||
|
errorMessage = "Failed to catch error.";
|
||||||
|
}
|
||||||
|
|
||||||
|
sendButton = (Button) findViewById(R.id.send_button);
|
||||||
|
sendButton.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent (Intent.ACTION_SEND);
|
||||||
|
intent.setType("plain/text");
|
||||||
|
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"sdk@affectiva.com"});
|
||||||
|
intent.putExtra(Intent.EXTRA_SUBJECT, "AffdexMe Crash Report");
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, errorMessage); // do this so some email clients don't complain about empty body.
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 205 B |
After Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 158 B |
After Width: | Height: | Size: 248 B |
After Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 272 B |
After Width: | Height: | Size: 305 B |
After Width: | Height: | Size: 451 B |
After Width: | Height: | Size: 472 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 674 B |
After Width: | Height: | Size: 713 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/transluscent_circle"
|
||||||
|
android:maxLevel="0"/>
|
||||||
|
<item android:drawable="@drawable/ic_switch_camera_black_48dp"
|
||||||
|
android:maxLevel="1"
|
||||||
|
/>
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/transluscent_circle"
|
||||||
|
android:maxLevel="0"/>
|
||||||
|
<item android:drawable="@drawable/ic_switch_camera_white_48dp"
|
||||||
|
android:maxLevel="1"
|
||||||
|
/>
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true" android:drawable="@drawable/camera_button_pressed"/>
|
||||||
|
<item android:drawable="@drawable/camera_button_not_pressed" />
|
||||||
|
</selector>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/transluscent_circle"
|
||||||
|
android:maxLevel="0"/>
|
||||||
|
<item android:drawable="@drawable/ic_more_vert_black_48dp"
|
||||||
|
android:maxLevel="1"
|
||||||
|
/>
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/transluscent_circle"
|
||||||
|
android:maxLevel="0"/>
|
||||||
|
<item android:drawable="@drawable/ic_more_vert_white_48dp"
|
||||||
|
android:maxLevel="1"
|
||||||
|
/>
|
||||||
|
</layer-list>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_pressed="true" android:drawable="@drawable/settings_button_pressed"/>
|
<item android:state_pressed="true" android:drawable="@drawable/settings_button_pressed"/>
|
||||||
<item android:drawable="@drawable/settings_button" />
|
<item android:drawable="@drawable/settings_button_not_pressed" />
|
||||||
</selector>
|
</selector>
|
10
AffdexMe/app/src/main/res/drawable/transluscent_circle.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid
|
||||||
|
android:color="#88FFFFFF"/>
|
||||||
|
<corners
|
||||||
|
android:radius="24dp"/>
|
||||||
|
<size android:height="48dp"
|
||||||
|
android:width="48dp"/>
|
||||||
|
</shape>
|
|
@ -1,7 +1,9 @@
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:id="@+id/main_layout"
|
||||||
android:layout_height="match_parent" tools:context=".MainActivity" android:focusable="true"
|
android:layout_height="match_parent" tools:context=".MainActivity" android:focusable="true"
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
android:keepScreenOn="true"
|
android:keepScreenOn="true"
|
||||||
|
@ -12,13 +14,6 @@
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:id="@+id/camera_preview"
|
android:id="@+id/camera_preview"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:id="@+id/main_layout"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
>
|
|
||||||
<com.affectiva.affdexme.DrawingView
|
<com.affectiva.affdexme.DrawingView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -45,7 +40,19 @@
|
||||||
android:layout_below="@id/metric_view_group"
|
android:layout_below="@id/metric_view_group"
|
||||||
android:id="@+id/settings_button"
|
android:id="@+id/settings_button"
|
||||||
android:onClick="settings_button_click"/>
|
android:onClick="settings_button_click"/>
|
||||||
</RelativeLayout>
|
<ImageButton
|
||||||
|
android:layout_width="@dimen/settings_button_size"
|
||||||
|
android:layout_height="@dimen/settings_button_size"
|
||||||
|
android:background="@null"
|
||||||
|
android:src="@drawable/camera_button_selector"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:layout_margin="@dimen/settings_button_margin"
|
||||||
|
android:contentDescription="Switch camera button"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_below="@id/settings_button"
|
||||||
|
android:id="@+id/camera_button"
|
||||||
|
android:onClick="camera_button_click"/>
|
||||||
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
23
AffdexMe/app/src/main/res/layout/error_reporter.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
<Button
|
||||||
|
android:padding="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:id="@+id/send_button"
|
||||||
|
android:text="Send"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_above="@id/send_button"
|
||||||
|
android:text="It looks like AffdexMe has crashed! Click below to send an automated report, then try restarting the app."/>
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|