Leak Canary in Phimpme Android

Leak Canary is a memory detection library for Android and Java. A memory leak occurs when you hold an object for too long after its purpose has been served. If some object is holding another object then the Garbage collector will not be able to collect and this is known as Memory Leak. These memory leaks can be minor (in KB’s) or can lead to an app in ANR state with OutOfMemoryError.Hence to recover and capture this memory leak, Leak Canary is used for Android and Java.

For every functioning done in android, the system needs resource such as memory. Hence in Java the Garbage Collector(GC) plays a major role in deallocating the memory. The GC is mainly used to reclaim memory. Now the question arises, why do we need a memory leak detection library when GC is already present. The answer is sometimes the developers makes programming mistakes and that leads to inhibit the GC to collect the objects that are of no use and mark them as useful objects.

The GC starts from one point(root) and marks active to all the objects that holds references from GC root and the objects which are not marked are wiped out of memory.Hence when some unuseful objects is marked active, memory leak occurs.Hence to eliminate these problems  of memory leaks, we have employed the use of Leak Canary in our project.

The Phimpme project and every related project has possible memory leaks, like for instance we have used fragments in settings activity and to catch that memory leak we have added the refwatcher instance. Hence if any memory leaks occur we get the error such as ‘org.fossasia.phimpme’  leaked 40kb.This can also be checked by Leaks App in the android phone, which has features of showing and sharing the heap dump and info.

To add the Leak Canary in your android app, follow these steps:

  • Add the dependencies in build.gradle(app level)

    dependencies {
       debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
       releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
     }
  • Add the following code to your Application class

    public class MyApplication extends Application{
    @Override
    public void onCreate() {
       if (LeakCanary.isInAnalyzerProcess(this)) {
           // This process is dedicated to LeakCanary for heap analysis.
           // You should not init your app in this process.
           return;
       }
       LeakCanary.install(this);
    }
    
  • Leak canary now will automatically detect the memory leaks  from all activities.

For fragment a refwatcher is needed, hence

public class MYFragment extends Fragment {
    ...

    @Override
    public void onDestroy() {
        super.onDestroy();
        MainApplication.getRefWatcher(getActivity()).watch(this);
    }
}

Hence LeakCanary is setup finally, and now the memory leaks will be detected.

Resources

 

Continue ReadingLeak Canary in Phimpme Android

Camera Controls Using Volume Buttons In The Phimpme Application

The Phimpme Android application has a camera, Gallery section, edit image section and also the inbuilt sharing option. In spite of having all of the above features, the Phimpme application doesn’t compromise on the quality and functions of each of the sections. For instance, we can control the camera fully with the help of just the volume buttons. For this, we have provided an option in the settings of the application to change and select the behaviour of the volume buttons according to the users choice. In this post, I will be discussing how we have achieved this functionality.

Step 1

First, we have to display an ArrayList of options using the ListPreference in the settings. The user can perform the following functions using the volume keys.

  1. Take Photo
  2. Focus
  3. Zoom in/out
  4. Change Exposure Level
  5. Switch Auto Level on/off

There are also two other option to change device volume and to do nothing in case the user wants the default behaviour.

The above options in the settings can be provided using the following lines of code.

<ListPreference
   android:defaultValue="volume_take_photo"
   android:entries="@array/preference_volume_keys_entries"
   android:entryValues="@array/preference_volume_keys_values"
   android:key="preference_volume_keys"
   android:summary="@string/preference_volume_keys_summary"
   android:title="@string/preference_volume_keys" />

Step 2

Now as the user selects a particular option from the ListPreference, the value in the SharedPreference associated with a particular key value gets updated. After this, we have to perform the particular activity as soon as the volume button is pressed. For this, we have to Override the onKeyDown() function of the KeyEvent.Callback class in Android. This function takes in the Integer keycode and the KeyEvent as the parameters.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
   if (MyDebug.LOG)
       Log.d(TAG, "onKeyDown: " + keyCode);
   boolean handled = mainUI.onKeyDown(keyCode, event);
   if (handled)
       return true;
   return super.onKeyDown(keyCode, event);
}

