Dear Android people, (Cyborgs?),

I have four items of news that you’ll probably be interested in:-

1. Android Clinic

The next Android Clinic will be on Saturday October 2nd. By popular demand, we’re running this one at a weekend, as many people have said they have work commitments on week days. If we get a good turn-out, then we’ll run further Clinics on weekends.

The theme for this clinic is “Writing Games”. A few people have expressed an interest in games, and those of you who’ve finished their MDEC prototype might be looking for a new project to undertake.

As usual, the timetable for the days is:-

10:00am to 12:00pm : Presentation (Writing Games)
12:00pm to 1:00pm : Lunch
1:00pm onwards : Individual support for your projects

Please be on time if you want to attend the presentation. Let us know if you’re coming.

See: https://sagemobile.wordpress.com/2010/09/10/android_clinic/

…for address, directions, and parking information.

These clinics are supported by Maxis, the Maxis 1Store, and the Maxis developer programme.

http://mdp.maxis.com.my
https://developer.1store.com.my/wps/portal/1store

2. Our Top Applications

Maxis have asked us to identify applications being developed that will be given special support. These applications are to be sold on the Maxis 1Store. We will be providing help in the form of technical support, pre-submission constructive reviews, discussions about design decisions, etc.

If you are thinking of selling an Application on the Maxis 1Store, and you would like YOUR application to be considered – CONTACT US NOW!

If you’ve already submitted your application to the Maxis store, or you’re about to do so – let us know.

3. New Android Training Courses

Sage will be running new Android training courses in Kota Baru and Kuching. Dates are still to be confirmed, but these will start on or after the 18th of October. Do you know anyone who’d like to attend? Please, spread the word, tell people about this, we’re recruiting participants NOW.

4. mYprize competition

http://www.myprize.my/what-is-myprize
Official website : http://www.ytlcomms.my/EN/Index.aspx

What is mYprize?

YTL Communications Sdn Bhd is launching the world’s first nationwide 4G network in Malaysia. YTL Communications’ 4G network is a wireless, high-speed, mobile Internet service.

They are challenging innovators and creative entrepreneurs around the world to submit original ideas, create unique applications or devices for the YTL 4G network today. They’ve created a competition, called mYprize, that offers a total of USD 1,000,000 in prize money for the best innovations for 4G.

Advertisements

Following on from WCs questions, I appreciate that the Android course didn’t go into any detail storing data on the server.  It was a Android course after all, not a server technology course.  Having said that, I always thought an overview of PHP and mySQL would be beneficial to a lot of students, who had no prior experience in server-side code.  So here it is, in a nutshell:-

I need to update the data on weekly basis.
May i know where the data can be stored? Does google provide a server to host the data?
My apps is about the daily consumer good pricing.
WC

It’s up to you to host your data.  Personally, I use a free hosting service provided by http://www.byethost.net.  Free hosts like this come with the ability to run PHP, and set up mySQL databases.

Let’s start with a simple PHP program:

<html>
<body>
<?php echo "Hello World!"; ?>
</body>
</html>

You can mix up PHP with HTML, as above. The parts of the program that do PHP things are enclosed by <?   ?> tags.  For example, the above program prints (echoes) “Hello World”.

PHP can execute commands to query an SQL database.  You will have already learnt some SQL language on the Android course.  This was related to Android’s SQLlite.  Here is a program to set up a database table, and populate it with some records:-

<?php
mysql_connect("localhost","root","password");
mysql_select_db("");
mysql_query("DROP DATABASE DEMO;");
mysql_query("CREATE DATABASE DEMO;");
mysql_select_db("DEMO");
mysql_query("CREATE TABLE PEOPLE(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,NAME TEXT,AGE INT);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Albert Smith',32);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Justin Archer',28);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Sarah Tully',35);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Janet Brown',30);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Robert Jones',26);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Alice Wendell',38);");
?>

As you can see, this program CREATEs a new TABLE, and INSERTs some records.

The strings that you pass to mysql_connect will relate to the details of the database you set up. You’ll need to set up a database first from the web host control panel. This is quite straight forward usually – but your web host probably has a user discussion forum, and there’s much more help and information on the internet about PHP and mySQL than there is for Android – so you should be able to sort this out yourself.

The following PHP program reads the database, and spits out the data as XML.

<?php
mysql_connect("localhost","root","password");
mysql_select_db("DEMO");
$query="SELECT * FROM PEOPLE;";
$result=mysql_query($query) or die("error:".$query);
header('Content-type: application/xml; charset="utf-8"',true);
echo "<table>\n";
while ($row=mysql_fetch_array($result)) {
	echo "<record>\n";
	echo "<id>".$row['ID']."</id>\n";
	echo "<name>".$row['NAME']."</name>\n";
	echo "<age>".$row['AGE']."</age>\n";
	echo "</record>\n";
	}
