Sunday, July 5, 2009

My first time experience with Android Webkit

As I was trying to play around with WebKit, I tried to load an web page through it in Android. A good starting point for WebKit may be found at

http://developer.apple.com/documentation/Cocoa/Conceptual/DisplayWebContent/DisplayWebContent.html .

The source code of my android application is pretty straight forward.

It goes like this:

public class WebKitExample extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

WebView webView;

setContentView(R.layout.main);

webView = (WebView)findViewById(R.id.appView);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl("http://www.google.com");
}
}

We need to add the XML resource in the main.layout as the following:

(WebView android:id="@+id/appView"
android:layout_height="wrap_content"
android:layout_width="fill_parent" /)

We also need to add the permission to the manifest file as the following:

(uses-permission android:name = "android.permission.INTERNET" /)

And the application will look like the following in the emulator.



Although the example shown here is pretty simple but it can be a starting point in learning Webkit in Android. Hope this helps the newbies of Android.

Friday, June 19, 2009

The flow of events during the Media Player Creation in Android Framework

The flow of events of the Android media player is complex. Moreover as i don't have a Linux machine, i have to depend on the careful study of the framework source code. i think i have got a strong enough reason to buy an Ubuntu machine.

Lets come to the fact findings. There are two sides of the Android Media Framework. What we as an user see is the Java interface which is called the Mediaplayer.java. However, this java interface interacts with a native mediaplayer object through Java Native Interface (JNI) mechanism. This interaction is done through the functionalities defined in Android_media_Mediaplayer.cpp. In this file the framework engineers have kept all the necessary JNI functions.

Now when we are about to start the MediaPlayer, the JNI function that is called is the

private native final void native_setup.

This function is actually responsible for creating a C++ mediaplayer object in the native side and storing an opaque reference to it in the Java client side. So when we interact with the client side Java mediaplayer object, we internally interact with this native C++ object.

The JNI layer actually delegates its task to a Mediaplayer object. The functionalities of this C++ class are defined in the file Mediaplayer.cpp.

Now the next step is that we set a data source in the Java side using the function setDataSource function in which the URI of the data source is passed. This in turn calls the native function

android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)


In the native source, this function is defined as

android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
{
sp(MediaPlayer) mp = getMediaPlayer(env, thiz);
........
........

........
........
status_t opStatus = mp->setDataSource(pathStr);

process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." );
}

Look at the line :

status_t opStatus = mp->setDataSource(pathStr);


This function is defined as

status_t MediaPlayer::setDataSource(const char *url)
{
......
......

if (url != NULL) {
const sp(IMediaPlayerService)& service(getMediaPlayerService());
if (service != 0) {
sp(IMediaPlayer) player(service->create(getpid(), this, url));
err = setDataSource(player);
}
}
return err;
}

Look at the line :

sp(IMediaPlayer) player(service->create(getpid(), this, url));

It actually takes the help of the IMediaPlayerservice layer and calls the create function on this. This function can be found in \\base\media\libmedia\IMediaPlayerService.cpp file.

The create function of the MediaPlayerService looks like the following.

sp MediaPlayerService::create(pid_t pid, const sp(IMediaPlayerClient)& client, const char* url)
{
.....

sp(Client) c = new Client(this, pid, connId, client);

.....

.....

if (NO_ERROR != c->setDataSource(url))
{
c.clear();
return c;
}
wp(Client) w = c;

Mutex::Autolock lock(mLock);

mClients.add(w);

return c;
}

Now look at the following line of sp(IMediaPlayer) MediaPlayerService::create(pid_t pid, const sp(IMediaPlayerClient)& client, const char* url)

if (NO_ERROR != c->setDataSource(url))

So we are basically calling the setDataSource on the Client.


This function is like the following:

status_t MediaPlayerService::Client::setDataSource(const char *url)
{
.....

.....

if (strncmp(url, "content://", 10) == 0) {

// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method

String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
LOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
player_type playerType = getPlayerType(url);

.....

.....

// create the right type of player
sp(MediaPlayerBase) p = createPlayer(playerType);
......

......
mStatus = p->setDataSource(url);

if (mStatus == NO_ERROR) mPlayer = p;

return mStatus;
}
}

From the above code snippet it becomes clear that we do

either:

if (strncmp(url, "content://", 10) == 0) {

// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method

String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
LOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;


or:

else {
player_type playerType = getPlayerType(url); //here it extracts the Player Type from the URL.
LOGV("player type = %d", playerType);

// create the right type of player
sp(MediaPlayerBase) p = createPlayer(playerType);

..............
..............

}


In the first case the setDataSource function looks like the following:

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
.......

.......

//here it gets the file type from the File descriptor
player_type playerType = getPlayerType(fd, offset, length);


// create the right type of player
sp(MediaPlayerBase) p = createPlayer(playerType);
........

.........

.........
}

Look at the line :

sp(MediaPlayerBase) p = createPlayer(playerType).

It becomes clear that we create the player here.

The sp(MediaPlayerBase) p = createPlayer (playerType) actually creates the right player. And we get the playertype from the file descriptor.


In the second case (the else part) we call sp p = createPlayer(playerType). We extract the file type from the URL. This helps us in creating the right player object.


The createPlayer function looks like the following:

sp(MediaPlayerBase) MediaPlayerService::Client::createPlayer(player_type playerType)
{
......

......

if (p == NULL) {
p = android::createPlayer(playerType, this, notify);
}
return p;
}


Hence it actually delegates the task to p = android::createPlayer(playerType, this, notify);

The above function is as follows;

static sp(MediaPlayerBase) createPlayer(player_type playerType, void* cookie,
notify_callback_f notifyFunc)

{
.....

switch (playerType) {
#ifndef NO_OPENCORE
case PV_PLAYER:

p = new PVPlayer();

break;
#endif
case SONIVOX_PLAYER:

p = new MidiFile();

break;

case VORBIS_PLAYER:

p = new VorbisPlayer();

break;
}
......

......

return p;
}

Thus we find that the right player is created through the parameterized factory function createPlayer.

i hope this explains how the right mediaplayer is created from the Uri that we pass in the client side java interface of the Mediaplyer.

Saturday, June 13, 2009

Parameterized factory design pattern in Android Media Service Framework

As i was going through the Media framework of Android, i have found the implementation of a parameterized factory pattern in the way MediaPlayerService class creates the concrete media players.

Let me give an idea of the parameterized factory implementation as discussed in the GoF book. It goes like this.

class Creator {

public:

virtual Product* CreateProduct( ProductId id);

};

And the implementation will look like the following:

Product* Creator :: CreateProduct (ProductId id)
{

if (id == Product1) return new Product1;

if (id == Product2) return new Product2;

//repeat for the other products

return 0;

}

Product1, Product2 etc are all derived from the base class Product.

Now let us dissect the Media Framework of Android to see how this design pattern has been implemented to create the different Media players.

The base class of all the players are MediaPlayerInterface which is again derived from MediaPlayerBase.

MediaPlayerService has got a static function called

"static sp createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc)"

which actually takes care of the creation of the concrete players namely PVPlayer, MidiFile and VorbisPlayer.

Hence the class MediaPlayerService works as the Factory class for creating the Concrete Players besides handling other responsibilities.

The class MediaPlayerService can be found at \base\media\libmediaplayerservice of the Android source code.

The createPlayer function goes like the following :

static sp(MediaPlayerBase) createPlayer(player_type playerType, void* cookie,
notify_callback_f notifyFunc)
{
sp(MediaPlayerBase) p;
switch (playerType) {
#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
break;

case VORBIS_PLAYER:
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
if (p == NULL) {
LOGE("Failed to create player object");
}
return p;
}

As we can see from the above code that MediaPlayerBase here works as the base class Product. And we create different products (different concrete media players) through the function createPlayer which works as the CreateProduct function in the example at the beginning.

The above similarity shows how a Parameterized Factory Pattern has been implemented in the Android Media Framework by MediaService layer to create different Media Players.

Wednesday, June 3, 2009

Composite Design Pattern in Android View and Widget

The Intent of this design pattern is stated in the GoF book as "Compose Objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly".

To explain it in a simpler fashion, let me give the same example as given in the GoF book. Suppose there is an object called Picture, a graphics object. This picture may consist of other pictures recursively as well as primitive objects like line, rectangle objects etc. All of these part objects which make the whole picture conform to the same Graphic interface. Hence to the client, a part object appears same as the whole picture consisted of other part objects. To draw a whole object, the client simply traverses through the whole picture and draws different parts.

The class diagram of the composite design pattern will look like the following:




The following participants take part in this design pattern:

Component -

it declares the interface for the objects ( part as well as whole)
helps in managing the objects (adding, removing)

Leaf -

represents leaf objects which don't have any children
these are the primitive objects

Composite -

defines behavior for components having children
stores the children

Client -

takes help of the Component interface to manipulate different objects

Its all about the theoretical side of the Composite Design Pattern. Now let us try to dissect the Android View and the Widget folders (which are available at \\base\core\java\android) to see how this design pattern has been implemented there.

In Android, the View class works as the Component class. However, the child management part (add component, remove component) has been moved to the Composite class which is the ViewGroup class. Actually the Add and Remove of a component has been declared in an interface called ViewManager and the ViewGroup implements that interface. Also the interface for a Composite object is declared as ViewParent interface and the ViewGroup (the Composite object) implements that as well.

The leaf classes like Button, ImageView etc are deduced either by directly subclassing the View (Component) or from the subclasses of the View (for example, the Button class is derived from TextView class which in turn is directly derived fron the View class). The Composite Class (ViewGroup) is deduced by directly subclassing the View and by implementing the two interfaces namely ViewParent (which defines the interface of a composite object) and ViewManager (which defines the interface from adding and removing components).

As expected the getParent function which is needed to get the Parent of a component is put in the View class (the Component).

The Composite object (ViewGroup) has an array to hold its children.

The simplified version of the class diagram of the Android View and Widgets are as follows:



For simplicity i have not shown the two interfaces namely ViewManager and ViewParent.

Now let us consider the class diagram as presented in the beginning of this discussion. There is a function called Operation. In Android implementation, the onDraw function in the Component (View) plays this role. The DispatchDraw function (which is called when the children are to be drawn) in the composite (ViewGroup) object actually traverses through the list of the objects and calls draw on each of the child object. For simplicity, in the class diagram it is shown that the dispatchDraw function is directly calling the onDraw function. However it actually takes help of another function called drawChild which is called on each child object of the ViewGroup object.

This way we can say that Android View and Widgets are some sort of implementation of the Composite Design Pattern.

Sunday, May 31, 2009

Observer Pattern in Java

As i was going through the different source code files of the Java Util package, i found the implementation of the Observer Pattern ( see the GoF book for more information on this pattern) in the two classes - namely Observer.java and Observable.java. i would like to throw some lights on these two classes. These two classes can be found in the Java\j2se\src\share\classes\java\util folder of the JDK source code.

Before explaining the application of Observer Pattern in Java, let me give you a brief introduction of this pattern. Observer pattern helps you in notifying and updating all the dependent objects, if one object changes state. This pattern has two main objects – Subject and Observer. Multiple number of observers can be attached to a particular Subject. All the observers are notified and in turn gotten updated if the Subject changes its state. This is also known as the publish-subscribe. The subject is the publisher of changes, and the Observers are the subscribers to those changes.

The class diagram will look like the following.



And the sequence diagram of this pattern is like this.



What these two diagrams essentially depict is that in the Observer Pattern, we have a Subject, which can attach one or more Observers through its Attach() function. Whenever it changes its state it Notifies all the attached Observers through its Notify function. The observers in turn synchronize their states with that of the Subject through the GetSubjectState function.

Now let me try to dissect the Java observer pattern.

Let us first start with the Observable.java class. As the name suggests it is the class which will implemented functionalities for being observed. Or in other words it is the class which helps in designing the Subject class of the Observer pattern discussion of the GoF book. We need to extend this class to get the Subject class.

Let us try to dissect this class. The following functions are there in this class:

Data Members: It has a vector to hold all the observers that are interested in observing this observable class. It has another boolean data member called "changed" to indicate if anything has changed in the Subject class ( which will be derived from this Observable class).

Constructor : This class has a no argument constructor to construct an empty vector of Observers.

Member Functions :
addObserver : To add an observer to its list of Observers.

deleteObserver : To delete a particular observer from the list of the observers

notifyObservers : there are two overloaded versions of this function. One takes an Object parameter as an argument and the other does not take any argument. The task of this function is to notify all the attached observers when any data of the subject gets changed. To check whether the data is changed it evaluates the boolean "changed" data member. This function also calls the update function of each observer objects to ask them to get in sync with the subject's changed state. The overloaded version that takes an one argument parameter is used to let the observers know about which attribute is changed. And the other version of this function which does not take any argument does not let the observer know about which attribute is changed.

deleteObservers : This function removes all the observers attached to this subject.

setChanged : This function sets the boolean data member "changed".

clearChanged : This function resets the boolean data member "changed".

hasChanged : This function helps us to know whether the data of the subject has been changed or not.

countObservers : This function returns the number of observers attached to this subject.

This is all about the Observable class which helps us to define to Subject class.

The Observable.java defines an interface called Observable having just one abstract function called update (Observable o, Object arg). As the name suggests, the Observer class that will implement this interface will override the update function to set the attribute passed as an argument (arg) from the Subject class. This method is called whenever any attribute in the Subject class gets changed.

Now let us try to see an example to understand how this Observer Pattern is used.

Let us first extend the Observable class to create the Subject class.


public class Subject extends Observable {
private String name;
private float price;

public ConcreteSubject(String name, float price) {
this.name = name;
this.price = price;
}

public String getName() {return name;}

public float getPrice() {return price;}

public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(name);
}

public void setPrice(float price) {
this.price = price;
setChanged();
notifyObservers(new Float(price));
}
}


