Adding option to Unfavourite image in Phimp.Me

This blog is in accordance with the P.R #1900. Here I have implemented the option to unfavourite image in the Phimp.Me android application.

Implementation

In the Phimp.Me app there are the following modes present:

1. all_photos:

All the photos are displayed in this mode irrespective of where they are saved.

2. fav_photos:

The photos which are added to favourites are displayed in the fav_photos.

3. Albums_mode:

All the albums which are present in the app are displayed in the albums_mode.

The main idea here is to find whether the selected image is already FAVOURITE or not. If it is already FAVORITED then it can be removed from that mode by removing its path form the Realm Database. If it isn’t already FAVORITED then the image is ignored and the next image is taken into consideration.

The process of removing the images from favourites can be an expensive one as the user can select myriad images which would ultimately block the Main UI. So it is better handled asynchronously and is implemented using the AsyncTask.

Whenever the user adds an image to the FAVOURITES, it gets added to the Realm Database where the model class being used is the FavouriteImagesModel.The selected media in the all_photos and fav_photos mode can be accessed via by selectedMedia.size()  and the number of selected media in the albums_mode can be accessed by getAlbum().getSelectedCount().

So in the execute method of doInBackground() a condition check is initially made and then 2 separate loops are run depending upon the mode in which the selected images exist.

Initially it is checked whether the selected image is already a FAVOURITE one or not by the following code. If it belongs to the favourite mode then the size of the favouriteImageModels would become 1.

RealmResults<FavouriteImagesModel> favouriteImagesModels = realm.where
                                               (FavouriteImagesModel.class).equalTo(“path”, selectedMedias.get(i).getPath( )).findAll( );

If ( favouriteImagesModels.size( ) == 1) {
            favouriteImagePresent = true;
             imagesUnfavourited++;
   }

Now as the image belongs to the favourite mode we ultimately use the following code to remove the image from FAVOURITES.

 favouriteImagesModels.deleteAllFromRealm();

The full code which handle the option to unfavourite an image is shown below.

@Override
                   protected Boolean doInBackground(String arg0) {
                    

        if ( all_photos || fav_photos )   {


                           realm = Realm.getDefaultInstance();
                           realm.executeTransaction ( new Realm.Transaction( ) {
                               

                               @Override
                               public void execute (Realm realm)  {
                                   for (int i = 0 ;  i < selectedMedias.size( ) ;  i++) {
                                       RealmResults<FavouriteImagesModel> favouriteImagesModels = realm.where
                                               (FavouriteImagesModel.class).equalTo(“path”, selectedMedias.get(i).getPath( )).findAll( );
                                       If ( favouriteImagesModels.size( ) == 1) {
                                           favouriteImagePresent = true;
                                           imagesUnfavourited++;
                                       }


                                       favouriteImagesModels.deleteAllFromRealm();
                                   }
                               }
                           });
                       }

         else if ( !fav_photos && !albumsMode ) {
                           realm = Realm.getDefaultInstance();
                           realm.executeTransaction(new Realm.Transaction() {
                           

                              @Override
                               public void execute(Realm realm) {
                                   for (int i = 0;  i < getAlbum().getSelectedCount();  i++) {
                                       RealmResults<FavouriteImagesModel> favouriteImagesModels = realm.where
                                               (FavouriteImagesModel.class).equalTo(“path”, getAlbum( ).getSelectedMedia(i).getPath( ) ).findAll( );
                                       If ( favouriteImagesModels.size() == 1) {
                                           favouriteImagePresent = true;
                                           imagesUnfavourited++;
                                       }
                                       favouriteImagesModels.deleteAllFromRealm();
                                   }
                               }
                   }

After the doInBackground( ) method has been executed the onPostExecute( ) comes into play and some other UI related changes are done such as a SnackBar message is shown if the image is removed from favourites.

Resources

  • Realm for Android

https://realm.io/blog/realm-for-android/

  • Asynchronous Transactions in Realm

https://realm.io/docs/java/latest/#working-with-realmobjects

 

Tags: GSoC18, FOSSASIA, Phimp.Me, Unfavourite image, Realm  

Continue ReadingAdding option to Unfavourite image in Phimp.Me

Implementing Filters in Phimp.me Android App

Image filters in phimp.me android app are implemented using the OpenCV library that enables the android developers to write code in C++/C which is compatible with java. I have implemented around eight filters in the filters.cpp file, mainly dealing with the colour variations that took place between the images.

Suppose that the color model used in consideration is the RGB (Red,Green,Blue) model and we define that every pixel is defined using these values. If we simply want to boost or focus on the red part of the image it can be done by enhancing the particular color in the source image i.e. modifying each pixel of the app by enhancing the blue color of each pixel. The code for the same can be written as :

void applyBlueBoostEffect(cv::Mat &src, cv::Mat &dst, int val) {
register int x, y;
float opacity = val * 0.01f;
cvtColor(src, src, CV_BGRA2BGR);
dst = Mat::zeros(src.size(), src.type());
uchar r, g, b,val1;

for (y = 0; y < src.rows; y++) {
for (x = 0; x < src.cols; x++) {
r = src.at<Vec3b>(y, x)[0];
g = src.at<Vec3b>(y, x)[1];
b = src.at<Vec3b>(y, x)[2];
val1 = saturate_cast<uchar>(b*(1+opacity));
if(val1 > 255) {
val1 = 255;
}
dst.at<Vec3b>(y, x)[0] =
saturate_cast<uchar>(r);
dst.at<Vec3b>(y, x)[1] =
saturate_cast<uchar>(g);
dst.at<Vec3b>(y, x)[2] =
saturate_cast<uchar>(val1);
}
}
}

In the above function what we are doing is taking the source image and converting it to a matrix of known number of rows and columns. Now, we loop over this matrix created and at each

position in the matrix calculate the red, green and blue values present there. There is a parameterized value “val” that determines the amount to which the color chosen is enhanced.

A simple variable val1 contains the enhanced value of the color chosen, here which is color blue. We modify and boost the color by the equation  :

B = B*(1 + (0.01f* val) )

Finally at this particular position in the matrix all the three values of the color are updated i.e. the original red and green color but the modified blue color.

The output of this filter converts images as below shown :

Before                                                                                   After

  

In the above method defined we instead of enhancing one color we can even modify two colors or all the three at the same time to get different effects as per the required needs. An example where I implemented a filter to enhance two colors at the same time is given below, the purpose of this filter is to add a violet color tone in the image.

The code for the filter is :

void applyRedBlueEffect(cv::Mat &src, cv::Mat &dst, int val) {
register int x, y;
float opacity = val * 0.01f;
cvtColor(src, src, CV_BGRA2BGR);
dst = Mat::zeros(src.size(), src.type());
uchar r, g, b;
uchar val1,val3;

for (y = 0; y < src.rows; y++) {
for (x = 0; x < src.cols; x++) {
r = src.at<Vec3b>(y, x)[0];
g = src.at<Vec3b>(y, x)[1];
b = src.at<Vec3b>(y, x)[2];
val1 = saturate_cast<uchar>(r*(1+opacity));
if(val1 > 255) {
val1 = 255;
}

val3 = saturate_cast<uchar>(b*(1+opacity));
if(val3 > 255) {
val3 = 255;
}
dst.at<Vec3b>(y, x)[0] =
saturate_cast<uchar>(val1);
dst.at<Vec3b>(y, x)[1] =
saturate_cast<uchar>(g);
dst.at<Vec3b>(y, x)[2] =
saturate_cast<uchar>(val3);
}
}
}

 

Here we can easily see that there are two values that are updated at the same time i.e. the red and the blue part. The resultant image in that case will have two color values updated and enhanced.

Similarly, instead of two we can also update all the three colors to get uniform enhancement across each color and the resultant image to have all the three colors with a boost effect overall.

The output that we get after the filter that boosts the red and blue colors of an image is  :

 BEFORE                                                                 

AFTER

Resources

Continue ReadingImplementing Filters in Phimp.me Android App

Option to Print Photos in the Phimpme Android Application

In the Phimpme Android application, users can perform various operations on the photos available such as copy, move, add the image to favourites collection, share the images with others, use it as covers, wallpapers and much more. However one another important functionality that has been added in the Phimpe Android application is printing of images. In this post we will be discussing about the implementation of the above mentioned functionality.

Step 1

First we need to create an instance of the class PrintHelper passing context as the constructor parameter which can be done with the following line of code.

PrintHelper photoPrinter = new PrintHelper(this);

Step 2

Now a  function call of setScalemode() is done where we require passing a parameter out of the two options SCALE_MODE_FIT and SCALE_MODE_FILL. The difference between the two options is explained below.

SCALE_MODE_FIT – This option sizes the image so that the whole image is displayed within the printable area of the page.

SCALE_MODE_FILLThis option scales the image so that it fills the entire printable area of the page. Choosing this setting means that some portion of the top and bottom, or left and right edges of the image is left out. This option is the default value if no scale mode is set.

Though neither of the scaling options alter the existing aspect ratio of the image, we are going with the latter of the two as the requirement here is to display the whole image in the printable area. The following code snippet is used to perform the desired function call.

photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);

Step 3

After obtaining an instance of the class PrintHelper and calling the function setScalemode with the proper scale parameter, the path of the image to be printed is extracted and is passed in as a parameter to the decodefile function of the class BitmapFactory which has another parameter.

A Bitmap object is the return result of the operation performed by the function decodefile. The Bitmap object is thereafter passed in as a parameter to the printBitmap() function of the PrintHelper class along with a string attribute which will denote the file name of the printed photo. The code snippet to the above mentioned operations are given below.

Bitmap bitmap = BitmapFactory.decodeFile(getAlbum().getCurrentMedia().getPath(), new BitmapFactory.Options());
photoPrinter.printBitmap(getString(R.string.print), bitmap);

After the printbitmap() is called no further action is required from the side of the application. The Android system print interface appears where the users can select the printing options. The user can proceed to print the image or cancel the operation. If the user decides to proceed with the operation a print job is created and printing operation notification appears in the system navigation bar. The system print interface appearing is displayed below.

This is how we have achieved the functionality of printing images in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository listed in the resources section below.

Resources

1.Android Developer Guide – https://developer.android.com/training/printing/index.html

2.Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

3.PrintHelper Class Guide – https://developer.android.com/reference/android/support/v4/print/PrintHelper.html

 

Continue ReadingOption to Print Photos in the Phimpme Android Application

Compressing Albums in the Phimpme Android Application

The Phimpme Android application comes in with all the functionalities ranging from viewing images to taking photos, editing pictures  and sharing them with the world from within a single application without having to switch to or install other social media apps on your mobile phone. Apart from these basic functionalities, the Phimpme Android app also comes with additional features to enhance user experience like the ability to compress the whole album with a large number of photos so that it becomes easier to share them. In this post, I will be explaining how we achieved this functionality to compress the Albums.

Step 1

The first thing we need to do before compressing an album is to get all the paths of the images in that album and store it in an ArrayList<String> so that it can be used later for the compression process. This can be done using the code snippet provided below, it stores all the paths of the file in a particular folder whose name ends with .jpg

path = new ArrayList<>();
File folder = new File(getAlbums().getSelectedAlbum(0).getPath() + "/");
File[] fpath = folder.listFiles();
for(int i = 0; i < fpath.length; i++){
   if(fpath[i].getPath().endsWith(".jpg") ){
       path.add(fpath[i].getPath());
   }
}

Step 2

Since the compression is a heavy task, we can make use of an AsyncTask to run the task on the background thread so that the user experience is not at all hampered. In the onPreExecute method of the AsyncTask, we need to display the Notification that the compression of the particular album has started, for this we have made use of the Notification handler class that we have created in the Phimpme Android application to ease the process of displaying the notification and to avoid repetition of codes. The onPreExecute method of the AsyncTask is given below.

@Override
protected void onPreExecute() {
   super.onPreExecute();
   NotificationHandler.make(R.string.folder, R.string.zip_fol, R.drawable.ic_archive_black_24dp );
}

Step 3

On the doInBackground method of the AsyncTask, we run the process to compress the files one by one. For this we will make use of the ZipEntry class which is used to represent a zip file entry in Android/Java. First we will create a File with the .zip extension.  After this, we will make use of an object of the class ZipOutputStream as depicted in the code snippet provided below.

BufferedInputStream origin = null; 
FileOutputStream dest = new FileOutputStream(_zipFile); 
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); 
byte data[] = new byte[BUFFER];

After initializing the ZipOutPutStream object, we will put the zip entries in it by using the putNextEntry function of the class. To create a Zip entry of a file, we need to make use of for loop to generate the object of type ZipEntry and after that by using the putNextEntry function of the class, we will put the entries one by one as depicted in the code snippet given below.

for (int i = 0; i < path.size(); i++) {
FileInputStream fi = new FileInputStream(path.get(i));
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(path.get(i).substring(path.get(i).lastIndexOf("/") + 1));
out.putNextEntry(entry);

While preparing the Zip file, we will update the progress of the compression operation by making use of the Notification handler class.

This is how we have implemented the feature to compress the Albums in the Phimpme Android Application. To get the full source code for the same, please check the Phimpme Android GitHub repository listed on the resources below.

Resources

  1. StackOverflow – Compressing Files in Android – https://stackoverflow.com/questions/25562262/how-to-compress-files-into-zip-folder-in-android
  2. Blog – Compressing Files in Android programmatically – http://stacktips.com/tutorials/android/how-to-programmatically-zip-and-unzip-file-in-android
  3. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
Continue ReadingCompressing Albums in the Phimpme Android Application

Enhancing Rotation in Phimp.me using Horizontal Wheel View

Installation

To implement rotation of an image in Phimp.me,  we have implemented Horizontal Wheel View feature. It is a custom view for user input that models horizontal wheel controller. How did we include this feature using jitpack.io?

Step 1: 

The jitpack.io repository has to be added to the root build.gradle:

allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}


Then, add the dependency to your module build.gradle:

compile 'com.github.shchurov:horizontalwheelview:0.9.5'


Sync the Gradle files to complete the installation.

Step 2: Setting Up the Layout

Horizontal Wheel View has to be added to the XML layout file as shown below:

<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2">

<com.github.shchurov.horizontalwheelview.HorizontalWheelView
android:id="@+id/horizontalWheelView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/rotate_apply"
android:padding="5dp"
app:activeColor="@color/accent_green"
app:normalColor="@color/black" />

</FrameLayout>


It has to be wrapped inside a Frame Layout to give weight to the view.
To display the angle by which the image has been rotated, a simple text view has to be added just above it.

<TextView
android:id="@+id/tvAngle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:textColor="@color/black"
android:textSize="14sp" />

Step 3: Updating the UI

First, declare and initialise objects of HorizontalWheelView and TextView.

HorizontalWheelView horizontalWheelView = (HorizontalWheelView) findViewById(R.id.horizontalWheelView);
TextView tvAngle= (TextView) findViewById(R.id.tvAngle);

 

Second, set up listener on the HorizontalWheelView and update the UI accordingly.

horizontalWheelView.setListener(new HorizontalWheelView.Listener() {
@Override
public void onRotationChanged(double radians) {
updateText();
updateImage();
}
});


updateText()
updates the angle and updateImage() updates the image to be rotated. The following functions have been defined below:

private void updateText() {
String text = String.format(Locale.US, "%.0f°", horizontalWheelView.getDegreesAngle());
tvAngle.setText(text);
}

private void updateImage() {
int angle = (int) horizontalWheelView.getDegreesAngle();
//Code to rotate the image using the variable 'angle'
rotatePanel.rotateImage(angle);
}


rotateImage()
is a method of ‘rotatePanel’ which is an object of RotateImageView, a custom view to rotate the image.

Let us have a look at some part of the code inside RotateImageView.

private int rotateAngle;


‘rotateAngle’ is a global variable to hold the angle by which image has to be rotated.

public void rotateImage(int angle) {
rotateAngle = angle;
this.invalidate();
}


The method invalidate() is used to trigger UI refresh and every time UI is refreshed, the draw() method is called.
We have to override the draw() method and write the main code to rotate the image in it.

The draw() method is defined below:

@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (bitmap == null)
return;
maxRect.set(0, 0, getWidth(), getHeight());// The maximum bounding rectangle

calculateWrapBox();
scale = 1;
if (wrapRect.width() > getWidth()) {
scale = getWidth() / wrapRect.width();
}

canvas.save();
canvas.scale(scale, scale, canvas.getWidth() >> 1,
canvas.getHeight() >> 1);
canvas.drawRect(wrapRect, bottomPaint);
canvas.rotate(rotateAngle, canvas.getWidth() >> 1,
canvas.getHeight() >> 1);
canvas.drawBitmap(bitmap, srcRect, dstRect, null);
canvas.restore();
}