echo "</table>\n";
?>

There are other ways to manipulate XML in PHP, but strings, and echo are easy to understand.
Finally, sometimes, you’ll need to pass data from the Android phone to the server. Like this:-

public void postData() {

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.yoursite.com/insert.php");

try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("name", "Fred Bloggs"));
        nameValuePairs.add(new BasicNameValuePair("age", "45"));
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        HttpResponse response = httpclient.execute(httppost);

       } catch (ClientProtocolException e) {

       } catch (IOException e) {
   }
}

And insert.php looks like this:-

<?php
mysql_connect("localhost","root","password");
mysql_select_db("DEMO");
$name = $_POST['name'];
$age = $_POST['age'];
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('$name',$age);");
?>

$_POST[label] is used to retrieve the values sent by the Android device.

Hi,
I wish to have the resource to programme the row and column layout.  Further, for the information updated, how can I host the data and let my application to retrieve the information or data?  Thanks for your concern.
Looking forward for your feedbacks.
WC

There are two common ways to display information as rows and columns.  The first is the GridLayout that I described in the previous post.  Or there’s a TableLayout, which imposes a row and column format on the contents.

For example:-

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="*" >
  <TableRow>
    <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="abcedfghij" />
    <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="klmn" />
  </TableRow>
  <TableRow>
    <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="opqr" />
    <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="stuvwxyz" />
  </TableRow>
</TableLayout>

Inside the <TableLayout>, we define each row’s contents inside <TableRow> tags.  Notice the … android:stretchColumns=”*”.  This means pad all the columns out so that the table takes up all the horizontal space.

But suppose that you don’t know how many rows your table has.  If your application is downloading data, you might now know how many rows you need to generate.  In this case, you might dynamically create your table in Java.

package com.danielfreeman.android;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class HelloDynamicTable extends Activity {

	protected static final String[][] DATA = {{"Fred","Bloggs","32"},{"Jane","Doh","28"},{"Peter","Smith","35"}};

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

        TableLayout table = new TableLayout(this);
        table.setLayoutParams(new TableLayout.LayoutParams(
        		TableLayout.LayoutParams.FILL_PARENT,
        		TableLayout.LayoutParams.WRAP_CONTENT)
        );
        table.setStretchAllColumns(true);

        for (String[] record : DATA) {

        	TableRow row = new TableRow(this);
        	row.setLayoutParams(new TableRow.LayoutParams(
            		TableRow.LayoutParams.FILL_PARENT,
            		TableRow.LayoutParams.WRAP_CONTENT)
            );

            for (String field : record) {
            	TextView column = new TextView(this);
            	column.setLayoutParams(new TableRow.LayoutParams(
            			TableRow.LayoutParams.FILL_PARENT,
            			TableRow.LayoutParams.WRAP_CONTENT)
                );
            	column.setText(field);
            	row.addView(column);
            }

            table.addView(row);
        }

        setContentView(table);
    }
}

You’ve asked about hosting data too. Do you mean on the server?  On the course, you will have learnt about obtaining and parsing XML data from the server.  My groups did an exercise using the SAX parser.  I think Mark’s group looked at the DOM parser.  In your application, are you also uploading changes, and storing them in a database on the server?  What exactly will your application do?

Perhaps this RSS reader tutorial will help:

http://www.helloandroid.com/tutorials/newsdroid-rss-reader

A few students seem to be using GridViews, and I’ve seen a couple of applications where the order of images is being randomised, and a user has to click on the right one.

A popular kid song plays.  Touch the picture that matches the song.  Compete against the clock to see how fast they can guess the song, or just play for the pure fun of hearing the songs and picking the picture.  I know how to play the music.  How can I display pictures, so that the user can choose?
Adeeb



Using a GridView is often as easy as copy and pasting the example on the Android developer site.

http://developer.android.com/guide/tutorials/views/hello-gridview.html

You’ll have a local copy of this page too, as it came with your SDK documentation.  Here, we are customising an adapter, and overriding getView(), just like we did in the previous example, for the list.

So that sorts out displaying a picture in a GridView, and listening for click events.  What about randomising the order of pictures.  I do this using a mapping array.


protected static final int[][] SHUFFLE = {{1,2,3,0},{3,0,1,2},{2,1,0,3},{0,3,2,1},{2,0,3,1}};

It’s a two dimensional array that maps a position to a randomised position.  The first index is a random number. (You can add more ‘random’ combinations if you wish, eg: {3,1,0,2}, etc. etc…)


reorder = random.nextInt(SHUFFLE.length);

Then access your array like this:-


imageView.setImageResource(PICTURES[SHUFFLE[reorder][position]]);

