Langkah pertama adalah membuat relasi tabel ‘kontak’ beserta inisiasi data yang diperlukan (query 1) :

CREATE TABLE kontak (
 id int PRIMARY KEY IDENTITY,
 name varchar(255) NOT NULL,
 address varchar(255),
 phone varchar(255),
 email varchar(255)
)
INSERT INTO dbo.kontak (name,address,phone,email) VALUES ('Javan','Bandung','0813','javan@javan.com');

Selanjutnya adalah membuat berkas XML menggunakan data dari tabel ‘kontak’ pada basisdata (query 2) :

SELECT ( SELECT * FROM dbo.kontak
 FOR
 XML PATH('Contact'),
 TYPE
)
FOR XML PATH(''),
ROOT('ContactList')
GO

Akan dihasilkan berkas XML sebagai berikut :

<ContactList>
  <Contact>
    <id>1</id>
    <name>Javan</name>
    <address>Bandung</address>
    <phone>0813</phone>
    <email>javan@javan.com</email>
  </Contact>
</ContactList>

T-SQL juga memungkinkan untuk membaca XML dan menambahkannya ke tabel ‘kontak’ seperti yang ditunjukkan oleh query 3 berikut :

DECLARE @MyXML XML
SET @MyXML = '<ContactList>
  <Contact>
    <name>Javan 2</name>
    <address>Bandung 2</address>
    <phone>08132</phone>
    <email>javan2@javan.com</email>
  </Contact>
</ContactList>'

INSERT INTO dbo.kontak (name,address,phone,email)
SELECT
a.b.value('Contact[1]/name[1]','varchar(255)') AS name,
a.b.value('Contact[1]/address[1]','varchar(255)') AS address,
a.b.value('Contact[1]/phone[1]','varchar(255)') AS phone,
a.b.value('Contact[1]/email[1]','varchar(255)') AS email
FROM @MyXML.nodes('ContactList') a(b)

Adapun data yang ada pada tabel kontak di basisdata adalah sebagai berikut (query 4) :

SELECT * FROM javan.dbo.kontak;

id name address phone Email
1 Javan Bandung 0813 javan@javan.com
2 Javan 2 Bandung 2 08132 javan2@javan.com

Untuk membaca berkas (file) eksternal, maka perlu didefenisikan sebuah fungsi (readFileAsString) yang mengembalikan string s yaitu isi dari berkas yang dibaca. Defenisi fungsi terkait adalah sebagai berikut :

CREATE FUNCTION [dbo].[readFileAsString] ( @Path VARCHAR(255), @Filename VARCHAR(100) )
RETURNS VARCHAR(max)
AS
BEGIN
	-- Definition
	DECLARE  @objFileSystem INT,
			@objTextStream INT,
			@objErrorObject INT,
			@strErrorMessage VARCHAR(1000),
			@command VARCHAR(1000),
			@chunk VARCHAR(8000),
			@string VARCHAR(max),
			@hr INT,
			@yesOrNo INT
	-- Algorithm
	SELECT @string = ''
	SELECT @strErrorMessage = 'opening the File System Object'
	EXECUTE @hr = sp_OACreate  'Scripting.FileSystemObject' , @objFileSystem OUT

	IF @hr=0 SELECT @objErrorObject=@objFileSystem, @strErrorMessage='Opening file "'+@path+'\'+@filename+'"',@command=@path+'\'+@filename
	-- For Reading ASCII formatted
	IF @hr=0 EXECUTE @hr = sp_OAMethod   @objFileSystem  , 'OpenTextFile', @objTextStream OUT, @command,1,false,0

	WHILE @hr=0
	BEGIN
		IF @hr=0 SELECT @objErrorObject=@objTextStream,
			@strErrorMessage='finding out if there is more to read in "'+@filename+'"'
		IF @hr=0 EXECUTE @hr = sp_OAGetProperty @objTextStream, 'AtEndOfStream', @yesOrNo OUTPUT

		IF @yesOrNo<>0  break
		IF @hr=0 SELECT @objErrorObject=@objTextStream,
			@strErrorMessage='reading from the output file "'+@filename+'"'
		IF @hr=0 EXECUTE @hr = sp_OAMethod  @objTextStream, 'Read', @chunk OUTPUT,4000
		SELECT @String = @string + @chunk
	END
	IF @hr=0 SELECT @objErrorObject=@objTextStream, @strErrorMessage='closing the output file "'+@filename+'"'
	IF @hr=0 EXECUTE @hr = sp_OAMethod  @objTextStream, 'Close'
	IF @hr<>0
	BEGIN
		DECLARE
			@Source VARCHAR(255),
			@Description VARCHAR(255),
			@Helpfile VARCHAR(255),
			@HelpID INT

		EXECUTE sp_OAGetErrorInfo  @objErrorObject,
			@source OUTPUT,@Description OUTPUT,@Helpfile OUTPUT,@HelpID OUTPUT
		SELECT @strErrorMessage='Error whilst '
				+coalesce(@strErrorMessage,'doing something')
				+', '+coalesce(@Description,'')
		SELECT @string=@strErrorMessage
	END
EXECUTE  sp_OADestroy @objTextStream
	-- Fill the table variable with the rows for your result set
	RETURN @string
END

Untuk menggunakan fungsi di atas maka perlu meng-enable ‘OLE Automation Procedures’ (karena menggunakan system procedure sp_OA*) dengan menggunakan query 5 sebagai berikut :

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO

Dengan memodifikasi query 3 dimana inisiasi nilai variabel string ‘MyXML’ diambil dari hasil pembacaan berkas xml oleh fungsi readFileAsString maka dapat didefinisikan procedure berikut yang bermanfaat untuk membaca berkas XML dengan format terdefenisi dan memasukkannya sebagai record baru pada tabel kontak.