private void calculateWrapBox() {
wrapRect.set(dstRect);
matrix.reset(); // Reset matrix is ​​a unit matrix
int centerX = getWidth() >> 1;
int centerY = getHeight() >> 1;
matrix.postRotate(rotateAngle, centerX, centerY); // After the rotation angle
matrix.mapRect(wrapRect);
}

 

And here you go:

Resources

Refer to Github- Horizontal Wheel View for more functions and for a sample application.

Continue ReadingEnhancing Rotation in Phimp.me using Horizontal Wheel View

Automatic Signing and Publishing of Android Apps from Travis

As I discussed about preparing the apps in Play Store for automatic deployment and Google App Signing in previous blogs, in this blog, I’ll talk about how to use Travis Ci to automatically sign and publish the apps using fastlane, as well as how to upload sensitive information like signing keys and publishing JSON to the Open Source repository. This method will be used to publish the following Android Apps:

Current Project Structure

The example project I have used to set up the process has the following structure:

It’s a normal Android Project with some .travis.yml and some additional bash scripts in scripts folder. The update-apk.sh file is standard app build and repo push file found in FOSSASIA projects. The process used to develop it is documented in previous blogs. First, we’ll see how to upload our keys to the repo after encrypting them.

Encrypting keys using Travis

Travis provides a very nice documentation on encrypting files containing sensitive information, but a crucial information is buried below the page. As you’d normally want to upload two things to the repo – the app signing key, and API JSON file for release manager API of Google Play for Fastlane, you can’t do it separately by using standard file encryption command for travis as it will override the previous encrypted file’s secret. In order to do so, you need to create a tarball of all the files that need to be encrypted and encrypt that tar instead. Along with this, before you need to use the file, you’ll have to decrypt in in the travis build and also uncompress it for use.

