‏إظهار الرسائل ذات التسميات step-by-step series. إظهار كافة الرسائل
‏إظهار الرسائل ذات التسميات step-by-step series. إظهار كافة الرسائل

الجمعة، 23 مايو 2014

Draw Path on canvas of custom View

This example show drawing Path of circle on canvas of custom View, user can adjust its ratio using twh SeekBar. It will be the base of coming exercises.


MainActivity.java
package com.example.androiddrawpath;

import android.app.Activity;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity {

SeekBar radiusBar;
MyView myView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
radiusBar = (SeekBar) findViewById(R.id.radiusbar);
myView = (MyView) findViewById(R.id.myview);
float defaultRatio = (float) (radiusBar.getProgress())
/ (float) (radiusBar.getMax());
myView.setShapeRadiusRatio(defaultRatio);

radiusBar.setOnSeekBarChangeListener(radiusBarOnSeekBarChangeListener);

};

OnSeekBarChangeListener radiusBarOnSeekBarChangeListener =
new OnSeekBarChangeListener() {

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
float defaultRatio = (float) (radiusBar.getProgress())
/ (float) (radiusBar.getMax());
myView.setShapeRadiusRatio(defaultRatio);
myView.invalidate();
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}

};

}

MyView.java, our custom View.
package com.example.androiddrawpath;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path.Direction;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

MyShape myShape;
float ratioRadius;

public MyView(Context context) {
super(context);
initMyView();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initMyView();
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMyView();
}

public void initMyView(){
myShape = new MyShape();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

int w = getWidth();
int h = getHeight();

if((w==0) || (h==0)){
return;
}

float x = (float)w/2.0f;
float y = (float)h/2.0f;
float radius;
if(w > h){
radius = h * ratioRadius;
}else{
radius = w * ratioRadius;
}

myShape.setCircle(x, y, radius, Direction.CCW);
canvas.drawPath(myShape.getPath(), myShape.getPaint());
}

public void setShapeRadiusRatio(float ratio){
ratioRadius = ratio;
}

}

MyShape.java, it is the object hold the Path and Paint to be drawn on our View.
package com.example.androiddrawpath;

import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;

public class MyShape {

private Paint paint;
private Path path;

public MyShape() {
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);

path = new Path();
}

public void setCircle(float x, float y, float radius, Path.Direction dir){
path.reset();
path.addCircle(x, y, radius, dir);
}

public Path getPath(){
return path;
}

public Paint getPaint(){
return paint;
}

}

Layout, /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: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.androiddrawpath.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:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="radius(%)"/>
<SeekBar
android:id="@+id/radiusbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="50" />

<com.example.androiddrawpath.MyView
android:id="@+id/myview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>

download filesDownload the files.


More example:



الأربعاء، 7 مايو 2014

Using Intent.ACTION_OPEN_DOCUMENT, for KitKat API 19 or higher

Android 4.4 KitKat, API 19, introduce new Intent.ACTION_OPEN_DOCUMENT, allow the user to select and return one or more existing documents. When invoked, the system will display the various DocumentsProvider instances installed on the device, letting the user interactively navigate through them. These documents include local media, such as photos and video, and documents provided by installed cloud storage providers.

Each document is represented as a content://

This example show how to select image file by calling startActivityForResult() with Intent of ACTION_OPEN_DOCUMENT, then load it in ImageView from the returned Uri.
  • To load image Intent.ACTION_OPEN_DOCUMENT, setType("image/*")
  • This example haven't handle resize of the image, so may be fail if load ImageView with large image.
  • If the app run on pre-KitKat devices, it will use old Intent.ACTION_GET_CONTENT.


package com.example.androidkitkatdocument;

import java.io.FileNotFoundException;

import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

public class MainActivity extends Activity {

private static final int RQS_OPEN_IMAGE = 1;

Button buttonOpen;
TextView textUri;
ImageView imageView;

Uri targetUri = null;

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

buttonOpen = (Button) findViewById(R.id.opendocument);
buttonOpen.setOnClickListener(buttonOpenOnClickListener);

textUri = (TextView) findViewById(R.id.texturi);
textUri.setOnClickListener(textUriOnClickListener);

imageView = (ImageView)findViewById(R.id.image);
}

