Martin's random and not so random knowledge

Random _rand = new Random(); Blog.Write(Knowledge[_rand.Next()]); Blog.Publish();

PHP: Creating a phpinfo page

Just wanted to show you how to create a phpinfo page.
This page will give you a lot of usefull information about the webserver your webpage is running on.

To start open your favorite text editor. (I like to use notepad++)
You only need to use call one methode: phpinfo()

<?php
  phpinfo();
?>

Save your file, make sure it has the php extension. For example “serverinfo.php”

Upload your file to your server with your favorite FTP tool (I like to use Filezilla)
Note: I would highly recommend to upload the file to user/password protected folders only. For more information on secure folders see: http://httpd.apache.org/docs/1.3/howto/htaccess.html

Now you navigate to the page with your webbrowser.

Very easy to do and very helpfull.

For more information see: http://php.net/manual/en/function.phpinfo.php


Android: Filling a table from resource file using xml (SQLite)

Last time I posted an article on how to fill a table with the help of a string array in a resource file:
Android Filling a table from resource file using string array (SQLite)
The drawback of that technique was that you could only import simple records. So this time I want to show you how to fill a table with complex records (multiple fields).

I will use plain xml as a resource file. This gives me the option to enter records and multiple field values for each record.
The xml will be formatted by using one tag for each record and I will use the tag attributes for field values.

Our resource file: res/values/animals_records.xml

<?xml version="1.0" encoding="utf-8"?>
<animals>
 	<record title="Dog" color="Brown" />
	<record title="Cat" color="Gray" />
	<record title="Rabbit" color="White" />
	<record title="Spider" color="Black" />
</animals>

As you can see I made a xml with records of animals. For every animal I specified the title and color, so thats two fields. You can add as many fields as you want.

We will be using a SQLiteOpenHelper to create/update the database.

/**
 * This class helps open, create, and upgrade the database file.
 */
private static class DatabaseHelper extends SQLiteOpenHelper {

	private final Context fContext;

	DatabaseHelper(Context context) {
		super(context, "sampledb", null, 1);
		fContext = context;
	} 

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("CREATE TABLE animals ("
				+ "_id INTEGER PRIMARY KEY,"
				+ "title TEXT,"
				+ "color TEXT"
				+ ");");

		//Add default records to animals
		ContentValues _Values = new ContentValues();
		//Get xml resource file
		Resources res = fContext.getResources();

		//Open xml file
		XmlResourceParser _xml = res.getXml(R.xml.animals_records);
		try
		{
			//Check for end of document
			int eventType = _xml.getEventType();
			while (eventType != XmlPullParser.END_DOCUMENT) {
				//Search for record tags
				if ((eventType == XmlPullParser.START_TAG) &&(_xml.getName().equals("record"))){
					//Record tag found, now get values and insert record
					String _Title = _xml.getAttributeValue(null, AnimalColumns.TITLE);
					String _Color = _xml.getAttributeValue(null, AnimalColumns.COLOR, 0);
					_Values.put(AnimalColumns.TITLE, _Title);
					_Values.put(AnimalColumns.COLOR, _Color);
					db.insert(AnimalColumns.TABLENAME, null, _Values);
				}
				eventType = _xml.next();
			}
		}
		//Catch errors
		catch (XmlPullParserException e)
		{
			Log.e(TAG, e.getMessage(), e);
		}
		catch (IOException e)
		{
			Log.e(TAG, e.getMessage(), e);

		}
		finally
		{
			//Close the xml file
			_xml.close();
		}
	}

	/* Update database to latest version */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		//Crude update, make sure to implement a correct one when needed.

		Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
				+ newVersion + ", which will destroy all old data");
		db.execSQL("DROP TABLE IF EXISTS animals");
		onCreate(db);
	}
}

Let’s look at some of the code.

Here we get the xml file and open it

//Get xml resource file
Resources res = fContext.getResources();

