New mobile apps for Docs, Sheets and Slides—work offline and on the go

Cross-posted on the Official Google Blog 

Every year, phones and tablets get better, and more of you are starting to use your mobile devices not just to view, but also to create and edit content. And while the Drive app is a convenient place to store your stuff, we want to make it easier for you to quickly find, edit and create documents, spreadsheets, and presentations on the go. Starting today, you can download new, standalone mobile apps for Docs and Sheets—with Slides coming soon. Need to find a spreadsheet? Go to the Sheets app. Need to create a document? Go to the Docs app. They’re all right there at your fingertips.

When you open the new apps, you’ll see your most recently edited files, which means less time searching and scrolling.


The apps also come with offline support built in, so you can easily view, edit and create files without an Internet connection. Now, if you have a brilliant idea for a best-selling novel while traipsing through the Amazonian rainforest (or you know, something more probable, like during flight takeoff)...no problem. You can jot down your idea in the Docs app on your phone, even when you’re offline.

You can get the apps on Google Play [Docs] [Sheets] and in the App Store [Docs] [Sheets]. If you don’t have time now, over the next few days you’ll be prompted to download the apps when you go to edit or create a document or spreadsheet in your Drive app. And of course, you’ll still be able to use the Drive app to view and organize all of your documents, spreadsheets, presentations, photos and more.

So enjoy the Amazon—we’re looking forward to buying that novel someday. And in the meantime, just remember: even if a crocodile eats your phone, your files are safe in the cloud!

Posted by Brian Levee, Product Manager

A good tutorial for Navigation Drawer

The navigation drawer is a panel that displays the app’s main navigation options on the left edge of the screen. It is hidden most of the time, but is revealed when the user swipes a finger from the left edge of the screen or, while at the top level of the app, the user touches the app icon in the action bar.

With navigation drawer, you can easily develop app with YouTube or Google+ apps like navigation.

It's a very good, must see, tutorial of Creating a Navigation Drawer.


Set text size and color of PagerTitleStrip on ViewPager

Previous example show how to Implement PagerTitleStrip on ViewPager. In the onCreate() method, we get view of PagerTitleStrip (pagerTitleStrip) without using it. We can set text size and color of the PagerTitleStrip by calling its setTextSize() and setTextColor() methods.

Example:
  PagerTitleStrip pagerTitleStrip = (PagerTitleStrip)findViewById(R.id.titlestrip);
pagerTitleStrip.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
pagerTitleStrip.setTextColor(Color.BLUE);

on tablet

on phone

Communication between Android using NFC to send text

This example send text between Android devices using NFC. Modify from last post of sending Uri between Android devices using NFC.


Modify AndroidManifest.xml include <intent-filter> of "android.nfc.action.NDEF_DISCOVERED".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidnfc"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.NFC"/>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidnfc.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>

</activity>
</application>

</manifest>

MainActivity.java
package com.example.androidnfc;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcAdapter.OnNdefPushCompleteCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements
CreateNdefMessageCallback, OnNdefPushCompleteCallback{

TextView textInfo;
EditText textOut;

NfcAdapter nfcAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInfo = (TextView)findViewById(R.id.info);
textOut = (EditText)findViewById(R.id.textout);

nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(nfcAdapter==null){
Toast.makeText(MainActivity.this,
"nfcAdapter==null, no NFC adapter exists",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(MainActivity.this,
"Set Callback(s)",
Toast.LENGTH_LONG).show();
nfcAdapter.setNdefPushMessageCallback(this, this);
nfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}

@Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
String action = intent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
Parcelable[] parcelables =
intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
NdefRecord NdefRecord_0 = inNdefRecords[0];
String inMsg = new String(NdefRecord_0.getPayload());
textInfo.setText(inMsg);
}
}

@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
}

@Override
public void onNdefPushComplete(NfcEvent event) {

final String eventString = "onNdefPushComplete\n" + event.toString();
runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(getApplicationContext(),
eventString,
Toast.LENGTH_LONG).show();
}
});

}

@Override
public NdefMessage createNdefMessage(NfcEvent event) {

String stringOut = textOut.getText().toString();
byte[] bytesOut = stringOut.getBytes();

NdefRecord ndefRecordOut = new NdefRecord(
NdefRecord.TNF_MIME_MEDIA,
"text/plain".getBytes(),
new byte[] {},
bytesOut);

NdefMessage ndefMessageout = new NdefMessage(ndefRecordOut);
return ndefMessageout;
}

}

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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidnfc.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<EditText
android:id="@+id/textout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

download filesDownload the files.

AudioRecord and AudioTrack, and to implement voice changer

This example show how to use android.media.AudioRecord and android.media.AudioTrack, to record and playback audio. And also show how to implement voice changer by recording and playing audio in different sampling frequency. (Actually, it is almost same as my old example)


AndroidAudioRecordActivity.java
package com.exercise.AndroidAudioRecord;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;

public class AndroidAudioRecordActivity extends Activity {

String[] freqText = {"11.025 KHz (Lowest)", "16.000 KHz", "22.050 KHz", "44.100 KHz (Highest)"};
Integer[] freqset = {11025, 16000, 22050, 44100};
private ArrayAdapter<String> adapter;

Spinner spFrequency;
Button startRec, stopRec, playBack;

Boolean recording;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startRec = (Button)findViewById(R.id.startrec);
stopRec = (Button)findViewById(R.id.stoprec);
playBack = (Button)findViewById(R.id.playback);

startRec.setOnClickListener(startRecOnClickListener);
stopRec.setOnClickListener(stopRecOnClickListener);
playBack.setOnClickListener(playBackOnClickListener);

spFrequency = (Spinner)findViewById(R.id.frequency);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, freqText);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spFrequency.setAdapter(adapter);

stopRec.setEnabled(false);
}

OnClickListener startRecOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {

Thread recordThread = new Thread(new Runnable(){

@Override
public void run() {
recording = true;
startRecord();
}

});

recordThread.start();
startRec.setEnabled(false);
stopRec.setEnabled(true);

}};

OnClickListener stopRecOnClickListener
= new OnClickListener(){

@Override
public void onClick(View arg0) {
recording = false;
startRec.setEnabled(true);
stopRec.setEnabled(false);
}};

OnClickListener playBackOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {
playRecord();
}

};

private void startRecord(){

File file = new File(Environment.getExternalStorageDirectory(), "test.pcm");

int selectedPos = spFrequency.getSelectedItemPosition();
int sampleFreq = freqset[selectedPos];

final String promptStartRecord =
"startRecord()\n"
+ file.getAbsolutePath() + "\n"
+ (String)spFrequency.getSelectedItem();

runOnUiThread(new Runnable(){

@Override
public void run() {
Toast.makeText(AndroidAudioRecordActivity.this,
promptStartRecord,
Toast.LENGTH_LONG).show();
}});

try {
file.createNewFile();

OutputStream outputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);

int minBufferSize = AudioRecord.getMinBufferSize(sampleFreq,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);

short[] audioData = new short[minBufferSize];

AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleFreq,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSize);

audioRecord.startRecording();

while(recording){
int numberOfShort = audioRecord.read(audioData, 0, minBufferSize);
for(int i = 0; i < numberOfShort; i++){
dataOutputStream.writeShort(audioData[i]);
}
}

audioRecord.stop();
dataOutputStream.close();

} catch (IOException e) {
e.printStackTrace();
}

}

void playRecord(){

File file = new File(Environment.getExternalStorageDirectory(), "test.pcm");

int shortSizeInBytes = Short.SIZE/Byte.SIZE;

int bufferSizeInBytes = (int)(file.length()/shortSizeInBytes);
short[] audioData = new short[bufferSizeInBytes];

try {
InputStream inputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);

int i = 0;
while(dataInputStream.available() > 0){
audioData[i] = dataInputStream.readShort();
i++;
}

dataInputStream.close();

int selectedPos = spFrequency.getSelectedItemPosition();
int sampleFreq = freqset[selectedPos];

final String promptPlayRecord =
"PlayRecord()\n"
+ file.getAbsolutePath() + "\n"
+ (String)spFrequency.getSelectedItem();

Toast.makeText(AndroidAudioRecordActivity.this,
promptPlayRecord,
Toast.LENGTH_LONG).show();

AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleFreq,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSizeInBytes,
AudioTrack.MODE_STREAM);

audioTrack.play();
audioTrack.write(audioData, 0, bufferSizeInBytes);


} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

}

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Sampling Frequency" />
<Spinner
android:id = "@+id/frequency"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/startrec"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Recording" />
<Button
android:id="@+id/stoprec"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop Recording" />
<Button
android:id="@+id/playback"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Play Back" />

</LinearLayout>

Permission of "android.permission.RECORD_AUDIO" and "android.permission.WRITE_EXTERNAL_STORAGE" are needed in AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidAudioRecord"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AndroidAudioRecordActivity"
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 filesDownload the files.

Download and try the APK HERE.

Run multi AsyncTask at the same time

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.

~ reference: AsyncTask | Android Developers



This example show how to execute multi AsyncTask at the same in parallel, by calling executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) for (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB), in our StartAsyncTaskInParallel() method. The first three ProgressBars updated by AsyncTask execute in normal approach by calling execute(), the last two ProgressBar updated by AsyncTask execute in parallel.


MainActivity.java
package com.example.androidparallelasynctask;

import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends Activity {

public class MyAsyncTask extends AsyncTask<Void, Integer, Void> {

ProgressBar myProgressBar;

public MyAsyncTask(ProgressBar target) {
myProgressBar = target;
}

@Override
protected Void doInBackground(Void... params) {
for(int i=0; i<100; i++){
publishProgress(i);
SystemClock.sleep(100);
}
return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
myProgressBar.setProgress(values[0]);
}

}

Button buttonStart;
ProgressBar progressBar1, progressBar2, progressBar3, progressBar4, progressBar5;
MyAsyncTask asyncTask1, asyncTask2, asyncTask3, asyncTask4, asyncTask5;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar1 = (ProgressBar)findViewById(R.id.progressbar1);
progressBar2 = (ProgressBar)findViewById(R.id.progressbar2);
progressBar3 = (ProgressBar)findViewById(R.id.progressbar3);
progressBar4 = (ProgressBar)findViewById(R.id.progressbar4);
progressBar5 = (ProgressBar)findViewById(R.id.progressbar5);

buttonStart = (Button)findViewById(R.id.start);
buttonStart.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
asyncTask1 = new MyAsyncTask(progressBar1);
asyncTask1.execute();
asyncTask2 = new MyAsyncTask(progressBar2);
asyncTask2.execute();
asyncTask3 = new MyAsyncTask(progressBar3);
asyncTask3.execute();
asyncTask4 = new MyAsyncTask(progressBar4);
StartAsyncTaskInParallel(asyncTask4);
asyncTask5 = new MyAsyncTask(progressBar5);
StartAsyncTaskInParallel(asyncTask5);
}});

}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void StartAsyncTaskInParallel(MyAsyncTask task) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();
}

}

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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidparallelasynctask.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<Button
android:id="@+id/start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start"/>

<ProgressBar
android:id="@+id/progressbar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<ProgressBar
android:id="@+id/progressbar2"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<ProgressBar
android:id="@+id/progressbar3"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<ProgressBar
android:id="@+id/progressbar4"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<ProgressBar
android:id="@+id/progressbar5"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />

</LinearLayout>