Step 3

We have defined another onKeyDown() method in the MainUI class to keep the code modularized. In this, we have made use of the Switch cases to perform the different actions. This can be done by using the following line of code snippet.

Switch (volume_keys) {
  case "volume_take_photo":
     main_activity.takePicture();
     return true;

  case "volume_zoom":
     if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
        main_activity.getPreview().zoomTo(main_activity.getPreview().getCameraController().getZoom() + 1);
     }
     else {
        main_activity.getPreview().zoomTo(main_activity.getPreview().getCameraController().getZoom() - 1);
     }
     return true;

In the above code snippet, we have defined the function to perform the zoom operation and to click picture using the volume keys. Similarly, we can add the functions to perform all the above mentioned activities. To get the full source code, please refer to the Phimpme Android GitHub repository mentioned in the resources section below.

Resources

  1. Android Developer Guide – KeyEvent.Callback class – https://developer.android.com/reference/android/view/KeyEvent.Callback.html
  2. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  3. StackOverflow – Handling key events in Android – https://stackoverflow.com/questions/5631977/keyevent-handling-in-android
  4. Blog post – Handleling Key Events – https://android-developers.googleblog.com/2009/12/back-and-other-hard-keys-three-stories.html

 

Continue ReadingCamera Controls Using Volume Buttons In The Phimpme Application

Slideshow option in the Phimpme Android Application

The Phimpme Android application along with all the basic features for viewing and sharing images also has some interesting functions, for example, the ability to view all the images at once using the slideshow option. The users can also manage the time duration for which a particular photo will be displayed before switching on to the next image. In this post, we will be discussing how we have achieved this functionality in the Phimpme Android application.

Step 1

First, we have to provide the user with an option to enter the time duration for which they want to view a particular photo. For this, we have made use of the themed dialog box which will take the input from the user and then we will be converting the time entered by them into milliseconds. This can be done by using the following code snippet.

dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.ok).toUpperCase(), new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
       String value= editTextTimeInterval.getText().toString();
       if(!"".equals(value))
       {
           slideshow=true;
           int intValue = Integer.parseInt(value);
           SLIDE_SHOW_INTERVAL = intValue * 1000;

Step 2

For changing the photo at a particular duration of time, we need to make use of the Runnable interface in Java, which uses a method run() to execute the tasks. To use it, we have to create a Handler object and initialize it. This can be done using the following lines of the code.

private Handler handler;
handler = new Handler();

After this, we have to define and initialize our Runnable object which will be used later to change the picture. The code snippet for initializing the runnable object is given below.

Runnable slideShowRunnable = new Runnable() {
   @Override
   public void run() {
       try{
           mViewPager.scrollToPosition((getAlbum().getCurrentMediaIndex() + 1) % getAlbum().getMedia().size());
       }
       catch (Exception e) {
           e.printStackTrace();
       }
       finally{
           handler.postDelayed(this, SLIDE_SHOW_INTERVAL);
       }

As the run() method gets executed, the scrollToPosition function of the ViewPager class gets called which changes the position of the image displayed to the next image available.

Step 3

To call the runnable object we created in the second step, we have to use the postDelayed function of the Handler class which takes in a Runnable object and the time in milliseconds as the parameter. The code snippet for this is provided below.

handler.postDelayed(this, SLIDE_SHOW_INTERVAL);

Please note that we have also included the above line of code in the finally block after each successful run of the method because as the slideshow starts, we will have to call this function to scroll to the new position after every finite provided duration.

This is how we have achieved the Slideshow functionality in the Phimpme Android application. To get the full source code for this implementation, please check out the Phimpme Android GitHub repository listed in the resources section below.

Resources

  1. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  2. Android Developer Guide – Handler class – https://developer.android.com/reference/android/os/Handler.html
  3. StackOverflow – Runnable in Java – https://stackoverflow.com/questions/13327571/in-a-simple-to-understand-explanation-what-is-runnable-in-java
  4. StackOverflow – Image Slideshow in Android – https://stackoverflow.com/questions/2995145/image-slideshow-example-in-android

 

Continue ReadingSlideshow option in the Phimpme Android Application

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:

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()
           .cacheOnDisc(true)
           .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
           .cacheInMemory(true)
           .bitmapConfig(Bitmap.Config.RGB_565)
           .build();
   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()
           .cacheInMemory(true)
           .cacheOnDisk(true)
           .build();

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

   this.imageLoader = ImageLoader.getInstance();
   imageLoader.init(config);
}

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.  

<org.fossasia.phimpme.editor.view.imagezoom.ImageViewTouch
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:id="@+id/share_image"
   android:layout_below="@+id/toolbar"
   android:layout_weight="10"
   android:layout_alignParentStart="true"
   android:scaleType="centerCrop"/>

Conclusion

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.

 

Github

Resources

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

Timer Option in Phimpme Android’s Camera

The Phimpme Android application comes in with all the options like clicking a picture, editing them and sharing it with the world using many many connected social media accounts. Not only this, it features a fully functional camera with lots of different functionality which a user wants in their day to day life. One such feature is the Timer option in Phimpme. In Phimpme, the user can go to the camera settings to enable or disable the Timer options and click their photos after setting the timer for a particular duration. After setting the timer and pressing the capture photo button, it also displays a ticker at the UI of the camera to notify the user the amount of time after which the photo will be clicked.

In this tutorial, I will be explaining how we have achieved this feature in the Phimpme application.

Step 1

The first thing we need to do is to display the options to the user in camera settings to enable/disable the timer and to select the specific amount of time for the delay in the capture. To do this we have made use of the pop-up view in which we have programmatically added all the timer values to be displayed to the user using the code snippet below:

final String[] timer_values = getResources().getStringArray(R.array.preference_timer_values);
  String[] timer_entries = getResources().getStringArray(R.array.preference_timer_entries);
String timer_value = sharedPreferences.getString(PreferenceKeys.getTimerPreferenceKey(), "0");
addArrayOptionsToPopup(Arrays.asList(timer_entries), getResources().getString(R.string.preference_timer), true, timer_index, false)

What the function addArrayOptionsToPopup does is that it adds the following arrays to the linear layout of the pop-up view programmatically.

Step 2

After displaying the timer values to the user, we need to think about the functionality of the camera if the timer is enabled. When the user presses the click picture button we check the condition whether the timer is enabled or not. If it is enabled, we make the application to wait for a specific amount of time before clicking the photo. This can be done using the CountDownTimer class which is provided by Android.

new CountDownTimer(timerDelay, 1000) {
   public void onTick(long millisUntilFinished) {
          //Called after each second
       }
       public void onFinish() {
         //Called after timer delay
       }
   }.start();

What the above piece of code does is to wait for the specific amount of time as specified by the timer delay. Suppose the user selects the option to wait for 5 seconds then we set the timerDelay to be 5000, then the above code calls the onTick method after each second where we update the user that how much time is remaining and on the onFinish method we call the takePicture method to capture the image using the following line of code below.

mCamera.takePicture(null, null, mPicture);

This is how we have implemented the option of Timer in the Phimpme Android application. To get the full source code of the Camera, please check out the Phimpme Android GitHub repository listed in the resources section below.

Resources

  1. Android Developer Guide : CountDown Timer – https://developer.android.com/reference/android/os/CountDownTimer.html
  2. StackOverflow – Implementing Timer in Camera – https://stackoverflow.com/questions/35355320/camera-application-timer-implementaion-issue
  3. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  4. GitHub – Open Camera Source Code – https://github.com/almalence/OpenCamera

 

Continue ReadingTimer Option in Phimpme Android’s Camera

Adding Voice Recognition in Description Dialog Box in Phimpme project

In this blog, I will explain how I added Voice Recognition in a dialog box to describe an image in Phimpme Android application. In Phimpme Android application we have an option to add a description for the image. Sometimes the description can be long. Adding Voice Recognition text to speech will ease the user’s experience to add a description for the image.

Adding appropriate Dialog Box

In order to take input from the user to prompt the Voice Recognition function, I have added an image button in the description dialog box. Since the description dialog box will only contain an EditText and a button will have used material design to make it look better and add caption on top of it.

 

<LinearLayout
   android:id="@+id/rl_description_dialog"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:orientation="horizontal"
   android:padding="15dp">
   <EditText
       android:id="@+id/description_edittxt"
       android:layout_weight="1"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:padding="15dp"
       android:hint="@string/description_hint"
       android:textColorHint="@color/grey"
       android:layout_margin="20dp"
       android:gravity="top|left"
       android:inputType="text" />
   <ImageButton
       android:layout_width="@dimen/mic_image"
       android:layout_height="@dimen/mic_image"
       android:layout_alignRight="@+id/description_edittxt"
       app2:srcCompat="@drawable/ic_mic_black"
       android:layout_gravity="center"
       android:background="@color/transparent"
       android:paddingEnd="10dp"
       android:paddingTop="12dp"
       android:id="@+id/voice_input"/>
</LinearLayout>

Function to prompt dialog box

We have added a function to prompt the dialog box from anywhere in the application. getDescriptionDialog() function is used to prompt the description dialog box. getDescriptionDialog() returns EditText which can be further be used to manipulate the text in the EditText. Please follow the following steps to inflate description dialog box in the activity.

First,

In the getDescriptionDialog() function we will inflate the layout by using getLayoutInflater function. We will pass the layout id as an argument in the function.

public EditText getDescriptionDialog(final ThemedActivity activity, AlertDialog.Builder descriptionDialog){
final View DescriptiondDialogLayout = activity.getLayoutInflater().inflate(R.layout.dialog_description, null);

Second,

Get the TextView in the description dialog box.

final TextView DescriptionDialogTitle = (TextView) DescriptiondDialogLayout.findViewById(R.id.description_dialog_title);

Third,

Present the dialog using cardview to make use of the material design. Then take an instance of the EditText. This EditText can be further used to input text from the user either by text or Voice Recognition.

final CardView DescriptionDialogCard = (CardView) DescriptiondDialogLayout.findViewById(R.id.description_dialog_card);
EditText editxtDescription = (EditText) DescriptiondDialogLayout.findViewById(R.id.description_edittxt);

Fourth,

Set onClickListener when the user clicks the mic image icon. This onClicklistener will prompt the voice Recognition in the activity. We need to specify the language for the speech to text input. In the case of Phimpme its English so “en-US”. We have set the maximum results to 15.  

ImageButton VoiceRecognition = (ImageButton) DescriptiondDialogLayout.findViewById(R.id.voice_input);
VoiceRecognition.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       // This are the intents needed to start the Voice recognizer
       Intent i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
       i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
       i.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 15); // number of maximum results..
       i.putExtra(RecognizerIntent.EXTRA_PROMPT, R.string.caption_speak);
       startActivityForResult(i, REQ_CODE_SPEECH_INPUT);

   }
});

