Monday 29 June 2015

HB Blog 80: How To Integrate Tablayout In Viewpager With PagerAdapter And FragmentPagerAdapter.

Android material design has changed complete look and feel of the Android applications. In lollipop 5.0 release,  Android design support library was introduced. It consisted of many component classes for navigation drawer, floating views such as labels, buttons, etc. as well as tablayout, etc.
In this post, I will show how to integrate tablayout in viewpager with pager adapter as well as fragment pager adapter. Firstly, we need to update Android Support Repository in the SDK Manager and then add design library with a single new dependency as follows,

1
 compile 'com.android.support:design:22.2.0'
TabLayout provides a horizontal layout to display tabs. The design library’s TabLayout implements both fixed tabs, where the view’s width is divided equally between all of the tabs, as well as scrollable tabs, where the tabs are not a uniform size and can scroll horizontally. Tabs can be added programmatically, For using viewpager with tablayout, you can create tabs directly from your PagerAdapter’s getPageTitle() and then connect the two together using setupWithViewPager(). This ensures that tab selection events update the ViewPager and page changes update the selected tab.

We have tablayout listeners as follows,
1)TabLayout.TabLayoutOnPageChangeListener - A ViewPager.OnPageChangeListener class which contains the necessary calls back to the provided TabLayout so that the tab position is kept in sync. 
2)TabLayout.ViewPagerOnTabSelectedListener - A TabLayout.OnTabSelectedListener class which contains the necessary calls back to the provided ViewPager so that the tab position is kept in sync.

Refer the below link for complete sample code:-
Download Sample Code
Download Apk File
Have a look on few code snippets,

activity_main.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/btn_pager_adapter"
        android:layout_gravity="center_horizontal" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/btn_fragment_adapter"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

MainActivity.java 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn_pager_adapter=(Button)findViewById(R.id.btn_pager_adapter);
        Button btn_fragment_adapter=(Button)findViewById(R.id.btn_fragment_adapter);

        btn_pager_adapter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MainActivity.this,PagerAdapterActivity.class);
                startActivity(intent);
            }
        });

        btn_fragment_adapter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MainActivity.this,FragmentPagerAdapterActivity.class);
                startActivity(intent);
            }
        });
    }
}

adapter_activity_main.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        app:layout_scrollFlags="scroll|enterAlways" />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </android.support.v4.view.ViewPager>

</LinearLayout>

FragmentPagerAdapterActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

import com.tablayout_as.Adapter.ViewFragmentPagerAdapter;


public class FragmentPagerAdapterActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.adapter_activity_main);
        tabSetup();
    }

    public void tabSetup(){
        TabLayout tabLayout = (TabLayout)findViewById(R.id.tab_layout);
        final ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
        ViewFragmentPagerAdapter viewFragmentPagerAdapter = new ViewFragmentPagerAdapter(getSupportFragmentManager());
        tabLayout.setTabsFromPagerAdapter(viewFragmentPagerAdapter);
        viewPager.setAdapter(viewFragmentPagerAdapter);
        viewPager.setCurrentItem(1);
      //  tabLayout.setupWithViewPager(viewPager);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                System.out.println("tab getText: " + tab.getText());
                System.out.println("tab getPosition: " + tab.getPosition());
                viewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

    }
}

ViewFragmentPagerAdapter.java 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.tablayout_as.Fragment.FragmentOne;
import com.tablayout_as.Fragment.FragmentThree;
import com.tablayout_as.Fragment.FragmentTwo;
import java.util.ArrayList;
import java.util.List;

public class ViewFragmentPagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public ViewFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
        this.fragments = new ArrayList<Fragment>();
        fragments.add(new FragmentOne());
        fragments.add(new FragmentTwo());
        fragments.add(new FragmentThree());
    }

    @Override
    public int getCount() {
        return fragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "Page " + position;
    }
}

FragmentOne.java/FragmentTwo.java/FragmentThree.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.tablayout_as.R;

/**
 * Created by harshalbenake on 21/05/15.
 */
public class FragmentOne extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragment_main,container,false);
        TextView textView=(TextView)view.findViewById(R.id.textView);
        textView.setText("FragmentOne");
        return view;
    }

}

