Display image responses in SUSI.AI Android app

SUSI.AI Android app has many response functionalities ranging from giving simple ANSWER type responses to complex TABLE and MAP type responses. Although, even after all these useful response types there were some missing action types all related to media. SUSI.AI app was not capable of playing any kind of image responses.So, to do this the links received in the response were used to fetch the corresponding image stored in the link.

Since, the app now has two build flavors corresponding to the F-Droid version and PlayStore version respectively it had to be considered that while adding the feature to display images any proprietary software was not included with the F-Droid version.

The JSON response from the server whenever a query for was asked gave the link to the image.  For eg : on querying : “Image of cat “ the server gave the response as :

Actions”: [

       {

         “language”: “en”,

         “type”: “answer”,

         “expression”: “https://pixabay.com/get/e830b1072ef5023ed1584d05fb1d4790e076e7d610ac104496f0c77ea0e9bcbf_640.jpg”

       }

So in the android app just like the usual answer type response a message was displayed with the link to the image present in the message.

Catching IMAGE response :

The image responses are of the type “answer” as seen in the server response above. So we a method had to be devised so that the responses which display the images are caught and displayed. In the file ChatFeedRecyclerAdapter.java a separate code to detect the IMAGE response was added as :

private static final int IMAGE = 17;

Next we must specify that what type of view that is to be used whenever an IMAGE response is encountered by the app. Since the action type is “answer” a specification was required to choose the type of the viewholder. Since the images are only displayed through the pixabay the URL of the images end with either “.jpg” or “.png”. So in the expression of the response if we check that it is a link and also it ends with either “.jpg” or “.png” it will be certain that the response given from the server is an image.

The code to identify the view type :

@Override
public int getItemViewType(int position) {
  ChatMessage item = getItem(position);

  if (item.getId() == -404) return DOTS;
  else if (item.getId() == -405) return NULL_HOLDER;
  else if (item.isDate()) return DATE_VIEW;
  else if (item.getContent().endsWith(“.jpg”) || item.getContent().endsWith(“.png”))
      return IMAGE;

Inflating the layout of type IMAGE

Now after determining that the response will be an image we have to inflate the layout of the viewholder to support images in the onCreateViewHolder() method . The layout  of the image response was inflated as follows :

case IMAGE:
  view = inflater.inflate(R.layout.image_holder, viewGroup, false);
  return new ImageViewHolder(view, clickListener);

Here ImageViewHolder is the view holder that is used for displaying the images , we will discuss it later in the post. Also now in the onBindViewHolder() method of the ChatFeedRecyclerAdapter.java file we have to specify the instance of the view holder if it was to support the image response. It was done as follows :

else if (holder instanceof ImageViewHolder) {
  ImageViewHolder imageViewHolder = (ImageViewHolder) holder;
  imageViewHolder.setView(getData().get(position));
}

ViewHolder for Images :

Like all other viewholders for different variety responses from the server a viewholder to display the images was also needed to be included in the app. So, ImageViewHolder.java was created which handles the images to de displayed in the app. In the setView() method ChatMessage object is passed and this object is  used to get the image url so that it is used to display the image using Picasso.

public void setView(ChatMessage model) {
  this.model = model;

  if (model != null) {
      imageURL = model.getContent();
      try {
          Picasso.with(itemView.getContext())
                  .load(imageURL)
                  .placeholder(R.drawable.ic_susi)
                  .into(imageView);
      } catch (Exception e) {
          Timber.e(e);
      }
  }

And on clicking the image we can view the image on full screen using a custom chrome tab as follows  :

imageView.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
      CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
      CustomTabsIntent customTabsIntent = builder.build();
      customTabsIntent.launchUrl(itemView.getContext(), Uri.parse(imageURL));
  }
});

Conclusion :

References :

  1. Susi server response in case of images : https://api.susi.ai/susi/chat.json?timezoneOffset=-330&q=image+of+cat
  2. Pixabay is the source used for fetching images : https://pixabay.com
  3. Display images using Picasso : https://guides.codepath.com/android/Displaying-Images-with-the-Picasso-Library

 

