Using Map View to Display Location of Clicked Image in Phimpme

Previously in Phimpme Android app we used to display all the images on the map, based on their location they have taken. In the upcoming version, we are introducing mapview to specify the location when user checks out the details of the image. In this post, I am explaining that how I have implemented Google’s mapView in Phimpme. Note: The prerequisite to display image location in the map view, an image should have geolocation in its meta data.

Let’s get started

Step -1 : First, enable the setting to ‘Show mapview in Image description’ and save it somewhere.

Although, it’s your choice you want to give users choice to view map or not.

First, we need to turn on the movie visibility from map provider in settings. Right now we are adding two maps in our list Google maps and openstreetmap.

Choose Map Provider from the list in Phimpme

Once you choose your preference, it will get stored in sharedPref. As we are displaying the map in the image details so we need to add Image view of map.

Step -2 : Add a ImageView in your XML, in which we will display map.

<ImageView
   android:id="@+id/photo_map"
   android:layout_width="match_parent"
   android:layout_height="150dp"
   android:visibility="gone"
/>

Keep default visibility of mapview is GONE, If a user will enable map view in setting then we will make this image visible.

Step -3 : Load image with map in ImageView:

Good things are that StaticMapProvier gives you the URL of the image in corresponding to particular GeoLocation, which actually is a view of the map.

Now we need to display mapview when the user taps on details of an image.

ImageView imgMap = (ImageView) dialogLayout.findViewById(R.id.photo_map);
final GeoLocation location;
if ((location = f.getGeoLocation()) != null) {
   PreferenceUtil SP = PreferenceUtil.getInstance(activity.getApplicationContext());

   StaticMapProvider staticMapProvider = StaticMapProvider.fromValue(
           SP.getInt(activity.getString(R.string.preference_map_provider), StaticMapProvider.GOOGLE_MAPS.getValue()));

   Glide.with(activity.getApplicationContext())
           .load(staticMapProvider.getUrl(location))
           .asBitmap()
           .centerCrop()
           .animate(R.anim.fade_in)
           .into(imgMap);

To load an image, we used Glide Image library, you can use any library of your choice.

MapView on the top of dialog box in Phimpme

Step 4: Open navigation on the tap of mapView or Image.

Attach a click listener on the imageView and on click of that create a Uri correspond to geolocation and through an Intent to Android to view that link, it will open Google maps with navigation.

 String uri = String.format(Locale.ENGLISH, "geo:%f,%f?z=%d", location.getLatitude(), location.getLongitude(), 17);
            activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(uri)));

Resources

Continue ReadingUsing Map View to Display Location of Clicked Image in Phimpme

Storing a Data List in Phimpme Android

In Phimpme Android, it is required to store all the available camera parameters like a list of ISO values, available camera resolution etc. so that it can be displayed to the user in the camera settings. In Phimpme, we have stored these list of data in SharedPreferences with some modifications. As we cannot store a list directly in SharedPreference, in this post I will be discussing how we achieved this in Phimpme Android application.

To store the ArrayList you have to create a function that will convert the array into a string by using some symbol.

Step – 1

First, Create a class say TinyDB which contains functions to store an array in sharedPreferences.

public class TinyDB
{
private SharedPreferences preferences;
public TinyDB(Context appContext) {
preferences = PreferenceManager.getDefaultSharedPreferences(appContext);
}
}

Step – 2

Create functions to convert the array into string and store in sharedPreferences.

putListInt() method will convert the string ArrayList to String and store in sharedPreferences.

Similarly, putListString() method will convert the integer ArrayList to string and store in sharedPreferences.

public void putListInt(String key, ArrayList<Integer> intList) {
  if (key == null) return;
  if (intList==null) return;
  Integer[] myIntList = intList.toArray(new Integer[intList.size()]);
  preferences.edit().putString(key, TextUtils.join(“‚‗‚”, myIntList)).apply();
}

  
public void putListString(String key, ArrayList<String> stringList) {
  if (key == null) return;
  if (stringList ==null)return;
  String[] myStringList = stringList.toArray(new String[stringList.size()]);
  preferences.edit().putString(key, TextUtils.join(“‚‗‚”, myStringList)).apply();
}

 

 

Now create the object of TinyDB.class to call the above functions using tinyDb object.

Now our data is saved in sharedPreference to get this data we have to create a getter for the ArrayList.

 

Step-3

Add two functions in TinyDB.class to get the string and integer ArrayList.