When the user clicks on a picture, you use the SHUFFLE[reorder] array again to unravel the ‘randomisation’, and check if they have the right answer:-


if (song == SHUFFLE[reorder][position]) {
}

Here is the entire example:-


public class SingAlong extends Activity implements OnItemClickListener {

	protected static final int DECREMENT = 5;
	protected static final int DELAY = 1000;
	protected static final int[] PICTURES = {R.drawable.blacksheep,R.drawable.humpty,R.drawable.rowboat,R.drawable.starsmoon};
	protected static final int[] LYRICS = {R.string.blacksheep,R.string.humpty,R.string.rowboat,R.string.twinkle};
	protected static final int[][] SHUFFLE = {{1,2,3,0},{3,0,1,2},{2,1,0,3},{0,3,2,1},{3,1,0,2}};

	protected ProgressBar progressBar;
	protected Handler handler = new Handler();
	protected GridView gridview;
	protected TextView lyrics;
	protected int progress = 100;
	protected Random random = new Random();
	protected int reorder = 0;
	protected int song = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        progressBar = (ProgressBar)findViewById(R.id.progress);

        gridview = (GridView)findViewById(R.id.gridview);
        gridview.setBackgroundColor(0xffffffff);
        gridview.setOnItemClickListener(this);

        lyrics = (TextView) findViewById(R.id.lyrics);

        handler.postDelayed(new TickTick(),DELAY);
        newSong();
    }

    protected void newSong() {
    	song = random.nextInt(LYRICS.length); //Which song?
    	reorder = random.nextInt(SHUFFLE.length); //Shuffle pictures
    	progress = 100;
    	progressBar.setProgress(progress);
    	gridview.setAdapter(new ImageAdapter(this));
    	lyrics.setText(LYRICS[song]);
    	playTheMusic(song);
    }

    protected void playTheMusic(int song) {
    	//Play the song.  0=blacksheep, 1=humpty, 2=rowboat, 3=twinkle
    }

    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
        if (song == SHUFFLE[reorder][position]) {
            Toast.makeText(this, "CORRECT - WELL DONE!", Toast.LENGTH_SHORT).show();
            newSong(); //Play another song again if they get it right
        }
        else {
        	Toast.makeText(this, "no - try again", Toast.LENGTH_SHORT).show();
        }
    }

    protected class TickTick implements Runnable {
   	   public void run() {
   		  progress-=DECREMENT;
   		  if (progress<0) {
   			Toast.makeText(SingAlong.this, "TRY AGAIN", Toast.LENGTH_SHORT).show();
   			newSong();
   		  }
   		  else {
   	   		  progressBar.setProgress(progress);
   		  }
   		handler.postDelayed(this, DELAY);
   	   }
   	}

    protected class ImageAdapter extends BaseAdapter {
        private Context mContext;

        public ImageAdapter(Context c) {
            mContext = c;
        }

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

        public Object getItem(int position) {
            return null;
        }

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

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView;
            if (convertView == null) {
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setPadding(8, 8, 8, 8);
            } else {
                imageView = (ImageView) convertView;
            }

            imageView.setImageResource(PICTURES[SHUFFLE[reorder][position]]);
            return imageView;
        }
    }
}

Notice that I’ve used a Handler as a timer, to update a progress bar of remaining time. I introduced this Handler trick to you a couple of days ago. see: https://sagemobile.wordpress.com/2010/09/12/dr-android-answers-threads-and-the-ui/

Here’s the layout file:-

<?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">
<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:gravity="center" >
<TextView
	android:id="@+id/lyrics"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
	android:textStyle="bold"
	android:gravity="center_vertical|center_horizontal"
	android:textSize="8pt"/>
</LinearLayout>
<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:gravity="bottom">
<GridView
    android:id="@+id/gridview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:numColumns="2"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="10dp"
    android:stretchMode="columnWidth"
    android:gravity="center"/>
  <ProgressBar android:id="@+id/progress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

Esther asks the following question:-

Hi there,
For my situation, i got a XML which one of the element contains a http string that points to an image on my webserver.  Any approach you would suggest for it to be downloaded to the drawable so that my application will be able to download it to drawable before displaying it with imageview
Can you also please suggest some tutorial on array adapter that might be useful to display image and text from an array.

Thanks.



To parse the XML and access the URL, I’d suggest modifying a SAX parser.  (I hope the other teachers on the course covered this – if yours didn’t let me know and I’ll elaborate).

Downloading an image isn’t too difficult.

See: http://www.helloandroid.com/tutorials/how-download-fileimage-url-your-device

In this example, they save the image to a file.  But in your case, you’ll want to take baf.toByteArray(); and assign it to an ImageView, something like this:-