CREATE PROCEDURE ReadFromXMLFile
@FilePath VARCHAR (1024),
@FileName VARCHAR (1024)
AS
DECLARE @MyXML XML
SET @MyXML = dbo.readFileAsString (@FilePath, @FileName)
INSERT INTO dbo.kontak (name,address,phone,email)
SELECT
 a.b.value('Contact[1]/name[1]','varchar(255)') AS name,
 a.b.value('Contact[1]/address[1]','varchar(255)') AS address,
 a.b.value('Contact[1]/phone[1]','varchar(255)') AS phone,
 a.b.value('Contact[1]/email[1]','varchar(255)') AS email
FROM @MyXML.nodes('ContactList') a(b)

Sebagai contoh pemakaian prosedur, untuk berkas XML di ‘D:\test.xml’ sebagai berikut :

<ContactList>
  <Contact>
    <id>1</id>
    <name>Javan 3</name>
    <address>Bandung 3</address>
    <phone>08133</phone>
    <email>javan3@javan.com</email>
  </Contact>
</ContactList>

Maka eksekusi prosedurnya adalah sebagai berikut (query 6) :

EXECUTE ReadFromXMLFile 'D:\','test.xml'

Adapun data terakhir yang ada pada tabel kontak di basisdata adalah sebagai berikut (query 7) :

SELECT * FROM javan.dbo.kontak;

id name address phone Email
1 Javan Bandung 0813 javan@javan.com
2 Javan 2 Bandung 2 08132 javan2@javan.com
3 Javan 3 Bandung 3 08133 javan3@javan.com

Titanium merupakan salah satu framework alternatif buatan Appcelerator yang dapat digunakan dalam mengembangkan aplikasi mobile untuk multi platform (saat ini mendukung platform Android, iOS dan Blackberry). Sama seperti phonegap, framework ini mendukung penggunaan bahasa pemrograman web untuk client side scripting yaitu HTML, CSS dan JavaScript. Akan tetapi terdapat beberapa perbedaan dalam mekanisme penggunaannya yang membuat framework ini patut untuk dicoba, yaitu :

  • Framework ini dapat menghasilkan aplikasi native dimana menggunakan elemen-elemen antarmuka native tidak sepertiphonegap yang pada dasarnya hanya mengandalkan web engine element dari suatu platform (misalnya WebView pada Android SDK) dalam mengeksekusi source halaman antarmuka web yang disimpan di lokal (assets). Hal ini dimungkinkan dengan menggunakan elemen-elemen antarmuka (UI) dari titanium (berupa kelas-kelas JavaScript) yang pada dasarnya akan mengeksekusi elemen-elemen UI native terkait pada saat runtime (interpreter). Secara teori maka rendering dan responsiveness antarmuka (UI) dari Titanium akan lebih baik dari phoneGap.
  • Karena menghasilkan ‘aplikasi native pada saar runtime’ maka framework ini dapat mengakses sumber daya native / API native(seperti kamera, GPS, AcceleroMeter dan sebagainya) dengan baik. Hal serupa sejauh ini masih sulit diimplementasikan padaphoneGap, kalaupun terdapat implementasi pustaka PhoneGap untuk mengakses sumber daya native, implementasi tersebut masih belum stabil.
  • Framework ini memiliki IDE khusus yang dirancang untuk mempermudah pengembangan aplikasi yaitu Titanium Studio. IDE ini merupakan pengembangan dari IDE Eclipse sehingga bagi pengguna Eclipse tidak akan memiliki kendala dalam menggunakannya.
  • Selain untuk membuat aplikasi mobile, framework ini juga dapat digunakan untuk membangun aplikasi desktop yang dapat berjalan native pada berbagai platform (saat ini untuk platform Windows, Linux dan MacOS)
Titanium Framework

Titanium Framework

Pada artikel ini akan diperlihatkan salah satu instansiasi aplikasi sederhana dari framework Titanium yaitu JavanArticle yang akan meminta RSS Feeds dari server dan menampilkan daftar artikel pada antarmuka aplikasi. Langkah pertama adalah dengan membuat proyek baru pada IDE Titanium Studio melalui menu File > New > Titanium Mobile Project, kemudian menginisiasi konfigurasi dasar dari proyek seperti pada gambar berikut.

Membuat Proyek Titanium Baru

Membuat Proyek Titanium Baru

Setelah mengklik tombol ‘Finish’ maka Titanium Studio akan otomatis membuat workspace baru dan juga template aplikasi standar yang sudah memiliki inisiasi kode aplikasi. Yang perlu diperhatikan adalah file script app.js pada folder Resources, dimana file inilah yang akan menjadi main file yang akan dieksekusi secara default pada saat runtime. Setelah itu replace lah seluruh kode pada berkasapp.js dengan kode berikut.

// Set warna latar aplikasi
Titanium.UI.setBackgroundColor('#000');

// Buat UI Window baru untuk aplikasi dan inisiasi properti UI yang dibutuhkan
var win = Titanium.UI.createWindow({
    title:'Javan Articles',
    backgroundColor:'#000'
});

// Buat UI Tabel untuk dan inisiasi properti UI yang dibutuhkan
// Variabel data akan digunakan untuk menampung objek-objek RSS feed yang diterima
var data = [];
var tableview = Titanium.UI.createTableView({
	data:data,
	headerTitle: 'List of Recent Articles',
	backgroundColor:'#000'
});

// Buat UI Baris Tabel dan inisiasi properti UI yang dibutuhkan
row = Titanium.UI.createTableViewRow({
		title: 'loading articles ...',
		backgroundColor:'#000',
		color: '#FF0'
	});

