From cb1265c0315da647aadbd5ae0eb5426ae0cedc41 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 15:26:40 -0800 Subject: [PATCH 01/16] TLIB.01-Solution-AddGradleDependency --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 1240229e..e460fb1a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,6 +26,6 @@ dependencies { }) compile 'com.android.support:design:25.2.0' compile 'com.android.support:appcompat-v7:25.2.0' - // TODO (1): Add Google Mobile Vision Library dependency + compile 'com.google.android.gms:play-services-vision:10.2.0' testCompile 'junit:junit:4.12' } From f7ff4b430a3f2016d28964e8d1b9b8c2d4611a61 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 18:02:33 -0800 Subject: [PATCH 02/16] TLIB.02-Exercise-DetectFaces --- .../main/java/com/example/android/emojify/MainActivity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index a4b4d2d2..4f3179c3 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -41,6 +41,9 @@ public class MainActivity extends AppCompatActivity { + // TODO (1): Create a Java class called Emojifier + // TODO (2): Create a static method in the Emojifier class called detectFaces() which detects and logs the number of faces in a given bitmap. + private static final int REQUEST_IMAGE_CAPTURE = 1; private static final int REQUEST_STORAGE_PERMISSION = 1; @@ -181,6 +184,8 @@ private void processAndSetImage() { // Resample the saved image to fit the ImageView mResultsBitmap = BitmapUtils.resamplePic(this, mTempPhotoPath); + // TODO (3): Call the new detectFaces() method, passing in the resampled bitmap to detect the faces in the picture. + // Set the new bitmap to the ImageView mImageView.setImageBitmap(mResultsBitmap); } From 4c1a576afd01c8c62bec7443c6bf13d0feb5dacf Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 17:50:56 -0800 Subject: [PATCH 03/16] TLIB.02-Solution-DetectFaces --- .../example/android/emojify/Emojifier.java | 64 +++++++++++++++++++ .../example/android/emojify/MainActivity.java | 10 ++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/example/android/emojify/Emojifier.java diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java new file mode 100644 index 00000000..e743f2d6 --- /dev/null +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2017 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.example.android.emojify; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; +import android.util.SparseArray; +import android.widget.Toast; + +import com.google.android.gms.vision.Frame; +import com.google.android.gms.vision.face.Face; +import com.google.android.gms.vision.face.FaceDetector; + +class Emojifier { + + private static final String LOG_TAG = Emojifier.class.getSimpleName(); + + /** + * Method for detecting faces in a bitmap. + * + * @param context The application context. + * @param picture The picture in which to detect the faces. + */ + static void detectFaces(Context context, Bitmap picture) { + + // Create the face detector, disable tracking and enable classifications + FaceDetector detector = new FaceDetector.Builder(context) + .setTrackingEnabled(false) + .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS) + .build(); + + // Build the frame + Frame frame = new Frame.Builder().setBitmap(picture).build(); + + // Detect the faces + SparseArray faces = detector.detect(frame); + + // Log the number of faces + Log.d(LOG_TAG, "detectFaces: number of faces = " + faces.size()); + + // If there are no faces detected, show a Toast message + if(faces.size() == 0){ + Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); + } + + // Release the detector + detector.release(); + } +} diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index 4f3179c3..413a498e 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -41,9 +41,6 @@ public class MainActivity extends AppCompatActivity { - // TODO (1): Create a Java class called Emojifier - // TODO (2): Create a static method in the Emojifier class called detectFaces() which detects and logs the number of faces in a given bitmap. - private static final int REQUEST_IMAGE_CAPTURE = 1; private static final int REQUEST_STORAGE_PERMISSION = 1; @@ -183,9 +180,10 @@ private void processAndSetImage() { // Resample the saved image to fit the ImageView mResultsBitmap = BitmapUtils.resamplePic(this, mTempPhotoPath); - - // TODO (3): Call the new detectFaces() method, passing in the resampled bitmap to detect the faces in the picture. - + + // Detect the faces + Emojifier.detectFaces(this, mResultsBitmap); + // Set the new bitmap to the ImageView mImageView.setImageBitmap(mResultsBitmap); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 623c8520..334c966e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,4 +23,5 @@ GO Permission denied The imageview that contains the emojified picture + No Faces Detected From f9b974261c8f6f3aacc02592fc5b09f424686d1b Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 18:19:02 -0800 Subject: [PATCH 04/16] TLIB.03-Exercise-GetClassificationProbabilities --- app/src/main/java/com/example/android/emojify/Emojifier.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index e743f2d6..35a034bd 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -58,7 +58,11 @@ static void detectFaces(Context context, Bitmap picture) { Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); } + // TODO (2): Iterate through the faces, calling getClassifications() for each face. + // Release the detector detector.release(); } + + // TODO (1): Create a static method called getClassifications() which logs the probability of each eye being open and that the person is smiling. } From c5cad47240372251a0e59e20d47107b1f47861ca Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 18:42:13 -0800 Subject: [PATCH 05/16] TLIB.03-Solution-GetClassificationProbabilities --- .../example/android/emojify/Emojifier.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 35a034bd..73ddfea3 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -56,13 +56,33 @@ static void detectFaces(Context context, Bitmap picture) { // If there are no faces detected, show a Toast message if(faces.size() == 0){ Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); + } else { + for (int i = 0; i < faces.size(); ++i) { + Face face = faces.valueAt(i); + + // Log the classification probabilities for each face. + getClassifications(face); + } + } - // TODO (2): Iterate through the faces, calling getClassifications() for each face. // Release the detector detector.release(); } - // TODO (1): Create a static method called getClassifications() which logs the probability of each eye being open and that the person is smiling. + + /** + * Method for logging the classification probabilities. + * + * @param face The face to get the classification probabilities. + */ + private static void getClassifications(Face face){ + // Log all the probabilities + Log.d(LOG_TAG, "getClassifications: smilingProb = " + face.getIsSmilingProbability()); + Log.d(LOG_TAG, "getClassifications: leftEyeOpenProb = " + + face.getIsLeftEyeOpenProbability()); + Log.d(LOG_TAG, "getClassifications: rightEyeOpenProb = " + + face.getIsRightEyeOpenProbability()); + } } From 7258a0cfcd5b3831a664dad254b4e3bcd2f184f0 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Tue, 24 Jan 2017 14:28:47 -0800 Subject: [PATCH 06/16] TLIB.04-Exercise-MatchFaceToEmoji --- .../main/java/com/example/android/emojify/Emojifier.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 73ddfea3..0638ceaa 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -62,6 +62,7 @@ static void detectFaces(Context context, Bitmap picture) { // Log the classification probabilities for each face. getClassifications(face); + // TODO (6): Change the call to getClassifications to whichEmoji() to log the appropriate emoji for the facial expression. } } @@ -78,11 +79,19 @@ static void detectFaces(Context context, Bitmap picture) { * @param face The face to get the classification probabilities. */ private static void getClassifications(Face face){ + // TODO (2): Change the name of the getClassifications() method to whichEmoji() (also change the log statements) // Log all the probabilities Log.d(LOG_TAG, "getClassifications: smilingProb = " + face.getIsSmilingProbability()); Log.d(LOG_TAG, "getClassifications: leftEyeOpenProb = " + face.getIsLeftEyeOpenProbability()); Log.d(LOG_TAG, "getClassifications: rightEyeOpenProb = " + face.getIsRightEyeOpenProbability()); + + // TODO (3): Create threshold constants for a person smiling, and and eye being open by taking pictures of yourself and your friends and noting the logs. + // TODO (4): Create 3 boolean variables to track the state of the facial expression based on the thresholds you set in the previous step: smiling, left eye closed, right eye closed. + // TODO (5): Create an if/else system that selects the appropriate emoji based on the above booleans and log the result. } + + + // TODO (1): Create an enum class called Emoji that contains all the possible emoji you can make (smiling, frowning, left wink, right wink, left wink frowning, right wink frowning, closed eye smiling, close eye frowning). } From 2a064f800b10fd5cc02f5c4e415301df59e3b177 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 18:12:27 -0800 Subject: [PATCH 07/16] TLIB.04-Solution-MatchFaceToEmoji --- .../example/android/emojify/Emojifier.java | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 0638ceaa..b61f6b63 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -30,6 +30,9 @@ class Emojifier { private static final String LOG_TAG = Emojifier.class.getSimpleName(); + private static final double SMILING_PROB_THRESHOLD = .15; + private static final double EYE_OPEN_PROB_THRESHOLD = .5; + /** * Method for detecting faces in a bitmap. * @@ -54,17 +57,17 @@ static void detectFaces(Context context, Bitmap picture) { Log.d(LOG_TAG, "detectFaces: number of faces = " + faces.size()); // If there are no faces detected, show a Toast message - if(faces.size() == 0){ + if(faces.size() == 0) { Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); } else { + + // Iterate through the faces for (int i = 0; i < faces.size(); ++i) { Face face = faces.valueAt(i); + // Get the appropriate emoji for each face + whichEmoji(face); - // Log the classification probabilities for each face. - getClassifications(face); - // TODO (6): Change the call to getClassifications to whichEmoji() to log the appropriate emoji for the facial expression. } - } @@ -74,24 +77,67 @@ static void detectFaces(Context context, Bitmap picture) { /** - * Method for logging the classification probabilities. + * Determines the closest emoji to the expression on the face, based on the + * odds that the person is smiling and has each eye open. * - * @param face The face to get the classification probabilities. + * @param face The face for which you pick an emoji. */ - private static void getClassifications(Face face){ - // TODO (2): Change the name of the getClassifications() method to whichEmoji() (also change the log statements) + + private static void whichEmoji(Face face) { + // Log all the probabilities - Log.d(LOG_TAG, "getClassifications: smilingProb = " + face.getIsSmilingProbability()); - Log.d(LOG_TAG, "getClassifications: leftEyeOpenProb = " + Log.d(LOG_TAG, "whichEmoji: smilingProb = " + face.getIsSmilingProbability()); + Log.d(LOG_TAG, "whichEmoji: leftEyeOpenProb = " + face.getIsLeftEyeOpenProbability()); - Log.d(LOG_TAG, "getClassifications: rightEyeOpenProb = " + Log.d(LOG_TAG, "whichEmoji: rightEyeOpenProb = " + face.getIsRightEyeOpenProbability()); - // TODO (3): Create threshold constants for a person smiling, and and eye being open by taking pictures of yourself and your friends and noting the logs. - // TODO (4): Create 3 boolean variables to track the state of the facial expression based on the thresholds you set in the previous step: smiling, left eye closed, right eye closed. - // TODO (5): Create an if/else system that selects the appropriate emoji based on the above booleans and log the result. - } + boolean smiling = face.getIsSmilingProbability() > SMILING_PROB_THRESHOLD; + + boolean leftEyeClosed = face.getIsLeftEyeOpenProbability() < EYE_OPEN_PROB_THRESHOLD; + boolean rightEyeClosed = face.getIsRightEyeOpenProbability() < EYE_OPEN_PROB_THRESHOLD; + + + // Determine and log the appropriate emoji + Emoji emoji; + if(smiling) { + if (leftEyeClosed && !rightEyeClosed) { + emoji = Emoji.LEFT_WINK; + } else if(rightEyeClosed && !leftEyeClosed){ + emoji = Emoji.RIGHT_WINK; + } else if (leftEyeClosed){ + emoji = Emoji.CLOSED_EYE_SMILE; + } else { + emoji = Emoji.SMILE; + } + } else { + if (leftEyeClosed && !rightEyeClosed) { + emoji = Emoji.LEFT_WINK_FROWN; + } else if(rightEyeClosed && !leftEyeClosed){ + emoji = Emoji.RIGHT_WINK_FROWN; + } else if (leftEyeClosed){ + emoji = Emoji.CLOSED_EYE_FROWN; + } else { + emoji = Emoji.FROWN; + } + } + + + // Log the chosen Emoji + Log.d(LOG_TAG, "whichEmoji: " + emoji.name()); + } + + // Enum for all possible Emojis + private enum Emoji { + SMILE, + FROWN, + LEFT_WINK, + RIGHT_WINK, + LEFT_WINK_FROWN, + RIGHT_WINK_FROWN, + CLOSED_EYE_SMILE, + CLOSED_EYE_FROWN + } - // TODO (1): Create an enum class called Emoji that contains all the possible emoji you can make (smiling, frowning, left wink, right wink, left wink frowning, right wink frowning, closed eye smiling, close eye frowning). } From 8691c1fc7b3157edddab13df40df9a9656bde805 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Tue, 24 Jan 2017 14:57:13 -0800 Subject: [PATCH 08/16] TLIB.05-Exercise-DrawEmojiOverFaces --- .../com/example/android/emojify/Emojifier.java | 14 +++++++++++++- .../com/example/android/emojify/MainActivity.java | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index b61f6b63..5e6874bf 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -41,6 +41,8 @@ class Emojifier { */ static void detectFaces(Context context, Bitmap picture) { + // TODO (3): Change the name of the detectFaces() method to detectFacesAndOverlayEmoji() and the return type from void to Bitmap + // Create the face detector, disable tracking and enable classifications FaceDetector detector = new FaceDetector.Builder(context) .setTrackingEnabled(false) @@ -56,6 +58,7 @@ static void detectFaces(Context context, Bitmap picture) { // Log the number of faces Log.d(LOG_TAG, "detectFaces: number of faces = " + faces.size()); + // TODO (7): Create a variable called resultBitmap and initialize it to the original picture bitmap passed into the detectFacesAndOverlayEmoji() method // If there are no faces detected, show a Toast message if(faces.size() == 0) { Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); @@ -67,12 +70,17 @@ static void detectFaces(Context context, Bitmap picture) { // Get the appropriate emoji for each face whichEmoji(face); + // TODO (4): Create a variable called emojiBitmap to hold the appropriate Emoji bitmap and remove the call to whichEmoji() + // TODO (5): Create a switch statement on the result of the whichEmoji() call, and assign the proper emoji bitmap to the variable you created + // TODO (8): Call addBitmapToFace(), passing in the resultBitmap, the emojiBitmap and the Face object, and assigning the result to resultBitmap + } } // Release the detector detector.release(); + // TODO (9): Return the resultBitmap } @@ -85,6 +93,7 @@ static void detectFaces(Context context, Bitmap picture) { private static void whichEmoji(Face face) { + // TODO (1): Change the return type of the whichEmoji() method from void to Emoji. // Log all the probabilities Log.d(LOG_TAG, "whichEmoji: smilingProb = " + face.getIsSmilingProbability()); Log.d(LOG_TAG, "whichEmoji: leftEyeOpenProb = " @@ -126,8 +135,11 @@ private static void whichEmoji(Face face) { // Log the chosen Emoji Log.d(LOG_TAG, "whichEmoji: " + emoji.name()); + + // TODO (2): Have the method return the selected Emoji type. } - + + // TODO (6) Create a method called addBitmapToFace() which takes the background bitmap, the Emoji bitmap, and a Face object as arguments and returns the combined bitmap with the Emoji over the face. // Enum for all possible Emojis private enum Emoji { SMILE, diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index 413a498e..4dc8eef0 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -183,6 +183,7 @@ private void processAndSetImage() { // Detect the faces Emojifier.detectFaces(this, mResultsBitmap); + // TODO (10): Change the method call from detectFaces() to detectFacesAndOverlayEmoji() and assign the result to mResultsBitmap. // Set the new bitmap to the ImageView mImageView.setImageBitmap(mResultsBitmap); From d681cc8cd08820b8f6b662b44dcb2cdbdfd19377 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Mon, 23 Jan 2017 17:01:11 -0800 Subject: [PATCH 09/16] TLIB.05-Solution-DrawEmojiOverFaces --- .../example/android/emojify/Emojifier.java | 114 +++++++++++++++--- .../example/android/emojify/MainActivity.java | 8 +- 2 files changed, 100 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 5e6874bf..7a4b160c 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -18,6 +18,8 @@ import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.util.Log; import android.util.SparseArray; import android.widget.Toast; @@ -30,18 +32,18 @@ class Emojifier { private static final String LOG_TAG = Emojifier.class.getSimpleName(); + private static final float EMOJI_SCALE_FACTOR = .9f; private static final double SMILING_PROB_THRESHOLD = .15; private static final double EYE_OPEN_PROB_THRESHOLD = .5; /** - * Method for detecting faces in a bitmap. + * Method for detecting faces in a bitmap, and drawing emoji depending on the facial + * expression. * * @param context The application context. * @param picture The picture in which to detect the faces. */ - static void detectFaces(Context context, Bitmap picture) { - - // TODO (3): Change the name of the detectFaces() method to detectFacesAndOverlayEmoji() and the return type from void to Bitmap + static Bitmap detectFacesandOverlayEmoji(Context context, Bitmap picture) { // Create the face detector, disable tracking and enable classifications FaceDetector detector = new FaceDetector.Builder(context) @@ -58,29 +60,67 @@ static void detectFaces(Context context, Bitmap picture) { // Log the number of faces Log.d(LOG_TAG, "detectFaces: number of faces = " + faces.size()); - // TODO (7): Create a variable called resultBitmap and initialize it to the original picture bitmap passed into the detectFacesAndOverlayEmoji() method + // Initialize result bitmap to original picture + Bitmap resultBitmap = picture; + // If there are no faces detected, show a Toast message - if(faces.size() == 0) { + if (faces.size() == 0) { Toast.makeText(context, R.string.no_faces_message, Toast.LENGTH_SHORT).show(); } else { // Iterate through the faces for (int i = 0; i < faces.size(); ++i) { Face face = faces.valueAt(i); - // Get the appropriate emoji for each face - whichEmoji(face); - - // TODO (4): Create a variable called emojiBitmap to hold the appropriate Emoji bitmap and remove the call to whichEmoji() - // TODO (5): Create a switch statement on the result of the whichEmoji() call, and assign the proper emoji bitmap to the variable you created - // TODO (8): Call addBitmapToFace(), passing in the resultBitmap, the emojiBitmap and the Face object, and assigning the result to resultBitmap + Bitmap emojiBitmap; + switch (whichEmoji(face)) { + case SMILE: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.smile); + break; + case FROWN: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.frown); + break; + case LEFT_WINK: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.leftwink); + break; + case RIGHT_WINK: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.rightwink); + break; + case LEFT_WINK_FROWN: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.leftwinkfrown); + break; + case RIGHT_WINK_FROWN: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.rightwinkfrown); + break; + case CLOSED_EYE_SMILE: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.closed_smile); + break; + case CLOSED_EYE_FROWN: + emojiBitmap = BitmapFactory.decodeResource(context.getResources(), + R.drawable.closed_frown); + break; + default: + emojiBitmap = null; + Toast.makeText(context, R.string.no_emoji, Toast.LENGTH_SHORT).show(); + } + + // Add the emojiBitmap to the proper position in the original image + resultBitmap = addBitmapToFace(resultBitmap, emojiBitmap, face); } } // Release the detector detector.release(); - // TODO (9): Return the resultBitmap + + return resultBitmap; } @@ -91,9 +131,7 @@ static void detectFaces(Context context, Bitmap picture) { * @param face The face for which you pick an emoji. */ - private static void whichEmoji(Face face) { - - // TODO (1): Change the return type of the whichEmoji() method from void to Emoji. + private static Emoji whichEmoji(Face face) { // Log all the probabilities Log.d(LOG_TAG, "whichEmoji: smilingProb = " + face.getIsSmilingProbability()); Log.d(LOG_TAG, "whichEmoji: leftEyeOpenProb = " @@ -136,10 +174,50 @@ private static void whichEmoji(Face face) { // Log the chosen Emoji Log.d(LOG_TAG, "whichEmoji: " + emoji.name()); - // TODO (2): Have the method return the selected Emoji type. + return emoji; + } + + /** + * Combines the original picture with the emoji bitmaps + * + * @param backgroundBitmap The original picture + * @param emojiBitmap The chosen emoji + * @param face The detected face + * @return The final bitmap, including the emojis over the faces + */ + private static Bitmap addBitmapToFace(Bitmap backgroundBitmap, Bitmap emojiBitmap, Face face) { + + // Initialize the results bitmap to be a mutable copy of the original image + Bitmap resultBitmap = Bitmap.createBitmap(backgroundBitmap.getWidth(), + backgroundBitmap.getHeight(), backgroundBitmap.getConfig()); + + // Scale the emoji so it looks better on the face + float scaleFactor = EMOJI_SCALE_FACTOR; + + // Determine the size of the emoji to match the width of the face and preserve aspect ratio + int newEmojiWidth = (int) (face.getWidth() * scaleFactor); + int newEmojiHeight = (int) (emojiBitmap.getHeight() * + newEmojiWidth / emojiBitmap.getWidth() * scaleFactor); + + + // Scale the emoji + emojiBitmap = Bitmap.createScaledBitmap(emojiBitmap, newEmojiWidth, newEmojiHeight, false); + + // Determine the emoji position so it best lines up with the face + float emojiPositionX = + (face.getPosition().x + face.getWidth() / 2) - emojiBitmap.getWidth() / 2; + float emojiPositionY = + (face.getPosition().y + face.getHeight() / 2) - emojiBitmap.getHeight() / 3; + + // Create the canvas and draw the bitmaps to it + Canvas canvas = new Canvas(resultBitmap); + canvas.drawBitmap(backgroundBitmap, 0, 0, null); + canvas.drawBitmap(emojiBitmap, emojiPositionX, emojiPositionY, null); + + return resultBitmap; } + - // TODO (6) Create a method called addBitmapToFace() which takes the background bitmap, the Emoji bitmap, and a Face object as arguments and returns the combined bitmap with the Emoji over the face. // Enum for all possible Emojis private enum Emoji { SMILE, diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index 4dc8eef0..4a676683 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -181,10 +181,10 @@ private void processAndSetImage() { // Resample the saved image to fit the ImageView mResultsBitmap = BitmapUtils.resamplePic(this, mTempPhotoPath); - // Detect the faces - Emojifier.detectFaces(this, mResultsBitmap); - // TODO (10): Change the method call from detectFaces() to detectFacesAndOverlayEmoji() and assign the result to mResultsBitmap. - + + // Detect the faces and overlay the appropriate emoji + mResultsBitmap = Emojifier.detectFacesandOverlayEmoji(this, mResultsBitmap); + // Set the new bitmap to the ImageView mImageView.setImageBitmap(mResultsBitmap); } From ff4ef950d9baf3105e47fd032ecde1fea134439a Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Wed, 25 Jan 2017 15:22:20 -0800 Subject: [PATCH 10/16] TLIB.06-Exercise-AddButterknife --- app/build.gradle | 1 + .../main/java/com/example/android/emojify/MainActivity.java | 4 ++++ app/src/main/res/layout/activity_main.xml | 2 ++ 3 files changed, 7 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index e460fb1a..169a6833 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,5 +27,6 @@ dependencies { compile 'com.android.support:design:25.2.0' compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.google.android.gms:play-services-vision:10.2.0' + // TODO (1): Add Butterknife library and annotations dependency testCompile 'junit:junit:4.12' } diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index 4a676683..b0952892 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -41,6 +41,8 @@ public class MainActivity extends AppCompatActivity { + // TODO (2): Replace all View declarations with Butterknife annotations + private static final int REQUEST_IMAGE_CAPTURE = 1; private static final int REQUEST_STORAGE_PERMISSION = 1; @@ -65,6 +67,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + // TODO (3): Replace the findViewById calls with the Butterknife data binding // Bind the views mImageView = (ImageView) findViewById(R.id.image_view); mEmojifyButton = (Button) findViewById(R.id.emojify_button); @@ -190,6 +193,7 @@ private void processAndSetImage() { } + // TODO (4): Replace OnClick methods with Butterknife annotations for OnClicks /** * OnClick method for the save button. * diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4c42b60b..32c534b5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,6 +13,8 @@ See the License for the specific language governing permissions and limitations under the License.--> + + Date: Wed, 25 Jan 2017 15:32:15 -0800 Subject: [PATCH 11/16] TLIB.06-Solution-AddButterknife --- app/build.gradle | 3 +- .../example/android/emojify/MainActivity.java | 47 ++++++++----------- app/src/main/res/layout/activity_main.xml | 5 -- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 169a6833..ecef6557 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,6 +27,7 @@ dependencies { compile 'com.android.support:design:25.2.0' compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.google.android.gms:play-services-vision:10.2.0' - // TODO (1): Add Butterknife library and annotations dependency + compile 'com.jakewharton:butterknife:8.4.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' testCompile 'junit:junit:4.12' } diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index b0952892..b2f55c01 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -39,23 +39,26 @@ import java.io.File; import java.io.IOException; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + public class MainActivity extends AppCompatActivity { - // TODO (2): Replace all View declarations with Butterknife annotations private static final int REQUEST_IMAGE_CAPTURE = 1; private static final int REQUEST_STORAGE_PERMISSION = 1; private static final String FILE_PROVIDER_AUTHORITY = "com.example.android.fileprovider"; - private ImageView mImageView; + @BindView(R.id.image_view) ImageView mImageView; - private Button mEmojifyButton; - private FloatingActionButton mShareFab; - private FloatingActionButton mSaveFab; - private FloatingActionButton mClearFab; + @BindView(R.id.emojify_button) Button mEmojifyButton; + @BindView(R.id.share_button) FloatingActionButton mShareFab; + @BindView(R.id.save_button) FloatingActionButton mSaveFab; + @BindView(R.id.clear_button) FloatingActionButton mClearFab; - private TextView mTitleTextView; + @BindView(R.id.title_text_view) TextView mTitleTextView; private String mTempPhotoPath; @@ -67,22 +70,15 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - // TODO (3): Replace the findViewById calls with the Butterknife data binding // Bind the views - mImageView = (ImageView) findViewById(R.id.image_view); - mEmojifyButton = (Button) findViewById(R.id.emojify_button); - mShareFab = (FloatingActionButton) findViewById(R.id.share_button); - mSaveFab = (FloatingActionButton) findViewById(R.id.save_button); - mClearFab = (FloatingActionButton) findViewById(R.id.clear_button); - mTitleTextView = (TextView) findViewById(R.id.title_text_view); + ButterKnife.bind(this); } /** * OnClick method for "Emojify Me!" Button. Launches the camera app. - * - * @param view The emojify me button. */ - public void emojifyMe(View view) { + @OnClick(R.id.emojify_button) + public void emojifyMe() { // Check for the external storage permission if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) @@ -193,13 +189,12 @@ private void processAndSetImage() { } - // TODO (4): Replace OnClick methods with Butterknife annotations for OnClicks + /** * OnClick method for the save button. - * - * @param view The save button. */ - public void saveMe(View view) { + @OnClick(R.id.save_button) + public void saveMe() { // Delete the temporary image file BitmapUtils.deleteImageFile(this, mTempPhotoPath); @@ -209,10 +204,9 @@ public void saveMe(View view) { /** * OnClick method for the share button, saves and shares the new bitmap. - * - * @param view The share button. */ - public void shareMe(View view) { + @OnClick(R.id.share_button) + public void shareMe() { // Delete the temporary image file BitmapUtils.deleteImageFile(this, mTempPhotoPath); @@ -225,10 +219,9 @@ public void shareMe(View view) { /** * OnClick for the clear button, resets the app to original state. - * - * @param view The clear button. */ - public void clearImage(View view) { + @OnClick(R.id.clear_button) + public void clearImage() { // Clear the image and toggle the view visibility mImageView.setImageResource(0); mEmojifyButton.setVisibility(View.VISIBLE); diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 32c534b5..b9e7065b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,7 +13,6 @@ See the License for the specific language governing permissions and limitations under the License.--> - @@ -63,7 +61,6 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" - android:onClick="clearImage" android:src="@drawable/ic_clear" android:visibility="gone" app:backgroundTint="@android:color/white" @@ -79,7 +76,6 @@ android:layout_marginBottom="@dimen/fab_margins" android:layout_marginEnd="@dimen/fab_margins" android:layout_marginRight="@dimen/fab_margins" - android:onClick="saveMe" android:src="@drawable/ic_save" android:visibility="gone" app:backgroundTint="@android:color/white" /> @@ -94,7 +90,6 @@ android:layout_marginBottom="@dimen/fab_margins" android:layout_marginLeft="@dimen/fab_margins" android:layout_marginStart="@dimen/fab_margins" - android:onClick="shareMe" android:src="@drawable/ic_share" android:visibility="gone" app:backgroundTint="@android:color/white" /> From 73021e0d314e1a718b475228a3c12829cdbb5343 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Wed, 25 Jan 2017 15:42:05 -0800 Subject: [PATCH 12/16] TLIB.07-Exercise-AddTimber --- app/build.gradle | 1 + app/src/main/java/com/example/android/emojify/Emojifier.java | 1 + app/src/main/java/com/example/android/emojify/MainActivity.java | 2 ++ 3 files changed, 4 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index ecef6557..c4ad3945 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,5 +29,6 @@ dependencies { compile 'com.google.android.gms:play-services-vision:10.2.0' compile 'com.jakewharton:butterknife:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' + // TODO (1): Add Timber dependency testCompile 'junit:junit:4.12' } diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 7a4b160c..97cd01d5 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -30,6 +30,7 @@ class Emojifier { + // TODO (3): Change all Log statements to Timber logs and remove the LOG_TAG variable private static final String LOG_TAG = Emojifier.class.getSimpleName(); private static final float EMOJI_SCALE_FACTOR = .9f; diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index b2f55c01..5beec22f 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -72,6 +72,8 @@ protected void onCreate(Bundle savedInstanceState) { // Bind the views ButterKnife.bind(this); + + // TODO (2): Set up Timber } /** From 2c31fe3921badd447bb41196e667310f0c822859 Mon Sep 17 00:00:00 2001 From: Nikita Gamolsky Date: Wed, 25 Jan 2017 15:47:06 -0800 Subject: [PATCH 13/16] TLIB.07-Solution-AddTimber --- app/build.gradle | 2 +- .../com/example/android/emojify/Emojifier.java | 18 +++++++++--------- .../example/android/emojify/MainActivity.java | 7 ++++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c4ad3945..f674ee7c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,6 +29,6 @@ dependencies { compile 'com.google.android.gms:play-services-vision:10.2.0' compile 'com.jakewharton:butterknife:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' - // TODO (1): Add Timber dependency + compile 'com.jakewharton.timber:timber:4.5.0' testCompile 'junit:junit:4.12' } diff --git a/app/src/main/java/com/example/android/emojify/Emojifier.java b/app/src/main/java/com/example/android/emojify/Emojifier.java index 97cd01d5..a0c1d2d1 100644 --- a/app/src/main/java/com/example/android/emojify/Emojifier.java +++ b/app/src/main/java/com/example/android/emojify/Emojifier.java @@ -20,7 +20,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.util.Log; import android.util.SparseArray; import android.widget.Toast; @@ -28,10 +27,10 @@ import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; +import timber.log.Timber; + class Emojifier { - // TODO (3): Change all Log statements to Timber logs and remove the LOG_TAG variable - private static final String LOG_TAG = Emojifier.class.getSimpleName(); private static final float EMOJI_SCALE_FACTOR = .9f; private static final double SMILING_PROB_THRESHOLD = .15; @@ -59,7 +58,7 @@ static Bitmap detectFacesandOverlayEmoji(Context context, Bitmap picture) { SparseArray faces = detector.detect(frame); // Log the number of faces - Log.d(LOG_TAG, "detectFaces: number of faces = " + faces.size()); + Timber.d("detectFaces: number of faces = " + faces.size()); // Initialize result bitmap to original picture Bitmap resultBitmap = picture; @@ -134,10 +133,10 @@ static Bitmap detectFacesandOverlayEmoji(Context context, Bitmap picture) { private static Emoji whichEmoji(Face face) { // Log all the probabilities - Log.d(LOG_TAG, "whichEmoji: smilingProb = " + face.getIsSmilingProbability()); - Log.d(LOG_TAG, "whichEmoji: leftEyeOpenProb = " + Timber.d("whichEmoji: smilingProb = " + face.getIsSmilingProbability()); + Timber.d("whichEmoji: leftEyeOpenProb = " + face.getIsLeftEyeOpenProbability()); - Log.d(LOG_TAG, "whichEmoji: rightEyeOpenProb = " + Timber.d("whichEmoji: rightEyeOpenProb = " + face.getIsRightEyeOpenProbability()); @@ -173,8 +172,9 @@ private static Emoji whichEmoji(Face face) { // Log the chosen Emoji - Log.d(LOG_TAG, "whichEmoji: " + emoji.name()); - + Timber.d("whichEmoji: " + emoji.name()); + + // return the chosen Emoji return emoji; } diff --git a/app/src/main/java/com/example/android/emojify/MainActivity.java b/app/src/main/java/com/example/android/emojify/MainActivity.java index 5beec22f..be311a78 100644 --- a/app/src/main/java/com/example/android/emojify/MainActivity.java +++ b/app/src/main/java/com/example/android/emojify/MainActivity.java @@ -42,6 +42,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import timber.log.Timber; public class MainActivity extends AppCompatActivity { @@ -73,7 +74,8 @@ protected void onCreate(Bundle savedInstanceState) { // Bind the views ButterKnife.bind(this); - // TODO (2): Set up Timber + // Set up Timber + Timber.plant(new Timber.DebugTree()); } /** @@ -181,7 +183,7 @@ private void processAndSetImage() { // Resample the saved image to fit the ImageView mResultsBitmap = BitmapUtils.resamplePic(this, mTempPhotoPath); - + // Detect the faces and overlay the appropriate emoji mResultsBitmap = Emojifier.detectFacesandOverlayEmoji(this, mResultsBitmap); @@ -191,7 +193,6 @@ private void processAndSetImage() { } - /** * OnClick method for the save button. */ From 13161947eadcc8c9f2968c0e7d37949365f6472d Mon Sep 17 00:00:00 2001 From: JK Eldon Date: Fri, 28 Apr 2017 14:51:29 -0700 Subject: [PATCH 14/16] Create README.md --- README.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..a96dc608 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# AdvancedAndroid_Emojify + +This is the toy app for the Libraries lesson of the [Advanced Android App Development course on Udacity](https://www.udacity.com/course/advanced-android-app-development--ud855). + +## How to use this repo while taking the course + +Each code repository in this class has a chain of commits that looks like this: + +![listofcommits](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58befe2e_listofcommits/listofcommits.png) + +These commits show every step you'll take to create the app. They include **Exercise** commits and **Solution** commits. + +Exercise commits contain instructions for completing the exercise, while solution commits show the completed exercise. You can tell what a commit is by looking at its commit message. + +For example, **TFCM.01-Exercise-AddGradleDependencies** is the first code step in the Firebase Cloud Messaging (FCM) lesson. This is the exercise commit, and the exercise is called Add Gradle Dependencies. + +Each commit also has a **branch** associated with it of the same name as the commit message, seen below: + +![branches](https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590390fe_branches-ud855/branches-ud855.png +) +Access all branches from this tab + +![listofbranches](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58befe76_listofbranches/listofbranches.png +) + + +![branchesdropdown](https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590391a3_branches-dropdown-ud855/branches-dropdown-ud855.png +) + + +The branches are also accessible from the drop-down in the "Code" tab + + +## Working with the Course Code + +Here are the basic steps for working with and completing exercises in the repo. This information is linked whenever you start a new exercise project, so don't feel you need to memorize all of this! In fact, skim it now, make sure that you know generally how to do the different tasks, and then come back when you start your first exercise. + +The basic steps are: + +1. Clone the repo +2. Checkout the exercise branch +3. Find and complete the TODOs +4. Optionally commit your code changes +5. Compare with the solution + + +**Step 1: Clone the repo** + +As you go through the course, you'll be instructed to clone the different exercise repositories, so you don't need to set these up now. You can clone a repository from github in a folder of your choice with the command: + +```bash +git clone https://github.com/udacity/REPOSITORY_NAME.git +``` + +**Step 2: Checkout the exercise branch** + +As you do different exercises in the code, you'll be told which exercise you're on, as seen below: +![exerciseexample](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf0087_exerciseexample/exerciseexample.png +) + +To complete an exercise, you'll want to check out the branch associated with that exercise. For the exercise above, the command to check out that branch would be: + +```bash +git checkout TFCM.01-Exercise-AddGradleDependencies +``` + +**Step 3: Find and complete the TODOs** + +This branch should always have **Exercise** in the title. Once you've checked out the branch, you'll have the code in the exact state you need. You'll even have TODOs, which are special comments that tell you all the steps you need to complete the exercise. You can easily navigate to all the TODOs using Android Studio's TODO tool. To open the TODO tool, click the button at the bottom of the screen that says TODO. This will display a list of all comments with TODO in the project. + +We've numbered the TODO steps so you can do them in order: +![todos](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf00e7_todos/todos.png +) + +**Step 4: Optionally commit your code changes** + +After You've completed the TODOs, you can optionally commit your changes. This will allow you to see the code you wrote whenever you return to the branch. The following git code will add and save **all** your changes. + +```bash +git add . +git commit -m "Your commit message" +``` + +**Step 5: Compare with the solution** + +Most exercises will have a list of steps for you to check off in the classroom. Once you've checked these off, you'll see a pop up window with a link to the solution code. Note the **Diff** link: + +![solutionwindow](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf00f9_solutionwindow/solutionwindow.png +) + +The **Diff** link will take you to a Github diff as seen below: +![diff](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf0108_diffsceenshot/diffsceenshot.png +) + +All of the code that was added in the solution is in green, and the removed code (which will usually be the TODO comments) is in red. +## Report Issues +Notice any issues with a repository? Please file a github issue in the repository. From 2a2a7bcf897547fa4cfef655423ce64af810f351 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 7 Feb 2019 17:47:23 -0500 Subject: [PATCH 15/16] Add tools attribute in the main activity layout file to show FAB in the design mode --- app/src/main/res/layout/activity_main.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b9e7065b..4051050d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -62,6 +62,7 @@ android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:src="@drawable/ic_clear" + tools:visibility="visible" android:visibility="gone" app:backgroundTint="@android:color/white" app:fabSize="mini" /> @@ -77,6 +78,7 @@ android:layout_marginEnd="@dimen/fab_margins" android:layout_marginRight="@dimen/fab_margins" android:src="@drawable/ic_save" + tools:visibility="visible" android:visibility="gone" app:backgroundTint="@android:color/white" /> @@ -91,6 +93,7 @@ android:layout_marginLeft="@dimen/fab_margins" android:layout_marginStart="@dimen/fab_margins" android:src="@drawable/ic_share" + tools:visibility="visible" android:visibility="gone" app:backgroundTint="@android:color/white" /> From cd27081e52e210773612fc8a589b1fd8e899eee4 Mon Sep 17 00:00:00 2001 From: elhennawy Date: Fri, 8 Feb 2019 03:02:12 -0500 Subject: [PATCH 16/16] update module-leve gradle using new build keywords instead the depecrated ones --- app/build.gradle | 18 +++++++++--------- build.gradle | 4 +++- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f674ee7c..6b2aca1b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.example.android.emojify" minSdkVersion 15 @@ -20,15 +20,15 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:design:25.2.0' - compile 'com.android.support:appcompat-v7:25.2.0' - compile 'com.google.android.gms:play-services-vision:10.2.0' - compile 'com.jakewharton:butterknife:8.4.0' + implementation 'com.android.support:design:25.2.0' + implementation 'com.android.support:appcompat-v7:25.2.0' + implementation 'com.google.android.gms:play-services-vision:10.2.0' + implementation 'com.jakewharton:butterknife:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' - compile 'com.jakewharton.timber:timber:4.5.0' - testCompile 'junit:junit:4.12' + implementation 'com.jakewharton.timber:timber:4.5.0' + testImplementation 'junit:junit:4.12' } diff --git a/build.gradle b/build.gradle index 74b2ab0d..a443fad3 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,11 @@ buildscript { repositories { + google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.1.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -14,6 +15,7 @@ buildscript { allprojects { repositories { + google() jcenter() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 04e285f3..35e5ec14 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 28 10:00:20 PST 2015 +#Thu Feb 07 20:58:16 EST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip