Location Based Service Code Igniter Library

Siang ini ada seorang rekan di Blackberry Developer Indonesia Group menanyakan tentang bagaimana membuat web service untuk reverse geocode. Reverse geocode adalah mendapatkan alamat ketika diketahui latitude dan longitude-nya. Layanan ini sebenarnya bukan hanya diberikan oleh Google, tapi juga Yahoo dan mungkin ada juga yang lain. Tetapi, berdasarkan perbandingan yang saya lakukan sekitar 2 tahun yang lalu, Google lebih akurat. Hanya saja, sayangnya kadang Google memang tidak mendapatkan alamat yang dicari, meskipun di saat lain sebenarnya alamat tersebut bisa didapat (artinya Google sebenarnya mengetahui alamat tersebut). Ini karena reverse geocoding adalah aktivitas yang berat. Oleh karenanya, disarankan Anda menyimpan hasil reverse geocoding ini (address) dengan lac dan cell id (bukan latitude dan longitude). Detail API-nya ada di https://developers.google.com/maps/documentation/geocoding/.

Letakkan file ini di dalam direktori /application/libraries di dalam Code Igniter. Berikutnya, gunakan di dalam controller.

Berikut ini Location Based Service class library untuk Code Igniter. Selamat menikmati.

<?php

/**
* Written by Amri Shodiq.
* Do not hesitate to copy and paste this code.
* It's not embarassing.
*/

if (!defined('BASEPATH'))
exit ('No direct script access allowed');
class Lbs {
public function getCompleteAddress($lac, $cid) {
$latLng = $this->getLatLong($lac, $cid);
if (is_array($latLng)) {
$data = $this->getAddress($latLng["lat"], $latLng["lng"]);

// $address = $data["meta"]["message"];
$address = $data["response"]["address"];
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
$response = array(
"lat"=>$latLng["lat"],
"lng"=>$latLng["lng"],
"address"=>$address,
"city"=>$data["response"]["city"]
);
return array(
"meta"=>$meta,
"response"=>$response
);
} else {
$meta = array(
"status"=>406,
"message"=>"Location is not known."
);
return array("meta"=>$meta);
}
}

public function reverseAddress($address) {
$use_curl = false;
if ($use_curl) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://maps.googleapis.com/maps/api/geocode/json?address=" . $address . "&sensor=true");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: application/binary"
));
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);

$data = json_decode($str, true);
if (isset($data["results"]) && is_array($data["results"])) {
$latLong = $data["results"][0]["geometry"]["location"];
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
return array("meta"=>$meta, "response"=>$latLong);
} else {
$meta = array(
"status"=>406,
"message"=>"Address is not known."
);
return array("meta"=>$meta);
}
} else {
$str = @file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?address=" . $address . "&sensor=true");
$data = json_decode($str, true);
if (isset($data["results"]) && is_array($data["results"])) {
$latLong = $data["results"][0]["geometry"]["location"];
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
return array("meta"=>$meta, "response"=>$latLong);
} else {
$meta = array(
"status"=>406,
"message"=>"Address is not known."
);
return array("meta"=>$meta);
}
}
}

private function getContent($url) {
$str = "";
$use_curl = false;
if ($use_curl) {
$ch = curl_init();
$useragent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1";
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: text/xml"
));
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);

echo "STR CURL: ".$str;
} else {
$str = file_get_contents($url, 0);
}

return $str;
}

public function getWeather($lac, $cid) {
// return $this->getContent("http://www.google.com/ig/api?weather=Depok,ID");

$latLng = $this->getLatLong($lac, $cid);
if (is_array($latLng)) {
$lat = $latLng["lat"];
$lng = $latLng["lng"];

$use_curl = false;
$url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" . $lat . "," . $lng . "&sensor=true";
$str = "";
if ($use_curl) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: application/binary"
));
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);
} else {
$str = @file_get_contents($url);
}

$data = json_decode($str, true);
if (isset($data["results"]) && is_array($data["results"])) {
$ac = $data["results"][0]["address_components"];
$len = count($ac);
$i = 0;
$city = "";
while ($i<$len) {
if (in_array("locality", $ac[$i]["types"])) $city = $ac[$i]["long_name"];
else if (in_array("country", $ac[$i]["types"])) $city .= ",".$ac[$i]["short_name"];
$i++;
}

// $city = $data["results"][0]["address_components"][3]["long_name"].",".$data["results"][0]["address_components"][5]["short_name"];

$url = "http://www.google.com/ig/api?weather=".str_replace("\"", "", $city);

// return $url;
// return $this->getContent($url);
return $this->getContent("http://www.google.com/ig/api?weather=Depok,ID");
} else {
return "false";
}


} else {
return "false";
}

// if (isset($data["results"]) && is_array($data["results"])) {
// $street = $data["results"][0]["formatted_address"];
// $meta = array(
// "status"=>200,
// "message"=>"Succeed."
// );
// return array("meta"=>$meta, "response"=>array("address"=>$street));
// } else {
// $meta = array(
// "status"=>406,
// "message"=>"Address is not known."
// );
// return array("meta", $meta);
// }
}

public function getAddress($lat, $lng) {
$use_curl = false;
if ($use_curl) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://maps.googleapis.com/maps/api/geocode/json?latlng=" . $lat . "," . $lng . "&sensor=true");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: application/binary"
));
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);

$data = json_decode($str, true);
if (isset($data["results"]) && is_array($data["results"])) {
$street = $data["results"][0]["formatted_address"];
$ac = $data["results"][0]["address_components"];
$len = count($ac);
$i = 0;
$city = "";
while ($i<$len) {
if (in_array("locality", $ac[$i]["types"])) $city = $ac[$i]["long_name"];
else if (in_array("country", $ac[$i]["types"])) $city .= ",".$ac[$i]["short_name"];
$i++;
}
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
return array("meta"=>$meta, "response"=>array("address"=>$street, "city"=>$city));
} else {
$meta = array(
"status"=>406,
"message"=>"Address is not known."
);
return array("meta", $meta);
}
} else {
$str = @file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?latlng=" . $lat . "," . $lng . "&sensor=true");
$data = json_decode($str, true);
if (isset($data["results"]) && is_array($data["results"])) {
$street = $data["results"][0]["formatted_address"];
$ac = $data["results"][0]["address_components"];
$len = count($ac);
$i = 0;
$city = "";
while ($i<$len) {
if (in_array("locality", $ac[$i]["types"])) $city = $ac[$i]["long_name"];
else if (in_array("country", $ac[$i]["types"])) $city .= ",".$ac[$i]["short_name"];
$i++;
}
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
return array("meta"=>$meta, "response"=>array("address"=>$street, "city"=>$city));
} else {
$meta = array(
"status"=>406,
"message"=>"Address is not known."
);
return array("meta"=>$meta);
}
}
}

public function getLatLong($lac, $cid) {

if (isset ($lac) && isset ($cid)) {
$CI =& get_instance();
$CI->load->database();

$data = "\x00\x0e" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00" .
"\x00\x00" .
"\x00\x00" .
"\x1b" .
"\x00\x00\x00\x00" .
"\x00\x00\x00\x00" .
"\x00\x00\x00\x00" .
"\x00\x00" .
"\x00\x00\x00\x00" .
"\x00\x00\x00\x00" .
"\x00\x00\x00\x00" .
"\x00\x00\x00\x00" .
"\xff\xff\xff\xff" .
"\x00\x00\x00\x00";

$is_umts_cell = ($cid > 65535);
if ($is_umts_cell) // GSM: 4 hex digits, UTMS: 6 hex digits
$data[0x1c] = 5;
else
$data[0x1c] = 3;

$hexlac = substr("00000000" . dechex($lac), -8);
$hexcid = substr("00000000" . dechex($cid), -8);

$data[0x1f] = pack("H*", substr($hexcid, 0, 2));
$data[0x20] = pack("H*", substr($hexcid, 2, 2));
$data[0x21] = pack("H*", substr($hexcid, 4, 2));
$data[0x22] = pack("H*", substr($hexcid, 6, 2));

$data[0x23] = pack("H*", substr($hexlac, 0, 2));
$data[0x24] = pack("H*", substr($hexlac, 2, 2));
$data[0x25] = pack("H*", substr($hexlac, 4, 2));
$data[0x26] = pack("H*", substr($hexlac, 6, 2));

/* I used file_get_contents() at my laptop webserver, but it seems like the PHP version
* at my hosting company is old and it is not supporting that.
* For the hosting company, here we're using cURL.
*/
$use_curl = false;
if ($use_curl) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.google.com/glm/mmap");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: application/binary"
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);
} else {
$context = array (
'http' => array (
'method' => 'POST',
'header' => "Content-type: application/binary\r\n" . "Content-Length: " . strlen($data
) . "\r\n",
'content' => $data
));
$xcontext = stream_context_create($context);
$str = file_get_contents("http://www.google.com/glm/mmap", FALSE, $xcontext);
}