// Letakkan baris tabel 'row' ke tabel 'tableview'
tableview.appendRow(row);

// Letakkan tabel 'tableview' pada window 'win'
win.add(tableview);

// Tampilkan Window ke Layar
win.open();

// Inisiasi koneksi ke server untuk memuat daftar artikel dari RSS Feeds
// Koneksi dilakukan secara asinkronus (AJAX)
var xhr = Titanium.Network.createHTTPClient();
// Inisiasi function handler yang menangani pemrosesan data yang diterima dari server
xhr.onload = function() {
	try {
		tableview.deleteRow(0, null); // hapus baris ke-0 pada tabel 'tableview'
		var doc = this.responseXML.documentElement; // assign data dari server sebagai objek XML 'doc'
		var items = doc.getElementsByTagName('item');
		var doctitle = doc.evaluate("//channel/title/text()").item(0).nodeValue;
		var urls = new Array();
		// Proses setiap item RSS
		for(var c=0; c		{
			urls[c] = items.item(c).getElementsByTagName('link').item(0).text;
			postName = items.item(c).getElementsByTagName('title').item(0).text;
			postUrl = items.item(c).getElementsByTagName('link').item(0).text;
			// Buat UI baris tabel 'row' dan inisiasi dengan title dari objek RSS ke - c
			row = Titanium.UI.createTableViewRow({
					title: postName,
					backgroundColor:'#000',
					color: '#FF0'
				});
			// Letakkan 'row' ke tabel 'tableview'
			tableview.appendRow(row);
			// Tambahkan handler yang akan dieksekusi ketia baris tabel di klik
			row.addEventListener('click', function (e){
				// Aksi yang akan dilakukan adalah membuka browser untuk membuka artikel terkait
				var intent = Titanium.Android.createIntent({
						action: Titanium.Android.ACTION_VIEW,
						data: urls[e.index],
					});
				intent.addCategory(Titanium.Android.CATEGORY_BROWSABLE);
				Ti.Android.currentActivity.startActivity(intent);
			});
		}
	} catch(E) {
		// Munculkan dialog jika terjadi 'exception' selama pemrosesan data dari server berlangsung
		alert(E);
	}
};

// Lakukan koneksi ke server untuk memulai operasi
xhr.open('GET', 'http://javan.co.id/feed/rss');
xhr.send();

Kode di atas akan memunculkan window aplikasi yang menampilkan daftar RSS Feeds dari http://javan.co.id/feed/rss dalam format tabel dimana langkah-langkah prosesnya sudah dijelaskan pada setiap komentar kode. Selanjutnya compile aplikasi terkait menjadiAndroid Package (.apk) dan jalankan pada emulator. Hal ini dapat dilakukan dengan melakukan klik kanan pada proyek terkait dan pilih menu Run As > Android Emulator. Anda juga dapat langsung menginstalasi aplikasi pada perangkat Android dengan melakukan klik kanan juga pada proyek terkait dan pilih menu “Install To Android Devices”. Baik pada emulator maupun pada perangkat android, saat aplikasi di jalankan lebih kurang akan memunculkan window aplikasi sesuai gambar berikut.

Instansiasi Aplikasi dari Titanium Framework

Instansiasi Aplikasi dari Titanium Framework

Untuk informasi lebih lanjut tentang framework ini serta contoh-contoh aplikasi lain yang dibuat menggunakan framework Titanium dapat dilihat pada situs terkait. Selamat mencoba dan bereksplorasi.

Dalam merancang antarmuka aplikasi Blackberry, terdapat berbagai komponen bawaan dari RIM yang dipakai dimana pada dasarnya merupakan turunan dari kelas Field. Kelas-kelas turunan dari kelas Field ini secara umum dibagi ke dalam 2 kelompok yaitu UI Component (turunan langsung dari kelas Field) yang berinteraksi langsung (input / output) dengan pengguna aplikasi serta UI Manager (turunan dari kelas Manager dimana kelas Manager merupakan turunan langsung dari kelas Field) yang mengatur posisi dari UI Component maupun UI Manager (nested manager) pada layar perangkat Blackberry. Jika dibandingkan dengan perancangan UI pada halaman web (menggunakan HTML/CSS) maka tag-tag seperti table, span maupun div termasuk ke dalam UI Manager sedangkan komponen-komponen form (seperti tag input), tag img dan sebagainya termasuk ke dalam UI Component.

Akan tetapi, UI Component dan UI Manager bawaan dari RIM kebanyakan tidak mengakomodasi kebutuhan-kebutuhan dari developer aplikasi BB. Untuk mengatasi ini maka kebanyakan para developer mencoba membuat Custom Field maupun Custom Manager sendiri untuk mengakomodasi kebutuhan aplikasi dengan meng-extend kelas-kelas pada UI Component, UI Manager ataupun kelas primitif Field maupun kelas primitif Manager. 

Pada artikel ini, penulis akan berbagi 2 buah contoh custom manager yaitu FlexibleHorizontalFieldManager dan FlexibleVerticalFieldManager yang secara berurutan merupakan turunan dari kelas HorizontalFieldManager dan VerticalFieldManager. Adapun masing-masing custom manager ini memperluas kemampuan dari parent manager dimana mencakup constructor, layout dan navigation. Perluasan behavior dari custom manager ini meliputi  :

  • Dapat memiliki width maupun height yang fleksibel (wrap content) sesuai dengan width terbesar dari komponen-komponen UI yang dikelolanya (untuk vertical manager) ataupun height terbesar dari komponen-komponen UI yang dikelola (untuk horizontal manager). Selain itu dapat memiliki width maupun height yang fix ataupun memenuhi dimensi layar dari perangkat BB.
  • Dapat menempatkan komponen-komponen UI yang dikelolanya secara evenly spaced – width (untuk horizontal manager) maupun evenly spaced – height (untuk vertical manager). Biasanya dibutuhkan untuk layouting toolbar dan kebutuhan lain.
  • Width maupun height dapat menyesuaikan bila komponen/manager sebelumnya maupun sesudahnya (pada parent layout) memiliki width dan height yang fix. Behaviour ini biasanya dibutuhkan untuk mengakomodasi layouting pada perangkat BB yang memiliki multiple orientation screen sehingga constraint layout dapat dijaga.
  • Behaviour tambahan seperti dapat berubah warna/gambar background ketika menerima fokus serta dapat menerima input click / touch. Dengan adanya behaviour tambahan ini maka dapat dijadikan sebagai alternatif lain dari ObjectListField dimana setiap list row memiliki komponen UI yang kompleks (baik dari segi layout maupun multiple event listener / 2 atau lebih komponen memiliki event listener masing-masing).
Adapun kode sumber untuk FlexibleHorizontalFieldManager adalah sebagai berikut :

/**
 * Class  : FlexibleHorizontalFieldManager.java
 * Author : Joel / 144key (joel@hutasoit.net) (2010)
 **/

package org.javan.bb.customui;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.container.AbsoluteFieldManager;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.decor.BackgroundFactory;

/**
 * Extended Class of HorizontalFieldManager that can handle several extended behaviour
 * @author joel
 */
public class FlexibleHorizontalFieldManager extends HorizontalFieldManager {
    /** Extended Attributes **/
        public static final int CLICKNOTIFY = 144;
        public static int FILL_PARENT = -1; // Use maximum width/height that provided by parent manager
        public static int WRAP_CONTENT = -2; // Use maximum/total width/height of the field child
        public static int USE_FIXED_HEADTAIL = -3; // Like fill_parent but substracted with sum of heading/trailing width/height
        public static int NO_COLOR = -4; // Constant for no color initiation
        private int fixedHeadWidth = 0; // Heading Width
        private int fixedHeadHeight = 0; // Heading Height
        private int fixedTailWidth = 0; // Trailing Width
        private int fixedTailHeight = 0; // Trailing Height
        private int flexibleWidth = FILL_PARENT; // Manager Width, default FILL_PARENT
        private int flexibleHeight = FILL_PARENT; // Manager Height, default FILL_PARENT
        private int hoverColor = NO_COLOR; // default NO_HOVER_COLOR to be painted
        private int baseColor = NO_COLOR; // default NO_BASE_COLOR to be painted
        private Bitmap bgImage = null; // default NO_BACKGROUND_IMAGE
        private Bitmap bgHoverImage = null; // default NO_BACKGROUND_HOVER_IMAGE
        private boolean distributedWidth = false; // default FIELD_WIDTH_NOT_DISTRIBUTED
        private boolean enableClick = false; // default NON_CLICKABLE
    /** Extended Methods **/
    public FlexibleHorizontalFieldManager() {
        super(Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT);
    }
    public FlexibleHorizontalFieldManager(long style) {
        super(Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT | style);
    }
    public FlexibleHorizontalFieldManager(int w, int h) {
        super((w == FILL_PARENT ? Manager.USE_ALL_WIDTH : ((long) 0)) | (h == FILL_PARENT ? Manager.USE_ALL_HEIGHT : ((long) 0)));
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public FlexibleHorizontalFieldManager(int w, int h, long style) {
        super((w == FILL_PARENT ? Manager.USE_ALL_WIDTH : ((long) 0)) | (h == FILL_PARENT ? Manager.USE_ALL_HEIGHT : ((long) 0)) | style);
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public void setHeadAndTailArea(int _fixedHeadWidth, int _fixedHeadHeight, int _fixedTailWidth, int _fixedTailHeight) {
        fixedHeadWidth = _fixedHeadWidth;
        fixedHeadHeight = _fixedHeadHeight;
        fixedTailWidth = _fixedTailWidth;
        fixedTailHeight = _fixedTailHeight;
    }
    public void setEnableClick(boolean _enableClick) {
        this.enableClick = _enableClick;
    }
    public boolean isAttached() {
        Manager m = getManager();
        return (m != null && m.isValidLayout() && m.isVisible() && isValidLayout() && isVisible());
    }
    public boolean isFocusable() {
        if (isAttached()) {
            return (enableClick ? enableClick : super.isFocusable());
        } else return super.isFocusable();
    }
    protected boolean touchEvent(TouchEvent arg0) {
        if (enableClick) {
            if (arg0.getEvent() == TouchEvent.CLICK) {
                fieldChangeNotify(CLICKNOTIFY);
                return true;
            }
        }
        return super.touchEvent(arg0);
    }
    protected boolean navigationClick(int i, int i1) {
        if (enableClick) {
            fieldChangeNotify(CLICKNOTIFY);
            return true;
        } else return super.navigationClick(i, i1);
    }
    protected boolean keyChar(char c, int i, int i1) {
        if (enableClick && c == Characters.ENTER) {
            fieldChangeNotify(CLICKNOTIFY);
            return true;
        } else return super.keyChar(c, i, i1);
    }
    public void setWitdh(int w) {
        flexibleWidth = w;
    }
    public void setHeight(int h) {
        flexibleHeight = h;
    }
    public void setDimension(int w, int h) {
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public void setDistributedWidth(boolean _newValue) {
        distributedWidth = _newValue;
    }
    public int getPreferredWidth() {
        if (flexibleWidth >= 0) {
            return flexibleWidth;
        } else if (flexibleWidth == USE_FIXED_HEADTAIL) {
            return (Display.getWidth() - fixedHeadWidth - fixedTailWidth);
        } else if (flexibleWidth == WRAP_CONTENT) {
            int totalWidth = 0;
            int numFields = getFieldCount();
            for (int i = 0; i < numFields; i++) {                 Field field = getField(i);                 totalWidth += field.getExtent().width+field.getMarginLeft()+field.getMarginRight();             }             return totalWidth;         } else {             // IF FILL_PARENT             if (getManager() != null && getManager().getClass().equals(AbsoluteFieldManager.class))                 // handle for absolutefieldmanager parent                 return Display.getWidth();              else                 return super.getPreferredWidth();         }     }     public int getPreferredHeight() {         if (flexibleHeight >= 0) {
            return flexibleHeight;
        } else if (flexibleHeight == WRAP_CONTENT) {
            int totalHeight = 0;
            int numFields = getFieldCount();
            for (int i = 0; i < numFields; i++) {                 Field field = getField(i);                 int tmpHeight = field.getExtent().height+field.getMarginTop()+field.getMarginBottom();                 if (tmpHeight > totalHeight) totalHeight = tmpHeight;
            }
            return totalHeight;
        } else if (flexibleHeight == USE_FIXED_HEADTAIL) {
            return (Display.getHeight() - fixedHeadHeight - fixedTailHeight);
        } else {
            // IF FILL_PARENT
            if (getManager() != null && getManager().getClass().equals(AbsoluteFieldManager.class))
                // handle for absolutefieldmanager parent
                return Display.getHeight();
            else
                return super.getPreferredHeight();
        }
    }
    protected void sublayout(int maxWidth, int maxHeight) {
        int totalWidth  = 0;
        int totalHeight = 0;
        if (flexibleWidth == WRAP_CONTENT || flexibleHeight == WRAP_CONTENT) {
            int numFields = getFieldCount();
            int availableWidth = maxWidth;
            int availableHeight = maxHeight;
            for (int i = 0; i < numFields; i++) {                 Field field = getField(i);                 layoutChild(field, availableWidth, maxHeight);                  availableWidth -= field.getExtent().width-field.getMarginLeft()-field.getMarginRight();                 availableHeight  = field.getExtent().height+field.getMarginTop()+field.getMarginBottom();                 totalWidth += field.getExtent().width+field.getMarginLeft()+field.getMarginRight();                 if (availableHeight > totalHeight && availableHeight < maxHeight) totalHeight = availableHeight;
            }
        }
        if (distributedWidth)
        // DistributedWidthHorizontalFieldManager
        {
            super.sublayout(maxWidth, maxHeight);
            int nbFieldForCalculation = ((getFieldCount() != 0) ? getFieldCount() : 1);
            int intervalPosition = (Display.getWidth() / nbFieldForCalculation);
            for (int i = 0; i < getFieldCount(); i++) {
                layoutChild(getField(i), maxWidth, maxHeight);
                setPositionChild(getField(i), (intervalPosition * i), getPaddingTop());
            }
        }
        if (!distributedWidth) super.sublayout((flexibleWidth == FILL_PARENT ? maxWidth : (flexibleWidth == WRAP_CONTENT ? totalWidth : (flexibleWidth == USE_FIXED_HEADTAIL ? (Display.getWidth() - fixedHeadWidth - fixedTailWidth) : flexibleWidth))),
                        (flexibleHeight == FILL_PARENT ? maxHeight : (flexibleHeight == WRAP_CONTENT ? totalHeight : (flexibleHeight == USE_FIXED_HEADTAIL ? (Display.getHeight() - fixedHeadHeight - fixedTailHeight) : flexibleHeight))));
        setExtent(distributedWidth ? Display.getWidth() : (flexibleWidth == FILL_PARENT ? maxWidth : (flexibleWidth == WRAP_CONTENT ? totalWidth : (flexibleWidth == USE_FIXED_HEADTAIL ? (Display.getWidth() - fixedHeadWidth - fixedTailWidth) : flexibleWidth))),
                  (flexibleHeight == FILL_PARENT ? maxHeight : (flexibleHeight == WRAP_CONTENT ? totalHeight : (flexibleHeight == USE_FIXED_HEADTAIL ? (Display.getHeight() - fixedHeadHeight - fixedTailHeight) : flexibleHeight))));
    }
    public void setBaseColor(int baseColor) {
        this.baseColor = baseColor;
        setBackground(BackgroundFactory.createSolidBackground(baseColor));
    }
    public void setHoverColor(int _color) {
        hoverColor = _color;
    }
    public void setBgImages(Bitmap img, Bitmap imgHover) {
        bgImage = img;
        bgHoverImage = imgHover;
        setBackground(BackgroundFactory.createBitmapBackground(bgImage));
    }
    protected void onFocus(int direction) {
        if (bgHoverImage != null) setBackground(BackgroundFactory.createBitmapBackground(bgHoverImage));
        else if (baseColor != NO_COLOR) setBackground(BackgroundFactory.createSolidBackground(hoverColor));
        else if (hoverColor != NO_COLOR) setBackground(BackgroundFactory.createSolidTransparentBackground(hoverColor, 192));
        super.onFocus(direction);
    }
    protected void onUnfocus() {
        if (bgImage != null) setBackground(BackgroundFactory.createBitmapBackground(bgImage));
        else if (baseColor != NO_COLOR) setBackground(BackgroundFactory.createSolidBackground(baseColor));
        else if (hoverColor != NO_COLOR) setBackground(BackgroundFactory.createSolidTransparentBackground(hoverColor, 0));
        super.onUnfocus();
    }
}

Sedangkan kode sumber untuk FlexibleVerticalFieldManager adalah sebagai berikut :

/**
 * Class  : FlexibleVerticalFieldManager.java
 * Author : Joel / 144key (joel@hutasoit.net) (2010)
 **/

package org.javan.bb.customui;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.container.AbsoluteFieldManager;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.decor.BackgroundFactory;

/**
 * Extended Class of VerticalFieldManager that can handle several extended behaviour
 * @author joel
 */
public class FlexibleVerticalFieldManager extends VerticalFieldManager {
    /** Extended Attributes **/
        public static final int CLICKNOTIFY = 144;
        public static int FILL_PARENT = -1; // Use maximum width/height that provided by parent manager
        public static int WRAP_CONTENT = -2; // Use maximum/total width/height of the field child
        public static int USE_FIXED_HEADTAIL = -3; // Like fill_parent but substracted with sum of heading/trailing width/height
        public static int NO_COLOR = -4; // Constant for no color initiation
        private int fixedHeadWidth = 0; // Heading Width
        private int fixedHeadHeight = 0; // Heading Height
        private int fixedTailWidth = 0; // Trailing Width
        private int fixedTailHeight = 0; // Trailing Height
        private int flexibleWidth = FILL_PARENT; // Manager Width, default FILL_PARENT
        private int flexibleHeight = FILL_PARENT; // Manager Height, default FILL_PARENT
        private int hoverColor = NO_COLOR; // default NO_HOVER_COLOR to be painted
        private int baseColor = NO_COLOR; // default NO_BASE_COLOR to be painted
        private Bitmap bgImage = null; // default NO_BACKGROUND_IMAGE
        private Bitmap bgHoverImage = null; // default NO_BACKGROUND_HOVER_IMAGE
        private boolean distributedHeight = false; // default FIELD_WIDTH_NOT_DISTRIBUTED
        private boolean enableClick = false; // default NON_CLICKABLE
    /** Extended Methods **/
    public FlexibleVerticalFieldManager() {
        super(Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT);
    }
    public FlexibleVerticalFieldManager(long style) {
        super(Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT | style);
    }
    public FlexibleVerticalFieldManager(int w, int h) {
        super((w == FILL_PARENT ? Manager.USE_ALL_WIDTH : ((long) 0)) | (h == FILL_PARENT ? Manager.USE_ALL_HEIGHT : ((long) 0)));
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public FlexibleVerticalFieldManager(int w, int h, long style) {
        super((w == FILL_PARENT ? Manager.USE_ALL_WIDTH : ((long) 0)) | (h == FILL_PARENT ? Manager.USE_ALL_HEIGHT : ((long) 0)) | style);
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public void setHeadAndTailArea(int _fixedHeadWidth, int _fixedHeadHeight, int _fixedTailWidth, int _fixedTailHeight) {
        fixedHeadWidth = _fixedHeadWidth;
        fixedHeadHeight = _fixedHeadHeight;
        fixedTailWidth = _fixedTailWidth;
        fixedTailHeight = _fixedTailHeight;
    }
    public void setEnableClick(boolean _enableClick) {
        this.enableClick = _enableClick;
    }
    public boolean isAttached() {
        Manager m = getManager();
        return (m != null && m.isValidLayout() && m.isVisible() && isValidLayout() && isVisible());
    }
    public boolean isFocusable() {
        if (isAttached()) {
            return (enableClick ? enableClick : super.isFocusable());
        } else return super.isFocusable();
    }
    protected boolean touchEvent(TouchEvent arg0) {
        if (enableClick) {
            if (arg0.getEvent() == TouchEvent.CLICK) {
                fieldChangeNotify(CLICKNOTIFY);
                return true;
            }
        }
        return super.touchEvent(arg0);
    }
    protected boolean navigationClick(int i, int i1) {
        if (enableClick) {
            fieldChangeNotify(CLICKNOTIFY);
            return true;
        } else return super.navigationClick(i, i1);
    }
    protected boolean keyChar(char c, int i, int i1) {
        if (enableClick && c == Characters.ENTER) {
            fieldChangeNotify(CLICKNOTIFY);
            return true;
        } else return super.keyChar(c, i, i1);
    }
    public void setWitdh(int w) {
        flexibleWidth = w;
    }
    public void setHeight(int h) {
        flexibleHeight = h;
    }
    public void setDimension(int w, int h) {
        flexibleWidth = w;
        flexibleHeight = h;
    }
    public void setDistributedHeight(boolean _newValue) {
        distributedHeight = _newValue;
    }
    public int getPreferredWidth() {
        if (flexibleWidth >= 0) {
            return flexibleWidth;
        } else if (flexibleWidth == USE_FIXED_HEADTAIL) {
            return (Display.getWidth() - fixedHeadWidth - fixedTailWidth );
        } else if (flexibleWidth == WRAP_CONTENT) {
            int totalWidth = 0;
            int numFields = getFieldCount();
            for (int i = 0; i < numFields; i++) {                 Field field = getField(i);                 int tmpWidth = field.getExtent().width+field.getMarginLeft()+field.getMarginRight();                 if (tmpWidth > totalWidth) totalWidth = tmpWidth;
            }
            return totalWidth;
        } else {
            // IF FILL_PARENT
            if (getManager() != null && getManager().getClass().equals(AbsoluteFieldManager.class))
                // handle for absolutefieldmanager parent
                return Display.getWidth();
            else
                return super.getPreferredWidth();
        }
    }
    public int getPreferredHeight() {
        if (flexibleHeight >= 0) {
            return flexibleHeight;
        } else if (flexibleHeight == USE_FIXED_HEADTAIL) {
            return (Display.getHeight() - fixedHeadHeight - fixedTailHeight);
        } else if (flexibleHeight == WRAP_CONTENT) {
            int totalHeight = 0;
            int numFields = getFieldCount();
            for (int i = 0; i < numFields; i++) {
                Field field = getField(i);
                totalHeight += field.getExtent().height+field.getMarginTop()+field.getMarginBottom();
            }
            return totalHeight;
        } else {
            // IF FILL_PARENT
            if (getManager() != null && getManager().getClass().equals(AbsoluteFieldManager.class))
                // handle for absolutefieldmanager parent
                return Display.getHeight();
            else
                return super.getPreferredHeight();
        }
    }
    protected void sublayout(int maxWidth, int maxHeight) {
        int totalWidth  = 0;
        int totalHeight = 0;
        if (flexibleWidth == WRAP_CONTENT || flexibleHeight == WRAP_CONTENT) {
            int numFields = getFieldCount();
            int availableWidth = maxWidth;
            int availableHeight = maxHeight;
            for (int i = 0; i < numFields; i++) {                 Field field = getField(i);                 layoutChild(field, maxWidth, availableHeight);                                 availableWidth = field.getExtent().width+field.getMarginLeft()+field.getMarginRight();                 availableHeight -= field.getExtent().height-field.getMarginTop()-field.getMarginBottom();                 if (availableWidth > totalWidth && availableWidth < maxWidth) totalWidth = availableWidth;
                totalHeight += field.getExtent().height+field.getMarginTop()+field.getMarginBottom();
            }
        }
        if (distributedHeight)
        // DistributedHeightVerticalFieldManager
        {
            super.sublayout(maxWidth, maxHeight);
            int nbFieldForCalculation = ((getFieldCount() != 0) ? getFieldCount() : 1);
            int intervalPosition = (Display.getHeight() / nbFieldForCalculation);
            for (int i = 0; i < getFieldCount(); i++) {
                layoutChild(getField(i), maxWidth, maxHeight);
                setPositionChild(getField(i), getPaddingLeft(), (intervalPosition * i));
            }
        }
        if (!distributedHeight) super.sublayout((flexibleWidth == FILL_PARENT ? maxWidth : (flexibleWidth == WRAP_CONTENT ? totalWidth : (flexibleWidth == USE_FIXED_HEADTAIL ? (Display.getWidth() - fixedHeadWidth - fixedTailWidth) : flexibleWidth))),
                        (flexibleHeight == FILL_PARENT ? maxHeight : (flexibleHeight == WRAP_CONTENT ? totalHeight : (flexibleHeight == USE_FIXED_HEADTAIL ? (Display.getHeight() - fixedHeadHeight - fixedTailHeight) : flexibleHeight))));
        setExtent((flexibleWidth == FILL_PARENT ? maxWidth : (flexibleWidth == WRAP_CONTENT ? totalWidth : (flexibleWidth == USE_FIXED_HEADTAIL ? (Display.getWidth() - fixedHeadWidth - fixedTailWidth) : flexibleWidth))),
                  distributedHeight ? Display.getHeight() : (flexibleHeight == FILL_PARENT ? maxHeight : (flexibleHeight == WRAP_CONTENT ? totalHeight : (flexibleHeight == USE_FIXED_HEADTAIL ? (Display.getHeight() - fixedHeadHeight - fixedTailHeight) : flexibleHeight))));
    }
    public void setBaseColor(int baseColor) {
        this.baseColor = baseColor;
        setBackground(BackgroundFactory.createSolidBackground(baseColor));
    }
    public void setHoverColor(int _color) {
        hoverColor = _color;
    }
    public void setBgImages(Bitmap img, Bitmap imgHover) {
        bgImage = img;
        bgHoverImage = imgHover;
        setBackground(BackgroundFactory.createBitmapBackground(bgImage));
    }
    protected void onFocus(int direction) {
        if (bgHoverImage != null) setBackground(BackgroundFactory.createBitmapBackground(bgHoverImage));
        else if (baseColor != NO_COLOR) setBackground(BackgroundFactory.createSolidBackground(hoverColor));
        else if (hoverColor != NO_COLOR) setBackground(BackgroundFactory.createSolidTransparentBackground(hoverColor, 192));
        super.onFocus(direction);
    }
    protected void onUnfocus() {
        if (bgImage != null) setBackground(BackgroundFactory.createBitmapBackground(bgImage));
        else if (baseColor != NO_COLOR) setBackground(BackgroundFactory.createSolidBackground(baseColor));
        else if (hoverColor != NO_COLOR) setBackground(BackgroundFactory.createSolidTransparentBackground(hoverColor, 0));
        super.onUnfocus();
    }
}

Adapun custom manager di atas masih dapat diperluas kemampuannya untuk berbagai keperluan. Selamat memakai dan mengembangkan bagi yang memerlukan, semoga bermanfaat :D

Baru saja nyoba Google+, layanan social-networking terbaru yang ditawarkan oleh gugel, sambil ngopi sore ;) coba ngemeng2x dikit … Jika dilihat layanan ini mirip dengan layanan2x social networking lain yang sudah lebih dulu mewabah.. sebut saja FB, twitter, myspace, dsb. Ya, google berusaha bangkit dari kegagalan sebelumnya (googlewave dan buzz) dgn kembali memberi isyarat perang layanan jejaring sosial. Beberapa fitur baru adalah fitur circle (lingkaran) dimana memungkinkan member untuk menempatkan temannya ke dalam grup sehingga memungkinkan member terkait untuk berbagi berbagai bentuk konten yang berbeda (share status, lokasi, media) ke grup tertentu (selective sharing). Kemudian fitur hangout yang merupakan fungsi video konferensi multi user (banyak pengguna) dimana mengizinkan teman kita untuk keluar masuk secara langsung dalam percakapan grup. Dan masih banyak fitur lain seperti huddle, sparks (penghubung member dengan pihak lain dalam jaringan yang memiliki minat yang sama) dan sebagainya.

Secara keseluruhan google+ menawarkan fitur2x yang lebih fleksibel dalam melakukan komunikasi pada jejaring sosial. Akan tetapi jika dikaitkan dengan layanan2x lain yang sudah ditawarkan oleh google hingga saat ini, terlihat gugel sepertinya berusaha untuk mengintegrasikan keseluruhan layanan2x berbasis internet mereka dimana hanya memakai 1 basisdata akun (maupun direktori) saja, menerapkan single-sign-on (SSO) serta layanan yang satu dengan yang lain dapat saling berinteraksi. Jika dilihat, hal ini lebih kurang sejalan dengan visi untuk mewujudkan cloud computing (or something called Software as a Services / SaaS … if I’m not wrong :(  ).

Dengan hanya memiliki 1 akun google saja, seorang end-user sudah memiliki akses ke banyak layanan internet dari gugel seperti GoogleSearch (search engine), Goggles, Google Bookmark (layanan sejenis Del.icio.us), GTalk (messenger & video call), GMail (email), YouTube (video), GoogleDocs (office / document sharing & collaboration), Google Books (eBooks sharing), Google Maps, Google Latitude, Google Analytics ….. hingga ke layanan terbarunya yaitu Google+. Ditambah dengan sistem operasi Google Android untuk smartphone dan tablet yang sudah mewabah menyaingi platform sebelumnya (iOS, Windows Mobile dan BB OS), akun google tersebut dapat dipakai sebagai primary account pada perangkat terkait untuk keperluan penyimpanan kontak (GoogleContact), akses android market, pembelian aplikasi di Android Market (lewat Google Checkout), dll. Belum lagi wacana2x terbaru yang hangat dibicarakan seperti Google Wallet dimana berdasarkan isu2x yang beredar dengan memanfaatkan teknologi NFC (Near Field Communication) yang sudah didukung sejak android 2.3.3 dan GoogleCheckout dapat mengubah perangkat android user menjadi dompet virtual (kartu pembayaran virtual) untuk berbagai keperluan seperti pembelian tiket, reservasi hotel dan sebagainya.

Antar layanan2x tersebut juga dapat saling berinteraksi. Misalnya anda dapat men-share dokumen pada GoogleDocs, video YouTube ke user yang lain lewat GMail, GTalk dan layanan komunikasi yang lain. Secara keseluruhan, user memandang layanan2x tersebut sebagai satu kesatuan dan lebih kurang tidak menyadari perbedaan layanan2x tersebut (transparan). Bahkan kebanyakan pengguna internet saat ini ketika memulai aktivitas browsing akan terlebih dahulu membuka GoogleSearch untuk mencari halaman situs terkait yang relevan dengan kata kunci pencarian (cara ini lebih efisien dibanding menghapal alamat2x situs dan memeriksa tiap situs untuk mencari hal2x yang dibutuhkan). GoogleSearch menjadikan seluruh situs2x web seakan2x satu kesatuan (transparan dalam hal relevansinya terhadap kata kunci pencarian) dimana pada dasarnya internet itu sendiri merupakan sistem terdistribusi yang memberikan transparansi kepada penggunanya (dimana pengguna kebanyakan tidak tahu dan bahkan tidak peduli bahwa seluruh layanan2x dalam jaringan internet itu dijalankan oleh banyak server).  Dan juga, jika situs yg dicari menggunakan bahasa asing yang tidak dimengerti oleh pengguna maka gugel menawarkan GoogleTranslate dalam mentranslasikan situs terkait ke dalam bahasa yang dimengerti oleh pengguna. Yeah, with all of this, just with single google account,  single-sign-on services and a client browser (such as google chrome on many platforms including android), all google services and product becomes integrated and transparent.

Bagi anda yang ingin meng-capture screenshoot dari layar smartphone/device android anda, maka Dalvik debug Monitor (DDM) dapat menjadi alternatif bagi anda (diluar aplikasi dari market) terutama bagi anda yang sudah menginstal Android SDK. DDM terdapat dalam Android SDK jadi anda perlu mengunduhnya dari link ini. Adapun beberapa langkah screencapture yaitu :

  1. Install SDK (jika dibutuhkan)
  2. Beralih ke Android Phone
  3. Tekan HomeButton kemudian pilih “Setting > Applications > Development” dan centang USB debugging
  4. Sambungkan  perangkat anda ke komputer menggunakan USB
  5. Jalankan ddms.bat (berada pada [Android SDK folder]\tools)
  6. Anda akan melihat daftar perangkat Android terhubung, kemudian pilihlah perangkat anda. Sebagai contoh dapat dilihat pada gambar di bawah ini :

    Dalvik Debug Monitor

    Dalvik Debug Monitor

  7. Kemudian pilih menu Device > ScreenCapture (atw tkn Ctrl+S), akan muncul window sebagai berikut :
DDM Screen Capture

DDM Screen Capture

  1. Anda tinggal mengklik tombol ‘Refresh’ untuk mendapatkan screenshoot dari layar android anda. Berikut capture dari smartphone saya …
SGS Screenshoot

SGS Screenshoot

DDM juga dapat digunakan untuk aktivitas-aktivitas terkait application debugging selama pengujian aplikasi pada perangkat android yang sebenarnya maupun emulator, seperti logging, profiling, resource usages information, cpu utilization dan sebagainya. Selamat mencoba :D