This video show how it run on devices running various Android version, include:
- Nexus 7 (1st generation), Android 4.4.2
- HTC One X, Android 4.2.2
- HTC Flyer, Android 3.2.1
- Nexus One, Android 2.3.6


download filesDownload the files.

Implement PagerTitleStrip on ViewPager

PagerTitleStrip is a non-interactive indicator of the current, next, and previous pages of a ViewPager. It is intended to be used as a child view of a ViewPager widget.

This example modify from last example.


Modify activity_main.xml, add PagerTitleStrip as a child view of a ViewPager.
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidviewpagerapp.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

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

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

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

</LinearLayout>

Modify MainActivity.java, override getPageTitle() method in MyPagerAdapter to return CharSequence of PageTitle.
package com.example.androidviewpagerapp;

import android.support.v4.view.PagerAdapter;
import android.support.v4.view.PagerTitleStrip;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;

public class MainActivity extends Activity {

ViewPager viewPager;
MyPagerAdapter myPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.myviewpager);
myPagerAdapter = new MyPagerAdapter();
viewPager.setAdapter(myPagerAdapter);

PagerTitleStrip pagerTitleStrip = (PagerTitleStrip)findViewById(R.id.titlestrip);

}

private class MyPagerAdapter extends PagerAdapter{

int NumberOfPages = 5;

int[] res = {
android.R.drawable.ic_dialog_alert,
android.R.drawable.ic_menu_camera,
android.R.drawable.ic_menu_compass,
android.R.drawable.ic_menu_directions,
android.R.drawable.ic_menu_gallery};
int[] backgroundcolor = {
0xFF101010,
0xFF202020,
0xFF303030,
0xFF404040,
0xFF505050};

String[] title = {
"Page 1",
"pAge 2",
"paGe 3",
"pagE 4",
"page 5"};

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

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

@Override
public Object instantiateItem(ViewGroup container, int position) {


TextView textView = new TextView(MainActivity.this);
textView.setTextColor(Color.WHITE);
textView.setTextSize(30);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setText(String.valueOf(position));

ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(res[position]);
LayoutParams imageParams = new LayoutParams(
LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
imageView.setLayoutParams(imageParams);

LinearLayout layout = new LinearLayout(MainActivity.this);
layout.setOrientation(LinearLayout.VERTICAL);
LayoutParams layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
layout.setBackgroundColor(backgroundcolor[position]);
layout.setLayoutParams(layoutParams);
layout.addView(textView);
layout.addView(imageView);

final int page = position;
layout.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Page " + page + " clicked",
Toast.LENGTH_LONG).show();
}});

container.addView(layout);
return layout;
}

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

@Override
public CharSequence getPageTitle(int position) {
return title[position];
}

}

}




download filesDownload the files.

- How to Set text size and color of PagerTitleStrip

Example of ViewPager with custom PagerAdapter

This example show how to implement ViewPager with custom PagerAdapter. (Another example(s) implement ViewPager with FragmentPagerAdapter, read HERE)


Modify activity_main.xml to include android.support.v4.view.ViewPager in layout.
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidviewpagerapp.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

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

</LinearLayout>

MainActivity.java
package com.example.androidviewpagerapp;

import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;

public class MainActivity extends Activity {

ViewPager viewPager;
MyPagerAdapter myPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.myviewpager);
myPagerAdapter = new MyPagerAdapter();
viewPager.setAdapter(myPagerAdapter);

}

private class MyPagerAdapter extends PagerAdapter{

int NumberOfPages = 5;

int[] res = {
android.R.drawable.ic_dialog_alert,
android.R.drawable.ic_menu_camera,
android.R.drawable.ic_menu_compass,
android.R.drawable.ic_menu_directions,
android.R.drawable.ic_menu_gallery};
int[] backgroundcolor = {
0xFF101010,
0xFF202020,
0xFF303030,
0xFF404040,
0xFF505050};

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

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

@Override
public Object instantiateItem(ViewGroup container, int position) {


TextView textView = new TextView(MainActivity.this);
textView.setTextColor(Color.WHITE);
textView.setTextSize(30);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setText(String.valueOf(position));

ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(res[position]);
LayoutParams imageParams = new LayoutParams(
LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
imageView.setLayoutParams(imageParams);

LinearLayout layout = new LinearLayout(MainActivity.this);
layout.setOrientation(LinearLayout.VERTICAL);
LayoutParams layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
layout.setBackgroundColor(backgroundcolor[position]);
layout.setLayoutParams(layoutParams);
layout.addView(textView);
layout.addView(imageView);

final int page = position;
layout.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Page " + page + " clicked",
Toast.LENGTH_LONG).show();
}});

container.addView(layout);
return layout;
}

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

}

}


download filesDownload the files.

Next:
Implement PagerTitleStrip on ViewPager

Java Programming for Android Developers For Dummies

Get started creating Android apps with Java in no time!

Java Programming for Android Developers For Dummies

The demand for Android apps is not slowing down but many mobile developers who want to create Android apps lack the necessary Java background. This beginner guide gets you up and running with using Java to create Android apps with no prior knowledge or experienced necessary!
  • Shows you the basic Java development concepts and techniques that are necessary to develop Android apps
  • Explores what goes into creating an Android app to give you a better understanding of the various elements
  • Addresses how to deal with standard programming challenges and debugging
Beginning Android Programming with Java For Dummies puts you well on your way toward creating Android apps quickly with Java.

Android Hacker's Handbook

The first comprehensive guide to discovering and preventing attacks on the Android OS

Android Hacker's Handbook

As the Android operating system continues to increase its share of the smartphone market, smartphone hacking remains a growing threat. Written by experts who rank among the world's foremost Android security researchers, this book presents vulnerability discovery, analysis, and exploitation tools for the good guys. Following a detailed explanation of how the Android OS works and its overall security architecture, the authors examine how vulnerabilities can be discovered and exploits developed for various system components, preparing you to defend against them.

If you are a mobile device administrator, security researcher, Android app developer, or consultant responsible for evaluating Android security, you will find this guide is essential to your toolbox.
  • A crack team of leading Android security researchers explain Android security risks, security design and architecture, rooting, fuzz testing, and vulnerability analysis
  • Covers Android application building blocks and security as well as debugging and auditing Android apps
  • Prepares mobile device administrators, security researchers, Android app developers, and security consultants to defend Android systems against attack
Android Hacker's Handbook is the first comprehensive resource for IT professionals charged with smartphone security.

Example of programming Android NFC

This example send Uri between Android devices using NFC.


To using NFC on your Android app, modify AndroidManifest.xml.
  • This example target minSdkVersion="16"
  • Add permission of "android.permission.NFC"
  • Add intent-filter of "android.nfc.action.NDEF_DISCOVERED"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidnfc"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.NFC"/>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidnfc.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"
android:host="android-er.blogspot.com"
android:pathPrefix="/" />
</intent-filter>

</activity>
</application>

</manifest>


MainActivity.java
package com.example.androidnfc;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcAdapter.OnNdefPushCompleteCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements
CreateNdefMessageCallback, OnNdefPushCompleteCallback{

TextView textInfo;

NfcAdapter nfcAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInfo = (TextView)findViewById(R.id.info);

nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(nfcAdapter==null){
Toast.makeText(MainActivity.this,
"nfcAdapter==null, no NFC adapter exists",
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(MainActivity.this,
"Set Callback(s)",
Toast.LENGTH_LONG).show();
nfcAdapter.setNdefPushMessageCallback(this, this);
nfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}

@Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
String action = intent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
Parcelable[] parcelables =
intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
NdefRecord NdefRecord_0 = inNdefRecords[0];
String inMsg = new String(NdefRecord_0.getPayload());
textInfo.setText(inMsg);
}
}

@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
}

@Override
public void onNdefPushComplete(NfcEvent event) {

final String eventString = "onNdefPushComplete\n" + event.toString();
runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(getApplicationContext(),
eventString,
Toast.LENGTH_LONG).show();
}
});

}

@Override
public NdefMessage createNdefMessage(NfcEvent event) {
NdefRecord rtdUriRecord = NdefRecord.createUri("http://arteluzevida.blogspot.com/");

NdefMessage ndefMessageout = new NdefMessage(rtdUriRecord);
return ndefMessageout;
}

}


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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidnfc.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>


download filesDownload the files.

Related:
Communication between Android using NFC to send text

Strategies for Developing Cross-Device Applications with Visual Studio 2013

This session will cover the strategic decisions developers have to make when targeting multiples devices in application. The video will explore the tools and technologies that available in Visual Studio 2013 for both web and native applications that target Windows, iOS and Android devices, as well as best practices to reuse code and skills across them.

source: http://channel9.msdn.com/Events/Build/2014/2-586

What's Google got to do with games?

Video from Google Developers Summit keynote, connecting you with the gaming community. How to use Google's latest technologies to build, distribute, promote, and monetize your games.


What's New in Ubuntu 14.04 LTS

Released on April 17, 2014, Ubuntu 14.04 is the latest Long Term Support release of the world's most popular open-source operating system.

See What's New in Ubuntu 14.04 LTS

Remote control Windows from Ubuntu Linux with Chrome Remote Desktop

With Chrome Remote Desktop "Enable remote connection" on Windows PC (refer to the last post), you can remote control it from Linux PC with Chrome Remote Desktop.

Remote access shared computer using Chrome Remote Desktop app on Android

The video show how to setup Chrome Remote Desktop on shared computer (running Windows 8.1) to enable remote access with PIN. Then you can control your computer remotely using Chrome Remote Desktop App on Android device.


In shared computer, Windows 8.1 in this example:
  • You need to log-in with a Google account.
  • Install Chrome Remote Desktop in Google Chrome.
  • Run the Chrome Remote Desktop App in Chrome's App pane.
  • Click the Get Started button in "My Computer" box.
  • Click "Enable remote connection".
  • Enter and re-enter the PIN you want, then OK.
  • You will be ask to grant permission by Windows.
  • Your computer, win-8b in this example, will be shown in "My Computer" box.
In Android:
  • Simple install Chrome Remote Desktop App.
  • Run it and select the same Google account in computer side.
  • You can see the computer, win-8b, in the list.

The following video show remote control shared PC from Android Phone. In this example, the Android phone connect Internet using 3G network. The shared PC running Windows 8.1, with Chrome Remote Desktop installed and setup "Enable remote connection", power-on with internet connection (via home network), even have not log-in Windows session, no any port forwarding setting on router. 



You can also access your shared Windows from Ubuntu Linux, read next post "Remote control Windows from Ubuntu Linux with Chrome Remote Desktop".

Related: Share computer desktop with Chrome Remote Desktop


Share computer desktop with Chrome Remote Desktop

Chrome Remote Desktop allows users to remotely access another computer through Chrome browser or a Chromebook.  Computers can be made available on an short-term basis for scenarios such as ad hoc remote support, or on a more long-term basis for remote access to your applications and files.  All connections are fully secured.

Chrome Remote Desktop is fully cross-platform.  Provide remote assistance to Windows, Mac and Linux users, or access your Windows (XP and above) and Mac (OS X 10.6 and above) desktops at any time, all from the Chrome browser on virtually any device, including Chromebooks.

This video show installation and setup Chrome Remote Desktop on Windows 8.1 to be shared. And install and setup on Ubuntu to access the shared Windows desktop.



Related: Access shared computer using Chrome Remote Desktop app on Android