public ArrayList<String> getListString(String key) {
        return new ArrayList<String>(Arrays.asList(TextUtils.split(preferences.
=getString(key, “”), “‚‗‚”)));
}



public ArrayList<Integer> getListInt(String key) {
  String[] myList = TextUtils.split(preferences.getString(key, “”), “‚‗‚”);
  ArrayList<String> arrayToList = new ArrayList<String>(Arrays.asList(myList));
  ArrayList<Integer> newList = new ArrayList<Integer>();

  for (String item : arrayToList)
      newList.add(Integer.parseInt(item));

  return newList;
}

Now to get the saved integer and string ArrayList simply call this function by creating an instance of TinyDB.class.

The below screenshot depicts how we have stored the list of camera resolutions in SharedPreference using TinyDB class.

So this is how you can store the entire ArrayList in sharedPreferences. For more detail, you can see the TinyDb.class in our Phimpme project.

Resources:  

https://stackoverflow.com/questions/7057845/save-arraylist-to-sharedpreferences

http://blog.nkdroidsolutions.com/arraylist-in-sharedpreferences/

http://findnerd.com/list/view/Save-ArrayList-of-Object-into-Shared-Preferences-in-Android/510?page=10&ppage=3

https://github.com/fossasia/phimpme-android/blob/development/app/src/main/java/org/fossasia/phimpme/opencamera/Camera/TinyDB.java

 

 

Continue ReadingStoring a Data List in Phimpme Android

Protecting Gallery Images in Phimpme Android

Encrypting media is very important to ensure privacy and for this some users install apps to lock protect their images with a password or any other security method i.e Gallery lock. In Phimpme, along with the camera, accounts and gallery, we are providing an inbuilt encryption option in which user can set password to hide media and to protect from deletion of media. In this post I am explaining how we implemented the security feature in the Phimpme Android app.

Step-1

In Phimpme I created a SecurityHelper class which contains the user password information along with the details of where the user has applied for the protection.

public class SecurityHelper {
   private boolean activeSecurity;
   private String passwordValue;
   private Context context;
   public SecurityHelper(Context context){
       this.context = context;
       }
}

The dialog box to enter the password in Phimpme.

Step -2

Now in phimpme, we will ask the user to enter the password and it gets to be done using edittext and on click on submit the password gets stored in sharedPreferences in preference_use_password in Strings.xml.

Step – 3

The next step is to protect Phimpme gallery so we have to check before deleting any images using gallery it can be done using SecurityHelper.isActiveSecurity() method.

If security option is activated, we will provide the dialog box in which user have to enter the password and we will compare the password with the saved password in Sharedpreference, if it matches then we will allow the deletion of the selected media.

if (securityObj.isActiveSecurity()) {
AlertDialog passwordDialog = passwordDialogBuilder.create();
           passwordDialog.show();

           passwordDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   // if password is correct, call DeletePhotos and perform deletion
                   if (securityObj.checkPassword(editTextPassword.getText().toString())) {
                       passwordDialog.dismiss();
                       new DeletePhotos();
                   }
                   // if password is incorrect, don't delete and notify user of incorrect password
                   else {
                       Toast.makeText(getApplicationContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show();
                       editTextPassword.getText().clear();
                       editTextPassword.requestFocus();
                   }
               }
           });
       } else new DeletePhotos().execute();
   }
});

This is how we are providing the inbuilt encryption to protect gallery in Phimpme-Android.

Resources

 

 

Continue ReadingProtecting Gallery Images in Phimpme Android

Adding Multiple Themes in Phimpme Android

In Phimpme-Android we decided to add a new feature that is providing multiple themes to the users. We have 3 types of themes in Phimpme Dark Theme, Light Theme and Amoled Theme. In this post, I am explaining how I added multiple themes support in phimpme android.

 Choose Theme in Phimpme Dialog

You need a Helper class that will store the data about the theme and all the colors related to a theme.

Before you begin you need to create a Helper class. In Phimpme I created a Helper class as ThemeHelper

public class ThemeHelper {

 public static final int DARK_THEME = 2;
 public static final int LIGHT_THEME = 1;
 public static final int AMOLED_THEME = 3;

 private PreferenceUtil SP;
 private Context context;

 private int baseTheme;
 private int primaryColor;
 private int accentColor;

 public ThemeHelper(Context context) {
  this.SP = PreferenceUtil.getInstance(context);
  this.context = context;
  updateTheme();
 }
}

Which contains all the basic method to get colors for textview, icon, toolbar, switch, imageview, background and app primary color.