//Open xml file
XmlResourceParser _xml = res.getXml(R.xml.animals_records);

Next we loop trough the xml file and check for record tags

//Check for end of document
int eventType = _xml.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
	//Search for record tags
	if ((eventType == XmlPullParser.START_TAG) &&(_xml.getName().equals("record"))){

Last we get the values from the attributes and insert a record into our table.

//Record tag found, now get values and insert record
String _Title = _xml.getAttributeValue(null, AnimalColumns.TITLE);
String _Color = _xml.getAttributeValue(null, AnimalColumns.COLOR, 0);
_Values.put(AnimalColumns.TITLE, _Title);
_Values.put(AnimalColumns.COLOR, _Color);
db.insert(AnimalColumns.TABLENAME, null, _Values);

This was the first code example of 2012, I hope it will be of some use to my readers.
Till next time, happy coding!


I’m back!

Hi all,

The last weeks were filled with christmas tree’s and fireworks. After the hollidays I was working on building a new pc. I’m eager to test how fast it can compile and the performance of the Android virtual device.

Stay tuned because I have some great stuff to post.

Martin


Year++

Well 2011 is almost over. I would like to conclude this year with the words of great Merlin:

You must set your sights upon the heights
Don’t be a mediocrity
Don’t just wait and trust to fate
And say, that’s how it’s meant to be
It’s up to you how far you go
If you don’t try you’ll never know
And so my lad as I’ve explained
Nothing ventured, nothing gained

Happy new year and see you again in 2012!


Android Filling a table from resource file using string array (SQLite)

In this post we will be filling a table in our database with values from a resource xml file.
You can use this technique to create default rows in your table on creation/updating of the database.

Our resource file: res/values/mytable.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 	<string-array
        name="mytable_records_v1">
 	    <item>First row</item>
   	    <item>Second row</item>
   	    <item>Third row</item>
	</string-array>
</resources>

As you can see I have named the array mytable_records_v1. Put the version in the id so you can make a new string array for future versions. For example in the future you want to add “Fourth row” in your table, you will then name the array “mytable_records_v2″ and only add the new records in your table in the update method.

We will be using a SQLiteOpenHelper to create/update the database.

/**
 * This class helps open, create, and upgrade the database file.
 */
private static class DatabaseHelper extends SQLiteOpenHelper {

	private final Context fContext;

	DatabaseHelper(Context context) {
		super(context, "sampledb", null, 1);
		fContext = context;
	} 

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("CREATE TABLE mytable ("
				+ "_id INTEGER PRIMARY KEY,"
				+ "title TEXT"
				+ ");");

		//Add default record to mytable
		ContentValues _Values = new ContentValues();
		//Get string array from resource file
		Resources res = fContext.getResources();
		String[] _mytable_Records = res.getStringArray(R.array.mytable_records_v1);
		//Loop trough array and insert records into table
		int _Length = _mytable_Records .length;
		for (int i = 0; i < _Length; i++) {
			_Values.put("title", _mytable_Records [i]);
			db.insert("mytable", null, _Values);
		}
	}

	/* Update database to latest version */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		//Crude update, make sure to implement a correct one when needed.

		Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
				+ newVersion + ", which will destroy all old data");
		db.execSQL("DROP TABLE IF EXISTS _mytable_Records ");
		onCreate(db);
	}
}

This sample will be very useful when dealing with simple lookup tables. However the downside is that there is only room for one field in the string array, so it won’t work for more complex records.

Till next post. Happy coding! :)


Android How to create a feedback button

Here I am again with a new Android post.
This time I will show you how to implement a feedback button in your application.

This code can also be used to send other emails.

First we will begin by putting a button on a layout called “feedback_sample.xml”

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
	<Button
		android:id="@+id/btn_feedback"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="@string/button_feedback"
		android:onClick="btnFeedbackOnClick"/>
</LinearLayout>


As you can see I have created a button called “btn_feedback”, it’s text is specified by a resource string and its OnClick event is set to “btnFeedbackOnClick”.