So, first install Travis CLI tool and login using travis login (You should have right access to the repo and Travis CI in order to encrypt the files for it)

Then add the signing key and fastlane json in the scripts folder. Let’s assume the names of the files are key.jks and fastlane.json

Then, go to scripts folder and run this command to create a tar of these files:

tar cvf secrets.tar fastlane.json key.jks

 

secrets.tar will be created in the folder. Now, run this command to encrypt the file

travis encrypt-file secrets.tar

 

A new file secrets.tar.enc will be created in the folder. Now delete the original files and secrets tar so they do not get added to the repo by mistake. The output log will show the the command for decryption of the file to be added to the .travis.yml file.

Decrypting keys using Travis

But if we add it there, the keys will be decrypted for each commit on each branch. We want it to happen only for master branch as we only require publishing from that branch. So, we’ll create a bash script prep-key.sh for the task with following content

#!/bin/sh
set -e

export DEPLOY_BRANCH=${DEPLOY_BRANCH:-master}

if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "iamareebjamal/android-test-fastlane" -o "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]; then
    echo "We decrypt key only for pushes to the master branch and not PRs. So, skip."
    exit 0
fi

openssl aes-256-cbc -K $encrypted_4dd7_key -iv $encrypted_4dd7_iv -in ./scripts/secrets.tar.enc -out ./scripts/secrets.tar -d
tar xvf ./scripts/secrets.tar -C scripts/

 