Now you to provide user to select theme and it can be done using dialog box. Once the user selected any of the theme we have to update that theme and it can be done by following code :

 public void updateTheme(){
  this.primaryColor = SP.getInt(context.getString(R.string.preference_primary_color),
        getColor(R.color.md_light_blue_300));
  this.accentColor = SP.getInt(context.getString(R.string.preference_accent_color),
        getColor(R.color.md_light_blue_500));
  baseTheme = SP.getInt(context.getString(R.string.preference_base_theme), LIGHT_THEME);
 }

Now we have updated the our theme in Phimpme now we have to set the color according to a theme.

To get colors of all components we need to add some function in our helper class which will provide us the colors according to the theme.

As I said we are having 3 themes in Phimpme so I used 3 case to compare which theme user has selected.

I have added the functions to get colors for background, text and subtext as follows in phimpme.

public int getBackgroundColor(){
  int color;
  switch (baseTheme){
    case DARK_THEME:color = getColor(R.color.md_dark_background);break;
    case AMOLED_THEME:color = getColor(R.color.md_black_1000);break;
    case LIGHT_THEME:
    default:color = getColor(R.color.md_light_background);
  }
  return color;
 }



 public int getTextColor(){
  int color;
  switch (baseTheme){
    case DARK_THEME:color = getColor(R.color.md_grey_200);break;
    case AMOLED_THEME:color = getColor(R.color.md_grey_200);break;
    case LIGHT_THEME:
    default:color = getColor(R.color.md_grey_800);
  }
  return color;
 }

 public int getSubTextColor(){
  int color;
  switch (baseTheme){
    case DARK_THEME:color = getColor(R.color.md_grey_400);break;
    case AMOLED_THEME:color = getColor(R.color.md_grey_400);break;
    case LIGHT_THEME:
    default:color = getColor(R.color.md_grey_600);
  }
  return color;
 }

In the above functions, I am comparing which theme user has selected and returned the color according to the theme.

Now set the color to text by using above function you don’t need care which theme user has selected because those function will check and return the color according to the theme.

So it can be done simply,

textview.setTextColor(getTextColor());
editText.setTextColor(getTextColor());
editText.setHintTextColor(getSubTextColor());

                                     Light Theme &  Dark Theme (Phimpme)

Resources:

https://github.com/fossasia/phimpme-android/blob/development/app/src/main/java/org/fossasia/phimpme/leafpic/util/ThemeHelper.java

http://www.hidroh.com/2015/02/16/support-multiple-themes-android-app/

Continue ReadingAdding Multiple Themes in Phimpme Android

Use of SwipeRefreshLayout in Phimpme

In an image application, the first thing we want is to get a list of all images from the users device at the start of the application in the splash screen. But what if the number of images in the device is altered by deleting or copying any other images to the device when the application is running. This is where the swipe refresh layout helps us to obtain the real-time list of images from our device by just swiping vertically downwards.

In the Phimpme application, we have made use of the swipe refresh layout to update the image according to the latest data. In this post, I will be discussing how we achieved this in the Phimpme application with the help of some code examples.

Steps to implement the SwipeRefreshLayout:

  1. The first thing we need to do is add the support library to our project build.gradle file.
dependencies {
 compile 'com.android.support:recyclerview-v7:25.3.1'
 compile 'com.android.support:support-v4:25.3.1'
}

2. Now add the SwipeRefreshLayout in Activity.xml file where you want to implement the SwipeRefreshLayout with the recyclerView and the child view should match the parent layout. This can be done using the line of code below:

<android.support.v4.widget.SwipeRefreshLayout
   android:id="@+id/swipeRefreshLayout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/height_bottombar" > <android.support.v7.widget.RecyclerView
   android:id="@+id/grid_albums"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_gravity="center_horizontal"
   android:scrollbarThumbVertical="@drawable/ic_scrollbar"
   android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>

3. Now we have to implement the onRefreshListener which handles the refresh operation when a vertical swipe is performed.

Activity.java

SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.sr);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
   @Override
   public void onRefresh() {
   }

});

 

Now we can do anything in onRefresh method which we want to do when user swipes vertically.

For example, we want to refresh the recyclerView with latest images and display the content so this should be done in a background thread.

So we will use AsyncTask to update the data.

  @Override
 public void onRefresh() {
new AsyncTask().execute(); //  This will execute the AsyncTask
   }
});

AsyncTask.java

private class AsyncTask extends AsyncTask<Void, Integer, Void> {


   @Override

   protected void onPreExecute() {

       swipeRefreshLayout.setRefreshing(true);

       super.onPreExecute();

   }


