Android Create Navigation Drawer using NavigationView

build.gradle

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    compile 'com.android.support:design:25.2.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.1'
    testCompile 'junit:junit:4.12'
}

/res/values/styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

/res/layout/toolbar_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:fitsSystemWindows="true"
    android:minHeight="?android:attr/actionBarSize"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

</android.support.v7.widget.Toolbar>

/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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"
    tools:context="iterator.ir.a045.MainActivity">

    <!--Content-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include
            layout="@layout/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <!--Drawer-->
    <android.support.design.widget.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/drawer_menu">

    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

/res/menu/drawer_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/itemHome"
            android:icon="@drawable/ic_home_black_24dp"
            android:title="Home" />

        <item
            android:id="@+id/itemAdd"
            android:icon="@drawable/ic_alarm_add_black_24dp"
            android:title="Add" />
    </group>


    <item android:title="Other">
        <menu>
            <item
                android:id="@+id/itemSettings"
                android:icon="@drawable/ic_settings_black_24dp"
                android:title="Settings" />

            <item
                android:id="@+id/itemShare"
                android:icon="@drawable/ic_share_black_24dp"
                android:title="Share" />
        </menu>
    </item>
</menu>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    Toolbar toolbar;

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

        toolbar= (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }
}

References
https://github.com/mhdr/AndroidSamples/tree/master/045
https://www.youtube.com/watch?v=mtOztjHmM0c&list=PLshdtb5UWjSp0879mLeCsDQN6L73XBZTk&index=76
https://developer.android.com/training/implementing-navigation/nav-drawer.html

Android Send data to a Fragment using Bundle

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        Fragment fragment=new PageFragment();
        Bundle bundle=new Bundle();
        bundle.putInt("pageNumber",10);
        fragment.setArguments(bundle);

        FragmentManager fragmentManager=getSupportFragmentManager();

        FragmentTransaction transaction= fragmentManager.beginTransaction();

        transaction.add(R.id.relativeLayoutFragmentContainer,fragment);

        transaction.commit();
    }

}

PageFragment.java

public class PageFragment extends Fragment {


    public PageFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view=inflater.inflate(R.layout.fragment_page, container, false);

        TextView textViewPage= (TextView) view.findViewById(R.id.textViewPage);
        Bundle bundle=getArguments();
        int pageNumber= bundle.getInt("pageNumber");

        String output=String.format("Page %d",pageNumber);
        textViewPage.setText(output);

        return view;
    }

}

References
https://github.com/mhdr/AndroidSamples/tree/master/044

Android Implement Swipe Views

To insert child views that represent each page, you need to hook this layout to a PagerAdapter. There are two kinds of adapter you can use:

FragmentPagerAdapter
This is best when navigating between sibling screens representing a fixed, small number of pages.
FragmentStatePagerAdapter
This is best for paging across a collection of objects for which the number of pages is undetermined. It destroys fragments as the user navigates to other pages, minimizing memory usage.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context="iterator.ir.a043.MainActivity">

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

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

</android.support.constraint.ConstraintLayout>

fragment_page.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="iterator.ir.a043.PageFragment">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/textViewCounter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="Fragment"
            android:textAppearance="@style/TextAppearance.AppCompat.Large" />
    </RelativeLayout>
</FrameLayout>

PageFragment.java

public class PageFragment extends Fragment {


    public PageFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view= inflater.inflate(R.layout.fragment_page, container, false);

        TextView textViewCounter= (TextView) view.findViewById(R.id.textViewCounter);

        Bundle bundle=getArguments();

        int counter=bundle.getInt("counter");
        String output=String.format("Page %d",counter);

        textViewCounter.setText(output);

        return view;
    }

}

SwipeAdapter.java

public class SwipeAdapter extends FragmentStatePagerAdapter {

    public SwipeAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment=new PageFragment();

        Bundle bundle=new Bundle();
        bundle.putInt("counter",position+1);

        fragment.setArguments(bundle);

        return fragment;
    }

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

MainActivity.java

public class MainActivity extends AppCompatActivity {

    ViewPager viewPager;

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

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

        SwipeAdapter adapter=new SwipeAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);

    }
}

References
https://github.com/mhdr/AndroidSamples/tree/master/043
https://developer.android.com/training/implementing-navigation/lateral.html

Android Working with Expandable List View

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="iterator.ir.a042.MainActivity">

    <ExpandableListView
        android:id="@+id/expandableListViewProvinces"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true" />
</RelativeLayout>

HeaderInfo.java

public class HeaderInfo {

    public String getProvoniceName() {
        return provoniceName;
    }

    public void setProvoniceName(String provoniceName) {
        this.provoniceName = provoniceName;
    }

    private String provoniceName;

    public int getPopulation() {
        return population;
    }

    private int population;

    public ArrayList<DetailInfo> getCities() {
        return cities;
    }

    public void setCities(ArrayList<DetailInfo> cities) {
        this.cities = cities;

        int pop=0;

        for (DetailInfo info:cities)
        {
            pop+=info.getPopulation();
        }

        this.population=pop;
    }

    private ArrayList<DetailInfo> cities=new ArrayList<>();

}

DetailInfo.java

public class DetailInfo {

    private String cityName;

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    private int population;
}

CustomAdapter.java

public class CustomAdapter extends BaseExpandableListAdapter {

    private Context context;
    private ArrayList<HeaderInfo> cInfo;

    public CustomAdapter(Context context,ArrayList<HeaderInfo> cInfo)
    {
        this.context=context;
        this.cInfo=cInfo;
    }

    @Override
    public int getGroupCount() {
        return cInfo.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return cInfo.get(groupPosition).getCities().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return cInfo.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return cInfo.get(groupPosition).getCities().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

        View view=convertView;

        if (view==null)
        {
            LayoutInflater layoutInflater=LayoutInflater.from(context);
            view=layoutInflater.inflate(R.layout.header_layout,parent,false);
        }

        HeaderInfo current=this.cInfo.get(groupPosition);

        if (current!=null)
        {
            TextView textViewProvinceName= (TextView) view.findViewById(R.id.textViewProvinceName);
            TextView textViewProvincePopulation= (TextView) view.findViewById(R.id.textViewProvincePopulation);

            textViewProvinceName.setText(current.getProvoniceName());
            textViewProvincePopulation.setText(String.valueOf(current.getPopulation()));
        }

        return view;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        View view=convertView;

        if (view==null)
        {
            LayoutInflater layoutInflater=LayoutInflater.from(context);
            view=layoutInflater.inflate(R.layout.detail_layout,parent,false);
        }

        DetailInfo current=this.cInfo.get(groupPosition).getCities().get(childPosition);

        if (current!=null)
        {
            TextView textViewCityName= (TextView) view.findViewById(R.id.textViewCityName);
            TextView textViewCityPopulation= (TextView) view.findViewById(R.id.textViewCityPopulation);

            textViewCityName.setText(current.getCityName());
            textViewCityPopulation.setText(String.valueOf(current.getPopulation()));
        }

        return view;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    ExpandableListView expandableListViewProvinces;
    ArrayList<HeaderInfo> provonices;

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

        GenerateData();

        expandableListViewProvinces= (ExpandableListView) findViewById(R.id.expandableListViewProvinces);
        CustomAdapter adapter=new CustomAdapter(this,provonices);
        expandableListViewProvinces.setAdapter(adapter);
    }