$opcode1 = ((ord($str[0]) << 8)) | ord($str[1]);
$opcode2 = ord($str[2]);

if (($opcode1 != 0x0e) || ($opcode2 != 0x1b))
return -2;

$retcode = ((ord($str[3]) << 24) | (ord($str[4]) << 16) | (ord($str[5]) << 8) | (ord($str[6])));
if ($retcode != 0)
return -2;

$lat = ((ord($str[7]) << 24) | (ord($str[8]) << 16) | (ord($str[9]) << 8) | (ord($str[10]))) / 1000000;
$lon = ((ord($str[11]) << 24) | (ord($str[12]) << 16) | (ord($str[13]) << 8) | (ord($str[14]))) / 1000000;

// exit script if cannot geocode cell e.g. not on google's database
if ($lat == 0 and $lon == 0)
return -3;

$data = array(
'cellid' => $cid,
'lac' => $lac,
'lat' => $lat,
'lon' => $lon,
);

$CI->db->insert('celltower', $data);

return array (
"lat" => $lat,
"lng" => $lon
);
} else
return -4;
}

// Reff: http://code.google.com/intl/id-ID/apis/maps/documentation/directions/
// http://localhost/rest/index.php/api/location/direction/<origin>/<destination>
// e.g: http://localhost/rest/index.php/api/location/direction/Sawangan-Depok/Senayan-Jakarta
public function getDirection($origin, $destination, $travelMode) {
$use_curl = false;
if ($use_curl) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://maps.googleapis.com/maps/api/directions/json?origin=".$origin."&destination=".$destination."&mode=".$travelMode."&sensor=false");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-type: application/binary"
));
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
if (curl_errno($ch))
return -1;

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$str = substr($response, $header_size);

curl_close($ch);

$data = json_decode($str, true);
if (isset($data["status"]) && $data["status"] == "OK") {
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
$res = $data["routes"][0]["legs"][0];
$startAddress = $res["start_address"];
$endAddress = $res["end_address"];
$startLocation = $res["start_location"];
$endLocation = $res["end_location"];
$duration = $res["duration"];
$distance = $res["distance"];

$steps = $res["steps"];
$len = count($steps);
$i = 0;
$row = array();
while ($i<$len) {
$text = $steps[$i]["html_instructions"];
$start = $steps[$i]["start_location"];
$end = $steps[$i]["end_location"];
$dist = $steps[$i]["distance"];
$dur = $steps[$i]["duration"];
array_push($row, array(
"text"=>strip_tags($text),
"start"=>$start,
"end"=>$end,
"distance"=>$dist,
"duration"=>$dur
));
$i++;
}
return array("meta"=>$meta, "response"=>array(
"start_address"=>$startAddress,
"end_address"=>$endAddress,
"start_location"=>$startLocation,
"end_location"=>$endLocation,
"duration"=>$duration,
"distance"=>$distance,
"steps"=>$row
));
} else {
$meta = array(
"status"=>406,
"message"=>"Direction is not known."
);
return array("meta"=>$meta);
}
} else {
$str = @file_get_contents("http://maps.googleapis.com/maps/api/directions/json?origin=".$origin."&destination=".$destination."&mode=".$travelMode."&sensor=false");
$data = json_decode($str, true);
if (isset($data["status"]) && $data["status"] == "OK") {
$meta = array(
"status"=>200,
"message"=>"Succeed."
);
$res = $data["routes"][0]["legs"][0];
$startAddress = $res["start_address"];
$endAddress = $res["end_address"];
$startLocation = $res["start_location"];
$endLocation = $res["end_location"];
$duration = $res["duration"];
$distance = $res["distance"];

$steps = $res["steps"];
$len = count($steps);
$i = 0;
$row = array();
while ($i<$len) {
$text = $steps[$i]["html_instructions"];
$start = $steps[$i]["start_location"];
$end = $steps[$i]["end_location"];
$dist = $steps[$i]["distance"];
$dur = $steps[$i]["duration"];
array_push($row, array(
"text"=>strip_tags($text),
"start"=>$start,
"end"=>$end,
"distance"=>$dist,
"duration"=>$dur
));
$i++;
}
return array("meta"=>$meta, "response"=>array(
"start_address"=>$startAddress,
"end_address"=>$endAddress,
"start_location"=>$startLocation,
"end_location"=>$endLocation,
"duration"=>$duration,
"distance"=>$distance,
"steps"=>$row
));
} else {
$meta = array(
"status"=>406,
"message"=>"Direction is not known."
);
return array("meta"=>$meta);
}
}
}

// Local search could use Google's local search API (deprecated) or
// custom search https://code.google.com/intl/id-ID/apis/customsearch/v1/overview.html (100 query per day, shit)
}

/* End of file Lbs.php */
?>

view raw Lbs.php This Gist brought to you by GitHub.
<?php

/**
* Example to show how to use this Lbs library from Code Igniter controller.
* In this case I use another library to create REST web service, it's REST_Controller.php.
*/

require APPPATH.'/libraries/REST_Controller.php';
class Location extends REST_Controller {
public function __construct() {
parent :: __construct();
$this->load->library('lbs');
}

// http://localhost/rest/index.php/api/location/geocode/<LAC>/<cell-id>/
// e.g: http://localhost/rest/index.php/api/location/geocode/10001/4390/
function geocode_get($lac, $cid) {
$this->response($this->lbs->getCompleteAddress($lac, $cid), 200);
}

// http://localhost/rest/index.php/api/location/reverse/<address-space-replaced-with-dash>
// eg: http://localhost/rest/index.php/api/location/reverse/Kuningan-Jakarta
function reverse_get($address) {
$this->response($this->lbs->reverseAddress($address), 200);
}

// http://localhost/rest/index.php/api/location/address/<latitude>/<longitude>/
// eg: http://localhost/rest/index.php/api/location/address/-6.39437/106.782386/
function address_get($lat, $lng) {
$result = $this->lbs->getAddress($lat, $lng);
$this->response($result, 200);
}

// http://localhost/rest/index.php/api/location/latlong/<LAC>/<Cell-ID>/
// eg: http://localhost/rest/index.php/api/location/latlong/10001/4390/
function latlong_get($lac, $cid) {
$result = $this->lbs->getLatLong($lac, $cid);

$meta = array();
if ($result == -1) {
$meta = array(
"status"=>503,
"message"=>"Request failed. Try again later."
);
$this->response(array("meta"=>$meta), 200);
} else if ($result == -2) {
$meta = array(
"status"=>404,
"message"=>"Invalid LAC or Cell ID."
);
$this->response(array("meta"=>$meta), 200);
} else if ($result == -3) {
$meta = array(
"status"=>406,
"message"=>"Cannot determine location."
);
$this->response(array("meta"=>$meta), 200);
} else if ($result == -4) {
$meta = array(
"status"=>406,
"message"=>"Parameters is not complete."
);
$this->response(array("meta"=>$meta), 200);
} else {
$meta = array(
"status"=>200,
"message"=>"Location is found."
);
$response = $result;
$this->response(array("meta"=>$meta, "response"=>$response), 200);
}
}

function direction_get($origin, $destination, $travelMode = "driving") {
$result = $this->lbs->getDirection($origin, $destination, $travelMode);
$this->response($result);
}

function weather_get($lac, $cid) {
// $this->response($this->lbs->getWeather($lac, $cid), 200);
echo $this->lbs->getWeather($lac, $cid);
}
}
?>

view raw Location.php This Gist brought to you by GitHub.

April 2, 2012  2 Comments

Bagaimana Mengaktifkan Template PhoneGap-based Application di Xcode

Teman-teman developer, ada kalanya programmer aplikasi native ingin juga mencoba membuat aplikasi HTML 5. PhoneGap saat ini boleh dibilang adalah framework paling populer untuk mengubah aplikasi HTML + JavaScript menjadi native. Ketika ingin membuat aplikasi untuk iOS, saat ini satu-satunya cara yang saya tahu adalah menggunakan Xcode. By default, Xcode dibuat untuk membangun aplikasi native. Lalu bagaimana caranya agar kita bisa coding aplikasi PhoneGap di Xcode?

Anda bisa membaca tutorialnya dari: http://bit.ly/qWy5H0. Masalahnya, adalah jika Anda sebodoh saya, Anda bisa saja menjadi agak bingung karena setelah langkah ke tiga, Anda tetap belum melihat pilihan PhoneGap-based Application dari template iOS di Xcode. Dalam tutorial ini saya hanya akan menambahkan informasi yang terlewat dari tutorial di atas. Saya berasumsi bahwa Anda sudah memiliki Xcode.

continue reading »

February 5, 2012  Leave a comment

Membuat Tampilan Aplikasi Blackberry yang Super

Beberapa hari yang lalu saya sempat menulis sebuah aplikasi Blackberry yang cukup unik, bernama Mario Hari Ini. Aplikasi ini menampilkan sekitar 20 quote terakhir Pak Mario Teguh. Aplikasi ini sebenarnya cukup super. Di hari pertama, aplikasi ini di download sekitar 70 orang. Di hari kedua mencapai 500 orang. Beberapa hari setelahnya (selama 3 hari) kira-kira 150 orang. Hari ini aplikasi ini sudah saya cabut.

Salah satu yang menarik dari aplikasi ini, yang ingin saya share saat ini adalah tampilannya. Saya akan sharing bagaimana membuat user interface seperti aplikai tersebut. Screen dengan background kayu. Kemudian di atasnya, kita menempelkan kertas bertuliskan quote tertentu dengan sebuah selotip.

Yang Anda butuhkan adalah 3 file ini, silakan download ketiga gambar berikut:

Background

 

Kertas

Selotip

Berikutnya ini langkah-langkah yang saya lakukan.

  1. Buat project Blackberry, beri nama Lakban
  2. Masukkan ketiga gambar tadi ke dalam direkori res/img/
  3. Buat package (di dalam direktori src) dengan nama com.durianapp.kertasdanlakban
  4. Gunakan code snippet berikut
  5. Anda sudah mendapatkan 2 file, Lakban.java dan LakbanScreen.java

    package com.durianapp.kertasdanlakban;
    import net.rim.device.api.ui.UiApplication;


    public class Lakban extends UiApplication {
    public Lakban() {
    pushScreen(new LakbanScreen());
    }

    public static void main(String[] args) {
    new Lakban().enterEventDispatcher();
    }
    }

    view raw Lakban.java This Gist brought to you by GitHub.

    package com.durianapp.kertasdanlakban;

    import net.rim.device.api.system.Bitmap;
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.container.VerticalFieldManager;
    import net.rim.device.api.ui.decor.Background;
    import net.rim.device.api.ui.decor.BackgroundFactory;

    public class LakbanScreen extends MainScreen {

    public LakbanScreen() {
    super(NO_VERTICAL_SCROLL);

    add(getMain());
    }

    private VerticalFieldManager mainManager;
    private VerticalFieldManager getMain() {
    if (mainManager == null) {
    mainManager = new VerticalFieldManager(VERTICAL_SCROLL | USE_ALL_WIDTH |
    USE_ALL_HEIGHT);
    mainManager.setBackground(getScreenBackground());
    }
    return mainManager;
    }

    private Background screenBg;
    private Background getScreenBackground() {
    if (screenBg == null) {
    screenBg = BackgroundFactory.createBitmapBackground(
    Bitmap.getBitmapResource("img/app-bg.jpg"));
    }
    return screenBg;
    }
    }

  6. Anda sudah bisa menjalankan aplikasi tersebut dan mendapatkan tampilan latar belakang dengan background kayu
  7. Sempurnakan code Anda dengan code berikut ini

    package com.durianapp.kertasdanlakban;
    import net.rim.device.api.ui.UiApplication;


    public class Lakban extends UiApplication {
    public Lakban() {
    pushScreen(new LakbanScreen());
    }

    public static void main(String[] args) {
    new Lakban().enterEventDispatcher();
    }
    }

    view raw Lakban.java This Gist brought to you by GitHub.
    package com.durianapp.kertasdanlakban;

    import net.rim.device.api.system.Bitmap;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.Graphics;
    import net.rim.device.api.ui.XYEdges;
    import net.rim.device.api.ui.component.TextField;
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.container.VerticalFieldManager;
    import net.rim.device.api.ui.decor.Background;
    import net.rim.device.api.ui.decor.BackgroundFactory;
    import net.rim.device.api.ui.decor.Border;
    import net.rim.device.api.ui.decor.BorderFactory;

    /**
    * This is just a simple example of how to make a good user experince using
    * native Java for Blackberry devices. In this snippet, I use a wooden background
    * image, a small tape image and a piece of paper image to make an application
    * feels like we put notes on a piece of paper, then we attached them to a table
    * using small tape.
    * @author amri.shodiq
    *
    */
    public class LakbanScreen extends MainScreen {

    public LakbanScreen() {
    super(NO_VERTICAL_SCROLL);

    add(getMain());

    getMain().add(createQuoteField("Janganlah memboroskan hidup untuk " +
    "membuktikan bahwa komentar miring orang lain itu salah."));

    getMain().add(createQuoteField("Letakkan sandal Anda di bawah tanda berikut."));
    }

    /**
    * Create a main container for all fields on top of this screen.
    */
    private VerticalFieldManager mainManager;
    private VerticalFieldManager getMain() {
    if (mainManager == null) {
    mainManager = new VerticalFieldManager(VERTICAL_SCROLL | USE_ALL_WIDTH |
    USE_ALL_HEIGHT);
    mainManager.setBackground(getScreenBackground());
    }
    return mainManager;
    }

    /**
    * Make a background with wooden texture
    */
    private Background screenBg;
    private Background getScreenBackground() {
    if (screenBg == null) {
    screenBg = BackgroundFactory.createBitmapBackground(
    Bitmap.getBitmapResource("img/app-bg.jpg"));
    }
    return screenBg;
    }

    /**
    * Note a quote on a piece of paper with a tape on top of it.
    * @param quote
    * @return
    */
    private Field createQuoteField(String quote) {
    VerticalFieldManager v2 = new VerticalFieldManager() {
    public void paint(Graphics g) {
    super.paint(g);
    // this is where we put the tape
    g.drawBitmap(
    (getWidth() - getTape().getWidth())/2,
    4, getTape().getWidth(), getTape().getHeight(), getTape(),
    0, 0);
    }
    };

    VerticalFieldManager v = new VerticalFieldManager(VerticalFieldManager.USE_ALL_WIDTH);
    v.setBorder(getQuoteBorder());
    // make a small margin to make the paper looks smaller than the table
    v.setMargin(8, 8, 8, 8);
    // make a small padding to make a little distance between the letter and
    // paper side.
    v.setPadding(8, 8, 8, 8);

    // We use TextField to make this screen scrollable on a non touch device
    TextField text = new TextField(TextField.NO_EDIT_MODE_INPUT|TextField.READONLY) {
    // override this method to hide blue pointer
    public void drawFocus(Graphics g, boolean on) {
    }
    };
    text.setText(quote);
    v.add(text);

    v2.add(v);

    return v2;
    }

    /**
    * Simply a bitmap instance of an image of tape.
    */
    private Bitmap tape;
    private Bitmap getTape() {
    if (tape == null) {
    tape = Bitmap.getBitmapResource("img/tape.png");
    }
    return tape;
    }

    /**
    * Border which represent a used paper.
    */
    private Border quoteBorder;
    private Border getQuoteBorder() {
    if (quoteBorder == null) {
    quoteBorder = BorderFactory.createBitmapBorder(
    new XYEdges(26, 16, 12, 16),
    Bitmap.getBitmapResource("img/note.png"));
    }
    return quoteBorder;
    }
    }

  8. Silakan jalankan aplikasi tersebut
  9. Anda bisa coba-coba dengan gambar-gambar lain dan memodifikasi code tersebut sesuai kebutuhan
Lumayan bukan?

 

November 17, 2011  3 Comments

Bagaimana Menggunakan Touch Charts?

Touch Chart adalah salah satu produk Sencha. Touch Charts, meskipun terpisah dengan Sencha Touch, tetapi framework ini sangat berhubungan dengan Sencha Touch. Touch Chart adalah framework yang memudahkan kita membuat Chart (atau mudahnya diagram) yang berjalan baik di perangkat mobile (baik tablet maupun ponsel) yang mendukung HTML5. Saat ini saya sudah mencoba coding Touch Charts, sudah saya test dengan ponsel saya (low end Android, Samsung Galaxy Young) dan hasilnya sangat memuaskan. Grafik tampil dengan sangat baik dan animasi mulus.

Anda bisa mencoba aplikasi sederhana saya, hanya untuk menunjukkan bagaimana framework ini bekerja. Silakan kunjungi

http://webapps.durianapp.com/touchchartexample/

atau

http://durianapp.com/webapps/touchchartexample/.

Jika Anda menggunakan desktop, saat ini sepertinya baru Safari dan Google Chrome yang bisa menampilkan contoh ini dengan baik (terkait dengan dukungan HTML5). Anda bisa menggunakan browser handphone Android atau iPhone untuk mencoba contoh ini.

Di bawah saya lampirkan source code yang saya gunakan. Hanya 2 file: index.html dan chart.js. Sangat sederhana.

continue reading »

November 16, 2011  2 Comments

« older posts
Mobile and Web Analytics