ByteArray myBytes = baf.toByteArray();
ImageView myImage = (ImageView) findViewById(R.id.myimage);
myImage.setImageBitmap(BitmapFactory.decodeByteArray(myBytes, 0, myBytes.length));

As for modifying an ArrayAdapter to display both image and text into a ListView – that’s pretty standard practice.  We create a new custom adapter that inherits from the ArrayAdapter class, and override the getView() method, so that it deals with a custom list item layout, which might contain text, images, etc. etc.

Here’s an example based on two arrays.  One containing text, the other containing a reference to images in our res/drawable folder:-

public class HelloArrayAdapterSubClass extends Activity {

	final protected static String[] DAYS = {"Monday","Tuesday","Wednesday"};
	final protected static int[] PICTURES = {R.drawable.mondayPic,R.drawable.tuesdayPic,R.drawable.wednesdayPic};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView list=(ListView)findViewById(R.id.days);

        list.setAdapter(new SwitchAdapter(this));
    }

    class SwitchAdapter extends ArrayAdapter<String> {
        Activity context;

        SwitchAdapter(Activity context) {
          super(context, R.layout.custom_list_item_3, DAYS);
          this.context=context;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

        View row;
        LayoutInflater inflater=context.getLayoutInflater();
        String myday = DAYS[position];
        int mypicture = PICTURES[position];

        row=inflater.inflate(R.layout.custom_list_item_3, null);
        TextView label=(TextView)row.findViewById(R.id.label);
        ImageView picture=(ImageView)row.findViewById(R.id.image);
        label.setText(myday);
        picture.setImageResource(mypicture);

        return(row);
        }
      }
}

Note the row=inflater.inflate().  Inflation is the conversion between a text XML layout description, and the instantiation of objects (inherited from View and ViewGroup) that make up what’s shown on the screen.

The custom layout looks like this:-

<?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="wrap_content"
	android:orientation="horizontal">
<ImageView
	android:id="@+id/image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
/>
<TextView
	android:id="@+id/label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="days of the week"/>
</LinearLayout>

The Android clinic today was fun. Good to see your applications coming together.

The deadline for your prototype submission is Friday. In the meantime, keep your questions coming by email, or comments here – and I’ll do my best to get you on track.

Mei Ling sent me the following question:-

I’m trying to create an Android Color Book application.

I’ve tried using the android.graphics.drawable library but it doesn’t seem to work. I believe the idea is to create an area which is recognizable by the application and by clicking on the area, the library would populate the selected area with the selected colors.

But I’m not sure which library should I use. As such, could you please advice me on the correct approach/library I should use?

Thanks!

Let’s talk about the approach.

At the outset, there’s a decision.  Bitmap or vector?  While it is possible to define your shapes as bitmaps, and alter their colour.  (Note the British English spelling with a “u”).  I want to pursue the vector way of doing things.

In the course, we used Canvas graphics within the onDraw() method of View or SurfaceView, like this:-

public class GraphThing extends View {

	protected static final float POSITION = 40.0f;
	protected static final float RADIUS = 32.0f;

	public GraphThing(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(3);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(POSITION, POSITION, RADIUS, paint);
    }
}

For your colouring book, I think it’s best to use View, not SurfaceView, and draw all the shapes as outlines initially. When the user clicks on a shape to colour it in – redraw it, ( invalidate() ) but with a colour filling.

How do we know if you’re clicking on a particular shape? You’ll have to but in some logic to make a decision based on the co-ordinates of your touch event. No need to be precise. Use a rectangular (x>x0 && x<x1 && y>y0 && y<y1), or circular ((x-x0)*(x-x0)+(y-y0)*(y-y0) < r*r ) or elliptical hit area.

I think the main issue is where you get your pictures from? Take a look at http://www.openclipart.org

These are .svg files. Although there are libraries for displaying .svg files, we probably want control over every path. We probably want to put each path inside a different view, and initially just draw black outlines. So we’ll be extracting the information we need from an .svg file, and using it inside our own drawing code. For example, a path that is defined like this:

d=”m -696.68139,700.23613 c 2.01698,-7.28388 20.55513,-7.05909 25.63256,-8.77305 0,0 -1.91288,38.43437 3.0606,57.65155 -7.68767,-0.42893 -8.41665,-1.67106 -8.41665,-1.67106 0,0 -11.47727,-41.7765 -20.27651,-47.20744 z”

This example describes a closed shape with starting point, and a lot of relative cubic splines.

You might make this into an array of values to create a Path. You can do this manually, or automatically. (Parse the XML file, and use regular expressions to insert commas, and then split into an array.)

Anyway, I hope I’ve given you some clues. We can discuss this in much more detail at the Android clinic tomorrow.