    private void GenerateData()
    {
        provonices=new ArrayList<>();


        DetailInfo detailInfo1=new DetailInfo();
        detailInfo1.setCityName("Rasht");
        detailInfo1.setPopulation(1000000);


        DetailInfo detailInfo2=new DetailInfo();
        detailInfo2.setCityName("Lahijan");
        detailInfo2.setPopulation(700000);

        DetailInfo detailInfo3=new DetailInfo();
        detailInfo3.setCityName("Anzali");
        detailInfo3.setPopulation(800000);

        DetailInfo detailInfo4=new DetailInfo();
        detailInfo4.setCityName("Fouman");
        detailInfo4.setPopulation(200000);

        ArrayList<DetailInfo> cities1=new ArrayList<>();
        cities1.add(detailInfo1);
        cities1.add(detailInfo2);
        cities1.add(detailInfo3);
        cities1.add(detailInfo4);

        HeaderInfo headerInfo1=new HeaderInfo();
        headerInfo1.setProvoniceName("Guilan");
        headerInfo1.setCities(cities1);

        DetailInfo detailInfo5=new DetailInfo();
        detailInfo5.setCityName("Tehran");
        detailInfo5.setPopulation(10000000);


        DetailInfo detailInfo6=new DetailInfo();
        detailInfo6.setCityName("Hashtgerd");
        detailInfo6.setPopulation(700000);


        ArrayList<DetailInfo> cities2=new ArrayList<>();
        cities2.add(detailInfo5);
        cities2.add(detailInfo6);


        HeaderInfo headerInfo2=new HeaderInfo();
        headerInfo2.setProvoniceName("Tehran");
        headerInfo2.setCities(cities2);


        DetailInfo detailInfo7=new DetailInfo();
        detailInfo7.setCityName("Qazvin");
        detailInfo7.setPopulation(1000000);


        ArrayList<DetailInfo> cities3=new ArrayList<>();
        cities3.add(detailInfo7);

        HeaderInfo headerInfo3=new HeaderInfo();
        headerInfo3.setProvoniceName("Qazvin");
        headerInfo3.setCities(cities3);

        provonices.add(headerInfo1);
        provonices.add(headerInfo2);
        provonices.add(headerInfo3);
    }
}

References
https://github.com/mhdr/AndroidSamples/tree/master/042

How to Configure Spring Session with JDBC for MySQL

build.gradle

buildscript {
	ext {
		springBootVersion = '1.5.2.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'

jar {
	baseName = 'logbook-server'
	version = '0.0.1-SNAPSHOT'
}

sourceCompatibility = 1.8

repositories {
	mavenCentral()
}


dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.session:spring-session')
	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	compile('org.springframework.boot:spring-boot-starter-web')
	compile('org.springframework.boot:spring-boot-starter-web-services')
	compile('org.springframework.boot:spring-boot-starter-websocket')
	runtime('org.springframework.boot:spring-boot-devtools')
	runtime('mysql:mysql-connector-java')
	compileOnly('org.springframework.boot:spring-boot-configuration-processor')
	compileOnly('org.projectlombok:lombok')
	testCompile('org.springframework.boot:spring-boot-starter-test')

	// https://mvnrepository.com/artifact/joda-time/joda-time
	compile group: 'joda-time', name: 'joda-time', version: '2.9.7'

	// https://mvnrepository.com/artifact/net.time4j/time4j-parent
	compile group: 'net.time4j', name: 'time4j-parent', version: '4.25'

	// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
	compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5'

	// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
	compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.56'

	// https://mvnrepository.com/artifact/com.google.code.gson/gson
	compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'

	// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat
	compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat'

	// https://mvnrepository.com/artifact/commons-io/commons-io
	compile group: 'commons-io', name: 'commons-io', version: '2.5'
}

application.properties

server.port=13602
spring.session.store-type=jdbc
server.compression.enabled=true
server.use-forward-headers=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
logging.file=logbook-server.log
spring.datasource.url=jdbc:mysql://localhost/logbook
spring.datasource.username=root
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true

spring.jpa.hibernate.ddl-auto=create

HttpSessionConfig.java

@Configuration
@EnableJdbcHttpSession
public class HttpSessionConfig {

}

then execute this script on MySQL

CREATE TABLE SPRING_SESSION (
        SESSION_ID CHAR(36),
        CREATION_TIME BIGINT NOT NULL,
        LAST_ACCESS_TIME BIGINT NOT NULL,
        MAX_INACTIVE_INTERVAL INT NOT NULL,
        PRINCIPAL_NAME VARCHAR(100),
        CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
) ENGINE=InnoDB;

CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
        SESSION_ID CHAR(36),
        ATTRIBUTE_NAME VARCHAR(200),
        ATTRIBUTE_BYTES BLOB,
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
) ENGINE=InnoDB;

CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);

References
http://docs.spring.io/spring-session/docs/current/reference/html5/#api-jdbcoperationssessionrepository-storage
http://stackoverflow.com/questions/37398905/spring-session-with-jdbc-configuration-table-test-spring-session-doesnt-exis