   @Override

   protected Void doInBackground(Void... arg0) {

       // refresh the content of recyclerView here

       return null;

   }


   @Override

   protected void onPostExecute(Void result) {

    swipeRefreshLayout.setRefreshing(false);

   }

}

 

When the user swipes up vertically the progress bar is shown to screen and which can be done by swipeRefreshLayout.setRefreshing(true) in onPreExecute() method.

In doInBackground() method we have to load the content of RecyclerView through an adapter.

Once the data is loaded and set to recyclerView onPostExecute() method is called and now we have to dismiss the loading progress bar by  

  swipeRefreshLayout.setRefreshing(false);

This is how SwipeRefreshLayout works.

The above code helps us to reload the album content in the gallery.

For more details refer here in the Phimpme project for SwipeRefreshLayout.

https://github.com/fossasia/phimpme-android/blob/development/app/src/main/java/vn/mbm/phimp/me/leafpic/activities/LFMainActivity.java

Resources :

https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

https://developer.android.com/training/swipe/add-swipe-interface.html

Continue ReadingUse of SwipeRefreshLayout in Phimpme

Use of ViewPager in Phimpme

Previously GalleryView was used in phimpme android app but as it is now deprecated, I decided to use ViewPager instead of GalleryView.

ViewPager allows us to view data with a horizontal swipe with the help of layoutManager.

Steps to implement the viewPager:

  1. First, add the ViewPager in Activity.xml file where you want to implement the ViewPager. This can be done using the line of code below:
<android.support.v4.view.ViewPager
             android:id="@+id/view_pager"
                android:layout_width="match_parent"
               android:layout_height="match_parent">

</android.support.v4.view.ViewPager>
  1.  To display the content of viewPager we use the viewPagerAdapter. Create new java file ViewPagerAdapter and extends it to PagerAdapter.

ViewPagerAdapter.java

public class ViewPagerAdapter extends PagerAdapter {
}
  1. After extending to PagerAdaper we have to override the two basic methods of PagerAdapter.

First, implement the constructor which helps us to provide the context of activity to ViewPagerAdapter.

You can override by pressing Alt+enter combination, click on “implement methods” and then selects these two methods.

It will implement two methods  

  • getCount()
  • isViewFromObject()

getCount will return the number of items in view pager.

  1. Now we override the few methods which are required to inflate and destroy view in viewPager.

First,

Override the instantiateItem() method it creates the page for given position.

@Override

public Object instantiateItem(ViewGroup container, int position) {
 return super.instantiateItem(container, position);
}

Now we will modify this method to inflate the view for viewPager.

As we want to display imageView in viewPager first we have to inflate the imageView and set Image according to the position of ViewPager.

Next steps,

  • Implement the customView for imageView.
  • And provide the data for  ViewPager i.e Array of images.

Create new custom_layout.xml and add ImageView in it.

<ImageView

   android:layout_width="match_parent"

   android:id="@+id/image_view"

   android:layout_height="match_parent" />

And create an array for images if you want to show images from the local memory so collect path of the images which you want to show with the array name Images.

Now we will use custom_layout layout in our ViewPager instantiateItem() method.

@Override

public Object instantiateItem(ViewGroup container, int position) {

   LayoutInflater layoutInflater = (LayoutInflater)  context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

   View view=  layoutInflater.inflate(R.layout.custom_view,null);

   ImageView imageView = (ImageView)view.findViewById(R.id.image_view);

   imageView.setBackgroundResource(images[position]);

   container.addView(view,0);

   return view;

}

The above code inflates the imageView in ViewPager.

Now we have to override destroyItem() method.  This method will destroy the content of viewPager from given position.

The below code will remove the view which we added in instantiateItem() method.

@Override

public void destroyItem(ViewGroup container, int position, Object object) {
  container.removeView((View) object);
}

Now PagerAdapter is ready, we can use this in our Activity.

  1. Reference the viewPager and set the ViewPagerAdapter to ViewPager.

Activity.java

@Override

protected void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);

   setContentView(R.layout.activity_main);

   ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);

   viewPager.setAdapter(new ViewPagerAdapter(this));

}

The above code will set the pagerAdapter to our viewPager and display the content which we defined in instantiateItem() method of pagerAdapter.

 

This is how viewPager will allow viewing images by swiping horizontally in Phimpme.

Resources:

https://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

https://github.com/fossasia/phimpme-android/pull/407/files

Continue ReadingUse of ViewPager in Phimpme