Friday, July 31, 2015
Microsoft's standalone Android Emulator
Microsoft Visual Studio 2015 now has options for Android development: C++, Cordova, and C# with Xamarin. When choosing one of those Android development options, Visual Studio will also install the brand new Visual Studio Emulator for Android to use as a target for debugging your app. You can also download the emulator without needing to install Visual Studio.
Source: Introducing Visual Studio’s Emulator for Android
Visual Studio Emulator for Android:
see it in action:
Source: Introducing Visual Studio’s Emulator for Android
Visual Studio Emulator for Android:
see it in action:
Tuesday, July 28, 2015
Open more than one project in Android Studio
Open more than one project in Android Studio:
- With one project opened
- Select menu File -> Reopen Project -> select the project to open
- Select New Window to open project.
- With one project opened
- Select menu File -> Reopen Project -> select the project to open
- Select New Window to open project.
FREE eBook: AdMob No-Nonsense Guide to Growing Your Mobile App
This handbook will walk you through practical ways to increase your app’s user engagement to help you eventually transition to growth. You’ll learn how to:
- Pick the right metric to represent user engagement
- Look at data to audit your app and find areas to fix
- Promote your app after you’ve reached a healthy level of user engagement
Sunday, July 26, 2015
FREE eBook - An Introduction to Network Programming with Java, 3rd Edition
An Introduction to Network Programming with Java, 3rd Edition
Description: Since the second edition of this text, the use of the Internet and networks generally has continued to expand at a phenomenal rate. This has led to both an increase in demand for network software and to improvements in the technology used to run such networks, with the latter naturally leading to changes in the former. During this time, the Java libraries have been updated to keep up with the new developments in network technology, so that the Java programming language continues to be one of the mainstays of network software development.
~ Link
Description: Since the second edition of this text, the use of the Internet and networks generally has continued to expand at a phenomenal rate. This has led to both an increase in demand for network software and to improvements in the technology used to run such networks, with the latter naturally leading to changes in the former. During this time, the Java libraries have been updated to keep up with the new developments in network technology, so that the Java programming language continues to be one of the mainstays of network software development.
~ Link
StaggeredGridLayoutManager on RecyclerView
android.support.v7.widget.StaggeredGridLayoutManager is a LayoutManager that lays out children in a staggered grid formation. It supports horizontal & vertical layout as well as an ability to layout children in reverse.
Example to create StaggeredGridLayoutManager:
staggeredGridLayoutManagerVertical =
new StaggeredGridLayoutManager(
2, //The number of Columns in the grid
LinearLayoutManager.VERTICAL);
staggeredGridLayoutManagerHorizontal =
new StaggeredGridLayoutManager(
3, //The number of rows in the grid
LinearLayoutManager.HORIZONTAL);
Modify last example "Android example using RecyclerView with CardView":
layout/activity_main.xml
<LinearLayout 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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/namefield"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/addbutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Add"/>
<RadioGroup
android:id="@+id/optGroupLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/optLinearLayoutVertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LinearLayout Vertical"
android:checked="true" />
<RadioButton
android:id="@+id/optLinearLayoutHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LinearLayout Horizontal" />
<RadioButton
android:id="@+id/optGridLayoutVertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GridLayout Vertical" />
<RadioButton
android:id="@+id/optGridLayoutHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GridLayout Horizontal" />
<RadioButton
android:id="@+id/optStaggeredGridLayoutVertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StaggeredGridLayout Vertical" />
<RadioButton
android:id="@+id/optStaggeredGridLayoutHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StaggeredGridLayout Horizontal" />
</RadioGroup>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/myrecyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
com.example.androidrecyclerview.MainActivity.java
package com.example.androidrecyclerview;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity implements RecyclerViewAdapter.OnItemClickListener{
private RecyclerView myRecyclerView;
private RecyclerViewAdapter myRecyclerViewAdapter;
EditText nameField;
Button btnAdd;
RadioGroup optGroupLayout;
RadioButton optLinearLayoutHorizontal;
RadioButton optLinearLayoutVertical;
RadioButton optGridLayoutHorizontal;
RadioButton optGridLayoutVertical;
RadioButton optStaggeredGridLayoutHorizontal;
RadioButton optStaggeredGridLayoutVertical;
private LinearLayoutManager linearLayoutManagerVertical;
private LinearLayoutManager linearLayoutManagerHorizontal;
private GridLayoutManager gridLayoutManagerVertical;
private GridLayoutManager gridLayoutManagerHorizontal;
private StaggeredGridLayoutManager staggeredGridLayoutManagerVertical;
private StaggeredGridLayoutManager staggeredGridLayoutManagerHorizontal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myRecyclerView = (RecyclerView)findViewById(R.id.myrecyclerview);
linearLayoutManagerVertical =
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
linearLayoutManagerHorizontal =
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
gridLayoutManagerVertical =
new GridLayoutManager(this,
2, //The number of Columns in the grid
LinearLayoutManager.VERTICAL,
false);
gridLayoutManagerHorizontal =
new GridLayoutManager(this,
3, //The number of rows in the grid
LinearLayoutManager.HORIZONTAL,
false);
staggeredGridLayoutManagerVertical =
new StaggeredGridLayoutManager(
2, //The number of Columns in the grid
LinearLayoutManager.VERTICAL);
staggeredGridLayoutManagerHorizontal =
new StaggeredGridLayoutManager(
3, //The number of rows in the grid
LinearLayoutManager.HORIZONTAL);
//set SpanSizeLookup()
gridLayoutManagerVertical.setSpanSizeLookup(new MySpanSizeLookup(5, 1, 2));
gridLayoutManagerHorizontal.setSpanSizeLookup(new MySpanSizeLookup(4, 1, 3));
myRecyclerViewAdapter = new RecyclerViewAdapter(this);
myRecyclerViewAdapter.setOnItemClickListener(this);
myRecyclerView.setAdapter(myRecyclerViewAdapter);
myRecyclerView.setLayoutManager(linearLayoutManagerVertical);
//Add MyItemDecoration
myRecyclerView.addItemDecoration(new MyItemDecoration(this));
nameField = (EditText)findViewById(R.id.namefield);
btnAdd = (Button)findViewById(R.id.addbutton);
btnAdd.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String newName = nameField.getText().toString();
if(!newName.equals("")){
if(myRecyclerViewAdapter.getItemCount()>1){
myRecyclerViewAdapter.add(1, newName);
}else{
myRecyclerViewAdapter.add(0, newName);
}
}
}
});
optGroupLayout = (RadioGroup)findViewById(R.id.optGroupLayout);
optLinearLayoutHorizontal = (RadioButton)findViewById(R.id.optLinearLayoutHorizontal);
optLinearLayoutVertical = (RadioButton)findViewById(R.id.optLinearLayoutVertical);
optGridLayoutHorizontal = (RadioButton)findViewById(R.id.optGridLayoutHorizontal);
optGridLayoutVertical = (RadioButton)findViewById(R.id.optGridLayoutVertical);
optStaggeredGridLayoutHorizontal = (RadioButton)findViewById(R.id.optStaggeredGridLayoutHorizontal);
optStaggeredGridLayoutVertical = (RadioButton)findViewById(R.id.optStaggeredGridLayoutVertical);
optGroupLayout.setOnCheckedChangeListener(optLayoutCheckedChangeListener);
//pre-load dummy items
myRecyclerViewAdapter.add(0, "SpanSizeLookup");
myRecyclerViewAdapter.add(0, "ItemDecoration");
myRecyclerViewAdapter.add(0, "GridLayoutManager");
myRecyclerViewAdapter.add(0, "LinearLayoutManager");
myRecyclerViewAdapter.add(0, "RecyclerViewAdapter");
myRecyclerViewAdapter.add(0, "RecyclerView example");
myRecyclerViewAdapter.add(0, "RecyclerView");
myRecyclerViewAdapter.add(0, "android-er.blogspot.com");
myRecyclerViewAdapter.add(0, "android-er");
myRecyclerViewAdapter.add(0, "android");
}
private RadioGroup.OnCheckedChangeListener optLayoutCheckedChangeListener =
new RadioGroup.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(optLinearLayoutVertical.isChecked()){
myRecyclerView.setLayoutManager(linearLayoutManagerVertical);
}else if(optLinearLayoutHorizontal.isChecked()){
myRecyclerView.setLayoutManager(linearLayoutManagerHorizontal);
}else if(optGridLayoutHorizontal.isChecked()){
myRecyclerView.setLayoutManager(gridLayoutManagerHorizontal);
}else if(optGridLayoutVertical.isChecked()){
myRecyclerView.setLayoutManager(gridLayoutManagerVertical);
}else if(optStaggeredGridLayoutHorizontal.isChecked()){
myRecyclerView.setLayoutManager(staggeredGridLayoutManagerHorizontal);
}else if(optStaggeredGridLayoutVertical.isChecked()){
myRecyclerView.setLayoutManager(staggeredGridLayoutManagerVertical);
}
}
};
@Override
public void onItemClick(RecyclerViewAdapter.ItemHolder item, int position) {
Toast.makeText(this,
"Remove " + position + " : " + item.getItemName(),
Toast.LENGTH_SHORT).show();
myRecyclerViewAdapter.remove(position);
}
}
Download the files (Android Studio Format).
- More step-by-step examples of RecyclerView.
Saturday, July 25, 2015
100 Questions and Answers to help you land your Dream Android Job: or to hire the right candidate!
There is a boom in the mobile applications market. It has been projected than 2015 more than a billion (with b) smartphones will be sold, twice as many as the number of personal computers . Mobile channels are increasing their revenues figures, with percentages over 100% being the norm and not the exception. Each business needs a mobile application, and therefore the demand of engineers, UX designers and QA testers is under huge demand. There is far more demand for jobs than offer, and the situation is even more optimistic for senior developers. "100 Questions and Answers to make you get your Android Dream Job" collects 100 questions and answers, divided in three levels, that the author has been summarising during several years both as an interviewer and as a candidate. If you are looking for a position as an Android developer, no matter how experience you are, or if you are looking to hire new members for your organisation, this book will provide you all the material you need to take the right decision and hire the right candidate!
Android read file "/proc/mounts"
Android example code to read "/proc/mounts", easy to be modified to read other text files.
com.example.android_proc_mounts.MainActivity.java
layout/activity_main.xml
com.example.android_proc_mounts.MainActivity.java
package com.example.android_proc_mounts;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class MainActivity extends ActionBarActivity {
TextView info;
String targetPath = "/proc/mounts";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView)findViewById(R.id.info);
info.setText(ReadFile(targetPath));
}
private String ReadFile(String path){
String result = "";
File file = new File(path);
if(file.exists()){
result += path + ":\n"
+ "======\n";
Scanner scanner = null;
try {
scanner = new Scanner(file);
while (scanner.hasNext()) {
String line = scanner.nextLine();
result += line + "\n"
+ "------\n";
}
} catch (FileNotFoundException e) {
e.printStackTrace();
result += e.toString();
}
}else{
return (path + " NOT exists");
}
return result;
}
}
layout/activity_main.xml
<LinearLayout
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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
Friday, July 24, 2015
Android example using RecyclerView with CardView
The former post show "Android CardView example", It can be embedded in RecyclerView.
Modify from last exercise of RecyclerView, "onDraw() and onDrawOver() of ItemDecoration for RecyclerView".
Create layout of the CardView, layout/layout_cardview.xml
Modify constructor of ItemHolder() in com.example.androidrecyclerview.RecyclerViewAdapter.java, ItemHolder(CardView cView, RecyclerViewAdapter parent), to include CardView. And also modify the method onCreateViewHolder(ViewGroup parent, int viewType).
com.example.androidrecyclerview.RecyclerViewAdapter.java
Download the files (Android Studio Format).
Next:
- StaggeredGridLayoutManager (Google+ App-like) on RecyclerView
- More step-by-step examples of RecyclerView.
Modify from last exercise of RecyclerView, "onDraw() and onDrawOver() of ItemDecoration for RecyclerView".
Create layout of the CardView, layout/layout_cardview.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
card_view:cardCornerRadius="20sp"
card_view:cardElevation="5sp">
<TextView
android:id="@+id/card_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40dp"/>
</android.support.v7.widget.CardView>
Modify constructor of ItemHolder() in com.example.androidrecyclerview.RecyclerViewAdapter.java, ItemHolder(CardView cView, RecyclerViewAdapter parent), to include CardView. And also modify the method onCreateViewHolder(ViewGroup parent, int viewType).
com.example.androidrecyclerview.RecyclerViewAdapter.java
package com.example.androidrecyclerview;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemHolder> {
private List<String> itemsName;
private OnItemClickListener onItemClickListener;
private LayoutInflater layoutInflater;
public RecyclerViewAdapter(Context context){
layoutInflater = LayoutInflater.from(context);
itemsName = new ArrayList<String>();
}
@Override
public RecyclerViewAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//View itemView = layoutInflater.inflate(R.layout.layout_item, parent, false);
//return new ItemHolder(itemView, this);
CardView itemCardView = (CardView)layoutInflater.inflate(R.layout.layout_cardview, parent, false);
return new ItemHolder(itemCardView, this);
}
@Override
public void onBindViewHolder(RecyclerViewAdapter.ItemHolder holder, int position) {
holder.setItemName(itemsName.get(position));
}
@Override
public int getItemCount() {
return itemsName.size();
}
public void setOnItemClickListener(OnItemClickListener listener){
onItemClickListener = listener;
}
public OnItemClickListener getOnItemClickListener(){
return onItemClickListener;
}
public interface OnItemClickListener{
public void onItemClick(ItemHolder item, int position);
}
public void add(int location, String iName){
itemsName.add(location, iName);
notifyItemInserted(location);
}
public void remove(int location){
if(location >= itemsName.size())
return;
itemsName.remove(location);
notifyItemRemoved(location);
}
public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private RecyclerViewAdapter parent;
TextView textItemName;
private CardView cardView;
/*
public ItemHolder(View itemView, RecyclerViewAdapter parent) {
super(itemView);
itemView.setOnClickListener(this);
this.parent = parent;
textItemName = (TextView) itemView.findViewById(R.id.item_name);
}
*/
public ItemHolder(CardView cView, RecyclerViewAdapter parent) {
super(cView);
cardView = cView;
cardView.setOnClickListener(this);
this.parent = parent;
textItemName = (TextView) cardView.findViewById(R.id.card_item_name);
}
public void setItemName(CharSequence name){
textItemName.setText(name);
}
public CharSequence getItemName(){
return textItemName.getText();
}
@Override
public void onClick(View v) {
final OnItemClickListener listener = parent.getOnItemClickListener();
if(listener != null){
listener.onItemClick(this, getPosition());
}
}
}
}
Download the files (Android Studio Format).
Next:
- StaggeredGridLayoutManager (Google+ App-like) on RecyclerView
- More step-by-step examples of RecyclerView.
Thursday, July 23, 2015
getExternalFilesDirs() and getExternalCacheDirs()
Start from Android 4.4 (API Level 19), methods getExternalFilesDirs(String type) and getExternalCacheDirs() were introduced.
File[] getExternalFilesDirs (String type) -
Returns absolute paths to application-specific directories on all external storage devices where the application can place persistent files it owns. These files are internal to the application, and not typically visible to the user as media.
File[] getExternalCacheDirs () -
Returns absolute paths to application-specific directories on all external storage devices where the application can place cache files it owns. These files are internal to the application, and not typically visible to the user as media.
Example code run on RedMi 2 (Android 4.4.4), WITH external SD Card:
both /storage/emulated/0/...(internal memory) and /storage/sdcard1/...(SD Card) are listed.
Run on Nexus 7 (Android 5.1.1) WITHOUT external SD Card:
Example code:
com.example.androidexternalstorage.MainActivity.java
layout/activity_main.xml
File[] getExternalFilesDirs (String type) -
Returns absolute paths to application-specific directories on all external storage devices where the application can place persistent files it owns. These files are internal to the application, and not typically visible to the user as media.
File[] getExternalCacheDirs () -
Returns absolute paths to application-specific directories on all external storage devices where the application can place cache files it owns. These files are internal to the application, and not typically visible to the user as media.
Example code run on RedMi 2 (Android 4.4.4), WITH external SD Card:
both /storage/emulated/0/...(internal memory) and /storage/sdcard1/...(SD Card) are listed.
Run on Nexus 7 (Android 5.1.1) WITHOUT external SD Card:
Example code:
com.example.androidexternalstorage.MainActivity.java
package com.example.androidexternalstorage;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;
import java.io.File;
public class MainActivity extends ActionBarActivity {
TextView info;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView)findViewById(R.id.info);
File extFilesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
String strInfo =
"Environment.getRootDirectory(): \n"
+ Environment.getRootDirectory() + "\n"
+ "Environment.getExternalStorageDirectory(): \n"
+ Environment.getExternalStorageDirectory() + "\n";
strInfo +=
"\ngetExternalFilesDir(null): \n"
+ getExternalFilesDir(null) + "\n"
+ "getExternalFilesDir(Environment.DIRECTORY_PICTURES): \n"
+ getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "\n"
+ "getExternalFilesDir(Environment.DIRECTORY_MUSIC): \n"
+ getExternalFilesDir(Environment.DIRECTORY_MUSIC) + "\n";
//API Level 19
File[] externalFilesDirs = getExternalFilesDirs(null);
strInfo += "\ngetExternalFilesDirs(null):\n";
for(File f : externalFilesDirs){
strInfo += f.getAbsolutePath() + "\n";
}
//API Level 19
File[] externalCacheDirs = getExternalCacheDirs();
strInfo += "\ngetExternalCacheDirs():\n";
for(File f : externalCacheDirs){
strInfo += f.getAbsolutePath() + "\n";
}
/*
//API Level 21
File[] externalMediaDirs = getExternalMediaDirs();
strInfo += "\ngetExternalMediaDirs():\n";
for(File f : externalMediaDirs){
strInfo += f.getAbsolutePath() + "\n";
}
*/
info.setText(strInfo);
}
}
layout/activity_main.xml
<LinearLayout
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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
Android CardView example
android.support.v7.widget.CardView is a FrameLayout with a rounded corner background and shadow.
Before use CardView in your app, you have to "Add Support Libraries of RecyclerView, CardView to Android Studio Project".
Example of using CardView in layout xml.
Tested on Nexus 7 running Android 5.1.1:
Related:
- Android example using RecyclerView with CardView
Before use CardView in your app, you have to "Add Support Libraries of RecyclerView, CardView to Android Studio Project".
Example of using CardView in layout xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<android.support.v7.widget.CardView
android:id="@+id/cardview1"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="28sp"
android:text="CardView 1"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/cardview2"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="28sp"
android:textColor="#ffa31f15"
android:text="CardView 2"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/cardview3"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="20sp"
card_view:cardBackgroundColor="#ffff0000"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="35sp"
android:textColor="#ffffffff"
android:text="CardView 3"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/cardview4"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="20sp"
card_view:cardElevation="5sp"
card_view:cardBackgroundColor="#ff0000ff"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="35sp"
android:textColor="#ffffffff"
android:text="CardView 4"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/cardview5"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="20sp"
card_view:cardElevation="5sp"
card_view:cardBackgroundColor="#ffffffff"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="35sp"
android:textColor="#ff505050"
android:text="CardView 5"/>
</android.support.v7.widget.CardView>
</LinearLayout>
Tested on Nexus 7 running Android 5.1.1:
Related:
- Android example using RecyclerView with CardView
Android Studio Color Chooser, when edit color in layout xml
When edit color value in layout xml using Android Studio, a color dot will appear on the left side. Click the color dot will open Color Chooser for you.
Wednesday, July 22, 2015
YouTube App now support vertical video in portrait full screen
Tuesday, July 21, 2015
onDraw() and onDrawOver() of ItemDecoration for RecyclerView
In the exercise of "Implement custom ItemDecoration for RecyclerView" we already implement our ItemDecoration to draw lines on items in RecyclerView, in onDraw() method. Further work on last exercise "set SpanSizeLookup to GridLayoutManager of RecyclerView", here we do more:
- draw Border on canvas of whole RecyclerView, in onDraw()
- draw a enlarged bitmap on low-right corner of RecyclerView, in onDrawOver()
com.example.androidrecyclerview.MyItemDecoration.java
package com.example.androidrecyclerview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class MyItemDecoration extends RecyclerView.ItemDecoration{
private Paint paintBlue, paintRed, paintBorder;
private int offset;
Bitmap bitmap;
int bitmap_w, bitmap_h;
Rect rectSrc;
public MyItemDecoration(Context c){
offset = 10;
paintBlue = new Paint(Paint.ANTI_ALIAS_FLAG);
paintBlue.setColor(Color.BLUE);
paintBlue.setStyle(Paint.Style.STROKE);
paintBlue.setStrokeWidth(3);
paintRed = new Paint(Paint.ANTI_ALIAS_FLAG);
paintRed.setColor(Color.RED);
paintRed.setStyle(Paint.Style.STROKE);
paintRed.setStrokeWidth(1);
paintBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
paintBorder.setColor(Color.GREEN);
paintBorder.setStyle(Paint.Style.STROKE);
paintBorder.setStrokeWidth(10);
bitmap = BitmapFactory.decodeResource(
c.getResources(),
android.R.drawable.ic_menu_info_details);
bitmap_w = bitmap.getWidth();
bitmap_h = bitmap.getHeight();
rectSrc = new Rect(0, 0, bitmap_w, bitmap_h);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(offset, offset, offset, offset);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
c.drawRect(
0,
0,
c.getWidth(),
c.getHeight(),
paintBorder);
for(int i=0; i<parent.getChildCount(); i++){
final View child = parent.getChildAt(i);
c.drawRect(
layoutManager.getDecoratedLeft(child),
layoutManager.getDecoratedTop(child),
layoutManager.getDecoratedRight(child),
layoutManager.getDecoratedBottom(child),
paintBlue);
c.drawRect(
layoutManager.getDecoratedLeft(child) + offset,
layoutManager.getDecoratedTop(child) + offset,
layoutManager.getDecoratedRight(child) - offset,
layoutManager.getDecoratedBottom(child) - offset,
paintRed);
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
c.drawBitmap(bitmap,
rectSrc,
new Rect(
c.getWidth()-(2*bitmap_w),
c.getHeight()-(2*bitmap_h),
c.getWidth(),
c.getHeight()),
null);
}
}
Have to modify constructor call of MyItemDecoration in MainActivity.java, such that we can get Resources drawable in MyItemDecoration.
myRecyclerView.addItemDecoration(new MyItemDecoration());
to: myRecyclerView.addItemDecoration(new MyItemDecoration(this));
Download the files (Android Studio Format).
Next:
- Android example using RecyclerView with CardView
- More step-by-step examples of RecyclerView.
Monday, July 20, 2015
set SpanSizeLookup to GridLayoutManager of RecyclerView
GridLayoutManager.SpanSizeLookup help to provide the number of spans each item of RecyclerView to occupies. Call setSpanSizeLookup(GridLayoutManager.SpanSizeLookup) method of GridLayoutManager to apply it.
This example modify from last exercise of "LinearLayoutManager and GridLayoutManager for RecyclerView". Create own custom GridLayoutManager.SpanSizeLookup, com.example.androidrecyclerview.MySpanSizeLookup.java
Modify com.example.androidrecyclerview.MainActivity.java, in onCreate() to implement and set MySpanSizeLookup().
Download the files (Android Studio Format).
Next:
- onDraw() and onDrawOver() of ItemDecoration for RecyclerView
- More step-by-step examples of RecyclerView.
This example modify from last exercise of "LinearLayoutManager and GridLayoutManager for RecyclerView". Create own custom GridLayoutManager.SpanSizeLookup, com.example.androidrecyclerview.MySpanSizeLookup.java
package com.example.androidrecyclerview;
import android.support.v7.widget.GridLayoutManager;
public class MySpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
int spanPos, spanCnt1, spanCnt2;
public MySpanSizeLookup(int spanPos, int spanCnt1, int spanCnt2) {
super();
this.spanPos = spanPos;
this.spanCnt1 = spanCnt1;
this.spanCnt2 = spanCnt2;
}
@Override
public int getSpanSize(int position) {
return (position % spanPos ==0 ? spanCnt2 : spanCnt1);
}
}
Modify com.example.androidrecyclerview.MainActivity.java, in onCreate() to implement and set MySpanSizeLookup().
package com.example.androidrecyclerview;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity implements RecyclerViewAdapter.OnItemClickListener{
private RecyclerView myRecyclerView;
private RecyclerViewAdapter myRecyclerViewAdapter;
EditText nameField;
Button btnAdd;
RadioGroup optGroupLayout;
RadioButton optLinearLayoutHorizontal;
RadioButton optLinearLayoutVertical;
RadioButton optGridLayoutHorizontal;
RadioButton optGridLayoutVertical;
private LinearLayoutManager linearLayoutManagerVertical;
private LinearLayoutManager linearLayoutManagerHorizontal;
private GridLayoutManager gridLayoutManagerVertical;
private GridLayoutManager gridLayoutManagerHorizontal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myRecyclerView = (RecyclerView)findViewById(R.id.myrecyclerview);
linearLayoutManagerVertical =
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
linearLayoutManagerHorizontal =
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
gridLayoutManagerVertical =
new GridLayoutManager(this,
2, //The number of Columns in the grid
LinearLayoutManager.VERTICAL,
false);
gridLayoutManagerHorizontal =
new GridLayoutManager(this,
3, //The number of rows in the grid
LinearLayoutManager.HORIZONTAL,
false);
//set SpanSizeLookup()
gridLayoutManagerVertical.setSpanSizeLookup(new MySpanSizeLookup(5, 1, 2));
gridLayoutManagerHorizontal.setSpanSizeLookup(new MySpanSizeLookup(4, 1, 3));
myRecyclerViewAdapter = new RecyclerViewAdapter(this);
myRecyclerViewAdapter.setOnItemClickListener(this);
myRecyclerView.setAdapter(myRecyclerViewAdapter);
myRecyclerView.setLayoutManager(linearLayoutManagerVertical);
//Add MyItemDecoration
myRecyclerView.addItemDecoration(new MyItemDecoration());
nameField = (EditText)findViewById(R.id.namefield);
btnAdd = (Button)findViewById(R.id.addbutton);
btnAdd.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String newName = nameField.getText().toString();
if(!newName.equals("")){
if(myRecyclerViewAdapter.getItemCount()>1){
myRecyclerViewAdapter.add(1, newName);
}else{
myRecyclerViewAdapter.add(0, newName);
}
}
}
});
optGroupLayout = (RadioGroup)findViewById(R.id.optGroupLayout);
optLinearLayoutHorizontal = (RadioButton)findViewById(R.id.optLinearLayoutHorizontal);
optLinearLayoutVertical = (RadioButton)findViewById(R.id.optLinearLayoutVertical);
optGridLayoutHorizontal = (RadioButton)findViewById(R.id.optGridLayoutHorizontal);
optGridLayoutVertical = (RadioButton)findViewById(R.id.optGridLayoutVertical);
optGroupLayout.setOnCheckedChangeListener(optLayoutCheckedChangeListener);
//pre-load dummy items
myRecyclerViewAdapter.add(0, "SpanSizeLookup");
myRecyclerViewAdapter.add(0, "ItemDecoration");
myRecyclerViewAdapter.add(0, "GridLayoutManager");
myRecyclerViewAdapter.add(0, "LinearLayoutManager");
myRecyclerViewAdapter.add(0, "RecyclerViewAdapter");
myRecyclerViewAdapter.add(0, "RecyclerView example");
myRecyclerViewAdapter.add(0, "RecyclerView");
myRecyclerViewAdapter.add(0, "android-er.blogspot.com");
myRecyclerViewAdapter.add(0, "android-er");
myRecyclerViewAdapter.add(0, "android");
}
private RadioGroup.OnCheckedChangeListener optLayoutCheckedChangeListener =
new RadioGroup.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(optLinearLayoutVertical.isChecked()){
myRecyclerView.setLayoutManager(linearLayoutManagerVertical);
}else if(optLinearLayoutHorizontal.isChecked()){
myRecyclerView.setLayoutManager(linearLayoutManagerHorizontal);
}else if(optGridLayoutHorizontal.isChecked()){
myRecyclerView.setLayoutManager(gridLayoutManagerHorizontal);
}else if(optGridLayoutVertical.isChecked()){
myRecyclerView.setLayoutManager(gridLayoutManagerVertical);
}
}
};
@Override
public void onItemClick(RecyclerViewAdapter.ItemHolder item, int position) {
Toast.makeText(this,
"Remove " + position + " : " + item.getItemName(),
Toast.LENGTH_SHORT).show();
myRecyclerViewAdapter.remove(position);
}
}
Download the files (Android Studio Format).
Next:
- onDraw() and onDrawOver() of ItemDecoration for RecyclerView
- More step-by-step examples of RecyclerView.
Sunday, July 19, 2015
Android Bluetooth to control LED brightness on Arduino Due + HC-06
Previous exercise "Android example to communicate with Bluetooth device, HC-06 Bluetooth Module" show how to send string. Here we implement our command format, such that we can use SeekBar on Android to control brightness of the Arduino Due on-board LED (pin 13), via Bluetooth to HC-06 Bluetooth Module.
Android Side:
com.example.androidbtcontrol.MainActivity.java
layout/activity_main.xml
uses-permission of "android.permission.BLUETOOTH" is needed in AndroidManifest.xml.
Download the files (Android Studio Format).
Arduino side:
Connection between Arduino and HC-06, refer to "Connect Arduino Due with HC-06 (Bluetooth Module)".
DueHC06_AT.ino
You can also monitor the state on PC using Serial Monitor.
Android Side:
com.example.androidbtcontrol.MainActivity.java
/*
Android Example to connect to and communicate with Bluetooth
In this exercise, the target is a Arduino Due + HC-06 (Bluetooth Module)
*/
package com.example.androidbtcontrol;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends ActionBarActivity {
private static final int REQUEST_ENABLE_BT = 1;
BluetoothAdapter bluetoothAdapter;
ArrayList<BluetoothDevice> pairedDeviceArrayList;
TextView textInfo, textStatus;
ListView listViewPairedDevice;
LinearLayout inputPane;
SeekBar barAnalogOut;
ArrayAdapter<BluetoothDevice> pairedDeviceAdapter;
private UUID myUUID;
private final String UUID_STRING_WELL_KNOWN_SPP =
"00001101-0000-1000-8000-00805F9B34FB";
ThreadConnectBTdevice myThreadConnectBTdevice;
ThreadConnected myThreadConnected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInfo = (TextView)findViewById(R.id.info);
textStatus = (TextView)findViewById(R.id.status);
listViewPairedDevice = (ListView)findViewById(R.id.pairedlist);
inputPane = (LinearLayout)findViewById(R.id.inputpane);
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
Toast.makeText(this,
"FEATURE_BLUETOOTH NOT support",
Toast.LENGTH_LONG).show();
finish();
return;
}
//using the well-known SPP UUID
myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this,
"Bluetooth is not supported on this hardware platform",
Toast.LENGTH_LONG).show();
finish();
return;
}
String stInfo = bluetoothAdapter.getName() + "\n" +
bluetoothAdapter.getAddress();
textInfo.setText(stInfo);
barAnalogOut = (SeekBar)findViewById(R.id.analogOut);
barAnalogOut.setOnSeekBarChangeListener(OnAnalogOutChangeListener);
}
SeekBar.OnSeekBarChangeListener OnAnalogOutChangeListener =
new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//will generate too much data sent!
//SendAnalogOut(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
SendAnalogOut(seekBar.getProgress());
}
};
private final byte SYNC_BYTE = (byte) 0xAA;
private final byte LENGTH_ANALOG = (byte) 3;
private final byte CMD_ANALOG = (byte) 1;
private void SendAnalogOut(int val){
byte[] bytesToSend = {SYNC_BYTE, LENGTH_ANALOG, CMD_ANALOG, (byte) val};
myThreadConnected.write(bytesToSend);
}
@Override
protected void onStart() {
super.onStart();
//Turn ON BlueTooth if it is OFF
if (!bluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
setup();
}
private void setup() {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
pairedDeviceArrayList = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device : pairedDevices) {
pairedDeviceArrayList.add(device);
}
pairedDeviceAdapter = new ArrayAdapter<BluetoothDevice>(this,
android.R.layout.simple_list_item_1, pairedDeviceArrayList);
listViewPairedDevice.setAdapter(pairedDeviceAdapter);
listViewPairedDevice.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
BluetoothDevice device =
(BluetoothDevice) parent.getItemAtPosition(position);
Toast.makeText(MainActivity.this,
"Name: " + device.getName() + "\n"
+ "Address: " + device.getAddress() + "\n"
+ "BondState: " + device.getBondState() + "\n"
+ "BluetoothClass: " + device.getBluetoothClass() + "\n"
+ "Class: " + device.getClass(),
Toast.LENGTH_LONG).show();
textStatus.setText("start ThreadConnectBTdevice");
myThreadConnectBTdevice = new ThreadConnectBTdevice(device);
myThreadConnectBTdevice.start();
}
});
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(myThreadConnectBTdevice!=null){
myThreadConnectBTdevice.cancel();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==REQUEST_ENABLE_BT){
if(resultCode == Activity.RESULT_OK){
setup();
}else{
Toast.makeText(this,
"BlueTooth NOT enabled",
Toast.LENGTH_SHORT).show();
finish();
}
}
}
//Called in ThreadConnectBTdevice once connect successed
//to start ThreadConnected
private void startThreadConnected(BluetoothSocket socket){
myThreadConnected = new ThreadConnected(socket);
myThreadConnected.start();
}
/*
ThreadConnectBTdevice:
Background Thread to handle BlueTooth connecting
*/
private class ThreadConnectBTdevice extends Thread {
private BluetoothSocket bluetoothSocket = null;
private final BluetoothDevice bluetoothDevice;
private ThreadConnectBTdevice(BluetoothDevice device) {
bluetoothDevice = device;
try {
bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);
textStatus.setText("bluetoothSocket: \n" + bluetoothSocket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
boolean success = false;
try {
bluetoothSocket.connect();
success = true;
} catch (IOException e) {
e.printStackTrace();
final String eMessage = e.getMessage();
runOnUiThread(new Runnable() {
@Override
public void run() {
textStatus.setText("something wrong bluetoothSocket.connect(): \n" + eMessage);
}
});
try {
bluetoothSocket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(success){
//connect successful
final String msgconnected = "connect successful:\n"
+ "BluetoothSocket: " + bluetoothSocket + "\n"
+ "BluetoothDevice: " + bluetoothDevice;
runOnUiThread(new Runnable(){
@Override
public void run() {
textStatus.setText(msgconnected);
listViewPairedDevice.setVisibility(View.GONE);
inputPane.setVisibility(View.VISIBLE);
}});
startThreadConnected(bluetoothSocket);
}else{
//fail
}
}
public void cancel() {
Toast.makeText(getApplicationContext(),
"close bluetoothSocket",
Toast.LENGTH_LONG).show();
try {
bluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
ThreadConnected:
Background Thread to handle Bluetooth data communication
after connected
*/
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = connectedInputStream.read(buffer);
String strReceived = new String(buffer, 0, bytes);
final String msgReceived = String.valueOf(bytes) +
" bytes received:\n"
+ strReceived;
runOnUiThread(new Runnable() {
@Override
public void run() {
textStatus.setText(msgReceived);
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
final String msgConnectionLost = "Connection lost:\n"
+ e.getMessage();
runOnUiThread(new Runnable(){
@Override
public void run() {
textStatus.setText(msgConnectionLost);
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
layout/activity_main.xml
<LinearLayout 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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<TextView
android:id="@+id/info"
android:textStyle="bold|italic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView
android:id="@+id/pairedlist"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/inputpane"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<SeekBar
android:id="@+id/analogOut"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="99"
android:progress="0"/>
</LinearLayout>
</LinearLayout>
uses-permission of "android.permission.BLUETOOTH" is needed in AndroidManifest.xml.
Download the files (Android Studio Format).
Arduino side:
Connection between Arduino and HC-06, refer to "Connect Arduino Due with HC-06 (Bluetooth Module)".
DueHC06_AT.ino
/*
Arduino Due + HC-06 (Bluetooth) -
receive command to control LED (pin 13) brightness
Serial (Tx/Rx) communicate to PC via USB
Serial3 (Tx3/Rx3) connect to HC-06
HC-06 Rx - Due Tx3
HC-06 Tx - Due Rx3
HC-06 GND - Due GND
HC-06 VCC - Due 3.3V
*/
#define HC06 Serial3
int SYNC_BYTE = 0xAA;
int CMD_ANALOG = 1;
int rxState;
int rxLength;
int rxCmd;
const int rxState_0_idle = 0;
const int rxState_1_sync = 1; //SYNC_BYTE received
const int rxState_2_cmd = 2; //length received, waiting CMD
const int rxState_3_data = 3; //CMD received, receiving data
int LED = 13;
void setup()
{
pinMode(LED, OUTPUT);
delay(1000);
Serial.begin(9600);
HC06.begin(9600);
Serial.write("\nTest Start\n");
rxState = rxState_0_idle;
}
void loop()
{
while(HC06.available())
{
char rxData = (int)HC06.read();
switch(rxState){
case rxState_0_idle:
if(rxData == SYNC_BYTE){
rxState = rxState_1_sync;
Serial.println("SYNC_BYTE received");
}
break;
case rxState_1_sync:
rxLength = rxData;
Serial.println("Length: " + String(rxLength));
rxLength--;
rxState = rxState_2_cmd;
break;
case rxState_2_cmd:
rxCmd = rxData;
Serial.println("CMD: " + String(rxCmd));
rxLength--;
rxState = rxState_3_data;
break;
case rxState_3_data:
Serial.println("data: " + String(rxData));
//we have one command only
if(rxCmd==CMD_ANALOG){
int brightness = map(rxData, 0, 99, 0, 255);
analogWrite(LED, brightness);
Serial.println("brightness: " + String(brightness));
HC06.println("brightness: " + String(brightness));
}
rxLength--;
if(rxLength==0){
rxState = rxState_0_idle;
}
break;
default:
rxState = rxState_0_idle;
};
}
}
You can also monitor the state on PC using Serial Monitor.
Import Android Eclipse project to Android Studio
This video show how to import Android Eclipse project to Android Studio. Here we use the the Eclipse project of "CalendarView example" as a example.
And how it run on device:
>> Know more about Migrating to Android Studio
And how it run on device:
>> Know more about Migrating to Android Studio
Saturday, July 18, 2015
Android example to communicate with Bluetooth device, HC-06 Bluetooth Module
The former exercise "Test HC-06 Bluetooth Module with Android BluetoothChat" show how to communicate between Android and HC-06 Bluetooth Module, using "Android BluetoothChat example".
And the post in my another blog "Arduino-er: Connect Arduino Due with HC-06 (Bluetooth Module)", show how to receive data from HC-06, send back to Bluetooth device and PC via USB.
Here, we are going to implement our own Android app (in Android Studio) to connect and communicate to Arduino Due + HC-06 Bluetooth Module. Actually, it is copied (with modified UUID) from my old example "Bluetooth communication between Android devices", AndroidBlueTooth part.
From the video, it can be noted that the first character always missed, or overwritten. We can verify it in Arduino IDE's Serial Monitor, the data received on Arduino Due (via Bluetooth) is correct.
[Updated@2015-10-31: Lost character Fixed, refer "Android communicate with Arduino + HC-06 Bluetooth Module, part II"]
com.example.androidbtcontrol.MainActivity.java
layout/activity_main.xml
Have to modify AndroidManifest.xml to uses-permission of "android.permission.BLUETOOTH".
Download the files (Android Studio Format).
Next:
- Android Bluetooth to control LED brightness on Arduino Due + HC-06
And the post in my another blog "Arduino-er: Connect Arduino Due with HC-06 (Bluetooth Module)", show how to receive data from HC-06, send back to Bluetooth device and PC via USB.
Here, we are going to implement our own Android app (in Android Studio) to connect and communicate to Arduino Due + HC-06 Bluetooth Module. Actually, it is copied (with modified UUID) from my old example "Bluetooth communication between Android devices", AndroidBlueTooth part.
From the video, it can be noted that the first character always missed, or overwritten. We can verify it in Arduino IDE's Serial Monitor, the data received on Arduino Due (via Bluetooth) is correct.
[Updated@2015-10-31: Lost character Fixed, refer "Android communicate with Arduino + HC-06 Bluetooth Module, part II"]
com.example.androidbtcontrol.MainActivity.java
/*
Android Example to connect to and communicate with Bluetooth
In this exercise, the target is a Arduino Due + HC-06 (Bluetooth Module)
Ref:
- Make BlueTooth connection between Android devices
http://android-er.blogspot.com/2014/12/make-bluetooth-connection-between.html
- Bluetooth communication between Android devices
http://android-er.blogspot.com/2014/12/bluetooth-communication-between-android.html
*/
package com.example.androidbtcontrol;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends ActionBarActivity {
private static final int REQUEST_ENABLE_BT = 1;
BluetoothAdapter bluetoothAdapter;
ArrayList<BluetoothDevice> pairedDeviceArrayList;
TextView textInfo, textStatus;
ListView listViewPairedDevice;
LinearLayout inputPane;
EditText inputField;
Button btnSend;
ArrayAdapter<BluetoothDevice> pairedDeviceAdapter;
private UUID myUUID;
private final String UUID_STRING_WELL_KNOWN_SPP =
"00001101-0000-1000-8000-00805F9B34FB";
ThreadConnectBTdevice myThreadConnectBTdevice;
ThreadConnected myThreadConnected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInfo = (TextView)findViewById(R.id.info);
textStatus = (TextView)findViewById(R.id.status);
listViewPairedDevice = (ListView)findViewById(R.id.pairedlist);
inputPane = (LinearLayout)findViewById(R.id.inputpane);
inputField = (EditText)findViewById(R.id.input);
btnSend = (Button)findViewById(R.id.send);
btnSend.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
if(myThreadConnected!=null){
byte[] bytesToSend = inputField.getText().toString().getBytes();
myThreadConnected.write(bytesToSend);
}
}});
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
Toast.makeText(this,
"FEATURE_BLUETOOTH NOT support",
Toast.LENGTH_LONG).show();
finish();
return;
}
//using the well-known SPP UUID
myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this,
"Bluetooth is not supported on this hardware platform",
Toast.LENGTH_LONG).show();
finish();
return;
}
String stInfo = bluetoothAdapter.getName() + "\n" +
bluetoothAdapter.getAddress();
textInfo.setText(stInfo);
}
@Override
protected void onStart() {
super.onStart();
//Turn ON BlueTooth if it is OFF
if (!bluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
setup();
}
private void setup() {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
pairedDeviceArrayList = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device : pairedDevices) {
pairedDeviceArrayList.add(device);
}
pairedDeviceAdapter = new ArrayAdapter<BluetoothDevice>(this,
android.R.layout.simple_list_item_1, pairedDeviceArrayList);
listViewPairedDevice.setAdapter(pairedDeviceAdapter);
listViewPairedDevice.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
BluetoothDevice device =
(BluetoothDevice) parent.getItemAtPosition(position);
Toast.makeText(MainActivity.this,
"Name: " + device.getName() + "\n"
+ "Address: " + device.getAddress() + "\n"
+ "BondState: " + device.getBondState() + "\n"
+ "BluetoothClass: " + device.getBluetoothClass() + "\n"
+ "Class: " + device.getClass(),
Toast.LENGTH_LONG).show();
textStatus.setText("start ThreadConnectBTdevice");
myThreadConnectBTdevice = new ThreadConnectBTdevice(device);
myThreadConnectBTdevice.start();
}
});
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(myThreadConnectBTdevice!=null){
myThreadConnectBTdevice.cancel();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==REQUEST_ENABLE_BT){
if(resultCode == Activity.RESULT_OK){
setup();
}else{
Toast.makeText(this,
"BlueTooth NOT enabled",
Toast.LENGTH_SHORT).show();
finish();
}
}
}
//Called in ThreadConnectBTdevice once connect successed
//to start ThreadConnected
private void startThreadConnected(BluetoothSocket socket){
myThreadConnected = new ThreadConnected(socket);
myThreadConnected.start();
}
/*
ThreadConnectBTdevice:
Background Thread to handle BlueTooth connecting
*/
private class ThreadConnectBTdevice extends Thread {
private BluetoothSocket bluetoothSocket = null;
private final BluetoothDevice bluetoothDevice;
private ThreadConnectBTdevice(BluetoothDevice device) {
bluetoothDevice = device;
try {
bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);
textStatus.setText("bluetoothSocket: \n" + bluetoothSocket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
boolean success = false;
try {
bluetoothSocket.connect();
success = true;
} catch (IOException e) {
e.printStackTrace();
final String eMessage = e.getMessage();
runOnUiThread(new Runnable() {
@Override
public void run() {
textStatus.setText("something wrong bluetoothSocket.connect(): \n" + eMessage);
}
});
try {
bluetoothSocket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(success){
//connect successful
final String msgconnected = "connect successful:\n"
+ "BluetoothSocket: " + bluetoothSocket + "\n"
+ "BluetoothDevice: " + bluetoothDevice;
runOnUiThread(new Runnable(){
@Override
public void run() {
textStatus.setText(msgconnected);
listViewPairedDevice.setVisibility(View.GONE);
inputPane.setVisibility(View.VISIBLE);
}});
startThreadConnected(bluetoothSocket);
}else{
//fail
}
}
public void cancel() {
Toast.makeText(getApplicationContext(),
"close bluetoothSocket",
Toast.LENGTH_LONG).show();
try {
bluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
ThreadConnected:
Background Thread to handle Bluetooth data communication
after connected
*/
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = connectedInputStream.read(buffer);
String strReceived = new String(buffer, 0, bytes);
final String msgReceived = String.valueOf(bytes) +
" bytes received:\n"
+ strReceived;
runOnUiThread(new Runnable(){
@Override
public void run() {
textStatus.setText(msgReceived);
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
final String msgConnectionLost = "Connection lost:\n"
+ e.getMessage();
runOnUiThread(new Runnable(){
@Override
public void run() {
textStatus.setText(msgConnectionLost);
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
layout/activity_main.xml
<LinearLayout 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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<TextView
android:id="@+id/info"
android:textStyle="bold|italic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/status"
android:textSize="28sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView
android:id="@+id/pairedlist"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/inputpane"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<EditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sent"/>
</LinearLayout>
</LinearLayout>
Have to modify AndroidManifest.xml to uses-permission of "android.permission.BLUETOOTH".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidbtcontrol" >
<uses-permission android:name="android.permission.BLUETOOTH"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Download the files (Android Studio Format).
Next:
- Android Bluetooth to control LED brightness on Arduino Due + HC-06
Subscribe to:
Posts (Atom)