Display currency symbols

This example TRY to show various available currency symbols on Android. This symbols reference to the file http://www.unicode.org/charts/PDF/U20A0.pdf, it contains an excerpt from the character code tables and list of character names for The Unicode Standard, Version 6.3.

Please note that some symbols cannot be shown, because it have not been installed in Android system.


MainActivity.java
package com.example.androidshowcurrency;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

public class MainActivity extends Activity {

MyCurrency[] MyCurrencyAll ={
new MyCurrency("$", "dollar sign"),
new MyCurrency("¢", "cent sign"),
new MyCurrency("£", "pound sign"),
new MyCurrency("¤", "currency sign"),
new MyCurrency("¥", "yen sign"),
new MyCurrency("ƒ", "latin small letter f with hook"),
new MyCurrency("", "afghani sign"),
new MyCurrency("৲", "bengali rupee mark"),
new MyCurrency("૱", "gujarati rupee sign"),
new MyCurrency("௹", "tamil rupee sign"),
new MyCurrency("฿", "thai currency symbol baht"),
new MyCurrency("¤", "khmer currency symbol riel"),
new MyCurrency("ℳ", "script capital m"),
new MyCurrency("元", "cjk unified ideograph-5143"),
new MyCurrency("円", "cjk unified ideograph-5186"),
new MyCurrency("圆", "cjk unified ideograph-5706"),
new MyCurrency("圓", "cjk unified ideograph-5713"),
new MyCurrency("", "rial sign"),
new MyCurrency("₠", "EURO-CURRENCY SIGN"),
new MyCurrency("₡", "COLON SIGN"),
new MyCurrency("₢", "CRUZEIRO SIGN"),
new MyCurrency("₣", "FRENCH FRANC SIGN"),
new MyCurrency("₤", "LIRA SIGN"),
new MyCurrency("₥", "MILL SIGN"),
new MyCurrency("₦", "NAIRA SIGN"),
new MyCurrency("₧", "PESETA SIGN"),
new MyCurrency("₨", "RUPEE SIGN"),
new MyCurrency("₩", "WON SIGN"),
new MyCurrency("₪", "NEW SHEQEL SIGN"),
new MyCurrency("₫", "DONG SIGN"),
new MyCurrency("€", "EURO SIGN"),
new MyCurrency("₭", "KIP SIGN"),
new MyCurrency("₮", "TUGRIK SIGN"),
new MyCurrency("₯", "DRACHMA SIGN"),
new MyCurrency("₰", "GERMAN PENNY SIGN"),
new MyCurrency("₱", "PESO SIGN"),
new MyCurrency("₲", "GUARANI SIGN"),
new MyCurrency("₳", "AUSTRAL SIGN"),
new MyCurrency("₴", "HRYVNIA SIGN"),
new MyCurrency("₵", "CEDI SIGN"),
new MyCurrency("₶", "LIVRE TOURNOIS SIGN"),
new MyCurrency("₷", "SPESMILO SIGN"),
new MyCurrency("₸", "TENGE SIGN"),
new MyCurrency("₹", "INDIAN RUPEE SIGN"),
new MyCurrency("₺", "TURKISH LIRA SIGN")
};

Spinner spinnerCurrency;
TextView textBigCurrency;

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

textBigCurrency = (TextView)findViewById(R.id.bigcurrency);
spinnerCurrency = (Spinner)findViewById(R.id.spinnerCurrency);

MySpinnerAdapter adapterCurr =
new MySpinnerAdapter(MainActivity.this,
R.layout.row,
MyCurrencyAll);
spinnerCurrency.setAdapter(adapterCurr);
spinnerCurrency.setOnItemSelectedListener(onItemSelectedListener);

}

OnItemSelectedListener onItemSelectedListener =
new OnItemSelectedListener(){

@Override
public void onItemSelected(AdapterView<?> parent,
View view, int position, long id) {
MyCurrency curr = (MyCurrency)(parent.getItemAtPosition(position));
textBigCurrency.setText(String.valueOf(curr.getSymbol()));
}

@Override
public void onNothingSelected(AdapterView<?> parent) {}

};

// define our custom class
public class MyCurrency {

private String symbol;
private String desc;

public MyCurrency(String symbol, String desc) {
this.symbol = symbol;
this.desc = desc;
}


public String getSymbol() {
return this.symbol;
}

public String getDesc() {
return this.desc;
}
}

// custom adapter
public class MySpinnerAdapter extends ArrayAdapter<MyCurrency> {

private MyCurrency[] myCurrencyArray;

public MySpinnerAdapter(Context context, int textViewResourceId,
MyCurrency[] myObjs) {
super(context, textViewResourceId, myObjs);
this.myCurrencyArray = myObjs;
}

public int getCount() {
return myCurrencyArray.length;
}

public MyCurrency getItem(int position) {
return myCurrencyArray[position];
}

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

@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
return getCustomView(position, convertView, parent);
}

@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
return getCustomView(position, convertView, parent);
}

private View getCustomView(int position, View convertView,
ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.row, parent, false);

TextView textSymbol = (TextView) view
.findViewById(R.id.textSymbol);
textSymbol.setText(myCurrencyArray[position].getSymbol());
TextView textDesc = (TextView) view
.findViewById(R.id.textDesc);
textDesc.setText(myCurrencyArray[position].getDesc());

return view;
}
}

}

/res/layout/row.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="wrap_content"
android:orientation="vertical"
android:padding="10dp" >

<TextView
android:id="@+id/textSymbol"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold" />
<TextView
android:id="@+id/textDesc"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="italic" />
</LinearLayout>

/res/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:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidspinnertext.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<Spinner
android:id="@+id/spinnerCurrency"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/bigcurrency"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:textSize="150sp" />

</LinearLayout>