OnClickListener buttonOpenOnClickListener =
new OnClickListener() {

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void onClick(View v) {
Intent intent = new Intent();

if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.KITKAT) {
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
} else {
intent.setAction(Intent.ACTION_GET_CONTENT);
}

intent.addCategory(Intent.CATEGORY_OPENABLE);

// set MIME type for image
intent.setType("image/*");

startActivityForResult(intent, RQS_OPEN_IMAGE);
}

};

OnClickListener textUriOnClickListener =
new OnClickListener(){

@Override
public void onClick(View v) {
if (targetUri != null){
Bitmap bm;
try {
bm = BitmapFactory.decodeStream(
getContentResolver()
.openInputStream(targetUri));
imageView.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

};

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {

if (resultCode == Activity.RESULT_OK) {

Uri dataUri = data.getData();

if (requestCode == RQS_OPEN_IMAGE) {
targetUri = dataUri;
textUri.setText(dataUri.toString());
}
}

}

}

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.androidkitkatdocument.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" />

<Button
android:id="@+id/opendocument"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Document of Image" />

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

<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</LinearLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidkitkatdocument"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />

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

More examples:
Using Intent.ACTION_OPEN_DOCUMENT with EXTRA_MIME_TYPES to open file of multi mime types
Open multi files using Intent.ACTION_OPEN_DOCUMENT, with EXTRA_ALLOW_MULTIPLE and getClipData()
Intent.ACTION_OPEN_DOCUMENT to load images in RecyclerView + CardView
Hello World to open photo using Intent.ACTION_OPEN_DOCUMENT, with FloatingActionButton and Snackbar


الخميس، 1 مايو 2014

Implement Android MP3 Player using MediaPlayer

MediaPlayer class can be used to control playback of audio/video files and streams. It is a example to implement MP3 Player using MediaPlayer. Please note that you have to keep follow the State Diagram, otherwise IllegalStateException will be thrown.


Create a new Android Project in Eclipse, using the auto-generated code extend from ActionBarActivity.

The mp3 file is stored in /res/raw/vespers.mp3. Filename match with the following code in initMediaPlayer().

mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);

MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

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 {

Button btnStart, btnPause, btnStop, btnSeek;
TextView textState, textDuration, textPosition;

MediaPlayer mediaPlayer;

private int stateMediaPlayer;
private final int STATE_Idle = 0;
private final int STATE_Initialized = 1;
private final int STATE_Preparing = 2;
private final int STATE_Prepared = 3;
private final int STATE_Started = 4;
private final int STATE_Paused = 5;
private final int STATE_Stopped = 6;
private final int STATE_PlaybackCompleted = 7;
private final int STATE_End = 8;
private final int STATE_Error = 9;

public PlaceholderFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initMediaPlayer();
}

@Override
public void onDestroy() {

Toast.makeText(getActivity(),
"release mediaPlayer",
Toast.LENGTH_LONG).show();
mediaPlayer.release();
mediaPlayer = null;
setPlayerState(STATE_End);

super.onDestroy();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btnStart = (Button) rootView.findViewById(R.id.start);
btnPause = (Button) rootView.findViewById(R.id.pause);
btnStop = (Button) rootView.findViewById(R.id.stop);
btnSeek = (Button) rootView.findViewById(R.id.seekto);

btnStart.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.start();
setPlayerState(STATE_Started);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Play at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnPause.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.pause();
setPlayerState(STATE_Paused);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Pause at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnStop.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Stopped
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

//Stop
mediaPlayer.stop();
setPlayerState(STATE_Stopped);

//then parepare in background thread
mediaPlayer.prepareAsync();
setPlayerState(STATE_Preparing);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Stop at Invalid state!",
Toast.LENGTH_LONG).show();
}

}
});

btnSeek.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.seekTo(0);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"SeekTo at Invalid state!",
Toast.LENGTH_LONG).show();
}
}});

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(STATE_Prepared);
displayDurationPosition();
}});

mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