fragment_main.xml/page_item.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="New Text"
        android:textColor="#ff0000"
        android:id="@+id/tv_page_item"
        android:gravity="center" />
</LinearLayout>

PagerAdapterActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import android.app.Activity;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import com.tablayout_as.Adapter.ViewPagerAdapter;


public class PagerAdapterActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.adapter_activity_main);

        tabSetup();
    }

    public void tabSetup(){
        TabLayout tabLayout = (TabLayout)findViewById(R.id.tab_layout);
        final ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
        ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getApplicationContext());
        tabLayout.setTabsFromPagerAdapter(viewPagerAdapter);
        viewPager.setAdapter(viewPagerAdapter);
        viewPager.setCurrentItem(1);
        tabLayout.setupWithViewPager(viewPager);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                System.out.println("tab getText: " + tab.getText());
                System.out.println("tab getPosition: " + tab.getPosition());
                viewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

    }
}

ViewFragmentPagerAdapter.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.tablayout_as.R;

public class ViewPagerAdapter extends PagerAdapter {
    Context mContext;
    LayoutInflater layoutInflater;
    public ViewPagerAdapter(Context context){
        this.mContext=context;
        layoutInflater=LayoutInflater.from(mContext);
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return object == view;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "Page " + position;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = layoutInflater.inflate(R.layout.page_item, container, false);
        container.addView(view);
        TextView title = (TextView) view.findViewById(R.id.tv_page_item);
        title.setText("Position: " + position);
        return view;
    }

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

}

Tuesday 23 June 2015

HB Blog 79: Custom Listing In Android And iOS.

In mobile OS, data representation in listing form is most important component. In Android we have listview whereas, we have tableview in iOS. In this post I will try to put how do we create custom listview adapter in Android and custom tableview cell in iOS.
In Android, for custom listview,
We actually don't create custom listview but what we do is, we create custom adapter for listview. This adapter can be created either by extending base adapter class or array adapter class depending on the type of objects that are to be displayed in listview. When we extend base adpater we override getView() method in which inflate our view that is to be display at the specified position in the data set.Also, we have getCount() and getItemId() methods to get number of items in the data set and get the row id associated with the specified position in the list.

Have a look on few code snippets,
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
private class MyCustomAdapter extends BaseAdapter {

        private static final int ITEM_TYPE_ONE = 1;
        private static final int ITEM_TYPE_TWO = 2;
        private static final int ITEM_TYPE_MAX_COUNT = ITEM_TYPE_ONE+ITEM_TYPE_TWO+1;

        private ArrayList<DataPojo> mData;
        private LayoutInflater mInflater;

        public MyCustomAdapter(ArrayList<DataPojo> data) {
            this.mData=data;
            mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getItemViewType(int position) {
            int type;
            DataPojo dataPojo=mData.get(position);
            if(dataPojo.flag){
                type=ITEM_TYPE_ONE;
            }
            else {
                type=ITEM_TYPE_TWO;
            }
            return type;
        }

        @Override
        public int getViewTypeCount() {
            return ITEM_TYPE_MAX_COUNT;
        }

        @Override
        public int getCount() {
            return mData.size();
        }

        @Override
        public Object getItem(int position) {
            return mData.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            int type = getItemViewType(position);
            if (convertView == null) {
                holder = new ViewHolder();
                switch (type) {
                    case ITEM_TYPE_ONE:
                        convertView = mInflater.inflate(R.layout.item_view_one,  null);
                        holder.textView1 = (TextView)convertView.findViewById(R.id.textView1);
                        holder.imageView=(ImageView)convertView.findViewById(R.id.imageView1);
                        break;
                    case ITEM_TYPE_TWO:
                        convertView = mInflater.inflate(R.layout.item_view_two, null);
                        holder.textView1 = (TextView)convertView.findViewById(R.id.textView1);
                        holder.imageView=(ImageView)convertView.findViewById(R.id.imageView1);
                        break;

                }
                convertView.setTag(holder);
            }

                holder = (ViewHolder)convertView.getTag();

            DataPojo dataPojo=mData.get(position);
            holder.textView1.setText(dataPojo.strValue);
            return convertView;
        }
    }

    public static class ViewHolder {
        public TextView textView1;
        public ImageView imageView;
    }

    public class DataPojo{
        public String strValue;
        public boolean flag;
    }
}

Finally, we use setAdapter() method to set our custom adapter to listview as follows,
1
 listView.setAdapter(mAdapter); 
 

In iOS, for custom tableview cell,
We create custom cell with required UI component design as well as custom class for that cell. Then, this cell is added to the tableview in cellForRowAtIndexPath method of tableview.We use this custom class to  represents the underlying data model of the custom cell by creating respective outlets for components in that cell. We also have delegates to customize height of cell, get number of items in the cell etc.
Have a look on few code snippets,
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *customTableIdentifier = @"CustomTableCell";

    CustomTableCell *cell = (CustomTableCell  *)[tableView dequeueReusableCellWithIdentifier:customTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }
   
    cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
    cell.imageView.image = [UIImage imageNamed:[myimage objectAtIndex:indexPath.row]];
    cell.rollNoLabel.text = [prepTime objectAtIndex:indexPath.row];
   
    return cell;
}

Wednesday 17 June 2015

HB Blog 78: Google's Page Rank Algorithm.

Basically, PageRank is an algorithm used by Google Search to rank websites in their search engine results. PageRank was named after Larry Page one of the founders of Google. Page Rank was developed by Larry Page and Sergey Brin as a part of there research project. It is designed to crawl and index the web efficiently and produce much more satisfying search results.

According to Google:-
    PageRank works by counting the number and quality of links to a page to determine a rough estimate of how important the website is. The underlying assumption is that more important websites are likely to receive more links from other websites.

Algorithm description:-
Usually crawling and index process done for retrieving search results were calculated based on backlinks or comments or various sorting algorithms, whereas Google came up with PageRank algorithm which normalize number of links on the page.

Sergey Brin and Lawrence Page explained in their research paper as follows:-
    "We assume page A has pages T1...Tn which point to it (i.e., are citations). The parameter d is a damping factor which can be set between 0 and 1. We usually set d to 0.85. Also C(A) is defined as the number of links going out of page A. The PageRank of a page A is given as follows:

    PR(A) = (1-d) + d (PR(T1)/C(T1) + ... + PR(Tn)/C(Tn))

    Note that the PageRanks form a probability distribution over web pages, so the sum of all web pages' PageRanks will be one.

PageRank or PR(A) can be calculated using a simple iterative algorithm, and corresponds to the principal eigenvector of the normalized link matrix of the web. Also, a PageRank for 26 million web pages can be computed in a few hours on a medium size workstation. "

Here,
PR(A)- Here "A" is some page for which page rank is to be calculated.
T1-Tn- They are page that points to page "A" from other sources.
C(A)- They are the links that go out of the page "A".
d- It is a damping factor. According to page rank theory, assume that the user clicks randomly on links and the stop after a point of time. The probability, at any step, that the person will continue is a damping factor d.

For more information and reference follow the below link of research paper by Sergey Brin and Lawrence Page that was published at Stanford University, Stanford, CA:-
http://infolab.stanford.edu/~backrub/google.html

Tuesday 9 June 2015

HB Blog 77: Hack - A Programming Language Created By Facebook.

Hack is a programming language for the HipHop Virtual Machine (HHVM), created by Facebook as a dialect of PHP. Hack allows programmers to use both dynamic typing and static typing. This kind of a type system is called gradual typing.
HHVM is an open-source virtual machine designed for executing programs written in Hack and PHP. HHVM uses a just-in-time (JIT) compilation approach to achieve superior performance while maintaining the development flexibility that PHP provides.
Starting with Hack language setup as follows:-
1)Install HHVM
Executing the following 4 commands from the command line will have HHVM installed and ready:
  1. wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | apt-key add -
  2. echo deb http://dl.hhvm.com/ubuntu saucy main | tee /etc/apt/sources.list.d/hhvm.list
  3. apt-get update
  4. apt-get install hhvm