download filesDownload the files.

Or, download the APK HERE.

Related:
Display available currencies java.util.Currency

Pro Android UI

Pro Android UI

If you’re an Android application developer, chances are you’re using fixed, scrolling, swipe-able, and other cutting-edge custom UI Designs in your Android development projects. These UI Design approaches as well as other Android ViewGroup UI layout containers are the bread and butter of Pro Android User Interface (UI) design and Android User Experience (UX) design and development.

Using a top down approach, Pro Android UI shows you how to design and develop the best user interface for your app, while taking into account the varying device form factors in the increasingly fragmented Android environment. Pro Android UI aims to be the ultimate reference and customization cookbook for your Android UI Design, and as such will be useful to experienced developers as well as beginners.

With Android’s powerful UI layout classes, you can easily create everything from the simplest of lists to fully tricked-out user interfaces. While using these UI classes for boring, standard user interfaces can be quite simple, customizing a unique UI design can often become extremely challenging.


What you’ll learn

  • How to design and develop a sleek looking and highly functional user interface (UI) design and experience (UX) design using Android APIs
  • What Android layout containers are, and how to best leverage them
  • How to design user-friendly UI layouts that conform to Android UI guidelines
  • What, when, why and how to use fundamental Android UI layout containers (ViewGroup subclasses) and Android UI widgets (View subclasses)
  • How to use new media assets such as images, video, and animation in a UI
  • How to create UI Fragments for UI design for specific ActionBar or Activity classes that you wish to create for UI designs within your applications
  • Scaling UI Design for the various Android smartphone and tablet form factors

  • Who this book is for
    This book is for experienced Android app developers.  It can also be for app developers and UI designers working on other platforms like iOS and BlackBerry who might also be interested in Android.

    Table of Contents

    Part I. Introduction to the Core Classes for Android UI Design: Development Tools, Layout Containers and Widgets
    1. Android UI Design Tools: Setting Up Your Android Development System
    2. Android UI Layouts: Layout Containers and the ViewGroup Class
    3. Android UI Widgets: User Interface Widgets and the View Class

    Part II. Introduction to Android Menu Class for UI Design: OptionsMenu, ContextMenu, PopupMenu and ActionBar
    4. Android UI Options Menus: OptionsMenu Class and an Introduction to the Android ActionBar
    5. Android UI Local Menus: The ContextMenu Class and PopupMenu Class
    6. Android UI Action Bar: Advanced ActionBar Design & ActionBar Class

    Part III. Android UI: Layout Considerations, Concepts & UI Containers: LinearLayout, RelativeLayout, FrameLayout
    7. Android UI Design Considerations: Styles, Screen Density Targets and New Media Formats
    8. Android UI Design Concepts: Wire-framing & UI Layout Design Patterns
    9. Android UI Layout Conventions, Differences and Approaches
    10. Android UI Theme Design & Digital Media Concepts

    Part IV. Basic Android UI Design: Basic Layout Containers: FrameLayout, LinearLayout,
    RelativeLayout, GridLayout
    11. Android’s FrameLayout Class: Using Digital Video in your UI Design
    12. Android’s LinearLayout Class: Horizontal and Vertical UI Design
    13. Android’s RelativeLayout Class: Complex UI Design Via a Single Layout Container
    14. Android’s GridLayout Class: Optimized UI Design using a Grid-based Layout

    Part V. Advanced Android UI Design: Advanced Layout Containers: DrawerLayout, SlidingPane, ViewPager, Strips
    15. Android DrawerLayout Class: Using Left and Right Side UI Drawer Design
    16. Android SlidingPaneLayout Class: Optimized UI Design using a Grid-based Layout Container
    17. Android ViewPager Class: Using View Paging to Navigate Complex View Hierarchies
    18. Android PagerTabStrip and PagerTitleStrip Classes: Design Navigation UI Elements for the ViewPager Layout

    Custom Spinner with different normal view and drop-down view

    It's another example of custom Spinner, which have different normal view and drop-down view, using custom object and adapter for the spinner. Our custom object have two String, one for display text, another for Internet address.

    In normal view, returned by getView() of our custom ArrayAdapter, there are one TextView to show the display text, and another button to open the target address if clicked. In drop-down view, returned by getDropDownView() of our custom ArrayAdapter, there are two TextView to show the display text, and the target address.


    /res/layout/row.xml, the layout of the normal view.
    <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="wrap_content"
    android:orientation="vertical" >

    <TextView
    android:id="@+id/gotext"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp"
    android:textStyle="bold"/>
    <Button
    android:id="@+id/gobutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
    </LinearLayout>

    /res/layout/dropdown.xml, the layout of the drop-down view.
    <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="wrap_content"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
    android:id="@+id/gotext"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp"
    android:textStyle="bold" />
    <TextView
    android:id="@+id/goaddr"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textStyle="italic" />
    </LinearLayout>

    /res/layout/activity_main.xml, the layout of our activity.
    <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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidspinnertext.MainActivity" >

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://arteluzevida.blogspot.com/"
    android:textStyle="bold" />

    <Spinner
    android:id="@+id/spinnergo"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
    <TextView
    android:id="@+id/textgo"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

    </LinearLayout>

    MainActivity.java
    package com.example.androidspinnertext;

    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemSelectedListener;
    import android.widget.ArrayAdapter;
    import android.widget.Button;
    import android.widget.Spinner;
    import android.widget.TextView;

    public class MainActivity extends Activity {

    MyClass[] objGo ={
    new MyClass("Android-er", "http://arteluzevida.blogspot.com/"),
    new MyClass("Arduino-er", "http://arduino-er.blogspot.com/"),
    new MyClass("Hello Raspberry Pi", "http://helloraspberrypi.blogspot.com/"),
    new MyClass("MyPhotoBlog", "http://photo-er.blogspot.com/"),
    new MyClass("g+ Androider+", "https://plus.google.com/102969667192015169220"),
    new MyClass("Youtube playlist: Android Development", "http://www.youtube.com/playlist?list=PLP7qPet500deChwUlhq-GsDl8Tun4_WMD"),
    new MyClass("Google Play", "https://play.google.com/store")
    };

    Spinner spinnerGo;
    TextView textViewGo;

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

    textViewGo = (TextView)findViewById(R.id.textgo);
    spinnerGo = (Spinner)findViewById(R.id.spinnergo);
    MySpinnerAdapter adapterGo =
    new MySpinnerAdapter(MainActivity.this,
    R.layout.row,
    objGo);
    spinnerGo.setAdapter(adapterGo);
    //spinnerGo.setOnItemSelectedListener(onItemSelectedListenerGo);

    }

    OnItemSelectedListener onItemSelectedListenerGo =
    new OnItemSelectedListener(){

    @Override
    public void onItemSelected(AdapterView<?> parent, View view,
    int position, long id) {
    MyClass obj = (MyClass)(parent.getItemAtPosition(position));
    textViewGo.setText(String.valueOf(obj.getTarget()));
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}

    };

    //define our custom class
    public class MyClass{

    private String text;
    private String target;

    public MyClass(String text, String target){
    this.text = text;
    this.target = target;
    }

    public void setText(String text){
    this.text = text;
    }

    public String getText(){
    return this.text;
    }

    public void setValue(String target){
    this.target = target;
    }

    public String getTarget(){
    return this.target;
    }
    }

    //custom adapter
    public class MySpinnerAdapter extends ArrayAdapter<MyClass>{

    private MyClass[] myObjs;

    public MySpinnerAdapter(Context context, int textViewResourceId,
    MyClass[] myObjs) {
    super(context, textViewResourceId, myObjs);
    this.myObjs = myObjs;
    }

    public int getCount(){
    return myObjs.length;
    }

    public MyClass getItem(int position){
    return myObjs[position];
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = getLayoutInflater();
    View spView = inflater.inflate(R.layout.row, parent, false);

    TextView sp_GoText = (TextView)spView.findViewById(R.id.gotext);
    sp_GoText.setText(myObjs[position].getText());

    Button sp_GoButton = (Button)spView.findViewById(R.id.gobutton);
    sp_GoButton.setText(myObjs[position].getTarget());

    sp_GoButton.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
    Uri uri = Uri.parse(myObjs[position].getTarget());
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    startActivity(intent);
    }});

    return spView;
    }

    @Override
    public View getDropDownView(int position, View convertView,
    ViewGroup parent) {
    LayoutInflater inflater = getLayoutInflater();
    View dropDownView = inflater.inflate(R.layout.dropdown, parent, false);

    TextView dd_GoText = (TextView)dropDownView.findViewById(R.id.gotext);
    dd_GoText.setText(myObjs[position].getText());

    TextView dd_GoAddr = (TextView)dropDownView.findViewById(R.id.goaddr);
    dd_GoAddr.setText(myObjs[position].getTarget());

    return dropDownView;

    }

    }

    }



    download filesDownload the files.

    Free ebook: Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition

    Visit HERE to download the Free ebook: Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition

    Spinner with different display text and return value

    In the most basic Spinner implementation, selected item can be retrieved by calling parent.getItemAtPosition(position) in onItemSelected() method in OnItemSelectedListener. It will be the same object of the display items, as show in the spinner0 of the example.

    Sometimes, we want to display some meaningful text in Spinner (such as "Sunday", "Monday"...), but return some other value when any item selected (such as 0, 2...).

    Spinner with different display text and return value
    Here I show two approaches:
    • The first one may be the simplest method, spinner1 in the example. Create another array to hold the values we want to return. And return the coresponding item on position in onItemSelected().
    • The second approach implement our custom class to hold the display text and the return value. And implement our custom Adapter, as shown in spinner2 in the example.

    package com.example.androidspinnertext;

    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemSelectedListener;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;
    import android.widget.TextView;

    public class MainActivity extends Activity {

    String[] text0 = { "Sunday", "Monday", "Tuesday",
    "Wednesday", "Thursday", "Friday", "Saturday" };

    String[] text1 = { "SUNDAY", "MONDAY", "TUESDAY",
    "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY" };
    int[] val1 = { 0, 1, 2, 3, 4, 5, 6};

    MyClass[] obj2 ={
    new MyClass("SUN", 0),
    new MyClass("MON", 1),
    new MyClass("TUE", 2),
    new MyClass("WED", 3),
    new MyClass("THU", 4),
    new MyClass("FRI", 5),
    new MyClass("SAT", 6)
    };

    Spinner spinner0, spinner1, spinner2;
    TextView textView0, textView1, textView2;

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

    textView0 = (TextView)findViewById(R.id.text0);
    spinner0 = (Spinner)findViewById(R.id.spinner0);
    ArrayAdapter<String> adapter0 =
    new ArrayAdapter<String>(MainActivity.this,
    android.R.layout.simple_spinner_item, text0);
    adapter0.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner0.setAdapter(adapter0);
    spinner0.setOnItemSelectedListener(onItemSelectedListener0);

    textView1 = (TextView)findViewById(R.id.text1);
    spinner1 = (Spinner)findViewById(R.id.spinner1);
    ArrayAdapter<String> adapter1 =
    new ArrayAdapter<String>(MainActivity.this,
    android.R.layout.simple_spinner_item, text1);
    adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner1.setAdapter(adapter1);
    spinner1.setOnItemSelectedListener(onItemSelectedListener1);

    textView2 = (TextView)findViewById(R.id.text2);
    spinner2 = (Spinner)findViewById(R.id.spinner2);
    MySpinnerAdapter adapter2 =
    new MySpinnerAdapter(MainActivity.this,
    android.R.layout.simple_spinner_item, obj2);
    //adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner2.setAdapter(adapter2);
    spinner2.setOnItemSelectedListener(onItemSelectedListener2);

    }

    OnItemSelectedListener onItemSelectedListener0 =
    new OnItemSelectedListener(){

    @Override
    public void onItemSelected(AdapterView<?> parent, View view,
    int position, long id) {
    String s0 = (String)parent.getItemAtPosition(position);
    textView0.setText(s0);
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}
    };

    OnItemSelectedListener onItemSelectedListener1 =
    new OnItemSelectedListener(){

    @Override
    public void onItemSelected(AdapterView<?> parent, View view,
    int position, long id) {
    String s1 = String.valueOf(val1[position]);
    textView1.setText(s1);
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}

    };

    OnItemSelectedListener onItemSelectedListener2 =
    new OnItemSelectedListener(){

    @Override
    public void onItemSelected(AdapterView<?> parent, View view,
    int position, long id) {
    MyClass obj = (MyClass)(parent.getItemAtPosition(position));
    textView2.setText(String.valueOf(obj.getValue()));
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}

    };

    //define our custom class
    public class MyClass{

    private String text;
    private int value;


    public MyClass(String text, int value){
    this.text = text;
    this.value = value;
    }

    public void setText(String text){
    this.text = text;
    }

    public String getText(){
    return this.text;
    }

    public void setValue(int value){
    this.value = value;
    }

    public int getValue(){
    return this.value;
    }
    }

    //custom adapter
    public class MySpinnerAdapter extends ArrayAdapter<MyClass>{

    private Context context;
    private MyClass[] myObjs;

    public MySpinnerAdapter(Context context, int textViewResourceId,
    MyClass[] myObjs) {
    super(context, textViewResourceId, myObjs);
    this.context = context;
    this.myObjs = myObjs;
    }

    public int getCount(){
    return myObjs.length;
    }

    public MyClass getItem(int position){
    return myObjs[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    TextView label = new TextView(context);
    label.setText(myObjs[position].getText());
    return label;
    }

    @Override
    public View getDropDownView(int position, View convertView,
    ViewGroup parent) {
    TextView label = new TextView(context);
    label.setText(myObjs[position].getText());
    return label;
    }
    }

    }

    <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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidspinnertext.MainActivity" >

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://arteluzevida.blogspot.com/"
    android:textStyle="bold" />

    <Spinner
    android:id="@+id/spinner0"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
    <TextView
    android:id="@+id/text0"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

    <Spinner
    android:id="@+id/spinner1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
    <TextView
    android:id="@+id/text1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

    <Spinner
    android:id="@+id/spinner2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
    <TextView
    android:id="@+id/text2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

    </LinearLayout>



    download filesDownload the files.

    Get user-agent of your WebView/browser

    To get the user-agent of your browser in HTML code, you can read navigator.userAgent.

    This example show user-agent of your WebView, and also include a link to HTML5TEST to test your HTML compatibility. It's how it run on Nexus 7 running Android 4.4.2 KitKat, and on HTC One X running 4.2.2.

    Run on Nexus 7, Android 4.4.2


    Run on HTC One X, Android 4.2.2


    Android 4.4 (KitKat) includes a new WebView component based on the Chromium open source project. The new WebView includes an updated version of the V8 JavaScript engine and support for modern web standards that were missing in the old WebView. It also shares the same rendering engine as Chrome for Android, so rendering should be much more consistent between the WebView and Chrome.

    The new WebView adds Chrome/_version_ to the user-agent string. 

    ~ about WebView for Android

    /assets/mypage.html
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width; user-scalable=0;" />
    <title>My HTML</title>
    </head>
    <body>
    <h1>MyHTML</h1>
    <p id="mytext">Hello!</p>
    <p>my User-agent</P>
    <p id="myUA">Hello!</p>
    <br/>
    visit: <a href="http://html5test.com/">http://html5test.com/</a>
    <script language="javascript">
    document.getElementById("myUA").innerHTML=navigator.userAgent;
    </script>

    </body>
    </html>

    MainActivity.java
    package com.example.androidbrowser;

    import android.support.v7.app.ActionBarActivity;
    import android.support.v4.app.Fragment;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.ViewGroup;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;

    public class MainActivity extends ActionBarActivity {

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

    if (savedInstanceState == null) {
    getSupportFragmentManager().beginTransaction()
    .add(R.id.container, new PlaceholderFragment()).commit();
    }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
    return true;
    }
    return super.onOptionsItemSelected(item);
    }

    /**
    * A placeholder fragment containing a simple view.
    */
    public static class PlaceholderFragment extends Fragment {

    WebView myBrowser;

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container,
    false);
    myBrowser = (WebView) rootView.findViewById(R.id.mybrowser);

    myBrowser.getSettings().setJavaScriptEnabled(true);
    myBrowser.loadUrl("file:///android_asset/mypage.html");

    //open new web page in the same myBrowser webview
    myBrowser.setWebViewClient(new WebViewClient() {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
    view.loadUrl(url);
    return false;
    }

    });


    return rootView;
    }

    }

    }

    /res/layout/fragment_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    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://arteluzevida.blogspot.com/"
    android:textStyle="bold" />

    <WebView
    android:id="@+id/mybrowser"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

    </LinearLayout>

    /res/layout/activity_main.xml, default generated without changed.
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.androidbrowser.MainActivity"
    tools:ignore="MergeRootFrame" />

    In order to visit Internet, permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidbrowser"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
    android:name="com.example.androidbrowser.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>

    Running on Nexus 7, Android 4.4 Kitkat.