Putting Text in the EditText

After Voice Recognition prompt ends the onActivityResult function checks to see if the data is received or not.

if (requestCode == REQ_CODE_SPEECH_INPUT && data!=null) {

We get the spoken text from intent data.getString() and store it in ArrayList. To store the received data in a string we need to get the first string from the ArrayList.

ArrayList<String> result = data
       .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
voiceInput = result.get(0);

Setting the received data in the the EditText

editTextDescription.setText(voiceInput);

Conclusion

Using Voice recognition is a quick and simple way to add a long description on the image. It’s Speech to Text feature works without many mistakes and is useful in our Phimpme Android application.

Github

https://github.com/fossasia/phimpme-android

Resources

Tutorial for speech to Text: https://www.androidhive.info/2014/07/android-speech-to-text-tutorial/

To add description dialog box: https://developer.android.com/guide/topics/ui/dialogs.html

Continue ReadingAdding Voice Recognition in Description Dialog Box in Phimpme project

Getting Image location in the Phimpme Android’s Camera

The Phimpme Android app along with a decent gallery and accounts section comes with a nice camera section stuffed with all the features which a user requires for the day to day usage. It comes with an Auto mode for the best experience and also with a manual mode for the users who like to have some tweaks in the camera according to their own liking. Along with all these, it also has an option to get the accurate coordinates where the image was clicked. When we enable the location from the settings, it extracts the latitude and longitude of the image when it is being clicked and displays the visible region of the map at the top of the image info section as depicted in the screenshot below.

In this tutorial, I will be discussing how we have implemented the location functionality to fetch the location of the image in the Phimpme app.

Step 1

For getting the location from the device, the first step we need is to add the permission in the androidmanifest.xml file to access the GPS and the location services. This can be done using the following lines of code below.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

After this, we need to download install the google play services SDK to access the Google location API. Follow the official google developer’s guide on how to install the Google play services into the project from the resources section below.

Step 2

To get the last known location of the device at the time of clicking the picture we need to make use of the FusedLocationProviderClient class and need to create an object of this class and to initialise it in the onCreate method of the camera activity. This can be done using the following lines of code below:

private FusedLocationProviderClient mFusedLocationClient;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

After we have created and initialised the object mFusedLocationClient, we need to call the getLastLocation method on it as soon as the user clicks on the take picture button in the camera. In this, we can also set onSuccessListener method which will return the Location object when it successfully extracts the present or the last known location of the device. This can be done using the following lines of code below:

mFusedLocationClient.getLastLocation()
       .addOnSuccessListener(this, new OnSuccessListener<Location>() {
           @Override
           public void onSuccess(Location location) {
               if (location != null) {
            //Get the latitude and longitude here
                  }

After this, we can successfully extract the latitude and the longitude of the device in the onSuccess method of the code snippet provided below and can store it in the shared preference to get the map view of the coordinates from a different activity of the application later on when the user tries to get the info of the images.

Step 3

After getting the latitude and longitude, we need to get the image view of the visible region of the map. We can make use of the Glide library to fetch the visible map area from the url which contains our location values and to set it to the image view.

The url of the visible map can be generated using the following lines of code.

String.format(Locale.US, getUrl(value), location.getLatitude(), location.getLongitude());

This is how we have added the functionality to fetch the coordinates of the device at the time of clicking the image and to display the map in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository.

Resources

  1. Google Developer’s : Location services guide – https://developer.android.com/training/location/retrieve-current.html
  2. Google Developer’s : Google play services SDK guide – https://developer.android.com/studio/intro/update.html#channels
  3. GitHub : Open camera Source Code –  https://github.com/almalence/OpenCamera
  4. GitHub : Phimpme Android – https://github.com/fossasia/phimpme-android/
  5. GitHub : Glide library – https://github.com/bumptech/glide

 

Continue ReadingGetting Image location in the Phimpme Android’s Camera

Zooming Feature in the Phimpme Android’s Camera

The Phimpme Android application comes with a complete package of camera, Edit images, sharing and gallery functionalities. It has a well featured and fully functional camera with all the capabilities that a user expects from a camera application. One such feature in the Phimpme Android application is the zooming functionality. It provides the user the option to zoom in using the pinch gesture of the fingers or the user can select the settings to zoom in from the volume buttons. In this tutorial, I will be explaining how I achieved the zooming functionality in the Phimpme Android app.

Step 1

The first thing we need to do is to check whether the device will support the zoom in functionality or not to avoid random crashes while runtime of the application and while performing the zoom action in case the camera of the device doesn’t support this feature. This can be done by the following lines of code:

Camera.Parameters params = mCamera.getParameters();
Boolean supports = params.isZoomSupported();

Step 2

Now after getting the camera parameters and checking whether the camera supports the zoom in functionality, we need to add the touch listener to the surface view of the camera so that we can get the touch locations and the finger spacing of the user to get the pinch to zoom in functionality. This can be done using the following line of code.

surfaceView.setOnTouchListener(this);

Whenever the user touches the screen this touch listener gives a callback to the overridden onTouchEvent method and passes the MotionEvent to the function. The motion event object in Android handles the movement reports. Now in the onTouchEvent method, we calculate the finger spacing between the two fingers and calculate the approximate amount by which the user wants to zoom in. The finger spacing can be calculated using the following lines of code.

float x = event.getX(0) - event.getX(1);
   float y = event.getY(0) - event.getY(1);
   return FloatMath.sqrt(x * x + y * y);

After getting the finger spacing we need to cancel the auto focus of the camera before performing the zoom action so that the application does not crash. This can be achieved by a single line of code below.

mCamera.cancelAutoFocus();

Step 3

The final step is to set the zoom level in the camera application by calculating the zoom level by using the finger spacing. For this, first we need to get the max zoom level supported by the device so that we do not apply the zoom level that is not supported by the device. The calculation of max zoom level and setting of the desired zoom level by the user can be performed by using the following lines of code.

int maxZoom = params.getMaxZoom();
   int zoom = params.getZoom();
   float newDist = getFingerSpacing(event);
   if (newDist > mDist) {
       //zoom in
       if (zoom < maxZoom)
           zoom++;
   } else if (newDist < mDist) {
       //zoom out
       if (zoom > 0)
           zoom--;
   }
   mDist = newDist;
   params.setZoom(zoom);

This is how we have achieved the functionality of zooming in and clicking pictures in the Phimpme Android application. To get the full source code and to know how to use the volume control buttons to zoom in/out, please refer to the Phimpme Android repository.

Resources

  1. GitHub – Open camera source code : https://github.com/almalence/OpenCamera
  2. Android developer’s guide – MotionEvents in Android : https://developer.android.com/reference/android/view/MotionEvent.html
  3. StackOverflow – Pinch to zoom functionality : https://stackoverflow.com/questions/8120753/android-camera-preview-zoom-using-double-finger-touch
  4. GitHub – Phimpme Android repository : https://github.com/fossasia/phimpme-android
Continue ReadingZooming Feature in the Phimpme Android’s Camera

Drawing Lines on Images in Phimpme

In the editing section of the Phimpme app, we want a feature which lets the user write something on the image in their own handwriting. The user can also select different colour palette available inside the app. We aligned this feature in our editor section as Phimpme Image app allows a user to use our custom camera with the large number of editing options (Enhancement, Transform, Applying Stickers, Applying filters and writing on images). In this post, I am explaining how I implemented the draw feature in Phimpme Android app.

Let’s get started

Step -1: Create bitmap of Image and canvas to draw

The first step is to create a bitmap of Image on which you want to draw lines. Now we need a canvas to draw and canvas requires bitmap to work. So in this step, we will create a bitmap and new canvas to draw the line.

BitmapFactory.Options bmOptions = new BitmapFactory.Options();

Bitmap bitmap =  BitmapFactory.decodeFile(ImagePath, bmOptions);

Canvas canvas = new Canvas(bitmap);

Once the canvas is initialized, we use paint class to draw on the canvas.

Step-2: Create Paint class to draw on canvas

In this step, we will create a new Paint class with some properties like colour, Stroke Width and Coordinate where we want to draw a line and it can be done by using the following code.

Paint paint = new Paint();

paint.setColor(Color.rgb(255, 153, 51));

paint.setStrokeWidth(10);

int startx = 50;

int starty = 90;

int endx = 150;

int endy = 360;

canvas.drawLine(startx, starty, , endy, paint);

The above code will result in a straight line on the canvas like the below screenshot.

Step-3: Add support to draw on touch dynamically

In step 2 we have added the feature to draw a straight line, but what if the user wants to draw the lines on canvas with on touch event. So to achieve this we have to apply onTouchListener and applying coordinates dynamically and it can be done by using the following code.

@Override

public boolean onTouchEvent(MotionEvent event) {

 boolean ret = super.onTouchEvent(event);

 float x = event.getX();

 float y = event.getY();

 switch (event.getAction()) {

     case MotionEvent.ACTION_DOWN:

         ret = true;

         last_x = x;

         last_y = y;

         break;

     case MotionEvent.ACTION_MOVE:

         ret = true;

         canvas.drawLine(last_x, last_y, x, y);

         last_x = x;

         last_y = y;

         this.postInvalidate();

         break;

     case MotionEvent.ACTION_CANCEL:

     case MotionEvent.ACTION_UP:

         ret = false;

         break;

 }

 return ret;

}

Now the above code will let you draw the lines dynamically. But, how? The answer is In on touch event, I am fetching coordinates of touch and applying it dynamically to a canvas. Now our feature is ready to draw the lines on canvas with finger touch.

Drawing line in Phimpme Editor

Step – 4: Adding eraser functionality

Till now we have added the draw on canvas functionality, but what if the user wants to erase particular area. So now we have to implement the eraser functionality. It is very simple now what we have to do again we have to draw, but we will set paint color to the transparent color. It will draw the transparent color on the existing line which results in the previous picture and it looks like we are erasing. It can be done by adding one line.

paint.setColor(eraser ? Color.TRANSPARENT : color);

Now we have done by drawing the lines on an image and erasing functionality.

Resources:

Continue ReadingDrawing Lines on Images in Phimpme

Upload Image to Imgur Anonymously Using Volley in Phimpme Android app

As Phimpme Android is an image app in which lets you share your image on multiple platform without installing that apps like Twitter, Facebook, Pinterest and Imgur. Imgur is the best place to share and enjoy the most awesome images on the Internet. Imgur provides APIs to  upload image from your account as well as anonymously. In this blog I am going to explain how I added the imgur upload feature in Phimpme Android app.

I have implemented upload to  Imgur anonymously. There is step by step guide to implementing it.

Step 1: Register your application on Imgur.

To register your application click here, For more detail read their documentation here Imgur API site.

Once you have registered your application, you will be provided with two keys, Client ID and Client Secret. Save them, we will need them later to upload an image and for = authentication purposes.

Step-2: Add a networking library in your Gradle, I have used volley.

Olley is a good networking library, works well for both API requests and File upload. To add volley in the project, add the following dependency

'com.android.volley:volley:1.0.0'

Step-3 Convert your image into the desired format to upload.

Imgur three kinds of images: A binary file, base64 data, or  URL of an image. (Up to 10MB).

In phimpme Android, we are uploading base64 image string.

So, we have to first convert our image to the bitmap and then convert the bitmap to base64. I recommend using an Image library to decode bitmap otherwise, there are chances of OutOfMemory exception thrown for large image files.

To convert bitmap to base64 string

public static String get64BaseImage (Bitmap bmp) {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
       byte[] imageBytes = baos.toByteArray();
       return Base64.encodeToString(imageBytes, Base64.DEFAULT);
   }

Best practice to add such methods into theutility class. Also, you can apply the image compression in above if you want to reduce the image size, here number 100 represents, preserve the  100% quality of the image.

Step-4:  Now we need 2 things, add image string in body and add AUTHENTICATION key in headers of the request.

We have added two methods to do above mentioned tasks.

  1. To upload the image data to Imgur.
  2. To add a header in our network request.

The header is required for Imgur to authenticate the client who uploads the file and your authentication key is your  CLIENT-ID, which we have generated in step 1.

@Override
               protected Map<String, String> getParams() throws AuthFailureError {
                   Map<String, String> parameters = new HashMap<String, String>();
                   parameters.put("image", imageString);
                   if(caption!=null && !caption.isEmpty())
                       parameters.put("title",caption);
                   return parameters;
               }


Now add the headers to authenticate the client.The above code contains the body part with the key as “image” and value as the imageString data, which was the result of get64BaseImage () method.

   @Override
               public Map<String, String> getHeaders() throws AuthFailureError {
                   Map<String, String> headers = new HashMap<String, String>();
                   headers.put("Authorization",”Client-Id {client-id});
                   return headers;
               }

Override the getHeader method of Volley library and return a map which has a key named “Authorization” and value is client id of Imgur.

Now we are ready to upload an image on Imgur through Phimpme Android app.

The problem I faced:

Whenever I was trying to upload large size images, I was getting volleytimeout exception, by default connection timeout was not sufficient to upload large files, so I resolved this error by adding below line in the request policy.

           request.setRetryPolicy(new DefaultRetryPolicy( 50000, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

Now it works seamlessly with large files even on slow internet network and we are receiving the URL of the image in the response.

Resources :

Continue ReadingUpload Image to Imgur Anonymously Using Volley in Phimpme Android app