To confirm that HHVM has been installed, type the following command:
hhvm --help
You should have the latest version of HHVM installed, have a php.ini or config.hdf set up if necessary, and HHVM running as a webserver serving your project.

2)Creating the project structure for app and getting the type checker running.
In the root of your project directory, create an empty file named .hhconfig. The type checker uses this file to know what directory tree to type check without needing to specify paths to every command.
Now, run hh_client. This will start up the type checking daemon, wait for it to finish checking the current directory tree, and report any errors that it found.
projects/
├── project-1/
│   └── app/
│       └── .hhconfig
├── project-2/
│   └── app/
└── .hhconfig
 3)Start Hack language and run hello world program as follows.
Hack language is preety much similar to PHP, for example use <?hh at the top of your file similar to php code <?php and save file with extension .hh. You can also save the file with ,php but it is better for distinguish hack files with php files.

1
2
3
4
5
<?hh
// void is used to indicate that a function does not return anything.
function say_hello(): void {
  echo "hello world";
} 

Wednesday 3 June 2015

HB Blog 76: Android M With Fingerprint Authentication.

Authentication is the act of confirming the truth of an attribute of a single piece of data (datum) or entity. Fingerprint recognition or fingerprint authentication refers to the automated method of verifying a match between two human fingerprints. Fingerprints are one of many forms of biometrics used to identify individuals and verify their identity.

Authentication
Android M Developer Preview offers new APIs to let you authenticate users by using their fingerprint scans on supported devices, and check how recently the user was last authenticated using a device unlocking mechanism (such as a lockscreen password). Use these APIs in conjunction with the Android Keystore system. The Android Keystore system lets you store private keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the private key material remaining non-exportable.
Fingerprint Authentication
To authenticate users via fingerprint scan, get an instance of the new android.hardware.fingerprint. FingerprintManager class and call the FingerprintManager.authenticate() method. Your app must be running on a compatible device with a fingerprint sensor. You must implement the user interface for the fingerprint authentication flow on your app, and use the standard Android fingerprint icon in your UI. If you are developing multiple apps that use fingerprint authentication, note that each app must authenticate the user’s fingerprint independently.

Use KeyGenerator to create a symmetric key in the Android Key Store which can be only be used after the user has authenticated with fingerprint and pass a KeyGeneratorSpec.

Use KeyGeneratorSpec.Builder.setUserAuthenticationRequired to permit the use of the key only after the user authenticate it including when authenticated with the user's fingerprint.

Use FingerprintManager.authenticate to tart listening to a fingerprint on the fingerprint sensor with a Cipher initialized with the symmetric key created.

Use FingerprintManager.AuthenticationCallback#onAuthenticationSucceeded() callback after the fingerprint (or password) is verified.

To use this feature in your app, add the USE_FINGERPRINT permission in your manifest.

1
2
<uses-permission
        android:name="android.permission.USE_FINGERPRINT" />
If you are testing this feature, follow these steps:
  1. Install Android SDK Tools Revision 24.3, if you have not done so.
  2. Enroll a new fingerprint in the emulator by going to Settings > Security > Fingerprint, then follow the enrollment instructions.
  3. Use an emulator to emulate fingerprint touch events with the following command. Use the same command to emulate fingerprint touch events on the lockscreen or in your app. 
adb -e emu finger touch <finger_id>
Confirm Credential
Your app can authenticate users based on how recently they last unlocked their device. This feature frees users from having to remember additional app-specific passwords, and avoids the need for you to implement your own authentication user interface. Your app should use this feature in conjunction with a public or secret key implementation for user authentication.
To set the timeout duration for which the same key can be re-used after a user is successfully authenticated, call the new android.security.keystore.KeyGenParameterSpec.setUserAuthenticationValidityDurationSeconds() method when you set up a KeyGenerator or KeyPairGenerator. This feature currently works for symmetric cryptographic operations.
Avoid showing the re-authentication dialog excessively -- your apps should try using the cryptographic object first and if the the timeout expires, use the createConfirmDeviceCredentialIntent() method to re-authenticate the user within your app.