Now we will specify our resource strings, these are allocated in the file “res/values/strings.xml”.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Feedback sample</string>
    <string name="button_feedback">Send feedback</string>
    <string name="title_send_feedback">Send feedback</string>

    <string name="mail_feedback_email">feedback@example.com</string>
    <string name="mail_feedback_subject">Feedback on your app</string>
    <string name="mail_feedback_message">Hi,
\n\nYour Feedback sample app rocks! I would like to give you some feedback:</string>

</resources>

Strings:
“app_name”: Your application title.
“button_feedback”: Text on feedback button.
“title_send_feedback”: Title of chooser dialog.
“mail_feedback_email”: Email address where the feedback is going.
“mail_feedback_subject”: Subject of the email.
“mail_feedback_message”: Default mail message.

Last we will create our activity “sample_feedback_activity.java”

package com.example.feedback;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class sample_feedback_activity extends Activity {

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

	//On click event for button feedback
	public void btnFeedbackOnClick(View v) {
         final Intent _Intent = new Intent(android.content.Intent.ACTION_SEND);
         _Intent.setType("text/html");
         _Intent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{ getString(R.string.mail_feedback_email) });
         _Intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.mail_feedback_subject));
         _Intent.putExtra(android.content.Intent.EXTRA_TEXT, getString(R.string.mail_feedback_message));
         startActivity(Intent.createChooser(_Intent, getString(R.string.title_send_feedback)));
	}
}

I am using type “text/html” you can also use “text/plain” but when testing the code on my Desire Z the default HTC mail app is not set for “text/plain” and it will only start GMail. By using “text/html” the user can use the HTC mail app.

I hope this post will help you develop your Android app.
Till next post.


Android Using joins with a provider (SQLite)

In this post I will show how to use a left outer join in your provider.
Now note that you can also create a view in your database and query on the view. I might do a post on that subject in the future.

For this example I will use a SQLite database with two tables:
book
_id – Id field
title – Title of our book
category – Id references to table categories.

categories
_id – Id field
title – Caption of our category

Note that I’m using title in both tables, I’ve used these field names so I can show you how to deal with fields that have the same name.

First I have created a helper class for our table:

/**
 * Books table
 */
public static final class BookColumns implements BaseColumns {
	// This class cannot be instantiated
	private BookColumns () {}

	/**
	 * The table name of books = "books"
	 */
	public static final String TABLENAME = "books";

	/**
	 * The title of the book
	 * <P>Type: TEXT</P>
	 */
	public static final String TITLE = "title";        

	/**
	 * The category of the book (ref to table categories)
	 * <P>Type: INT</P>
	 */
	public static final String CATEGORY = "category";
}

/**
 * Categories table
 */
public static final class CategoriesColumns implements BaseColumns {
	// This class cannot be instantiated
	private CategoriesColumns () {}

	/**
	 * The table name of categories = "categories"
	 */
	public static final String TABLENAME = "categories";

	/**
	 * The caption of the category
	 * <P>Type: TEXT</P>
	 */
	public static final String TITLE = "title";
}

Next I have created a provider, nothing special just your basic provider.
I want to get the title of the category as a field when getting our books or one book.

First I will need to define the projection maps. But here a problem occurs. I want to get the book title and our category title in one query, but both field names are named the same.
Luckily In SQL you can specify your exact field name with a prefix of the table name. I will use this to map the category title to a more suitable field name. But in the helper class I only specified the field names. To keep my code clean I will modify the helper classes.

/**
 * Books table
 */
public static final class BookColumns implements BaseColumns {
	// This class cannot be instantiated
	private BookColumns () {}

	/**
	 * The table name of books = "books"
	 */
	public static final String TABLENAME = "books";

	/**
	 * The id of the book, includes tablename prefix
	 * <P>Type: INT</P>
	 */
	public static final String FULL_ID =  TABLENAME + "." + _ID;	

	/**
	 * The title of the book
	 * <P>Type: TEXT</P>
	 */
	public static final String TITLE = "title";     

	/**
	 * The title of the book, includes tablename prefix
	 * <P>Type: TEXT</P>
	 */
	public static final String FULL_TITLE =  TABLENAME + "." + TITLE;	

	/**
	 * The category of the book (ref to table categories)
	 * <P>Type: INT</P>
	 */
	public static final String CATEGORY = "category";        

	/**
	 * The category of the book, includes tablename prefix (ref to table categories)
	 * <P>Type: INT</P>
	 */
	public static final String FULL_CATEGORY =  TABLENAME + "." + CATEGORY;
}

/**
 * Categories table
 */
public static final class CategoriesColumns implements BaseColumns {
	// This class cannot be instantiated
	private CategoriesColumns () {}

	/**
	 * The table name of categories = "categories"
	 */
	public static final String TABLENAME = "categories";

	/**
	 * The id of the category, includes tablename prefix
	 * <P>Type: INT</P>
	 */
	public static final String FULL_ID =  TABLENAME + "." + _ID;	

	/**
	 * The caption of the category
	 * <P>Type: TEXT</P>
	 */
	public static final String TITLE = "title";        

	/**
	 * The caption of the category, includes tablename prefix
	 * <P>Type: TEXT</P>
	 */
	public static final String FULL_TITLE =  TABLENAME + "." + TITLE;
}

Now I can define the projection maps.

static {
	//Setup projection maps
	sCategoriesProjectionMap = new HashMap<String, String>();
	sCategoriesProjectionMap.put(CategoryColumns._ID, CategoryColumns.FULL_ID);
	sCategoriesProjectionMap.put(CategoryColumns.TITLE, CategoryColumns.FULL_TITLE);

	sBooksProjectionMap = new HashMap<String, String>();
	sBooksProjectionMap.put(BookColumns._ID, BookColumns.FULL_ID);
	sBooksProjectionMap.put(BookColumns.TITLE, BookColumns.FULL_TITLE);
	sBooksProjectionMap.put(BookColumns.COMMENT, BookColumns.FULL_COMMENT);
	sBooksProjectionMap.put(BookColumns.CATEGORY, BookColumns.FULL_CATEGORY);
	sBooksProjectionMap.put(BookColumns.PRICE, BookColumns.FULL_PRICE);
	sBooksProjectionMap.put(BookColumns.PRIORITY, BookColumns.FULL_PRIORITY);
	sBooksProjectionMap.put(BookColumns.CREATED_DATE, BookColumns.FULL_CREATED_DATE);
	sBooksProjectionMap.put(BookColumns.MODIFIED_DATE, BookColumns.FULL_MODIFIED_DATE);
	sBooksProjectionMap.put("category_title", CategoryColumns.FULL_TITLE);
}

Note that I map all the fields to the full field name with the table name prefix.
Also note this line:

sBooksProjectionMap.put("category_title", CategoryColumns.FULL_TITLE);

Here I’m mapping categories.title to a new field named “category_title”. The new fieldname is unique and has a proper name.

