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"/>
|
||||
|
||||
<application
|
||||
android:name="com.affectiva.errorreporting.CustomApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:hardwareAccelerated="true"
|
||||
|
@ -38,6 +39,16 @@
|
|||
android:value="com.affectiva.affdexme.MainActivity" />
|
||||
</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>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -25,13 +25,17 @@ import com.affectiva.android.affdex.sdk.detector.Face;
|
|||
*/
|
||||
public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
|
||||
class PointFArraySharer {
|
||||
PointF[] nextPointsToDraw = null;
|
||||
}
|
||||
|
||||
//Inner Thread class
|
||||
class DrawingThread extends Thread{
|
||||
private SurfaceHolder mSurfaceHolder;
|
||||
private Paint circlePaint;
|
||||
private Paint boxPaint;
|
||||
private 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 volatile boolean stopFlag = false; //boolean to indicate when thread has been told to stop
|
||||
private final PointFArraySharer sharer;
|
||||
private DrawingViewConfig config;
|
||||
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);
|
||||
|
||||
config = con;
|
||||
sharer = new PointFArraySharer();
|
||||
|
||||
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.
|
||||
public void updatePoints(PointF[] pointList) {
|
||||
nextPointsToDraw = pointList;
|
||||
synchronized (sharer) {
|
||||
sharer.nextPointsToDraw = pointList;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
public void invalidatePoints() {
|
||||
nextPointsToDraw = null;
|
||||
synchronized (sharer) {
|
||||
sharer.nextPointsToDraw = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,7 +110,6 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
|||
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
|
||||
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.
|
||||
|
@ -114,35 +122,28 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
|||
if (c!= null) {
|
||||
synchronized (mSurfaceHolder) {
|
||||
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //clear previous dots
|
||||
if ((nextPointsToDraw != null) ) {
|
||||
draw(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (c!= null) {
|
||||
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
|
||||
}
|
||||
|
||||
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 = nextPointsToDraw;
|
||||
PointF[] points;
|
||||
synchronized (sharer) {
|
||||
if (sharer.nextPointsToDraw == null)
|
||||
return;
|
||||
points = sharer.nextPointsToDraw;
|
||||
}
|
||||
|
||||
//Coordinates around which to draw bounding box.
|
||||
float leftBx = config.surfaceViewWidth;
|
||||
|
@ -218,10 +219,9 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
|||
private int surfaceViewHeight = 0;
|
||||
private float screenToImageRatio = 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 isDrawMeasurementsEnabled = false;
|
||||
private boolean isDimensionsNeeded = true;
|
||||
|
||||
private Paint textPaint;
|
||||
private int textSize;
|
||||
|
@ -235,32 +235,16 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
|||
this.upperTextSpacing = upperTextSpacing;
|
||||
}
|
||||
|
||||
public void updateImageDimensions(int w, int h) {
|
||||
|
||||
if ( (w <= 0) || (h <= 0)) {
|
||||
throw new IllegalArgumentException("Image Dimensions must be positive.");
|
||||
public void updateViewDimensions(int surfaceViewWidth, int surfaceViewHeight, int imageWidth, int imageHeight) {
|
||||
if (surfaceViewWidth <= 0 || surfaceViewHeight <= 0 || imageWidth <= 0 || imageHeight <= 0) {
|
||||
throw new IllegalArgumentException("All dimensions submitted to updateViewDimensions() must be positive");
|
||||
}
|
||||
|
||||
imageWidth = w;
|
||||
imageHeight = h;
|
||||
if (!isSurfaceViewDimensionsNeeded) {
|
||||
screenToImageRatio = (float)surfaceViewWidth / (float)imageWidth;
|
||||
}
|
||||
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;
|
||||
this.imageWidth = imageWidth;
|
||||
this.imageHeight = imageHeight;
|
||||
this.surfaceViewWidth = surfaceViewWidth;
|
||||
this.surfaceViewHeight = surfaceViewHeight;
|
||||
screenToImageRatio = (float)surfaceViewWidth / imageWidth;
|
||||
isDimensionsNeeded = false;
|
||||
}
|
||||
|
||||
public void setDrawThickness(int t) {
|
||||
|
@ -365,29 +349,17 @@ public class DrawingView extends SurfaceView implements SurfaceHolder.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isImageDimensionsNeeded() {
|
||||
return drawingViewConfig.isImageDimensionsNeeded;
|
||||
public boolean isDimensionsNeeded() {
|
||||
return drawingViewConfig.isDimensionsNeeded;
|
||||
}
|
||||
|
||||
public boolean isSurfaceDimensionsNeeded() {
|
||||
return drawingViewConfig.isSurfaceViewDimensionsNeeded;
|
||||
public void invalidateDimensions() {
|
||||
drawingViewConfig.isDimensionsNeeded = true;
|
||||
}
|
||||
|
||||
public void invalidateImageDimensions() {
|
||||
drawingViewConfig.isImageDimensionsNeeded = true;
|
||||
}
|
||||
|
||||
public void updateImageDimensions(int w, int h) {
|
||||
public void updateViewDimensions(int surfaceViewWidth, int surfaceViewHeight, int imageWidth, int imageHeight) {
|
||||
try {
|
||||
drawingViewConfig.updateImageDimensions(w, h);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG,e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSurfaceViewDimensions(int w, int h) {
|
||||
try {
|
||||
drawingViewConfig.updateSurfaceViewDimensions(w, h);
|
||||
drawingViewConfig.updateViewDimensions(surfaceViewWidth,surfaceViewHeight,imageWidth,imageHeight);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG,e.getMessage());
|
||||
}
|
||||
|
|
|
@ -67,13 +67,15 @@ import com.affectiva.android.affdex.sdk.detector.Face;
|
|||
*/
|
||||
|
||||
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";
|
||||
public static final int NUM_METRICS_DISPLAYED = 6;
|
||||
|
||||
//Affectiva SDK Object
|
||||
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
|
||||
private RelativeLayout metricViewLayout;
|
||||
|
@ -93,6 +95,7 @@ public class MainActivity extends Activity
|
|||
private SurfaceView cameraView; //SurfaceView used to display camera images
|
||||
private DrawingView drawingView; //SurfaceView containing its own thread, used to draw facial tracking dots
|
||||
private ImageButton settingsButton;
|
||||
private ImageButton cameraButton;
|
||||
|
||||
//Application settings variables
|
||||
private int detectorProcessRate;
|
||||
|
@ -105,7 +108,12 @@ public class MainActivity extends Activity
|
|||
private float numberOfFrames = 0;
|
||||
private long timeToUpdate = 0;
|
||||
|
||||
//Camera-related variables
|
||||
private boolean isFrontFacingCameraDetected = true;
|
||||
private boolean isBackFacingCameraDetected = true;
|
||||
int cameraPreviewWidth = 0;
|
||||
int cameraPreviewHeight = 0;
|
||||
CameraDetector.CameraType cameraType;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -115,20 +123,33 @@ public class MainActivity extends Activity
|
|||
|
||||
initializeUI();
|
||||
|
||||
determineCameraAvailability();
|
||||
|
||||
initializeCameraDetector();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* use the app.
|
||||
*/
|
||||
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
|
||||
isFrontFacingCameraDetected = false;
|
||||
void determineCameraAvailability() {
|
||||
PackageManager manager = getPackageManager();
|
||||
isFrontFacingCameraDetected = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
|
||||
isBackFacingCameraDetected = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA);
|
||||
|
||||
if (!isFrontFacingCameraDetected && !isBackFacingCameraDetected) {
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
pleaseWaitTextView.setVisibility(View.INVISIBLE);
|
||||
TextView notFoundTextView = (TextView) findViewById(R.id.not_found_textview);
|
||||
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() {
|
||||
|
@ -145,6 +166,7 @@ public class MainActivity extends Activity
|
|||
cameraView = (SurfaceView) findViewById(R.id.camera_preview);
|
||||
drawingView = (DrawingView) findViewById(R.id.drawing_view);
|
||||
settingsButton = (ImageButton) findViewById(R.id.settings_button);
|
||||
cameraButton = (ImageButton) findViewById(R.id.camera_button);
|
||||
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
|
||||
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,
|
||||
* 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/
|
||||
//detector.setLicensePath("YourLicenseFile");
|
||||
detector.setImageListener(this);
|
||||
detector.setFaceListener(this);
|
||||
detector.setCameraDetectorDimensionsListener(this);
|
||||
detector.setOnCameraEventListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -329,8 +353,10 @@ public class MainActivity extends Activity
|
|||
}
|
||||
|
||||
void mainWindowResumedTasks() {
|
||||
startCamera();
|
||||
if (!drawingView.isSurfaceDimensionsNeeded()) {
|
||||
|
||||
startDetector();
|
||||
|
||||
if (!drawingView.isDimensionsNeeded()) {
|
||||
progressBarLayout.setVisibility(View.GONE);
|
||||
}
|
||||
resetFPSCalculations();
|
||||
|
@ -341,14 +367,14 @@ public class MainActivity extends Activity
|
|||
setMenuVisible(false);
|
||||
}
|
||||
}
|
||||
},5000);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
void startCamera() {
|
||||
|
||||
//this app will always detect valence (it will also always detect measurements, but measurement don't need to be enabled)
|
||||
detector.setDetectValence(true);
|
||||
void startDetector() {
|
||||
if (!isBackFacingCameraDetected && !isFrontFacingCameraDetected)
|
||||
return; //without any cameras detected, we cannot proceed
|
||||
|
||||
detector.setDetectValence(true); //this app will always detect valence
|
||||
if (!detector.isRunning()) {
|
||||
try {
|
||||
detector.start();
|
||||
|
@ -356,9 +382,10 @@ public class MainActivity extends Activity
|
|||
Log.e(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onFaceDetectionStarted() {
|
||||
leftMetricsLayout.animate().alpha(1); //make left and right metrics appear
|
||||
|
@ -375,8 +402,7 @@ public class MainActivity extends Activity
|
|||
void performFaceDetectionStoppedTasks() {
|
||||
leftMetricsLayout.animate().alpha(0); //make left and right metrics disappear
|
||||
rightMetricsLayout.animate().alpha(0);
|
||||
|
||||
drawingView.invalidatePoints(); //inform the drawing thread that the latest facial tracking points are now invalid
|
||||
drawingView.updatePoints(null);
|
||||
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
|
||||
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 (faces == null) {
|
||||
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() == 0) {
|
||||
drawingView.updatePoints(null); //the drawingView takes null points to mean it doesn't have to draw anything
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -448,54 +467,6 @@ public class MainActivity extends Activity
|
|||
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
|
||||
* the FPS variables were last reset.
|
||||
|
@ -522,22 +493,26 @@ public class MainActivity extends Activity
|
|||
public void onPause() {
|
||||
super.onPause();
|
||||
progressBarLayout.setVisibility(View.VISIBLE);
|
||||
stopCamera();
|
||||
}
|
||||
|
||||
private void stopCamera() {
|
||||
performFaceDetectionStoppedTasks();
|
||||
|
||||
detector.setDetectAllEmotions(false);
|
||||
detector.setDetectAllExpressions(false);
|
||||
stopDetector();
|
||||
}
|
||||
|
||||
void stopDetector() {
|
||||
if (detector.isRunning()) {
|
||||
try {
|
||||
detector.stop();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, e.getMessage());
|
||||
Log.e(LOG_TAG,e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -547,6 +522,7 @@ public class MainActivity extends Activity
|
|||
isMenuVisible = b;
|
||||
if (b) {
|
||||
settingsButton.setVisibility(View.VISIBLE);
|
||||
cameraButton.setVisibility(View.VISIBLE);
|
||||
|
||||
//We display the navigation bar again
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
|
@ -567,6 +543,7 @@ public class MainActivity extends Activity
|
|||
|
||||
|
||||
settingsButton.setVisibility(View.INVISIBLE);
|
||||
cameraButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,6 +591,86 @@ public class MainActivity extends Activity
|
|||
public void settings_button_click(View view) {
|
||||
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"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<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>
|
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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/main_layout"
|
||||
android:layout_height="match_parent" tools:context=".MainActivity" android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:keepScreenOn="true"
|
||||
|
@ -12,13 +14,6 @@
|
|||
android:layout_centerInParent="true"
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -45,7 +40,19 @@
|
|||
android:layout_below="@id/metric_view_group"
|
||||
android:id="@+id/settings_button"
|
||||
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
|
||||
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>
|