Tuesday, August 18, 2009

AutoAndroid: Pizza order sample









This document can be read in Google Docs (http://docs.google.com/View?id=ddwc44gs_203g7xcxfr9), cut and paste link if you have problems accessing it.






We analyzed the basic concepts behind autandroid in a previous post, now let's introduce a slightly more interesting example.


pizza order example












This sample includes autoandroid.jar and can be downloaded from http://codtech.com/downloads/android/index.html#source as an Eclipse project (AutoAndroidSamples.zip).





This introductory example provides some automatic behavior of UI components.

Our objective is to obtain, writing as less code as possible, the following functionality.



A standard Activity displays some Buttons to launch different samples. Right now we have only two Buttons corresponding to our samples.













Clicking the Pizza order samples Button launches the Dialog.











Some automatic behavior has been defined in the XML file and thus it's automatically available in the Dialog.

This behavior includes:



  • If quantity is 0, then OK is disabled


  • Quantity value is automatically updated depending on the seek bar position



  • All values are exported so they can be retrieved from the parent Activity


  • Cancel and OK buttons have the corresponding default behavior




Once some values are entered, pressing the OK Button the Dialog is dismissed and the values are passed back to the invoking Activity.











pizza_order_sample.xml


This is the layout of our sample dialog.

We can do it as we normally do using ADT's Layout Editor.













However, to provide the extra behavior we have to add some properties in the XML view of the editor.










<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:auto="http://schemas.android.com/apk/res/com.codtech.android.samples.autoandroid"

    android:orientation="vertical" android:layout_height="fill_parent"

    android:layout_width="300dip"  

    android:id="@+id/LinearLayoutPizzaOrder">



    <com.codtech.android.auto.widget.AutoRadioGroup

        android:id="@+id/RadioGroupPizza"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        auto:export="true"

        auto:name="pizza">

        <RadioButton android:id="@+id/RadioButton01"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="6dip" android:text="Margherita"

            android:layout_marginTop="-6dip" android:checked="true">

        </RadioButton>

        <RadioButton android:id="@+id/RadioButton02"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="6dip" android:text="Prosciutto">

        </RadioButton>

        <RadioButton android:id="@+id/RadioButton03"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="6dip"

            android:text="Quattro Stagioni">

        </RadioButton>

    </com.codtech.android.auto.widget.AutoRadioGroup>

    

    <TextView android:id="@+id/TextView02"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" android:text="Additionals"

        android:textStyle="bold" android:layout_marginLeft="3dip"

        android:layout_marginTop="3dip"></TextView>

        

    <com.codtech.android.auto.view.AutoCheckBox 

        android:id="@+id/CheckBoxExtraMozzarella"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginLeft="6dip"

        android:text="Extra mozzarella"

        auto:export="true">

    </com.codtech.android.auto.view.AutoCheckBox>

        

    <com.codtech.android.auto.view.AutoCheckBox

        android:id="@+id/CheckBoxPepperoni"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginLeft="6dip"

        android:text="Pepperoni"

        auto:export="true">

    </com.codtech.android.auto.view.AutoCheckBox>

        

    <TextView android:id="@+id/TextView03"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" android:text="Quantity"

        android:textStyle="bold" android:layout_marginLeft="3dip"

        android:layout_marginTop="3dip"></TextView>



    <LinearLayout android:id="@+id/LinearLayout02"

        android:layout_height="wrap_content"

        android:layout_width="fill_parent"

        android:orientation="horizontal">

        <com.codtech.android.auto.view.AutoSeekBar 

            android:layout_height="wrap_content"

            android:layout_margin="6dip"

            android:layout_width="wrap_content"

            android:layout_weight="1" android:id="@+id/SeekBarQuantity"

            auto:update="@+id/TextViewQuantity"

            android:max="10"

            auto:export="true"

            auto:name="quantity"

            auto:sensitize="@+id/ButtonPizzaOrderDialogOk">

        </com.codtech.android.auto.view.AutoSeekBar>

        <TextView android:layout_width="wrap_content"

            android:layout_weight="0" android:layout_margin="6dip"

            android:layout_height="fill_parent"

            android:layout_gravity="center"

            android:gravity="center_vertical|right"

            android:textStyle="bold" android:id="@id/TextViewQuantity"

            android:maxLength="3" android:text="0"

            android:background="#555555"

            ></TextView>

    </LinearLayout>

    

    <RelativeLayout android:id="@+id/LinearLayout01"

        android:layout_height="wrap_content"

        android:layout_width="fill_parent"

        android:layout_margin="3dip"

        android:background="@color/dialog_action_background">

        <Button android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_alignParentLeft="true"

            android:text="Cancel" android:width="100dip"

            android:id="@+id/ButtonPizzaOrderDialogCancel"

            auto:dialog_action="cancel"

            android:layout_margin="3dip"></Button>

        <Button android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_alignParentRight="true"

            android:text="OK" android:width="100dip"

            android:id="@id/ButtonPizzaOrderDialogOk"

            auto:dialog_action="positive"

            android:clickable="false"

            android:enabled="false"

            android:layout_margin="3dip"

            ></Button>

    </RelativeLayout>



</LinearLayout>







Let's explain the changes:




  1. Define the namespace auto. The name that appears after http://schemas.android.com/apk/res is usually the package name of your application and will be used in an attribute definition (attrs.xml).


  2. The root layout must have an ID as it's used by some methods in the library and should be identifiable. The name here is LinearLayoutPizzaOrder but it could be whatever you like.


  3. Then, a com.codtech.android.auto.widget.AutoRadioGroup which is a class that extends RadioGroup and provides some automatic behavior.


  4. Mark the AutoRadioGroup as exported so we can obtain its value later. This is achieved using auto:export="true".



  5. As it is exported we give it a name, text in this case, to obtain the value later. auto:name="pizza" does the trick.



  6. Two AutoCheckBoxes,also exported hold additional options.


  7. An AutoSeekBar, exported under the name "quantity" provides also two other options, automatically update a text field depending on the seek bar value using auto:update="@+id/TextViewQuantity". It also automatically sensitize the OK Button using auto:sensitize="@+id/ButtonPizzaOrderDialogOk".


  8. Finally, mark the buttons using auto:dialog_action="positive" and auto:dialog_action="cancel".



Styleable attributes


The way we are adding these attributes is by defining styleable attributes in a file usually attrs.xml.










<?xml version="1.0" encoding="utf-8"?>



<resources>

<declare-styleable name="com.codtech.android.samples.autoandroid">

    <attr name="name" format="string" />

    <attr name="init" format="string" />

    <attr name="sensitize" format="reference" />

    <attr name="show" format="reference" />

    <attr name="update" format="reference" />

    <attr name="export" format="boolean" />

    <attr name="dialog_ok" format="boolean" />

    <attr name="dialog_action" format="string" />

</declare-styleable>

</resources>




AutoAndroidSamples.java


This is our sample Activity.










/*

 * Copyright © 2009 COD Technologies Ltd.  www.codtech.com


 *


 * $Id: AutoAndroidSamples.java 131 2009-08-15 00:28:47Z diego $


 *


 *


 */




package com.codtech.android.samples.autoandroid;




import android.app.Activity;


import android.app.Dialog;


import android.content.DialogInterface;


import android.content.DialogInterface.OnDismissListener;


import android.os.Bundle;


import android.view.View;


import android.view.View.OnClickListener;


import android.widget.Button;


import android.widget.Toast;




import com.codtech.android.auto.app.AutoDialog;






public class AutoAndroidSamples extends Activity implements OnClickListener, OnDismissListener {


    private static final int DIALOG_SAMPLE_ID = R.id.Button01;


    private static final int DIALOG_PIZZA_ORDER_SAMPLE_ID = R.id.Button02;


    


    private AutoDialog ad01;


    private AutoDialog ad02;




    /** Called when the activity is first created. */


    @Override


    public void onCreate(Bundle savedInstanceState) {


        super.onCreate(savedInstanceState);


        setContentView(R.layout.samples);


        


        ((Button) findViewById(R.id.Button01)).setOnClickListener(this);


        ((Button) findViewById(R.id.Button02)).setOnClickListener(this);


    }




    /* (non-Javadoc)


     * @see android.view.View.OnClickListener#onClick(android.view.View)


     */


    @Override


    public void onClick(View v) {


        showDialog(v.getId());        


    }




    


    /* (non-Javadoc)


     * @see android.app.Activity#onCreateDialog(int)


     */


    @Override


    protected Dialog onCreateDialog(int id) {


        switch (id) {


        case DIALOG_SAMPLE_ID:


            ad01 = new AutoDialog(this, R.layout.dialog_sample,


                R.string.dialog_sample_title);


            ad01.setOnDismissListener(this);


            return ad01;




        case DIALOG_PIZZA_ORDER_SAMPLE_ID:


            
ad02 = new AutoDialog(this, R.layout.pizza_order_sample,

               
R.string.dialog_pizza_order_sample_title);

            
ad02.setOnDismissListener(this);

            
return ad02;

            


        default:


            break;


        }


        


        return super.onCreateDialog(id);


    }




    /* (non-Javadoc)


     * @see android.app.Activity#onPrepareDialog(int, android.app.Dialog)


     */


    @Override


    protected void onPrepareDialog(int id, Dialog dialog) {


        // TODO Auto-generated method stub


        super.onPrepareDialog(id, dialog);


    }




    /* (non-Javadoc)


     * @see android.content.DialogInterface.OnDismissListener#
onDismiss(android.content.DialogInterface)


     */


    @Override


    public void onDismiss(DialogInterface dialog) {


        if ( dialog instanceof AutoDialog ) {


            AutoDialog ad = (AutoDialog)dialog;


            


            if ( ad.isCanceled() ) {


                return;


            }


            


            
Bundle bundle = ad.getAutoBundle();

            


            if ( ad.equals(ad01) ) {


                Toast.makeText(this, "Entered value: " + bundle.getString("text"),


                    Toast.LENGTH_SHORT).show();


            }


            else if ( ad.equals(ad02)) {


                
Toast.makeText(this, composePizzaOrderMessage(bundle),

                   
Toast.LENGTH_SHORT).show();

            }


        }


    }




    /**


     * @param bundle


     * @return


     */


    private String composePizzaOrderMessage(Bundle bundle) {


        final int quantity = bundle.getInt("quantity");


        if ( quantity > 0 ) {


            final StringBuilder msg = new StringBuilder(String.format("Make %d %s pizza%s",


               quantity, bundle.get("pizza"), (quantity > 1) ? "s" : ""));


            final boolean extraMozzarella = bundle.getBoolean("extra mozzarella");


            final boolean pepperoni = bundle.getBoolean("pepperoni");


            if ( extraMozzarella ) {


                msg.append(" with extra mozzarella");


                if ( pepperoni ) {


                    msg.append(" and pepperoni");


                }


            }


            else if ( pepperoni ) {


                msg.append(" with pepperoni");


            }


            


            return msg.toString();


        }




        return "No pizzas ordered";


    }




}



Creating the AutoDialog specifying the layout and the title in the constructor is all we need to have our Dialog working.

When the Dialog is dismissed we can obtain all of the exported values in a Bundle using the getAutoBundle() method.




Conclusion


This is a more practical example of AutoAndroid. With almost no code we have managed common behavior that frequently appears in Android applications. Some other samples will follow demonstrating other features. Stay tuned.



If you have comments, ideas, critiques or whatever just drop me a line or leave a comment in the blog.




Copyright © 2009 Diego Torres Milano. All rights reserved.


















































1 comment:

blacharnia said...

Hi,

Cool stuff but where is the file AutoDialog.java? It cannot be found in the AutoAndroidSamples.zip.

BR

blacharnia