Of course, you’ll have to change the commands and arguments according to your need and repo. Specially, the decryption command keys ID

The script checks if the repo and branch are correct, and the commit is not of a PR, then decrypts the file and extracts them in appropriate directory

Before signing the app, you’ll need to store the keystore password, alias and key password in Travis Environment Variables. Once you have done that, you can proceed to signing the app. I’ll assume the variable names to be $STORE_PASS, $ALIAS and $KEY_PASS respectively

Signing App

Now, come to the part in upload-apk.sh script where you have the unsigned release app built. Let’s assume its name is app-release-unsigned.apk.Then run this command to sign it

cp app-release-unsigned.apk app-release-unaligned.apk
jarsigner -verbose -tsa http://timestamp.comodoca.com/rfc3161 -sigalg SHA1withRSA -digestalg SHA1 -keystore ../scripts/key.jks -storepass $STORE_PASS -keypass $KEY_PASS app-release-unaligned.apk $ALIAS

 

Then run this command to zipalign the app

${ANDROID_HOME}/build-tools/25.0.2/zipalign -v -p 4 app-release-unaligned.apk app-release.apk

 

Remember that the build tools version should be the same as the one specified in .travis.yml

This will create an apk named app-release.apk

Publishing App

This is the easiest step. First install fastlane using this command

gem install fastlane

 

Then run this command to publish the app to alpha channel on Play Store

fastlane supply --apk app-release.apk --track alpha --json_key ../scripts/fastlane.json --package_name com.iamareebjamal.fastlane

 

You can always configure the arguments according to your need. Also notice that you have to provide the package name for Fastlane to know which app to update. This can also be stored as an environment variable.