Now for the last part I will need to make the join when getting our data.

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
		String sortOrder) {

	SQLiteQueryBuilder _QB = new SQLiteQueryBuilder();
	int _TableType = 0;

	switch (sUriMatcher.match(uri)) {
	case CATEGORIES:
		_QB.setTables(CategoryColumns.TABLENAME);
		_QB.setProjectionMap(sCategoriesProjectionMap);
		_TableType = CATEGORIES;
		break;

	case CATEGORY_ID:
		_QB.setTables(CategoryColumns.TABLENAME);
		_QB.setProjectionMap(sCategoriesProjectionMap);
		_QB.appendWhere(CategoryColumns.FULL_ID + "=" + uri.getPathSegments().get(1));
		_TableType = CATEGORIES;
		break;

	case BOOKS:
		_QB.setTables(BookColumns.TABLENAME +
				" LEFT OUTER JOIN " + CategoryColumns.TABLENAME + " ON " +
				BookColumns.FULL_CATEGORY + " = " + CategoryColumns.FULL_ID);
		_QB.setProjectionMap(sBooksProjectionMap);
		_TableType = BOOKS;
		break;

	case BOOK_ID:
		_QB.setTables(BookColumns.TABLENAME +
				" LEFT OUTER JOIN " + CategoryColumns.TABLENAME + " ON " +
				BookColumns.FULL_CATEGORY + " = " + CategoryColumns.FULL_ID);
		_QB.setProjectionMap(sBooksProjectionMap);
		_QB.appendWhere(BookColumns.FULL_ID + "=" + uri.getPathSegments().get(1));
		_TableType = BOOKS;
		break;

	default:
		throw new IllegalArgumentException("Unknown URI " + uri);
	}

	//Set your sort order here
	String _OrderBy;
	if (TextUtils.isEmpty(sortOrder)) {
		// If no sort order is specified use the default
		switch(_TableType) {
		case CATEGORIES:
			_OrderBy = CategoryColumns.FULL_TITLE + " ASC";
			break;

		case BOOKS:
			_OrderBy = BookColumns.FULL_TITLE + " ASC";
			break;

		default:
			throw new UnknownError("Unknown table type for sort order");
		}
	} else {
		_OrderBy = sortOrder;
	}

	// Get the database and run the query
	SQLiteDatabase _DB = fDatabaseHelper.getReadableDatabase();
	Cursor _Result = _QB.query(_DB, projection, selection, selectionArgs, null, null, _OrderBy);

	// Tell the cursor what uri to watch, so it knows when its source data changes
	_Result.setNotificationUri(getContext().getContentResolver(), uri);
	return _Result;
}

The actual join is done in this line:

_QB.setTables(BookColumns.TABLENAME +
		" LEFT OUTER JOIN " + CategoryColumns.TABLENAME + " ON " +
		BookColumns.FULL_CATEGORY + " = " + CategoryColumns.FULL_ID);

As you can see I have put a left outer join on the category table and specified the relation between the tables.

Here I use the full _id field name to specify which _id field I’m referring to:

_QB.appendWhere(BookColumns.FULL_ID + "=" + uri.getPathSegments().get(1));

And that’s it. I hope to have given you a better understanding of using joins with providers in Android.


Delphi Scrolling text label component

Here’s a component I made a long time ago. This is a label that scroll’s the text.

You can set the scroll speed with the property: ScrollSpeed
You can specify if the text should scroll once or repeat in a loop with the property: RepeatScroll
And you have two events that tell you when the scrolling starts and stops: OnStartScroll, OnEndScroll

unit caScrollLabel;

interface

uses
  StdCtrls, Messages, Windows, ExtCtrls, Controls, Classes;

type
  TcaScrollLabel = class(TLabel)
  private
    FScrollTimer: TTimer;
    FScrollPos: Integer;
    FTextWidth: Integer;
    FOnEndScroll: TNotifyEvent;
    FOnStartScroll: TNotifyEvent;
    FScrolling: Boolean;
    FRepeatScroll: Boolean;
    FScrollSpeed: Cardinal;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
    procedure ScrollTimer(Sender: TObject);
    procedure SetOnEndScroll(const Value: TNotifyEvent);
    procedure SetOnStartScroll(const Value: TNotifyEvent);
    procedure SetRepeatScroll(const Value: Boolean);
    procedure SetScrollSpeed(const Value: Cardinal);
  protected
    procedure Paint; override;
    procedure SetAutoSize(Value: Boolean); override;
    procedure DoStartScroll;
    procedure DoEndScroll;
    procedure StartScrolling();
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Scrolling: Boolean read FScrolling;
  published
    property OnStartScroll: TNotifyEvent read FOnStartScroll write SetOnStartScroll;
    property OnEndScroll: TNotifyEvent read FOnEndScroll write SetOnEndScroll;
    property RepeatScroll: Boolean read FRepeatScroll write SetRepeatScroll;
    property ScrollSpeed: Cardinal read FScrollSpeed write SetScrollSpeed;
  end;