@Override
public void onCompletion(MediaPlayer mp) {
setPlayerState(STATE_PlaybackCompleted);
displayDurationPosition();
}});

textState = (TextView) rootView.findViewById(R.id.state);
textState.setText(getPlayerState());

textDuration = (TextView) rootView.findViewById(R.id.duration);
textPosition = (TextView) rootView.findViewById(R.id.position);
displayDurationPosition();

textDuration.setOnClickListener(new OnClickListener(){

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

textPosition.setOnClickListener(new OnClickListener(){

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

return rootView;
}

private void displayDurationPosition(){
textDuration.setText(
"Duration: " + mediaPlayer.getDuration() + " ms");
textPosition.setText(
"Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
}

private void initMediaPlayer() {
Toast.makeText(getActivity(),
"initMediaPlayer()",
Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
setPlayerState(STATE_Prepared);
}

private void setPlayerState(int st){
stateMediaPlayer = st;

String stringState = getPlayerState();
if(textState!=null){
textState.setText(stringState);
}else{
Toast.makeText(getActivity(),
stringState, Toast.LENGTH_LONG).show();
}

}

private String getPlayerState(){
String strSt;
switch(stateMediaPlayer){
case STATE_Idle:
strSt = "Idle";
break;
case STATE_Initialized:
strSt = "Initialized";
break;
case STATE_Preparing:
strSt = "Preparing";
break;
case STATE_Prepared:
strSt = "Prepared";
break;
case STATE_Started:
strSt = "Started";
break;
case STATE_Paused:
strSt = "Paused";
break;
case STATE_Stopped:
strSt = "Stopped";
break;
case STATE_PlaybackCompleted:
strSt = "PlaybackCompleted";
break;
case STATE_End:
strSt = "End";
break;
case STATE_Error:
strSt = "Error";
break;
default:
strSt = "unknown...";
}
return strSt;
}
}

}

fragment_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.androidmp3player.MainActivity$PlaceholderFragment" >

<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" />

<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pause" />
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop" />
<Button
android:id="@+id/seekto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Seek To Beginning" />
<TextView
android:id="@+id/state"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/duration"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/position"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

Auto generated activity_main.xml.
<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.androidmp3player.MainActivity"
tools:ignore="MergeRootFrame" />


download filesDownload the files (not include the mp3 file).

Next:
Implement OnErrorListener.
Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer
Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()

الأحد، 23 فبراير 2014

Runnable in background thread

This exercise show how to run a Runnable in background.
Runnable in background thread
Runnable in background thread

In this exercise, we need to check if the current thread is the main thread, or called UI thread. Using the code:

Looper.getMainLooper().getThread()==Thread.currentThread()

If it's true, means it's in main thread, otherwise it's in background thread.

The example show how to implement a Thread with Runnable object. And call its start() method to starts the new Thread of execution. Also notice that if you call its run() method, it will calls the run() method of the Runnable object directly, in current thread.

package com.example.androidthread;

import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

Button buttonStart, buttonRun;
TextView textInfo;

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

buttonStart.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View arg0) {
Thread thread = new Thread(new MyRunnable());
thread.start(); //in background thread
}});

buttonRun.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View arg0) {
Thread thread = new Thread(new MyRunnable());
thread.run(); //in current thread
}});
}

private class MyRunnable implements Runnable {

@Override
public void run() {
// check if it's run in main thread, or background thread
if(Looper.getMainLooper().getThread()==Thread.currentThread()){
//in main thread
textInfo.setText("in main thread");
}else{
//in background thread

runOnUiThread(new Runnable(){

@Override
public void run() {
textInfo.setText("in background thread");
}

});
}
}

}

}

<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=".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" />
<Button
android:id="@+id/buttonstart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="start()" />
<Button
android:id="@+id/buttonrun"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="run()" />
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>


More example about Thread:
Set name of Thread
Share object between threads with synchronized methods
Share object between threads with synchronized Statements
Synchronized Statements with separate lock object, I
Synchronized Statements with separate lock object, II
Example of using Lock/ReentrantLock
Solve Producer–consumer problem with wait() and notifyAll()