Thursday 24 December 2015

Curious Case of RecyclerView


Sorry for the title as I was supposed to write Serious instead of Curious but no problem that will work too.

Assumptions :
1. Done with the most simplest implementation of the RecyclerView.
2. Provided options to each list item for deleting it.

So in this post we will not discuss about the RecyclerView implementation and adding options to add/delete item from it. 

We will be discussing about an issue that will occur for sure if implementation is not done with some care.

While implementation RecyclerView, there appears an inconsistency while adding and deleting items leading to an issue with addition and deletion of items from the list due to list not getting reset causing unchanged item indexes in the list.

A very frequent example of crash :
Delete second last item and then try deleting last item you will get crash due to IndexOutOfBoundsException.


Usually we add following line to remove an item from the RecylcerView

.....
mDataList.remove(position);
notifyItemRemoved(position);
.....


Possible Resolution : 
1. We can avoid this by simple calling notifyDataSetChanged() which resets the complete list but using this the added animation with item placement in event of addition or deletion. Also it is an expensive call in comparsion to notifyItemRemoved() or notifyItemInserted().

2. But to resolve this issue along with animation up, we need to add one more method call just below the above two method calls

.....
mDataList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataList.size());
.....

It just resets the RecylerView and hence index of list items get updated.


More : 
1. Similar issue can also be seen when you add a new item to the RecyclerView at any position.
2. And in that case notifyItemInserted() is called and should be followed by notifyItemRangeChanged() .


Please comment in case of any clarifications.


Monday 14 September 2015

Always Visible Multiple InfoWindows on Google Map



This post is about resolution of an issue that I faced when I started working on a requirement in which multiple info windows were supposed to be shown and that too simultaneously.

Conventionally there is no such method/class in Google maps api that could allow developers to implement this functionality. Though we can add multiple markers default or customized with an attached infowindow but cannot show all the infowindow simultaneously.


Prerequisite : 
Get google map key for your map to be launched correctly. Please following link to create one
https://developers.google.com/maps/documentation/android-api/signup


Alternative:
Whatever. Above feature is highly needed along with autoupdating the content on the info window.
Never knew Markers were enough to replicate it into an infowindow too.



Conception: 
We will be going to create custom Markers in which we will draw all the information as bitmap and then set it to the markers icon property using

customMarkerOption.icon(BitmapDescriptorFactory.fromBitmap(createMarkerBitmap("76.3, 23.4 75%"))));


where customMarkerOption is an instance of MarkerOptions and createMarkerBitmap() is the method that creates bitmap using the content to be shown on map.



private Bitmap createMarkerBitmap(String iMarkerText) {
         Bitmap.Config conf = Bitmap.Config.ARGB_8888;
         Bitmap bmp = Bitmap.createBitmap(200, 100, conf);
         Canvas canvas = new Canvas(bmp);
 
         canvas.drawRect(0,75,200,175, mMarkerContainerPaint);
         canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.purple_marker),100,25,mMarkerTextPaint);
         canvas.drawText(iMarkerText, 50, 100, mMarkerTextPaint);
 
         return bmp;
     }


You can set up the map and use MarkerOptions instances above to create markers on map. And the content will also update automatically.

You can get the complete source for the demo app here.
MapDemos


Please check and let me know in case of issues.

Tuesday 23 June 2015

Issues with Animators


What are animators ? Why do we need them ? What is the difference with the conventional view animations ? How animators are implemented in android ?


Well today in this post I will not talk about these, instead I will put light on some issues that I faced while working and came to know about the reason very late.

The main issues that I noticed are :

1. I cannot reuse an ObjectAnimator and AnimatorSet object to get it usable for multiple views.
2. I cannot clear animation from my view. I mean resetting the view to its original position.

So after delving deeply into the android developer docs I reached to the following solutions at the time of writing :

1. Clone the create ObjectAnimator and AnimatorSet object to create a completely different copy of that object which could be used easily with a new view.
2. To get the reset functionality for animator set, we should be creating an animator that animates the same property to back to its original state(reverse action of the animator).


Please comment in case of issues :

Wednesday 1 April 2015

Simplest steps to integrate Parse for push notifications in Android

This blog entry is about how to fastly integrate Parse for push notifications in android. It only provide information on how to get started with the Parse's sample and the flow for most basic configurations.

Prerequisites : 

Signup into the www.parse.com. Create a project which will generate few keys like APPLICATION ID and CLIENT KEY to be used later in the project while integrating sdk.

Integration and Configuration:

1. Make a quickstart by navigating to this url https://www.parse.com/apps/quickstart
2. Select the Push options.
3. Select Android
4. Out of the two options : Create a new project and Add to existing project. Choose what you want to do ?

5. Choosing New Project will take you to https://www.parse.com/apps/quickstart#parse_push/android/new
Follow the steps on this page to make respective changes in the source files : Well you can find this step defined in the app properly

5.1 Download the the project and import it in the android studio.
5.2 We will need to connect to parse. This will require us to edit some of the files in the project.

5.2.1 Edit the Application class's onCreate() method

             public void onCreate() {
                // Replace the APPLICATION ID and CLIENT KEY with the one created for a project
                Parse.initialize(this, "APPLICATION ID", "CLIENT KEY");
             }

5.2.2 Add the following service and broadcast receiver definitions to AndroidManifest.xml immediately before the closing </application> tag:


<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParseBroadcastReceiver">
  <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <action android:name="android.intent.action.USER_PRESENT" />
  </intent-filter>
</receiver>
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
    android:exported="false">
  <intent-filter>
    <action android:name="com.parse.push.intent.RECEIVE" />
    <action android:name="com.parse.push.intent.DELETE" />
    <action android:name="com.parse.push.intent.OPEN" />
    </intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
  <intent-filter>
    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
 
    <!--
      IMPORTANT: Change "com.parse.starter" to match your app's package name.
    -->
    <category android:name="com.parse.starter" />
  </intent-filter>
</receiver>


Change the android:name attribute of <category> element above to match your application's package name.

Also add the permissions below, typically immediately before the opening <application> tag:


<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
 
<!--
  IMPORTANT: Change "com.parse.starter.permission.C2D_MESSAGE" in the lines below
  to match your app's package name + ".permission.C2D_MESSAGE".
-->
<permission android:protectionLevel="signature"
    android:name="com.parse.starter.permission.C2D_MESSAGE" />
<uses-permission android:name="com.parse.starter.permission.C2D_MESSAGE" />


Change the android:name attribute of <category> element above to match your application's package name.

5.2.3 Compile and run.

6. Similarly follow all the substeps just as in step 5 to do the Parse integration in android sdk.


Testing for push notifications : 

OK, now you are done with the most basic integration so you are good to go for testing.

7. Navigate to https://www.parse.com/apps to open dashboard containing all your projects created till now. Select the current project and the select the "Push" option.

7.1 Now here you will find an option/button to send a push message. You can also see the notification history if any notifications send previously.
7.2 Once selected one can also find a box to create a message to be sent. And the settings to choose the devices that can receive the notifications.
7.3 Also you can update the time of delivery of notification
7.4 Once message is configured properly, it can be pushed to the devices.


8. If everything is fine, app will receive the notifications and on clicking notification it will launch the application with the launcher activity. 

Ok ,you are done here with the integration of Parse for push notifications in android. 
Wait .... We are missing something .... ?
Don't you want to use one of the icon for the notification from your app reserve rather than default icon ? I know you are dying to add .
Don't you want to an implementation specific to your app like an desired activity to be launched. Yes you always wanted to drive
So we will do it in our app by creating our app's version of class com.parse.ParsePushBroadcastReceiver which allows to customize notification and implementation on receiving push message.



public class MyReceiver extends ParsePushBroadcastReceiver {
  
     @Override
     protected Notification getNotification(Context context, Intent intent) {
         final Notification notification = super.getNotification(context, intent);
  // TODO Update this notification here          
         return notification;
     }
 
     @Override
     protected void onPushOpen(Context context, Intent intent) {
  //TODO For app specific implementation comment the following line calling super version of this method  
  // super.onPushOpen(context, intent);

  //TODO Add App Specific implementation below
         Intent lastIntent = new Intent(context,SecondActivity.class);
         lastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         context.startActivity(lastIntent);
     }
}



This is just a brief walk through of Parse for push notifications in android. It is a very big thing in itself. Parse is a collection of multiple sdks for various platform.

References: https://www.parse.com/

Source: https://github.com/Keshava11/parsecheck

Thursday 15 January 2015

Enable detection of USB Devices on Ubuntu


You just connected your android device to the system to begin debugging and found nothing but ????? under the Devices window in your IDE. Now what ?

To get the device running on the Ubuntu we will need to register all the devices with a udev file which contains usb configuration for each device connecting to the system.
In the udev rules file each device manufacturer is identified by a unique vendor id as specified by ATTR{idVendor}.

Main steps :
1. Open terminal, assuming you are at home directory
    write command to change directory i.e. <cd ..> {without arrows} twice.
    Now change directory to <cd etc/udev/rules.d/> {without arrows}

2. Write command with root access to create a file
    $ sudo gedit 51-android.rules
    It will prompt for password : enter your system's root password
    It will create and open up the file with gedit (or you can use the editor of your choice too).

3. Now you will need to add entries corresponding to each device you are going to connect to your system.
And the format for those entries is as follows :
   SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"
   where "0bb4" is the vendor id for HTC found along side more other manufacturers in the list at
   http://developer.android.com/tools/device.html#VendorIds

   Also the MODE assignment specifies read/write permissions, and GROUP defines which Unix group owns the device node.

4. Once you are done with the above step, close the gedit or the editor you were using to edit the file.

5. Now we will change the permissions for the new created rules file as follows:
  $ chmod a+r /etc/udev/rules.d/51-android.rules

Really! In what world ? 
  If in any case you had restarted your terminal just after editing the file and hence getting the Operation not permitted error for the above 5th step,
  then you got to run the above command with sudo at the first place and again entering password when prompted for.
  $ sudo chmod a+r /etc/udev/rules.d/51-android.rules

6. Once done, you are good to go to play with your device connected to your machine.


Connect your device with usb debugging ON to the machine. And here you are annoyed one more time by a prompt on the device to check the Allow USB debugging dialog box.
But don't worry this will be last time you will be bugged.

Here is the sample file 51-android.rules file containing most vendor details about most used devices in the world. If you didn't found your device, please match with the above given vendor id's
and add one for yours.

Above list contains vendor Id's for Samsung, Motorola, Sony, Google, LG, Lenovo, Acer, Asus, Intel, Huawei etc.