Using Universal Image Loader to Display Image on Phimpme Android Application

In Phimpme Android application we needed to load image on the sharing Activity fast so that there won’t be any delay that is visible by a user in the loading of any activity. We used Universal Image Loader to load the image on the sharing Activity to load Image faster.

Getting Universal Image Loader

To get Universal Image Loader in your application go to Gradle(app)-> and then add the following line of code inside dependencies:


compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'


Initialising Universal Image Loader and Displaying Image

To display image on using Universal Image Loader we need to convert the image into a URI from a file path:

saveFilePath = getIntent().getStringExtra(EXTRA_OUTPUT);
Uri uri = Uri.fromFile(new File(saveFilePath));

How an image should be displayed

We need to display the image in such a way that it covers the whole image view in the sharing Activity. The image should be zoomed out. The quality of the image should not be distorted or reduced. The image should look as it is. The image should be zoomable so that the user can pinch to zoom in and zoom out. For the image to adjust the whole Image View we set ImageScaleType.EXACTLY_STRETCHED. We will also set cacheInMemory to true and cacheOnDisc to true.  

private void initView() {
   saveFilePath = getIntent().getStringExtra(EXTRA_OUTPUT);
   Uri uri = Uri.fromFile(new File(saveFilePath));
   ImageLoader imageLoader = ((MyApplication)getApplicationContext()).getImageLoader();
   DisplayImageOptions options = new DisplayImageOptions.Builder()
   imageLoader.displayImage(uri.toString(), shareImage, options);

Image Loader function in MyApplication class:

private void initImageLoader() {
   File cacheDir = com.nostra13.universalimageloader.utils.StorageUtils.getCacheDirectory(this);
   int MAXMEMONRY = (int) (Runtime.getRuntime().maxMemory());
   // System.out.println("dsa-->"+MAXMEMONRY+"   "+(MAXMEMONRY/5));//.memoryCache(new
   // LruMemoryCache(50 * 1024 * 1024))
   DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()

   ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
           this).memoryCacheExtraOptions(480, 800).defaultDisplayImageOptions(defaultOptions)
           .diskCacheExtraOptions(480, 800, null).threadPoolSize(3)
           .threadPriority(Thread.NORM_PRIORITY - 2)
           .memoryCache(new LruMemoryCache(MAXMEMONRY / 5))
           .diskCache(new UnlimitedDiskCache(cacheDir))
           .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
           .imageDownloader(new BaseImageDownloader(this)) // default
           .imageDecoder(new BaseImageDecoder(false)) // default

   this.imageLoader = ImageLoader.getInstance();

Image View in Sharing Activity XML file:

In the Sharing Activity Xml resource, we need to specify the width of the image view and the height of the image view. In Phimpme Android application we are using ImageViewTouch so that we have features like touch to zoom in zoom out. The scale type of the imageView is centerCrop so that image which is loaded is zoomed out and focus is in the center of the image.  



To load image faster on any ImageView we should use Universal Image Loader. It helps load the activity faster and allows many features as discussed in the blog.




Continue ReadingUsing Universal Image Loader to Display Image on Phimpme Android Application

Implementation of Set Different Language for Query in SUSI Android

SUSI.AI has many skills. Some of which are displaying web search of a certain query, provide a list of relevant information of a topic, displaying a map of the certain position and simple text message of any query. Previously SUSI.AI reply all query in English language but now one important feature is added in SUSI.AI and that feature is, reply query of the user in the language that user wants. But to get the reply in different language user has to send language code of that language along with query to SUSI Server. In this blog post, I will show you how it is implemented in SUSI Android app.

Different language supported in SUSI Android

Currently, different languages added in option in SUSI Android and their language code are:

Language Language Code
English en
German de
Spanish es
French fr
Italian it
Default Default language of the device.

Layout design

I added an option for choosing the different language in settings. When the user clicks on Language option a dialog box pops up. I used listpreference to show the list of different languages.







“title” is used to show the title of setting, “entries” is used to show the list of entry to the user and “entryValue” is the value corresponding to each entry. I used listpreference because it has own UI so we don‘t have to develop our own UI for it and also it stores the string into the SharedPreferences so we don’t need to manage the values in SharedPreference. SharedPreference needed to set value in Language in settings so that once user close app and again open it setting will show same value otherwise it will show default value. We used an array of string to show the list of languages.

<string-array name=“languagentries”>








SetLanguage implementation

To set language user must choose Language option in setting.

On clicking Language option a dialog box pop up with the list of different languages. When the user chooses a language then we save corresponding language code in preference with key “prefLanguage” so that we can use it later to send it to the server along with the query. It also uses to send language to the server to store user language on the server, so that user can use the same language in the different client.

querylanguage.setOnPreferenceChangeListener { _, newValue ->

  PrefManager.putString(Constant.LANGUAGE, newValue.toString())

  if(!settingsPresenter.getAnonymity()) {

      settingsPresenter.sendSetting(Constant.LANGUAGE, newValue.toString(), 1)



newValue.toString() is the value i.e language code of corresponding language.

Now when we query anything from SUSI.AI we send language code along with query to the server. Default language is default language of the device. Before sending language to the server we check language is default language or any specific language.

val language = if (PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT).equals(Constant.DEFAULT))


else PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT)

And after that, we send the corresponding language along with query to the server.

clientBuilder.susiApi.getSusiResponse(timezoneOffset, longitude, latitude, source, language, query)


Continue ReadingImplementation of Set Different Language for Query in SUSI Android

Making SUSI Alexa skill as an express app

Previously SUSI Alexa skill was deployed using AWS Lambda service (Refer to this blog). Each SUSI.AI Bot should be deployed on Google cloud using Kubernetes. To accomplish that, we need to remove the dependency of the SUSI Alexa skill from AWS Lambda service. We need to make it an express app, to be able to deploy it to Google cloud. Let’s start with on how to achieve it:

SUSI Alexa skill:

We require three files to make the skill as an express app. The main entry point for the skill would be server.js file, which will serve the incoming request using two helper files alexa.js and handlers.js.


This file acts as the main entry point for the incoming request. We handle two type of requests using it, that are:

  1. Launch request
  2. Intent request

Launch request is triggered when a person utters “Alexa, open susi chat” , “Alexa, start susi chat”, “Alexa, launch susi chat” etc. This request is responded with an introductory phrase about SUSI.AI. To catch this request:

if (type === "LaunchRequest") {
        var endpoint = ""+"Welcome"; // ENDPOINT GOES HERE
        http.get(endpoint, (response1) => {
            var body = "";
            response1.on("data", (chunk) => { body += chunk; });
            response1.on("end", () => {
                var viewCount;
                viewCount = JSON.parse(body).answers[0].actions[0].expression;
                endpoint = ""+"Get+started"; // ENDPOINT GOES HERE
                body = "";
                http.get(endpoint, (response2) => {
                    response2.on("data", (chunk) => { body += chunk; });
                    response2.on("end", () => {
                        viewCount += JSON.parse(body);.answers[0].actions[0].expression;

Intent request gets triggered, when any other phrase is uttered by the user except Launch related phrases. We check if the intent triggered has a corresponding handler to handle the request. If the handler is found in handlers.js file, we call it passing the required arguments to the handler function. Let’s see how handlers make this step possible.


This file decides on what function to run when a particular type of intent is triggered. As we have just one intent for our SUSI Alexa skill i.e. callSusiApi, we have just one function in our handlers.js file. During its execution, the first step we do is extract the query value:

let query = slots.query.value;

Depending upon the query value, we run its corresponding code. For example, in case of a generic query (i.e. any query except stop, cancel and help):

var endpoint = ""+query; // ENDPOINT GOES HERE

http.get(endpoint, (response1) => {
    var body = "";
    response1.on("data", (chunk) => { body += chunk; });
    response1.on("end", () => {
        var data = JSON.parse(body);
            // handle rss and table type results
            viewCount = data.answers[0].actions[0].expression;

At the end of the function we respond to the user with an answer to his/her query using:



When we get a request from the user, we pass that request and response object to this file. This file helps us wrap the required request properties into an object and return that back to the server file, which was the entry point for the request. Now, we can easily extract the properties in server file and work with those:

We extract the properties like this:

let session = req.body.session,
session.attributes = session.attributes || {};

if (req.body.request.intent) {
    intent =;
    slots = req.body.request.intent.slots;

Then we return the object back at the end:

return {
        type: req.body.request.type,
        intent: intent,
        slots: slots,
        session: session,
        response: {
            say: (text, shouldEndSession) => say(text, shouldEndSession),
            ask: (text, shouldEndSession) => say(text, shouldEndSession)

Great, we have made the SUSI Alexa skill as an express app. The next step is to do some changes in the configuration tab of our skill:

  1. Instead of Amazon resource number, we fill our webhook address here: 

  2. A new property shows up that is SSL certificate. As we are using Heroku for webhook services, we select the second option as shown below: 

  3. It’s time to test the skill: 

    This repository by Salesforce helped me a lot in making the SUSI skill as an express app.


    1. Developing Alexa Skills Locally with Node.js by Josh Skeen from Bignerdranch.
    2. Amazon Alexa Skills: Create a Custom Skill by Simon Coope from SJCNET.
Continue ReadingMaking SUSI Alexa skill as an express app

How to Parse HTML Tags and Anchor Clickable Links in SUSI Android App

Html tags are used to define how contents of a webpage should be formatted and displayed. Sometimes the SUSI answer type response contains some html tags but showing these html tags without parsing would distort the normal text flow in SUSI Android.

For the query ‘Ask me something’ SUSI’s reply is

“data”: [
      “question”: “Which soccer team won the Copa Am&eacute;rica 2015 Championship ? “,                                          

In SUSI Android this message looks like

As you can see that showing html tags without parsing distort the normal text flow. So we need to parse html tags properly. We use Html class for this purpose. Html class is present in android.text package and you can import it in the class where you want to use it.

import android.text.Html

fromHtml method of Html class is used to parse html tags. But for API level less than 24 and equal to or greater than 24 we use different parameters in fromHtml method.

For API level less than 24 we used


But for API level equal to or greater than 24 we have to use

Html.fromHtml(model.getContent(), Html.FROM_HTML_MODE_COMPACT)

Here the second parameter is legacy flags which decides how text inside a tag will be shown after parsing.

In case of Html.fromHtml(String string) legacy flag is by default FROM_HTML_MODE_LEGACY. It indicates that separate block-level elements with blank lines.

So after parsing html tags using fromHtml

But return type of fromHtml method is Spanned so if you need String then you have to convert it into string using toString() method.

Anchor action type in susi response contains link and text.

       “link”: “”,
       “text”: “Link to Openstreetmap: Singapore”

Here the text is the text we show in textview and link is used to show web content in the browser when user click on text. So first link and text are attached together like

“<a href=\”” +susiResponse.getAnswers().get(0).getActions().get(i).getAnchorLink() + “\”>”
+ susiResponse.getAnswers().get(0).getActions().get(1).getAnchorText() + “</a>”

Here text between the tag is description of link and after parsing we show this text in textview. It can be parsed using fromHtml method of Html class and textview is made clickable by



Continue ReadingHow to Parse HTML Tags and Anchor Clickable Links in SUSI Android App

Reset Password Option in SUSI Android App

Login and signup are an important feature for some android apps like chat apps because the user will want to save and secure personal messages from others. In SUSI Android app we provide a token to a logged-in user for a limit period of time so that once the user logs in and someone else gets access to the device, then he/she can’t use the user account for a long period of time. It is a security provided from our side but the user also has to maintain some security. Cyber security risks have increased and hacking technologies have improved a lot in the past 10 years. So, using the same password for a long period of time absolutely puts your account security at risk. So to keep your account secure you should change/reset your password regularly. In this blog post, I will show you how reset password option is implemented in SUSI Android app.

Layout design for reset password

Reset password option is added in the setting. When the user clicks on reset password option a dialog box pops up. There are three textinputlayout boxes – each for the current password, new password and confirm password. I have used textinputlayout instead of simple edittext box because it helps user to show first “hint” and when user taps on, hint will come up with text over it as floating label so that the user can understand what to add in that box and also in case of error we can show that error to user.

Reset Password implementation

On clicking reset password option a dialog box appears in which user inserts the current password, new password and confirm password to confirm the new password. Before sending new password to the server we perform two checks

  1. New password should not be empty and length of new password should be at least six.
  2. New password and confirm password must be same.
if (!CredentialHelper.isPasswordValid(newPassword)) {




if (newPassword != conPassword) {

settingView?.invalidCredentials(false, Constant.NEW_PASSWORD)



And when these two checks are passed we send “new password” to server.

Endpoint use to reset password is mail id&password=current password&newpassword=newpassword

As you can see it needed three parameters

  • changepassword: Your email id
  • password : Your current password
  • newpassword: Your new password

When user logs in, we save user’s email id so that the user doesn’t have to provide it again and again when the user wants to change the password.


The user provides current password and new password through dialog box. We used resetPassword method to reset the password. We send these three parameters to the server using resetPassword method and if the password changed successfully then server sends a message.

override fun resetPassword(password: String, newPassword: String, listener: ISettingModel.onSettingFinishListener) {

  val email = PrefManager.getString(Constant.SAVE_EMAIL, null)

  resetPasswordResponseCall = ClientBuilder().susiApi


  resetPasswordResponseCall.enqueue(object : Callback<ResetPasswordResponse> {

  } )


We used retrofit library for network call and resetPasswordResponse is a model class using which we are retrieving server response.


Continue ReadingReset Password Option in SUSI Android App

Using Firebase Test Lab for Testing test cases of Phimpme Android

As now we started writing some test cases for Phimpme Android. While running my instrumentation test case, I saw a tab of Cloud Testing in Android Studio. This is for Firebase Test Lab. Firebase Test Lab provides cloud-based infrastructure for testing Android apps. Everyone doesn’t have every devices of all the android versions. But testing on all of them is equally important.

How I used test lab in Phimpme

  • Run your first test on Firebase

Select Test Lab in your project on the left nav on the Firebase console, and then click Run a Robo test. The Robo test automatically explores your app on wide array of devices to find defects and report any crashes that occur. It doesn’t require you to write test cases. All you need is the app’s APK. Nothing else is needed to use Robo test.

Upload your Application’s APK (app-debug-unaligned.apk) in the next screen and click Continue

Configure the device selection, a wide range of devices and all API levels are present there. You can save the template for future use.

Click on start test to start testing. It will start the tests and show the real time progress as well.

  • Using Firebase Test Lab from Android Studio

It required Android Studio 2.0+. You needs to edit the configuration of Android Instrumentation test.

Select the Firebase Test Lab Device Matrix under the Target. You can configure Matrix, matrix is actually on what virtual and physical devices do you want to run your test. See the below screenshot for details.

Note: You need to enable the firebase in your project

So using test lab on firebase we can easily test the test cases on multiple devices and make our app more scalable.


Continue ReadingUsing Firebase Test Lab for Testing test cases of Phimpme Android

FOSSASIA at Google Code-In 2016 Grand Prize Trip

This year FOSSASIA came up with a whopping number of GCI participants, making it to the top. FOSSASIA is a mentor organization at the Google Code-In contest, which introduces pre-university students towards open source development.

Every year Google conducts the grand prize trip to all the GCI winners and I represented FOSSASIA as a mentor.

FOSSASIA GCI winners and Mentor at Google Mountain View Campus.

Day 1: Meet and Greet with the Diverse Communities

We all headed towards the San Francisco Google office and had a great time interacting with members from diverse open source organizations from different parts of the world. I had some interactive conversations with the kids, on how they scheduled their sleep hours in order to complete the task and got feedback from the mentors from different time zones! I was also overwhelmed while listening to their interests apart from open source contributions.

“I am a science enthusiast, mainly interested in Computer Science and its wide range of applications. I also enjoy playing the piano, reading, moving, and having engaging conversations with my friends. As a participant in the GCI contest, I got the chance to learn by doing, I got an insight of how it is like to work on a real open-source project, met some great people, helped others (and received help myself). Shortly, it was amazing, and I’m proud to have been a part of it. ” Shared by one of our Winner Oana Rosca.

There were people from almost 14 different countries, in fact, FOSSASIA, as a team, was the most diverse group 🙂

Day 2: Award Ceremony

We had two winners from FOSSASIA, Arkhan Kaiser from Indonesia and Oana Rosca from Romania. There were 8 organizations with 16 winners. The award ceremony was celebrated on day 2 and each winner was felicitated by Chris DiBona, the director of the Google open source team.

Talks by Googlers

We had amazing speakers from Google who spoke about their work, experiences, and journey to Google. Our first speaker was Jeremy Allison, a notable contributor to “Samba” which is a free software re-implementation of the SMB/CIFS networking protocol. He spoke on “How the Internet works” and gave a deeper view of the internet magic.

We had various speakers from different domains such as Grant Grundler from the Chrome team, Lyman Missimer from Google Expeditions, Katie Dektar from the Making and Science team, Sean Lip from Oppia(Googler and Oppia org admin), Timothy Papandreou from Waymo and Andrew Selle from TensorFlow.

Day 3: Fun Activities

We had various fun activities organized by the Google team. I had a great time cruising towards the Alcatraz island.  Later we had a walk on the Golden Gate bridge. Here comes the fun part of the tour “the cruise dinner” which was the best part of the day.

Day 4: End of the trip

Oana, Arkhan and I gave a nice presentation about our work during GCI. We spoke about all the amazing projects under FOSSASIA. One cool thing we did is that we “Doodled” our presentation 🙂 Here are few images from the actual presentation.

The day ended well with loads of good memories and information. Thanks to the open source technologies and their availability along with a beautiful friendly community, these memories and connections will now remain for a lifetime.

Continue ReadingFOSSASIA at Google Code-In 2016 Grand Prize Trip

How Anonymous Mode is Implemented in SUSI Android

Login and signup are an important feature for some android apps like chat app because user wants to save messages and secure messages from others. In SUSI Android we save messages for logged in user on the server corresponding to their account. But  users can also  use the app without logging in. In this blog, I will show you how the anonymous mode is implemented in SUSI Android .

When the user logs in using the username and password we provide a token to user for a limited amount of time, but in case of anonymous mode we never provide a token to the user and also we set ANONYMOUS_LOGGED_IN flag true which shows that the user is using the app anonymously.


PrefManager.putBoolean(Constant.ANONYMOUS_LOGGED_IN, true)

We use ANONYMOUS_LOGGED_IN flag to check user is using the app anonymously or not. When a user opens the app we first check user is already logged in or not. If the user is not logged in then we check ANONYMOUS_LOGGED_IN flag is true or false. The true means user is using the app in anonymous mode.

if(PrefManager.getBoolean(Constant.ANONYMOUS_LOGGED_IN, false)) {

 intent = new Intent(LoginActivity.this, MainActivity.class);



Else we show login page to the user. The user can use app either by login using username and password or anonymously by clicking skip button. On clicking skip button ANONYMOUS_LOGGED_IN flag set to true.

public void skip() {

Intent intent = new Intent(LoginActivity.this,MainActivity.class);


PrefManager.putBoolean(Constant.ANONYMOUS_LOGGED_IN, true);



If the user is using the app in anonymous mode but he/she want to login then he/she can login. There is an option for login in menu.

When the user selects login option from the menu, then it redirects the user to the login screen and ANONYMOUS_LOGGED_IN flag is set to false. ANONYMOUS_LOGGED_IN flag is set to false to ensure that instead of login if the user closes the app and again open it, then he/she can’t use the app until logged in or click skip button.


PrefManager.putBoolean(Constant.ANONYMOUS_LOGGED_IN, false);


Continue ReadingHow Anonymous Mode is Implemented in SUSI Android

How Settings of SUSI Android App Are Saved on Server

The SUSI Android allows users to specify whether they want to use the action button of soft keyboard as carriage return or else send action. The user can use SUSI.AI on different client like Android , iOS, Web. To give user uniform experience, we need to save user settings on the server so that if the user makes any change in setting in any chat client then that it changes in other chat clients too. So every chat client must store user specific data on the server to make sure that all chat clients access this data and maintain the same state for that particular user and must accordingly push and pull user data from and to the server to update the state of the app.

We used special key to store setting information on server. For eg.

Setting Key Value Use
Enter As Send enter_send true/false true means pressing enter key send message and false means pressing enter key adds new line.
Mic Input mic_input true/false true means default input method is speech but supports keyboard input too. false means the only input method is keyboard input.
Speech Always speech_always true/false true means we get speech output irrespective of input type.
Speech Output speech_output true/false true means we get speech output in case of speech input and false means we don’t get speech output.
Theme theme dark/light dark means theme is dark and light means theme is light

How setting is stored to server

Whenever user settings are changed, the client updates the changed settings on the server so that the state is maintained across all chat clients. When user change setting, we send three parameters to the server ‘key’, ‘value’ and ‘token’. For eg. let ‘Enter As Send’ is set to false. When user changes it from false to true, we immediately update it on the server. Here key will be ‘enter_send’ and value will be ‘true’.

The endpoint used to add or update User Settings is :


SETTING_NAME’ is the key of the corresponding setting, ‘SETTING_VALUE’ is it’s updated value and ‘ACCESS_TOKEN’ is used to find correct user account. We used the retrofit library for network call.

settingResponseCall = ClientBuilder().susiApi .changeSettingResponse(key, value,  PrefManager.getToken())

If the user successfully updated the setting on the server then server reply with message ‘You successfully changed settings of your account!’

How setting is retrieved from server

We retrieve setting from the server when user login. The endpoint used to fetch User Settings is


It requires “ACCESS_TOKEN” to retrieve setting data for a particular user. When user login, we use getUserSetting method to retrieve setting data from the server. PrefManager.getToken() is used to get “ACCESS_TOKEN”.

userSettingResponseCall = ClientBuilder().susiApi .getUserSetting(PrefManager.getToken())

We use userSettingResponseCall to get a response of ‘UserSetting’ type using which we can retrieve different setting from the server. ‘UserSetting’ contain ‘Session’ and ‘Settings’ and ‘Settings’ contain the value of all settings. We save the value of all settings on the server in string format, so after retrieving settings we convert them into the required format. For eg. ‘Enter As Send’ value is of boolean format, so after retrieving we convert it to boolean format.

var settings: Settings ?= response.body().settings



Continue ReadingHow Settings of SUSI Android App Are Saved on Server

Adding Manual ISO Controls in Phimpme Android

The Phimpme Android application comes with a well-featured camera to take high resolution photographs. It features an auto mode in the camera as well as a manual mode for users who likes to customise the camera experience according to their own liking. It provides the users to select from the range of ISO values supported by their devices with a manual mode to enhance the images in case the auto mode fails on certain circumstances such as low lighting conditions.

In this tutorial, I will be discussing how we achieved this in Phimpme Android with some code snippets and screenshots.

To provide the users with an option to select from the range of ISO values, the first thing we need to do is scan the phone for all the supported values of ISO and store it in an arraylist to be used to display later on. This can be done by the snippet provided below:

String iso_values = parameters.get("iso-values");
if( iso_values == null ) {
 iso_values = parameters.get("iso-mode-values"); // Galaxy Nexus
 if( iso_values == null ) {
    iso_values = parameters.get("iso-speed-values"); // Micromax A101
    if( iso_values == null )
       iso_values = parameters.get("nv-picture-iso-values"); // LG dual P990

Every device supports a different set of keyword to provide the list of ISO values. Hence, we have tried to add every possible keywords to extract the values. Some of the keywords used above covers almost 90% of the android devices and gets the set of ISO values successfully.

For the devices which supports the ISO values but doesn’t provide the keyword to extract the ISO values, we can provide the standard list of ISO values manually using the code snippet provided below:


After extracting the set of ISO values, we need to create a list to display to the user and upon selection of the particular ISO value as depicted in the Phimpme camera screenshot below

Now to set the selected ISO value, we first need to get the ISO key to set the ISO values as depicted in the code snippet provided below:

if( parameters.get(iso_key) == null ) {
 iso_key = "iso-speed"; // Micromax A101
 if( parameters.get(iso_key) == null ) {
    iso_key = "nv-picture-iso"; // LG dual P990
    if( parameters.get(iso_key) == null ) {
       if ( Build.MODEL.contains("Z00") )
          iso_key = "iso"; // Asus Zenfone 2 Z00A and Z008

Getting the key to set the ISO values is similar to getting the key to extract the ISO values from the device. The above listed ISO keys to set the values covers most of the devices.

Now after we have got the ISO key, we need to change the camera parameter to reflect the selected change.

parameters.set(iso_key, supported_values.selected_value);

To get the full source code on how to set the ISO values manually, please refer to the Phimpme Android repository.


  1. Stackoverflow – Keywords to extract ISO values from the device:
  2. Open camera Android source code:
  3. Blog – Learn more about ISO values in photography:
Continue ReadingAdding Manual ISO Controls in Phimpme Android