As this is clear from the implementation of the Subject class, that whenever we call the setter function to change the attributes of the Subject's object, we call the notifyObservers and pass that attribute as a parameter.

Now let us see how we create two different observers namely NameObserver and PriceObserver to observe these two attributes of the Subject class.

// An observer of name changes.
public class NameObserver implements Observer {
private String name;
public NameObserver() {
name = null;
System.out.println("NameObserver created: Name is " + name);
}

public void update(Observable obj, Object arg) {

if (arg instanceof String) {
name = (String)arg;
System.out.println("NameObserver: Name changed to " + name);
}
}
}

// An observer of price changes.
public class PriceObserver implements Observer {
private float price;
public PriceObserver() {
price = 0;
System.out.println("PriceObserver created: Price is " + price);
}

public void update(Observable obj, Object arg) {
if (arg instanceof Float) {
price = ((Float)arg).floatValue();
System.out.println("PriceObserver: Price changed to " +
price);
}
}
}

As it has become clear from the above two implementations that the update function actually helps in synchronizing the state of the concrete observers with that of the Subject.

Now the client of the Observer framework will look like the following :

// Test program for Subject, NameObserver and PriceObserver
public class TestObservers {

public static void main(String args[]) {

// Create the Subject and Observers.
ConcreteSubject s = new ConcreteSubject("Corn Pops", 20.5f);
NameObserver nameObs = new NameObserver();
PriceObserver priceObs = new PriceObserver();

// Add those Observers!
s.addObserver(nameObs);
s.addObserver(priceObs);

// Make changes to the Subject.
s.setName("Frosted Flakes"); // It prints NameObserver: Name changed to Frosted Flakes

s.setPrice(30.6f); //It prints PriceObserver: Price changed to 30.6

s.setPrice(50.8f); //It prints PriceObserver: Price changed to 50.8

s.setName("Sugar Crispies"); // It prints NameObserver: Name changed to Sugar Crispies
}
}

Hope the above discussion will help people understand of how the Java supports implementing the Observer pattern.

Thursday, March 12, 2009

Bridge Pattern

Sunday, January 25, 2009

Android Widget - through Java Code

There are two ways to create android resources/view - either through the XML layout or through pure java code. In this article I have tried to implement the android view through the second method - i.e. through Java code. I have implemented a Table Layout and few widgets like static text, edit box and slider bar. There are three sets of all these widgets - namely Red, Green and Blue. These three are the percentage of the RGB color code. For example if we make Red as 100, and Green and Blue as 0, it will paint the background of the device with Red. It has also shown how to create a prompt dialog when you enter a value more than 100 in any of the edit boxes.

The application will look like the following:



The code for this application is as follow -

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.LinearLayout.LayoutParams;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class Widget extends Activity implements View.OnClickListener /*, View.OnKeyListener */{
/** Called when the activity is first created. */

private final static int idLayout = 1;
private final static int idTitle = 2;

private final static int idTextRed = 3;
private final static int idTextGreen = 4;
private final static int idTextBlue = 5;

private final static int idEditRedText = 6;
private final static int idEditGreenText = 7;
private final static int idEditBlueText = 8;

private final static int idSeekBarRed = 9;
private final static int idSeekBarGreen = 10;
private final static int idSeekBarBlue =11;

private final static int idButtonOK = 12;

private final static int MaxColorValue = 255;

private static int RedProgress = 0;
private static int GreenProgress = 0;
private static int BlueProgress = 0;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

TableLayout layout = new TableLayout(this);
layout.setId(idLayout);
layout.setLayoutParams(
new LayoutParams(LayoutParams.FILL_PARENT,android.view.ViewGroup.LayoutParams.FILL_PARENT));
layout.setFocusable(true);

TextView title = new TextView(this);
title.setText(R.string.title);
title.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
//title.s(Alignment.ALIGN_CENTER);
title.setId(idTitle);
layout.addView(title,0);


//For Item 1
TextView ItemRed = new TextView(this);
ItemRed.setFocusable(true);
ItemRed.setText("% RED");
ItemRed.setTextColor(Color.LTGRAY);
ItemRed.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));

//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemRed.setId(idTextRed);
//Add it to our linear layout
layout.addView(ItemRed, 1);

EditText EditTextRed = new EditText(this);
EditTextRed.setFocusable(true);
EditTextRed.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextRed.setId(idEditRedText);

layout.addView(EditTextRed, 2);

SeekBar SeekBarRed = new SeekBar(this);
SeekBarRed.setFocusable(true);
SeekBarRed.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarRed.setMax(MaxColorValue);
SeekBarRed.setId(idSeekBarRed);


layout.addView(SeekBarRed, 3);


//For item 2
TextView ItemGreen = new TextView(this);
ItemGreen.setFocusable(true);
ItemGreen.setText("% GREEN");
ItemGreen.setTextColor(Color.LTGRAY);
ItemGreen.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));


//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemGreen.setId(idTextGreen);
//Add it to our linear layout
layout.addView(ItemGreen, 4);

EditText EditTextGreen = new EditText(this);
EditTextGreen.setFocusable(true);
EditTextGreen.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextRed.setId(idEditGreenText);

layout.addView(EditTextGreen, 5);

SeekBar SeekBarGreen = new SeekBar(this);
SeekBarGreen.setFocusable(true);
SeekBarGreen.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarGreen.setMax(MaxColorValue);
SeekBarGreen.setId(idSeekBarGreen);
layout.addView(SeekBarGreen, 6);


TextView ItemBlue = new TextView(this);
ItemBlue.setFocusable(true);
ItemBlue.setText("% BLUE");
ItemBlue.setTextColor(Color.LTGRAY);
ItemBlue.setLayoutParams(
new TableLayout.LayoutParams(
TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));


//Give the menu item an ID for tracking reasons.
//The ID is a static int defined locally to the class
ItemBlue.setId(idTextBlue);
//Add it to our linear layout
layout.addView(ItemBlue, 7);


EditText EditTextBlue = new EditText(this);
EditTextBlue.setFocusable(true);
EditTextBlue.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
EditTextBlue.setId(idEditBlueText);

layout.addView(EditTextBlue, 8);

SeekBar SeekBarBlue = new SeekBar(this);
SeekBarBlue.setFocusable(true);
SeekBarBlue.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
SeekBarBlue.setMax(MaxColorValue);
SeekBarBlue.setId(idSeekBarBlue);
layout.addView(SeekBarBlue, 9);

Button OKBtn = new Button(this);
OKBtn.setFocusable(true);
OKBtn.setLayoutParams(
new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
OKBtn.setId(idButtonOK);
OKBtn.setText("OK");
layout.addView(OKBtn,10);


setContentView(layout);

OKBtn.setOnClickListener(this);

EditTextRed.setOnClickListener(this);
EditTextGreen.setOnClickListener(this);
EditTextBlue.setOnClickListener(this);

//EditTextRed.setOnClickListener(OnEditClickEvent);
//EditTextGreen.setOnClickListener(OnEditClickEvent);
// EditTextBlue.setOnClickListener(OnEditClickEvent);

SeekBarRed.setOnSeekBarChangeListener(OnSeekBarProgress);
SeekBarGreen.setOnSeekBarChangeListener(OnSeekBarProgress);
SeekBarBlue.setOnSeekBarChangeListener(OnSeekBarProgress);
}