This is all for this blog, you can read more about travis CLI, fastlane features and signing process in these links below:

Continue ReadingAutomatic Signing and Publishing of Android Apps from Travis

Enabling Google App Signing for Android Project

Signing key management of Android Apps is a hectic procedure and can grow out of hand rather quickly for large organizations with several independent projects. We, at FOSSASIA also had to face similar difficulties in management of individual keys by project maintainers and wanted to gather all these Android Projects under singular key management platform:

To handle the complexities and security aspect of the process, this year Google announced App Signing optional program where Google takes your existing key’s encrypted file and stores it on their servers and asks you to create a new upload key which will be used to sign further updates of the app. It takes the certificates of your new upload key and maps it to the managed private key. Now, whenever there is a new upload of the app, it’s signing certificate is matched with the upload key certificate and after verification, the app is signed by the original private key on the server itself and delivered to the user. The advantage comes where you lose your key, its password or it is compromised. Before App Signing program, if your key got lost, you had to launch your app under a new package name, losing your existing user base. With Google managing your key, if you lose your upload key, then the account owner can request Google to reassign a new upload key as the private key is secure on their servers.

There is no difference in the delivered app from the previous one as it is still finally signed by the original private key as it was before, except that Google also optimizes the app by splitting it into multiple APKs according to hardware, demographic and other factors, resulting in a much smaller app! This blog will take you through the steps in how to enable the program for existing and new apps. A bit of a warning though, for security reasons, opting in the program is permanent and once you do it, it is not possible to back out, so think it through before committing.

For existing apps:

First you need to go to the particular app’s detail section and then into Release Management > App Releases. There you would see the Get Started button for App Signing.

The account owner must first agree to its terms and conditions and once it’s done, a page like this will be presented with information about app signing infrastructure at top.

So, as per the instructions, download the PEPK jar file to encrypt your private key. For this process, you need to have your existing private key and its alias and password. It is fine if you don’t know the key password but store password is needed to generate the encrypted file. Then execute this command in the terminal as written in Step 2 of your Play console:

java -jar pepk.jar –keystore={{keystore_path}} –alias={{alias}} –output={{encrypted_file_output_path}} –encryptionkey=eb10fe8f7c7c9df715022017b00c6471f8ba8170b13049a11e6c09ffe3056a104a3bbe4ac5a955f4ba4fe93fc8cef27558a3eb9d2a529a2092761fb833b656cd48b9de6a

You will have to change the bold text inside curly braces to the correct keystore path, alias and the output file path you want respectively.

Note: The encryption key has been same for me for 3 different Play Store accounts, but might be different for you. So please confirm in Play console first

When you execute the command, it will ask you for the keystore password, and once you enter it, the encrypted file will be generated on the path you specified. You can upload it using the button on console.

After this, you’ll need to generate a new upload key. You can do this using several methods listed here, but for demonstration we’ll be using command line to do so:

keytool -genkey -v -keystore {{keystore_path}} -alias {{alias_name}} -keyalg RSA -keysize 2048 -validity 10000

The command will ask you a couple of questions related to the passwords and signing information and then the key will be generated. This will be your public key and be used for further signing of your apps. So keep it and the password secure and handy (even if it is expendable now).

After this step, you need to create a PEM upload certificate for this key, and in order to do so, execute this command:

keytool -export -rfc -keystore {{keystore_path}} -alias {{alias_name}} -file {{upload_certificate.pem}}

After this is executed, it’ll ask you the keystore password, and once you enter it, the PEM file will be generated and you will have to upload it to the Play console.

If everything goes right, your Play console will look something like this:

 

Click enrol and you’re done! Now you can go to App Signing section of the Release Management console and see your app signing and new upload key certificates

 

You can use the SHA1 hash to confirm the keys as to which one corresponds to private and upload if ever in confusion.

For new apps:

For new apps, the process is like a walk in park. You just need to enable the App Signing, and you’ll get an option to continue, opt-out or re-use existing key.

 

If you re-use existing key, the process is finished then and there and an existing key is deployed as the upload key for this app. But if you choose to Continue, then App Signing will be enabled and Google will use an arbitrary key as private key for the app and the first app you upload will get its key registered as the upload key

 

This is the screenshot of the App Signing console when there is no first app uploaded and you can see that it still has an app signing certificate of a key which you did not upload or have access to.

If you want to know more about app signing program, check out these links:

Continue ReadingEnabling Google App Signing for Android Project