implementation

uses
  SysUtils, Graphics, Math;

{ TcaScrollLabel }

procedure TcaScrollLabel.CMTextChanged(var Message: TMessage);
begin
  inherited;
  StartScrolling();
end;

constructor TcaScrollLabel.Create(AOwner: TComponent);
begin
  inherited;
  AutoSize := False;
  FScrollTimer := TTimer.Create(nil);
  FScrollTimer.OnTimer := ScrollTimer;
  FScrollTimer.Interval := 100;
  FScrollSpeed := 100;
  FScrollPos := 0;
  FTextWidth := 0;
end;

destructor TcaScrollLabel.Destroy;
begin
  FreeAndNil(FScrollTimer);
  inherited;
end;

procedure TcaScrollLabel.DoEndScroll;
begin
  FScrolling := False;
  if Assigned(OnEndScroll) then
    OnEndScroll(Self);
  if RepeatScroll then
    StartScrolling();
end;

procedure TcaScrollLabel.DoStartScroll;
begin
  FScrolling := True;
  if Assigned(OnStartScroll) then
    OnStartScroll(Self);
end;

procedure TcaScrollLabel.Paint;
var
  lRect: TRect;
begin
  if not Assigned(Parent) then
    Exit;
  lRect := ClientRect;
  if not (csDesigning in ComponentState) then
    lRect.Left := (lRect.Right - FScrollPos);
  Canvas.Font := Font;
  if not Transparent then
  begin
    Canvas.Brush.Color := Color;
    Canvas.Brush.Style := bsSolid;
    Canvas.FillRect(lRect);
  end else
    Canvas.Brush.Style := bsClear;
  TextOut(Canvas.Handle, lRect.Left, lRect.Top, PChar(Caption), Length(Caption));
end;

procedure TcaScrollLabel.ScrollTimer(Sender: TObject);
begin
  if FScrollPos >= (FTextWidth + Width) then
  begin
    FScrollTimer.Enabled := False;
    DoEndScroll;
  end
  else
    Inc(FScrollPos, 3);
  if Assigned(Parent) then
    Repaint;
end;

procedure TcaScrollLabel.SetAutoSize(Value: Boolean);
begin
  inherited SetAutoSize(False);
end;

procedure TcaScrollLabel.SetOnEndScroll(const Value: TNotifyEvent);
begin
  FOnEndScroll := Value;
end;

procedure TcaScrollLabel.SetOnStartScroll(const Value: TNotifyEvent);
begin
  FOnStartScroll := Value;
end;

procedure TcaScrollLabel.SetRepeatScroll(const Value: Boolean);
begin
  FRepeatScroll := Value;
end;

procedure TcaScrollLabel.SetScrollSpeed(const Value: Cardinal);
begin
  FScrollSpeed := Value;
  FScrollTimer.Interval := Value;
end;

procedure TcaScrollLabel.StartScrolling;
var
  lRect: TRect;
  lFlags: Cardinal;
begin
  if not Assigned(Parent) then
    Exit;
  if Assigned(FScrollTimer) then
  begin
    DoStartScroll;
    FScrollPos := 0;
    FScrollTimer.Enabled := not (csDesigning in ComponentState);
    lRect := Rect(0,0,0,0);
    Canvas.Font := Font;
    lFlags := DT_LEFT or DT_CALCRECT or DT_SINGLELINE or DT_NOPREFIX;
    DrawText(Canvas.Handle, PChar(Caption), Length(Caption), lRect, lFlags);
    FTextWidth := lRect.Right - lRect.Left;
  end;
end;

end.