OnSeekBarChangeListener OnSeekBarProgress =
new OnSeekBarChangeListener() {

public void onProgressChanged(SeekBar s, int progress, boolean touch){

if(touch){
TableLayout layout = (TableLayout)s.getParent();

EditText Red = (EditText)layout.getChildAt(2);
EditText Green = (EditText)layout.getChildAt(5);
EditText Blue = (EditText)layout.getChildAt(8);

if(s.getId()== idSeekBarRed ){
RedProgress = progress;
Red.setText(Integer.toString(RedProgress*100/254));
}

if(s.getId()== idSeekBarGreen ){

GreenProgress = progress;
Green.setText(Integer.toString(GreenProgress*100/254));
}


if(s.getId()== idSeekBarBlue ){

BlueProgress = progress;
Blue.setText(Integer.toString(BlueProgress*100/254));
}

int color = Color.rgb(RedProgress, GreenProgress, BlueProgress);
layout.setBackgroundColor(color);

}
}

public void onStartTrackingTouch(SeekBar s){

}

public void onStopTrackingTouch(SeekBar s){

}
};


OnClickListener onAlertOkListener =
new OnClickListener() {
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
return;
}

};

public void onClick(View v){

Button b = (Button)v;

if(b.getId() == idButtonOK){

TableLayout layout = (TableLayout)(v.getParent());

EditText Red = (EditText)layout.getChildAt(2);
EditText Green = (EditText)layout.getChildAt(5);
EditText Blue = (EditText)layout.getChildAt(8);

SeekBar SeekBarRed = (SeekBar)layout.getChildAt(3);
SeekBar SeekBarGreen = (SeekBar)layout.getChildAt(6);
SeekBar SeekBarBlue = (SeekBar)layout.getChildAt(9);


String RedText = Red.getText().toString();
String GreenText = Green.getText().toString();
String BlueText = Blue.getText().toString();

//By default these values will be 0
int RedValue = 0;
int GreenValue = 0;
int BlueValue = 0;

if(!RedText.equals(new String("")) ) {
RedValue = Integer.parseInt(RedText);
}

if(!GreenText.equals(new String(""))) {
GreenValue = Integer.parseInt(GreenText);
}

if(!BlueText.equals(new String(""))) {
BlueValue = Integer.parseInt(BlueText);
}

if (b.getId()== idButtonOK) {

if( RedValue>=0 && RedValue<=100) {
RedProgress = 254*RedValue/100;
SeekBarRed.setProgress(RedProgress);
}

else {
//Alert Dialog
LayoutInflater li = LayoutInflater.from(this);
View view = li.inflate(R.layout.promptdialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("X");
builder.setView(view);
builder.setPositiveButton("Ok", onAlertOkListener);
Dialog PromptDialog = builder.create();
PromptDialog.show();
return;

}

if( GreenValue>=0 && GreenValue<=100) {
GreenProgress = 254*GreenValue/100;
SeekBarGreen.setProgress(GreenProgress);
}

else {
//Alert Dialog
LayoutInflater li = LayoutInflater.from(this);
View view = li.inflate(R.layout.promptdialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("X");
builder.setView(view);
builder.setPositiveButton("Ok", onAlertOkListener);
Dialog PromptDialog = builder.create();
PromptDialog.show();
return;
}

if(BlueValue>=0 && BlueValue<=100) {
BlueProgress = 254*BlueValue/100;
SeekBarBlue.setProgress(BlueProgress);
}

else {
//Alert Dialog
LayoutInflater li = LayoutInflater.from(this);
View view = li.inflate(R.layout.promptdialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("X");
builder.setView(view);
builder.setPositiveButton("Ok", onAlertOkListener);
Dialog PromptDialog = builder.create();
PromptDialog.show();
return;
}

int color = Color.rgb(RedProgress, GreenProgress, BlueProgress);
layout.setBackgroundColor(color);

}
}
}

};

The promptdialog.xml has been written in the following manner:

(?xml version="1.0" encoding="utf-8"?)
(LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
)
(TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/alert"
/)
(/LinearLayout)

Play around with it.

Feel happy to work in Android...

Search This Blog

Loading...

Is the information useful