Continue ReadingDisplay image responses in SUSI.AI Android app

Adding Support for Displaying Images in SUSI iOS

SUSI provided exciting features in the chat screen. The user can ask a different type of queries and SUSI respond according to the user query. If the user wants to get news, the user can just ask news and SUSI respond with the news. Like news, SUSI can respond to so many queries. Even user can ask SUSI for the image of anything. In response, SUSI displays the image that the user asked. Exciting? Let’s see how displaying images in the chat screen of SUSI iOS is implemented.

Getting image URL from server side –

When we ask susi for the image of anything, it returns the URL of image source in response with answer action type. We get the URL of the image in the expression key of actions object as below:

actions:
[
{
language: "en",
type: "answer",
expression:
"https://pixabay.com/get/e835b60f2cf6033ed1584d05fb1d4790e076e7d610ac104496f1c279a0e8b0ba_640.jpg"
}
]

 

Implementation in App –

In the app, we check if the response coming from server is image URL or not by following two methods.

One – Check if the expression is a valid URL:

func isValidURL() -> Bool {
if let url = URL(string: self) {
return UIApplication.shared.canOpenURL(url)
}
return false
}

The method above return boolean value if the expression is valid or not.

Two – Check if the expression contains image source in URL:

func isImage() -> Bool {
let imageFormats = ["jpg", "jpeg", "png", "gif"]

if let ext = self.getExtension() {
return imageFormats.contains(ext)
}

return false
}

The method above returns the boolean value if the URL string is image source of not by checking its extension.

If both the methods return true, the expression is a valid URL and contain image source, then we consider it as an Image and proceed further.

In collectionView of the chat screen, we register ImageCell and present the cell if the response is the image as below.

Registering the Cell –

register(_:forCellWithReuseIdentifier:) method registers a class for use in creating new collection view cells.

collectionView?.register(ImageCell.self, forCellWithReuseIdentifier: ControllerConstants.imageCell)

Presenting the Cell using cellForItemAt method of UICollectionView

The implementation of cellForItemAt method is responsible for creating, configuring, and returning the appropriate cell for the given item. We do this by calling the dequeueReusableCell(withReuseIdentifier:for:) method of the collection view and passing the reuse identifier that corresponds to the cell type we want. That method always returns a valid cell object. Upon receiving the cell, we set any properties that correspond to the data of the corresponding item, perform any additional needed configuration, and return the cell.

if let expression = message.answerData?.expression, expression.isValidURL(), expression.isImage() {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ControllerConstants.imageCell, for: indexPath) as? ImageCell {
cell.message = message
return cell
}
}

In ImageCell, we present a UIImageView that display the image. When cell the message var, it call downloadImage method to catch and display image from server URL using Kingfisher method.

In method below –

  1. Get image URL string and check if it is image URL
  2. Convert image string to image URL
  3. Set image to the imageView
func downloadImage() {
if let imageString = message?.answerData?.expression, imageString.isImage() {
if let url = URL(string: imageString) {
imageView.kf.setImage(with: url, placeholder: ControllerConstants.Images.placeholder, options: nil, progressBlock: nil, completionHandler: nil)
}
}
}

We have added a tap gesture to the imageView so that when the user taps the image, it opens the full image in the browser by using the method below:

@objc func openImage() {
if let imageURL = message?.answerData?.expression {
if let url = URL(string: imageURL) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}

 

Final Output –

Resources –

  1. Apple’s Documentations on collectionView(_:cellForItemAt:) method
  2. Apple’s Documentations on register(_:forCellWithReuseIdentifier:) method
  3. SUSI iOS Link: https://github.com/fossasia/susi_iOS
  4. SUSI API Link: http://api.susi.ai/
  5. Kingfisher – A lightweight, pure-Swift library for downloading and caching images from the web
Continue ReadingAdding Support for Displaying Images in SUSI iOS

Option to exclude albums in Phimpme Android Application

In the Phimpme Android Application, users can perform various operations on the albums available such as move, creating a .zip file of the album, rename an album, delete the album and much more. However one another important functionality that has been implemented in the application is the option to exclude album/albums. In this post we will be discussing how we achieved the functionality to exclude albums in Phimpme Android Application.

Step 1

First we need to keep track of the albums selected by the user to exclude. This can be done by storing the selected albums in an Arraylist<Album> which can be referred later when required for the process of exclusion. The storing of the albums can be done with the help of following lines of code.

private int toggleSelectAlbum(int index) {
if (dispAlbums.get(index) != null) {
  dispAlbums.get(index).setSelected(!dispAlbums.get(index).isSelected());
  if (dispAlbums.get(index).isSelected()) selectedAlbums.add(dispAlbums.get(index));
  else selectedAlbums.remove(dispAlbums.get(index));
}
return index;
}

Step 2

After the selected albums are stored in an Arraylist<Album>, a function call of excludeSelectedAlbums() of HandlingAlbums class is done passing in Context as the parameter. In the method excludeSelectedAlbums() the selected albums are retrieved from the Arraylist one by one and another method excludeAlbum() is called with the album, context being passed as the parameters. The code snippet performing the above operation is provided below.

public void excludeSelectedAlbums(Context context) {
for (Album selectedAlbum : selectedAlbums)
  excludeAlbum(context, selectedAlbum);
clearSelectedAlbums();
}

Step 3

Thereafter an instance of class CustomsAlbumHelper is created and excludeAlbum() method is called with path of the album passed as parameter, and the selected album is removed from the list containing the currently displayed albums. Code snippets for the above operations are provided below.

private void excludeAlbum(Context context, Album a) {
CustomAlbumsHelper h = CustomAlbumsHelper.getInstance(context);
h.excludeAlbum(a.getPath());
dispAlbums.remove(a);
}

Step 4

Now in the excludeAlbum() method of CustomsAlbumHelper class a writable instance of albums_settings sqlite database is obtained. A check is performed if the current album is present in the albums table or not, if not then a row representing the current album is created. Thereafter the excluded value for the current album in the table is updated to integer 1 denoting that the album is excluded. The code snippet required for the above mentioned operations are provided below.

public void excludeAlbum(String path) {
  SQLiteDatabase db = this.getWritableDatabase();
  checkAndCreateAlbum(db, path);
  ContentValues values = new ContentValues();
  values.put(ALBUM_EXCLUDED, 1);
  db.update(TABLE_ALBUMS, values, ALBUM_PATH+“=?”, new String[]{    path});
  db.close();
}

This is how we have achieved the functionality of excluding albums 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.

The screenshot for the display of the excluded albums is provided below.

Resources

  1. Android Developer Guide –https://developer.android.com/training/data-storage/sqlite.html
  1. Github-Phimpme Android Repository –https://github.com/fossasia/phimpme-android/
  1. Sqlite Operations Tutorial – https://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Continue ReadingOption to exclude albums in Phimpme Android Application

Option to hide albums in Phimpme Android Application

In Phimpme Android Application, users can perform various operations on the albums available such as move, creating a .zip file for the album, delete the album, exclude an album, rename an album, pin an album to the top and more. However one another important functionality that has been added in the application is the option to hide  album/albums. So in this post I will be discussing how we achieved the functionality to hide albums in Phimpme Android Application.

Step 1

First we need to get the albums which are selected to be hidden. This can be done by storing the selected items in an Arraylist<Album> which will keep track of the users choice to hide albums. This can be achieved with the following lines of code.

private int toggleSelectAlbum(int index) {
if (dispAlbums.get(index) != null) {
  dispAlbums.get(index).setSelected(!dispAlbums.get(index).isSelected());
  if (dispAlbums.get(index).isSelected()) selectedAlbums.add(dispAlbums.get(index));
  else selectedAlbums.remove(dispAlbums.get(index));
}
return index;
}

Step 2

After storing of the albums to be hidden a function hideSelectedAlbums() is called with Context being passed as the parameter. Now inside this function we retrieve the albums looping through the Arraylist that stores the albums to be hidden and call another function hideAlbum() passing in the album and context as the parameters. The code snippet representing the above operation is given below.

public void hideSelectedAlbums(Context context) {
for (Album selectedAlbum : selectedAlbums)
  hideAlbum(selectedAlbum, context);
clearSelectedAlbums();
}

Step 3.

Now a .nomedia file is added to the directories/albums which are to be hidden and the android Media Scanner System service is triggered thereafter. As a result of the presence of the .nomedia file inside the directory the Media Scanner service won’t scan the particular directory/album thereby the album will not be picked up at the time of displaying the albums. The code snippet to perform the mentioned operation is provided below.

File dirName = new File(path);
File file = new File(dirName, “.nomedia”);
if (!file.exists()) {
try {
  FileOutputStream out = new FileOutputStream(file);
  out.flush();
  out.close();
  scanFile(context, new String[]{ file.getAbsolutePath() });
} catch (Exception e) {
  e.printStackTrace();
}
}

The screenshot for the display of hidden folders is provided below.

This is how we have achieved the functionality of hiding albums 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/reference/android/media/MediaScannerConnection.html
  2. Github-Phimpme Android Repository –https://github.com/fossasia/phimpme-android/
  3. Hiding directories using .nomedia file – http://www.easycodeway.com/2016/08/hide-files-in-android-using-nomedia-file.html
Continue ReadingOption to hide albums in Phimpme Android Application

Displaying Image location Address In Phimpme Android Application

In Phimpme Android application one of the features available is to view the details of any image. The details consists of attributes including Date and time at which the image was captured, size of the image, title, path, EXIF data, description added to the image, location etc. However in the location attribute the location coordinates of the image as well as the location address can be displayed depending on the user’s preference. The process of obtaining the coordinates from address is called as Geocoding and obtaining string address from coordinates is called reverse Geocoding. So in this post I will be explaining how to implement set of strings denoting the address from the available coordinates.

Step 1

First we need to create an instance of the class Geocoder passing context and function Locale.getDefault() as the parameters.  The function of the attribute Locale.getdefault is provided below.

Locale.getDefault() – It returns the current value of the default locale for the current instance of the Java Virtual Machine. The Java Virtual Machine sets the default locale during startup based on the host environment.The code snippet to perform the above mentioned operation is given below.

Geocoder geocoder = new Geocoder(context, Locale.getDefault());

Step 2

Now a function call of getFromLocation() of the Geocoder class is done where we need to pass the Lattitude and Longitude values of the Location object as parameters. The lattitude and longitudes values can be obtained by the use of the Location object functions getLatitude() and getLongitude() respectively. The function getFromLocation() will return a list of Address objects which will contain the extracted addresses from the passed latitude and longitude values. We also need to pass a third parameter an integer value which will determine the maximum no of addresses to be returned. Here we have requested for a maximum of one address. The following code snippet is used to perform the desired function call.

try {
 List<Address> addressList = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
} catch (IOException e) {
  e.printStackTrace();
}

Step 3

After obtaining the list of Address objects returned from the function call of getFromLocation() we will extract the first address from the list since we want a maximum of 1 address. The Address object will contain information like the address name, country, state, postal code etc. Now the set of strings describing the location can be retrieved with the help of the function getMaxAddressLineIndex() of Address class. The code snippets to perform the above mentioned operations is provided below.

ArrayList<String> addresslines = new ArrayList<String>();
Address address = addressList.get(0);
for(int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
  addresslines.add(address.getAddressLine(i));
}
details.put(context.getString(R.string.location), TextUtils.join(System.getProperty(“line.separator”),
      addresslines));

The screenshot displaying the location address is provided below.

This is how we have achieved the functionality of displaying location address in a set of strings from available coordinates 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/location/display-address.html

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

3.Address Class Guide- https://developer.android.com/reference/android/location/Address.html

 

Continue ReadingDisplaying Image location Address In Phimpme Android Application

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

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

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

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