Friday, July 30, 2010

Video Klip Keong Racun Akan Dibuat 3 Agustus

Charly ST12 belum mau bicara banyak tentang proyek baru Lagu Keong Racun. Tapi dalam waktu dekat, tepatnya 3 Agustus, video klip Keong Racun yang dinyanyikan Putry Penelope akan mulai digarap.

“Pokoknya Insya Allah tanggal 3 Agustus nanti, kita baru akan membuat video klip dengan lagu dan aransemen baru,” ujar Charly yang ditemui di Kawasan Sentul, Kamis (29/7/2010).

Lirik :Lagu Keong Racun Dia mengakui player musik langsung digarap olehnya. Termasuk juga pemilihan penyanyi yang baru, yakni duo Putry Penelope.

“Karena kita memang sudah kenal dan karakternya cocok,” kata dia.

Charly mengatakan dia belum mau bicara banyak, apalagi karena semua masih dalam proses pembuatan. Begitu juga video klipnya yang belum dibuat.

“Mudah-mudahan bermanfaat buat orang banyak. Saya cuma mau berkreasi dalam bermusik,” tegasnya.

Sebelumnya vokalis ST12 ini menegaskan tidak punya urusan menanggapi kekecewaan penyanyi asli Keong Racun, Lissa. Dia mengatakan yang terpenting dia sudah mempunyai izin resmi untuk mengaransemen ulang lagu yang awalnya bergenre dangdut koplo ini.

Lagu Keong Racun sendiri menjadi perbincangan hangat masyarakat dunia maya, setelah duo Shinta dan Jojo menyanyikan lagu tersebut secara lypsinc dan diunggah ke youtube. Tingkah keduanya yang menggelitik, membuat Shinta dan Jojo menjadi trending topik di microblogging Twitter pada 27 Juli 2010 lalu.

Tuesday, July 27, 2010

Licensing Service Technology Highlights

We’ve just announced the introduction of a licensing server for Android Market. This should address one of the concerns we’ve heard repeatedly from the Android developer community.

The impact and intent, as outlined in the announcement, are straightforward. If you want to enable your app to use the licensing server, there’s no substitute for reading the authoritative documentation: Licensing Your Applications. Here are some technical highlights.


  • This capability has been in the Android Market client app since 1.5, so you don’t have to be running the latest Android flavor to use it.


  • It’s secure, based on a public/private key pair. Your requests to the server are signed with the public key and the responses from the server with the private key. There’s one key pair per publisher account.


  • Your app doesn’t talk directly to the licensing server; it IPCs to the Android Market client, which in turn takes care of talking to the server.


  • There’s a substantial tool-set that will ship with the SDK, the License Verification Library (LVL). It provides straightforward entry points for querying the server and handling results. Also, it includes modules that you can use to implement certain licensing policies that we expect to be popular.



Media_http2bpblogspot_ofgrr


  • LVL is provided in source form as an Android Library project. It also comes with a testing framework.


  • There’s a Web UI on the publisher-facing part of the Market’s Web site for key management; it includes setup for production and testing.


  • Obviously, you can’t call out to the server when the device is off-network. In this situation you have to decide what to do; one option is to cache licensing status, and LVL includes prebuilt modules to support that.


We think this is a major improvement over the copy-protection option we’ve offered up to this point, and look forward to feedback from developers.

Licensing Service For Android Applications

[This post is by Eric Chu, Android Developer Ecosystem. — Tim Bray]

In my conversations with Android developers, I often hear that you’d like better protection against unauthorized use of your applications. So today, I’m pleased to announce the release of a licensing service for applications in Android Market.

This simple and free service provides a secure mechanism to manage access to all Android Market paid applications targeting Android 1.5 or higher. At run time, with the inclusion of a set of libraries provided by us, your application can query the Android Market licensing server to determine the license status of your users. It returns information on whether your users are authorized to use the app based on stored sales records.


Media_http3bpblogspot_udebi

This licensing service operating real time over the network provides more flexibility in choosing license-enforcement strategies, and a more secure approach in protecting your applications from unauthorized use, than copy protection.

The licensing service is available now; our plan is for it to replace the current Android Market copy-protection mechanism over the next few months. I encourage you to check out the Licensing Your Applications section of our Developer Guide and the Android Market Help Center to learn how you can take advantage of this new service immediately.

Monday, July 26, 2010

Kedua Korban Alami Depresi & Takut Dikeluarkan dari Sekolah

Video Delta Mas 02, Pasangan Anak Baru Gede (ABG) yang dipaksa beradegan mesum di sebuah lahan kosong di Cikarang, Bekasi mengalami depresi. Tidak hanya itu, korban ketakutan akan dikeluarkan dari sekolah.

“Mereka ketakutan akan dikeluarkan dari sekolah. Mereka adalah korban,” kata Kapolres Bekasi Kabupaten AKBP Setija saat dihubungi wartawan, Jumat (24/7/2010) malam.

Kedua korban yang diduga pelajar di sebuah SMA sudah dikantongi identitasnya. Namun, polisi belum melakukan pemeriksaan terhadap keduanya.

“Korban belum kita mintai keterangan, karena mereka takut,” katanya.

Pada Kamis (23/7) malam, polisi sudah mencoba meminta keterangan dari korban anak laki-laki. Namun, korban tidak berani mengungkapkan peristiwa yang dialaminya itu.

Lebih jauh Setija mengungkapkan, polisi telah melakukan langkah-langkah persuasif dalam melakukan penyelidikan terhadap korban. “Kita juga yakinkan kepada orangtua korban kalau mereka menjadi korban,” ungkapnya.

Sebelumnya diberitakan, beredar rekaman video pasangan ABG yang dipaksa membuka baju seragam sekolah, berlari dalam keadaan setengah telanjang hingga berbuat mesum di lahan kosong di Cikarang, Bekasi.

Video tersebut terdiri dari dua bagian. Pada bagian pertama video yang berdurasi 3 menit 2 detik, pasangan ABG itu disuruh membuka baju seragamnya. Pelaku kemudian menyuruh keduanya untuk berlari di lahan terbuka dalam keadaan setengah telanjang.

Pada bagian kedua, video yang berdurasi 2 menit 19 detik, pasangan ABG dipaksa untuk saling berpelukan dan mempraktekan adegan mesum. Sepanjang rekaman, keduanya tampak tertekan dan meminta agar adegan tersebut tidak direkam.

Tidak hanya itu, korban ABG perempuan menangis saat dipaksa sekelompok pemuda tersebut. Video itu ditengarai dibuat pada Februari 2010 silam. Hingga kini, pelaku belum ditangkap.

Saturday, July 24, 2010

Adjustment to Market Legals

Please note that we have updated the Android Market Developer Distribution Agreement (DDA). This is in preparation for some work we’re doing on introducing new payment options, which we think developers will like.

In the spirit of transparency, we wanted to highlight the changes:


  • In Section 13.1, “authorized carriers” have been added as an indemnified party.


  • Section 13.2 is new in its entirety, covering indemnity for payment processors for claims related to tax accrual.


These new terms apply immediately to anyone joining Android Market as a new publisher. Existing publishers have been notified of this change via email; they have up to 30 days to sign into the Android Market developer console to accept the new terms.

Friday, July 23, 2010

Bicycle

My friend Jeffery got a bike for his sixth birthday. Soon afterward, he learned how to ride without his training wheels and became the coolest kid at school. Sometimes I went to Jeffery's house when my mom was at work. Jeffery never wanted to draw pictures with me or play tag.  Instead, he would ride his bike really fast up and down his driveway and make motorcycle noises while I stood in front of his house and watched him.

One day, I got tired of just sitting and watching Jeffery be cool. I wanted to be cool too. I wanted Jeffery to teach me how to ride his bike. It looked easy enough.




Media_httpimg708image_tqxxx



He showed me how to get up on the seat and how to pedal. He pushed the bike while I sat on it. It was almost like I was riding it by myself! I began to feel fairly confident that I was going to be the best bike-rider in the world.




Media_httpimg684image_scguf



We teetered slowly up and down the driveway a couple times. But on our third time out, Jeffery suddenly veered us off to the left and said "Hey! I wonder if you can make it down this hill!!" Then he gave me a shove and sent me rolling down a steep, grassy incline toward an oak tree.


Media_httpimg340image_epnjv


Media_http3bpblogspot_ymnrh



I careened down the hill at chaotic speed and slammed into the tree, at which point I was launched off Jeffery's bike straight into a fence post.




Media_httpimg534image_qgbcn




As I was lying there at the bottom of the hill, bleeding from my face, I decided that bikes were fucking dangerous and should be avoided at any cost.  I don't know how or why my five-year-old mind came to the conclusion that the bike was at fault for my injuries, but on that day, I became convinced that bicycles were deadly satan-machines that would eventually destroy me.

My sixth birthday was a few months later, and when it finally came, I could barely contain my excitement. I had asked for roller-skates or a pony and I was pretty confident about my chances of at least getting roller-skates. As soon as I woke up, I raced into the kitchen where my parents were already waiting.




Media_httpimg710image_znjqj




When my mom told me to look outside for my present, it gave me reason to believe that I would be getting a pony, which was at least nine times better than roller-skates. I was so ecstatic about the possibility of getting a real, live, ride-able animal that I temporarily forgot where the door was and began pinging around the house like a gnat on meth.




Media_httpimg217image_lwlcq




Once I was able to control myself enough to find my way out of the house, I ran to the backyard fully expecting to find a tiny horse standing there in the grass.  Imagine my surprise when I rounded the corner and was instead confronted by a bicycle.  In a matter of seconds, I went from overjoyed birthday-mode to feeling like my parents were trying to kill me.




Media_httpimg691image_blycc



Media_httpimg691image_xgfud



I ran screaming and crying from my birthday present. It was not the reaction my parents were expecting.




Media_httpimg406image_rlspp



Media_httpimg718image_ebejh



My parents had apparently underestimated how traumatized I was by my first biking experience. They immediately went into damage-control mode. In a tone of voice that was so enthusiastic it was almost condescending, my dad said "How about I teach you how to ride your new bike, Allie?!" I buried my face in my mom's skirt and cried harder. "Well, do you want to go for a ride on my bike?" My dad continued. "You can sit on the bar while I pedal! It'll be fun!"

I don't know how he finally convinced me, but the next thing I can remember is sitting on the cross bar of my dad's bike, clinging to him in unadulterated terror.




Media_httpimg11images_lhznb




My dad pedaled slowly and safely around the block, doing his best to reassure me that bikes are fun and they are not dangerous satan beasts that want all of my blood. Five minutes had passed and I still hadn't been brutally murdered by the bike, so I began to relax a little. My mom stood in our driveway and watched with adoration. For a little while, it was the perfect family moment.




Media_httpimg202image_xtlqj




The next few seconds were a real turning point in my life. My dad and I were failure in motion, drifting slowly toward our fate like a miniature Hindenburg.  In my memory, I hear his voice in warped slow-motion saying "Haaaaaa... haaaaaa... haaaaaaa... thiiiiissss iiiisssssss fffuuuuuuuuuuuunnnn! Hoooorrrraaaaaaaayyyyyyy! Leeeeeeet'ssss goooooooo riiiide oooonnn thhheeee grrrraaaaaaaaasssss!"





Media_httpimg59images_nmrbt




In what I imagine was an attempt to enrich my biking experience with different riding surfaces, my dad veered off onto a little strip of grass.

I don't know how we hit the rock and why we were both catapulted over the handlebars when it happened; we certainly weren't traveling at an outrageous speed. What I do know is when my dad's front tire hit the rock, my hard-earned trust shriveled up like an injured banana slug.





Media_httpimg263image_togdt



Media_httpimg203image_qjqyx



All 220 pounds of my dad came down on top of me elbow-first. I struggled free from underneath his crumpled body and ran to my mom.  My dad just lay there face-down in the road, like a Hefty bag full of shame.



Media_httpimg340image_zyqsc


Media_httpimg690image_gndwv



My fear of bicycles stuck with me for over a decade. While all my friends were riding their awesome bikes around town making badass motorcycle noises and popping mad wheelies, I was the weird kid running behind them, trying but failing to maintain some semblance of dignity.





Media_httpimg718image_pimww


Wednesday, July 21, 2010

Membagi Resep Keluarga di Jamuan Makan Rahasia

Resep Kue Basah Anda membayangkan datang ke pesta jamuan makan, tanpa tahu menu yang akan dimakan? Atau siapa saja yang akan datang? Bahkan lokasi pun baru akan Anda ketahui paling cepat dua hari sebelum jamuan.

Resep Kue Kering Tak jarang Anda harus bersiap dengan masakan yang belum pernah dirasakan, dengar namanya atau bahkan sama sekali tak terbayangkan. Mungkin saja Anda langsung menyukainya atau justru kaget dengan keunikan rasanya. Mari kita intip serunya jamuan makan rahasia yang berlangsung akhir pekan lalu di Aula Golden Leaf Residence, Bintaro, Jakarta.

Bangku-bangku layaknya pesta dijajarkan rapih di aula terbuka itu. Di hadapannya meja prasmanan berisikan 5 menu utama, satu makanan pembuka, dua makanan penutup, dan satu jenis makanan kecil tertutup rapi.

Rasa penasaran memang jadi daya tarik utama Underground Secret Dining. Tak heran jika tamu yang datang di siang hari itu langsung melirik ke meja prasmanan. Hampir semua tidak tahan langsung membuka tutup wadah makanan dan mengintip menu yang disediakan.

"Sayur Iklik, apa itu? kok bening begini ya? Wah pepes peda, sudah lama saya tidak lihat ini. Kalau yang ini, semur jengkol, belum pernah saya makan, keren, kok kering ya?" celoteh seorang perempuan 30 tahunan yang datang dengan suaminya sembari membuka penutup makanan satu-persatu.

Sang suami tak kalah bersemangatnya memperhatikan tumpukan mangkuk berisi kue dadar gulung dan daging kambing. Sementara di sebelahnya ada panci pemanas berisikan kuah yang mirip gulai. Wajahnya berkerut, manandakan ia belum pernah melihat masakan seperti itu.

Pria di belakangnya justru asyik memotret makanan penutup kue talam sekaut dan es cincau hijau yang belum pernah ia dengar dengan kamera digital canggih merk terkenal.

Underground Secret Dining memang hanya menyajikan masakan tradisional yang hampir dilupakan serta masakan khas rumahan yang bisa dipastikan tak ada di restoran manapun.

Monday, July 19, 2010

Multithreading For Performance

[This post is by Gilles Debunne, an engineer in the Android group who loves to get multitasked. — Tim Bray]


Media_http4bpblogspot_tfeig

A good practice in creating responsive applications is to make sure your main UI thread does the minimum amount of work. Any potentially long task that may hang your application should be handled in a different thread. Typical examples of such tasks are network operations, which involve unpredictable delays. Users will tolerate some pauses, especially if you provide feedback that something is in progress, but a frozen application gives them no clue.

In this article, we will create a simple image downloader that illustrates this pattern. We will populate a ListView with thumbnail images downloaded from the internet. Creating an asynchronous task that downloads in the background will keep our application fast.

An Image downloader

Downloading an image from the web is fairly simple, using the HTTP-related classes provided by the framework. Here is a possible implementation:


static Bitmap downloadBitmap(String url) {
final AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
final HttpGet getRequest = new HttpGet(url);

try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url);
return null;
}

final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// Could provide a more explicit error message for IOException or IllegalStateException
getRequest.abort();
Log.w("ImageDownloader", "Error while retrieving bitmap from " + url, e.toString());
} finally {
if (client != null) {
client.close();
}
}
return null;
}


A client and an HTTP request are created. If the request succeeds, the response entity stream containing the image is decoded to create the resulting Bitmap. Your applications' manifest must ask for the INTERNET to make this possible.

Note: a bug in the previous versions of BitmapFactory.decodeStream may prevent this code from working over a slow connection. Decode a new FlushedInputStream(inputStream) instead to fix the problem. Here is the implementation of this helper class:


static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}

@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int byte = read();
if (byte < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}


This ensures that skip() actually skips the provided number of bytes, unless we reach the end of file.

If you were to directly use this method in your ListAdapter's getView method, the resulting scrolling would be unpleasantly jaggy. Each display of a new view has to wait for an image download, which prevents smooth scrolling.

Indeed, this is such a bad idea that the AndroidHttpClient does not allow itself to be started from the main thread. The above code will display "This thread forbids HTTP requests" error messages instead. Use the DefaultHttpClient instead if you really want to shoot yourself in the foot.

Introducing asynchronous tasks

The AsyncTask class provides one of the simplest ways to fire off a new task from the UI thread. Let's create an ImageDownloader class which will be in charge of creating these tasks. It will provide a download method which will assign an image downloaded from its URL to an ImageView:


public class ImageDownloader {

public void download(String url, ImageView imageView) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
task.execute(url);
}
}

/* class BitmapDownloaderTask, see below */
}


The BitmapDownloaderTask is the AsyncTask which will actually download the image. It is started using execute, which returns immediately hence making this method really fast which is the whole purpose since it will be called from the UI thread. Here is the implementation of this class:


class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;

public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}

@Override
// Actual download method, run in the task thread
protected Bitmap doInBackground(String... params) {
// params comes from the execute() call: params[0] is the url.
return downloadBitmap(params[0]);
}

@Override
// Once the image is downloaded, associates it to the imageView
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}

if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}


The doInBackground method is the one which is actually run in its own process by the task. It simply uses the downloadBitmap method we implemented at the beginning of this article.

onPostExecute is run in the calling UI thread when the task is finished. It takes the resulting Bitmap as a parameter, which is simply associated with the imageView that was provided to download and was stored in the BitmapDownloaderTask. Note that this ImageView is stored as a WeakReference, so that a download in progress does not prevent a killed activity's ImageView from being garbage collected. This explains why we have to check that both the weak reference and the imageView are not null (i.e. were not collected) before using them in onPostExecute.

This simplified example illustrates the use on an AsyncTask, and if you try it, you'll see that these few lines of code actually dramatically improved the performance of the ListView which now scrolls smoothly. Read Painless threading for more details on AsyncTasks.

However, a ListView-specific behavior reveals a problem with our current implementation. Indeed, for memory efficiency reasons, ListView recycles the views that are displayed when the user scrolls. If one flings the list, a given ImageView object will be used many times. Each time it is displayed the ImageView correctly triggers an image download task, which will eventually change its image. So where is the problem? As with most parallel applications, the key issue is in the ordering. In our case, there's no guarantee that the download tasks will finish in the order in which they were started. The result is that the image finally displayed in the list may come from a previous item, which simply happened to have taken longer to download. This is not an issue if the images you download are bound once and for all to given ImageViews, but let's fix it for the common case where they are used in a list.

Handling concurrency

To solve this issue, we should remember the order of the downloads, so that the last started one is the one that will effectively be displayed. It is indeed sufficient for each ImageView to remember its last download. We will add this extra information in the ImageView using a dedicated Drawable subclass, which will be temporarily bind to the ImageView while the download is in progress. Here is the code of our DownloadedDrawable class:


static class DownloadedDrawable extends ColorDrawable {
private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
super(Color.BLACK);
bitmapDownloaderTaskReference =
new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
}

public BitmapDownloaderTask getBitmapDownloaderTask() {
return bitmapDownloaderTaskReference.get();
}
}


This implementation is backed by a ColorDrawable, which will result in the ImageView displaying a black background while its download is in progress. One could use a “download in progress” image instead, which would provide feedback to the user. Once again, note the use of a WeakReference to limit object dependencies.

Let's change our code to take this new class into account. First, the download method will now create an instance of this class and associate it with the imageView:


public void download(String url, ImageView imageView) {
if (cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url, cookie);
}
}


The cancelPotentialDownload method will stop the possible download in progress on this imageView since a new one is about to start. Note that this is not sufficient to guarantee that the newest download is always displayed, since the task may be finished, waiting in its onPostExecute method, which may still may be executed after the one of this new download.


private static boolean cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

if (bitmapDownloaderTask != null) {
String bitmapUrl = bitmapDownloaderTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
bitmapDownloaderTask.cancel(true);
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}


cancelPotentialDownload uses the cancel method of the AsyncTask class to stop the download in progress. It returns true most of the time, so that the download can be started in download. The only reason we don't want this to happen is when a download is already in progress on the same URL in which case we let it continue. Note that with this implementation, if an ImageView is garbage collected, its associated download is not stopped. A RecyclerListener might be used for that.

This method uses a helper getBitmapDownloaderTask function, which is pretty straigthforward:


private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}


Finally, onPostExecute has to be modified so that it will bind the Bitmap only if this ImageView is still associated with this download process:


if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
// Change bitmap only if this process is still associated with it
if (this == bitmapDownloaderTask) {
imageView.setImageBitmap(bitmap);
}
}


With these modifications, our ImageDownloader class provides the basic services we expect from it. Feel free to use it or the asynchronous pattern it illustrates in your applications to ensure their responsiveness.

Demo

The source code of this article is available online on Google Code. You can switch between and compare the three different implementations that are described in this article (no asynchronous task, no bitmap to task association and the final correct version). Note that the cache size has been limited to 10 images to better demonstrate the issues.


Media_http1bpblogspot_exchu

Future work

This code was simplified to focus on its parallel aspects and many useful features are missing from our implementation. The ImageDownloader class would first clearly benefit from a cache, especially if it is used in conjuction with a ListView, which will probably display the same image many times as the user scrolls back and forth. This can easily be implemented using a Least Recently Used cache backed by a LinkedHashMap of URL to Bitmap SoftReferences. More involved cache mechanism could also rely on a local disk storage of the image. Thumbnails creation and image resizing could also be added if needed.

Download errors and time-outs are correctly handled by our implementation, which will return a null Bitmap in these case. One may want to display an error image instead.

Our HTTP request is pretty simple. One may want to add parameters or cookies to the request as required by certain web sites.

The AsyncTask class used in this article is a really convenient and easy way to defer some work from the UI thread. You may want to use the Handler class to have a finer control on what you do, such as controlling the total number of download threads which are running in parallel in this case.

Saturday, July 17, 2010

RPM Ketiban Sial karena Video Porno Luna Maya

Lagu Luna Maya Label RPM yang mengedarkan single terbaru Luna Maya mengaku ketiban sial, karena video porno milik presenter Dahsyat tersebut keluar 2-3 bulan setelah teken kontrak.

“Kita juga sebenarnya tidak mengambil momentum ini. Kita hanya menyepakati komitmen awal yang sudah kita lakukan bersama Luna,” kata Vice President Commerce RPM Isra Rudin saat dihubungi wartawan melalui telepon, Rabu (14/7/2010).

Malah lanjutnya, justru mereka ketiban sial dengan tersebarnya video porno tersebut. “Mungkin malah kalau bisa dibilang, kita kejatuhan sial dengan masalah Luna. Karena kita tidak memprediksi masalah itu Luna itu,” ujarnya.

Isra mengungkapkan, kontrak antara RPM dengan Luna sudah ditandatangani sejak 2-3 bulan, sebelum video porno tersebut beredar. Karenanya, rilis single Tak Bisa Bersamamu dilakukan untuk memenuhi kontrak perjanjian tersebut. “Ini kembali komitmen awal kita dengan Luna,” jelasnya.

Meskipun merasa dirugikan, RPM melihat lagu Luna Maya ini memiliki peluang yang cukup bagus. “Kami pasti merasa dirugikan. Tapi kami lihat lagu ini cukup bagus dan kita ingin menjalankan kontrak yang sudah diteken oleh Luna,” pungkasnya. (uky)

Friday, July 16, 2010

Market Statistics Adjustments

If you look closely today, you'll notice that some per-app Android Market statistics have lower values; not big differences, but noticeable in a few cases. We discovered last week that, starting in early June, certain events had been double-counted: installs, uninstalls, impressions, and so on. The most obvious symptom was (for paid apps) a discrepancy between the number of installs and the number of reported sales through Checkout.

The underlying problem has been corrected and following data repair, the reported statistics should now be accurate. Our apologies for the glitch.

Android Market Welcomes Korea!

As of today, Android Market is open for business to application buyers in the Republic of Korea. We hope that this will make the outstanding Android devices now available in that nation even more useful and fun. We welcome the people of Korea, acknowledged everywhere as one of the world's most-wired societies, to the world of Android.

Thursday, July 15, 2010

Panti Pijat Diminta Buka Malam Saja

Panti pijat di wilayah Kota Batu diminta hanya buka saat malam hari saja selama bulan ramadan.

Kepala Bagian Kesra Pemkot Batu, Agus Salim mengatakan, saat ini dilakukan rapat koordinasi dengan berbagai pihak untuk selanjutnya membuat rumusan surat keputusan (SK) walikota yang mengatur jam buka panti pijat.

”Biasanya seminggu sebelum Ramadhan SK walikota yang mengatur ketertiban masyarakat itu diterbitkan,” ujar Agus, Selasa (13/7) setelah rapat koordinasi di Pemkot Batu.

Ditambahkankannya, pada hari biasa panti pijat buka sejak pagi hingga malam. Namun saat Ramadan, jam buka biasanya diatur setelah ibadah tarawih hingga pukul 02. 00 dini hari. Saat ini masih dikoordinasikan oleh berbagai instansi terkait di Kota Batu tentang teknisnya. Jumlah panti pijat di Kota Batu 14 tempat.

Koordinasi ini rencananya melibatkan Satpol PP, pihak kepolisian, Majelis Ulama Indonesia (MUI) Kota Batu. Selain membahas jam buka dan tutup panti pijat, Pemkot juga mengatur tentang penjualan makanan dan minuman saat siang hari. Juga larangan untuk bermain petasan yang menimbulkan bunyi ledakan.

“Ini semua untuk ketertiban masyarakat dan toleransi ibadah, apalagi memasuki bulan suci Ramadan. Segera koordinasi lanjutan dengan berbagai pihak dilakukan untuk kemudian menerbitkan SK walikota,” tutur Agus Salim.

Untuk penjual makanan dan minuman yang diminta tutup siang hari itu, terutama yang berjualan di tempat terbuka. Sedangkan rumah makan yang berjualan di ruangan dengan tertutup tidak ada masalah.

Related Post :

Monday, July 12, 2010

How to have your (Cup)cake and eat it too

[This post is by Adam Powell, his second touchy-feely outing in just a few weeks. I asked him to send me a better picture than we ran last time, and got this in response. Photo by our own Romain Guy. — Tim Bray]


Media_http3bpblogspot_kduhl

Android developers concerned with targeting every last device with their apps are no doubt familiar with this chart:


Media_http3bpblogspot_rhjqz

On July 1, 2010 this was the breakdown of active devices running different versions of the Android platform. With all of the new platform features added to the Android SDK in each version, this chart has many developers shouting the F-word when they are forced to choose between integrating newer platform features and providing their app to the widest possible audience.

Savvy Android developers already know that these two options aren’t really mutually exclusive, but that straddling between them can be painful. In this post I’m going to show you that it doesn’t have to be that way.

Several weeks ago we took a look at how to handle multitouch on Android 2.0 (Eclair) and above, and by the end we had a simple demo app. That app uses features exclusive to Android 2.2 (Froyo) which as of this writing hasn’t had a chance to reach many devices yet. In this post we’re going to refactor that demo to run on devices all the way back to Android 1.5 (Cupcake). If you’d like to follow along, start off by grabbing the code in the trunk of the android-touchexample project on Google Code.

The problem manifests

The uses-sdk tag in your AndroidManifest.xml can specify both a minSdkVersion and a targetSdkVersion. You can use this to declare that while your app is prepared to run on an older version of the platform, it knows about newer versions. Your app can now build against newer SDKs. However, if your code accesses newer platform functionality directly you will probably see something like this in the system log of devices running an older version of Android:


E/dalvikvm(  792): Could not find method android.view.MotionEvent.getX, referenced from method com.example.android.touchexample.TouchExampleView.onTouchEvent
W/dalvikvm( 792): VFY: unable to resolve virtual method 17: Landroid/view/MotionEvent;.getX (I)F
W/dalvikvm( 792): VFY: rejecting opcode 0x6e at 0x0006
W/dalvikvm( 792): VFY: rejected Lcom/example/android/touchexample/TouchExampleView;.onTouchEvent (Landroid/view/MotionEvent;)Z
W/dalvikvm( 792): Verifier rejected class Lcom/example/android/touchexample/TouchExampleView;
D/AndroidRuntime( 792): Shutting down VM
W/dalvikvm( 792): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)


We broke the contract of minSdkVersion, and here is the result. When we build our app against SDK 8 (Froyo) but declare minSdkVersion="3" (Cupcake) we promise the system that we know what we’re doing and we won’t try to access anything that doesn’t exist. If we mess this up, we see the above, and our users see an ugly error message.


Media_http1bpblogspot_hznkl

Cue a lot of frustrated users and one-star ratings on Market. We need a safe way of accessing newer platform functionality without making the verifier angry on older platform versions.

Stop and reflect

Many Android developers are already familiar with the practice of accomplishing this through reflection. Reflection lets your code interface with the runtime, detect when certain methods or classes are present, and invoke or instantiate them without touching them directly.

The prospect of querying each platform feature individually and conditionally invoking it using reflection isn’t pretty. It’s ugly. It’s slow. It’s cumbersome. Most of all, heavy use can turn your app’s codebase into an unmaintainable mess. What if I said there is a way to write Android apps that target Android 1.5 (Cupcake) through 2.2 (Froyo) and beyond with a single codebase and no reflection at all?

Lazy Loading

Computer science researcher Bill Pugh published and popularized a method of writing singletons in Java that takes advantage of the laziness of ClassLoaders. Wikipedia explains his solution further. The code looks like this:


public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}

/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}


There is a very important guaranteed behavior at work here explained by the comment above SingletonHolder. Java classes are loaded and initialized on first access - instantiating the class or accessing one of its static fields or methods for the first time. This is relevant to us because classes are verified by the VM when they are loaded, not before. We now have everything we need to write Android apps that span versions without reflection.

Designing for compatibility

As it turns out this is fairly simple to apply. You generally will want your app to degrade gracefully on older platform versions, dropping features or providing alternate functionality when the platform support isn’t available. Since Android platform features are tied to the API level you have only one axis to consider when designing for compatibility.

In most cases this version support can be expressed as a simple class hierarchy. You can design your app to access version-sensitive functionality through a version-independent interface or abstract class. Subclasses of that interface intended to run on newer platform versions will support newer platform features, and subclasses intended for older versions might need to present alternate ways for your users to access app functionality.

Your app can use a factory method, abstract factory, or other object creation pattern to instantiate the proper subclass at runtime based on the information exposed by android.os.Build.VERSION. This last step insures that the system will never attempt to load a class it can’t verify, preserving compatibility.

The principle in practice

At the beginning of this post I said that we are going to refactor the touch example app from Making Sense of Multitouch to be compatible from API level 3 (Cupcake) on through API level 8 (Froyo). In that post I pointed out that GestureDetectors can be a useful pattern for abstracting the processing of touch events. At the time I didn’t realize how soon that statement would be put to the test. We can refactor the version-specific elements of the demo app’s touch handling into an abstract GestureDetector.

Before we begin the real work, we need to change our manifest to declare that we support API level 3 devices with minSdkVersion in the uses-sdk tag. Keep in mind that we’re still targeting SDK 8, both with targetSdkVersion in our manifest and in our project configuration. Our manifest now looks like this:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.touchexample"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TouchExampleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" />
</manifest>


Our TouchExampleView class isn’t compatible with Android versions prior to Froyo thanks to its use of ScaleGestureDetector, and it isn’t compatible with versions prior to Eclair thanks to its use of the newer MotionEvent methods that return multitouch data. We need to abstract that functionality out into classes that will not be loaded on versions of the platform that don’t support it. To do this, we will create the abstract class VersionedGestureDetector.

The example app allows the user to perform two gestures, drag and scale. VersionedGestureDetector will therefore publish two events to an attached listener, onDrag and onScale. TouchExampleView will obtain a VersionedGestureDetector instance appropriate to the platform version, filter incoming touch events through it, and respond to the resulting onDrag and onScale events accordingly.

The first pass of VersionedGestureDetector looks like this:


public abstract class VersionedGestureDetector {
OnGestureListener mListener;

public abstract boolean onTouchEvent(MotionEvent ev);

public interface OnGestureListener {
public void onDrag(float dx, float dy);
public void onScale(float scaleFactor);
}
}


We’ll start with the simplest functionality first, the VersionedGestureDetector for Cupcake. For simplicity’s sake in this example we will implement each version as a private static inner class of VersionedGestureDetector. You can organize this however you please, of course, as long as you use the lazy loading technique shown above or some equivalent. Don’t touch any class that directly accesses functionality not supported by your platform version.


private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = ev.getX();
mLastTouchY = ev.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = ev.getX();
final float y = ev.getY();

mListener.onDrag(x - mLastTouchX, y - mLastTouchY);

mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}


This simple implementation dispatches onDrag events whenever a pointer is dragged across the touchscreen. The values it passes are the X and Y distances traveled by the pointer.

In Eclair and later we will need to properly track pointer IDs during drags so that our draggable object doesn’t jump around as extra pointers enter and leave the touchscreen. The base implementation of onTouchEvent in CupcakeDetector can handle drag events for us with a few tweaks. We’ll add the methods getActiveX and getActiveY to fetch the appropriate touch coordinates and override them in EclairDetector to get the coordinates from the correct pointer:


private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;

float getActiveX(MotionEvent ev) {
return ev.getX();
}

float getActiveY(MotionEvent ev) {
return ev.getY();
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);

mListener.onDrag(x - mLastTouchX, y - mLastTouchY);

mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}


And now EclairDetector, overriding the new getActiveX and getActiveY methods. Most of this code should be familiar from the original touch example:


private static class EclairDetector extends CupcakeDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;

@Override
float getActiveX(MotionEvent ev) {
return ev.getX(mActivePointerIndex);
}

@Override
float getActiveY(MotionEvent ev) {
return ev.getY(mActivePointerIndex);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}

mActivePointerIndex = ev.findPointerIndex(mActivePointerId);
return super.onTouchEvent(ev);
}
}


EclairDetector calls super.onTouchEvent after determining the active pointer index and lets CupcakeDetector take care of dispatching the drag event. Supporting multiple platform versions doesn’t have to mean code duplication.

Finally, let’s add scale gesture support for Froyo devices that have ScaleGestureDetector. We’ll need a couple more changes to CupcakeDetector first; we don’t want to drag normally while scaling. Some devices have touchscreens that don’t deal well with it, and we would want to handle it differently on devices that do anyway. We’ll add a shouldDrag method to CupcakeDetector that we’ll check before dispatching onDrag events.

The final CupcakeDetector:


private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;

float getActiveX(MotionEvent ev) {
return ev.getX();
}

float getActiveY(MotionEvent ev) {
return ev.getY();
}

boolean shouldDrag() {
return true;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);

if (shouldDrag()) {
mListener.onDrag(x - mLastTouchX, y - mLastTouchY);
}

mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}


EclairDetector remains unchanged. FroyoDetector is below. shouldDrag will return true as long as we do not have a scale gesture in progress:


private static class FroyoDetector extends EclairDetector {
private ScaleGestureDetector mDetector;

public FroyoDetector(Context context) {
mDetector = new ScaleGestureDetector(context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override public boolean onScale(ScaleGestureDetector detector) {
mListener.onScale(detector.getScaleFactor());
return true;
}
});
}

@Override
boolean shouldDrag() {
return !mDetector.isInProgress();
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
}


Now that we have our detector implementations in order we need a way to create them. Let’s add a factory method to VersionedGestureDetector:


public static VersionedGestureDetector newInstance(Context context,
OnGestureListener listener) {
final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
VersionedGestureDetector detector = null;
if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
detector = new CupcakeDetector();
} else if (sdkVersion < Build.VERSION_CODES.FROYO) {
detector = new EclairDetector();
} else {
detector = new FroyoDetector(context);
}

detector.mListener = listener;

return detector;
}


Since we’re targeting Cupcake, we don’t have access to Build.VERSION.SDK_INT yet. We have to parse the now-deprecated Build.VERSION.SDK instead. But why is accessing Build.VERSION_CODES.ECLAIR and Build.VERSION_CODES.FROYO safe? As primitive static final int constants, these are inlined by the compiler at build time.

Our VersionedGestureDetector is ready. Now we just need to hook it up to TouchExampleView, which has become considerably shorter:


public class TouchExampleView extends View {
private Drawable mIcon;
private float mPosX;
private float mPosY;

private VersionedGestureDetector mDetector;
private float mScaleFactor = 1.f;

public TouchExampleView(Context context) {
this(context, null, 0);
}

public TouchExampleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mIcon = context.getResources().getDrawable(R.drawable.icon);
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());

mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback());
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}

@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);

canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mIcon.draw(canvas);
canvas.restore();
}

private class GestureCallback implements VersionedGestureDetector.OnGestureListener {
public void onDrag(float dx, float dy) {
mPosX += dx;
mPosY += dy;
invalidate();
}

public void onScale(float scaleFactor) {
mScaleFactor *= scaleFactor;

// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

invalidate();
}
}
}


Wrapping up

We’ve now adapted the touch example app to work from Android 1.5 on through the latest and greatest, taking advantage of newer platform features as available without a single reflective call. The same principles shown here can apply to any new Android feature that you want to use while still allowing your app to run on older platform versions:


  • The ClassLoader loads classes lazily and will only load and verify classes on first access.


  • Factor out app functionality that can differ between platform versions with a version-independent interface or abstract class.


  • Instantiate a version-dependent implementation of it based on the platform version detected at runtime. This keeps the ClassLoader from ever touching a class that it will not be able to verify.


To see the final cross-version touch example app, check out the “cupcake” branch of the android-touchexample project on Google Code.

Extra Credit

In this example we didn’t provide another way for pre-Froyo users to zoom since ScaleGestureDetector was only added as a public API for 2.2. For a real app we would want to offer some alternate affordance to users. Traditionally Android offers a set of small tappable zoom buttons along the bottom of the screen. The ZoomControls and ZoomButtonsController classes in the framework can help you present these controls to the user in a standard way. Implementing this is left as an exercise for the reader.

Sunday, July 11, 2010

Menunggu Torehan Sejarah di Soccer City

Prediksi Belanda vs Spanyol, Pesta sepakbola terbesar di muka bumi memasuki babak akhir ketika Belanda dan Spanyol akan adu kekuatan di Stadion Soccer City, Johannesburg. Siapa pun yang tampil sebagai pemenang di stadion berkapastas 94 ribu tempat duduk itu akan mengukir sejarah sebagai juara baru.

Belanda vs Spanyol akan jadi yang terbaik dari 32 negara peserta Piala Dunia 2010. Spanyol akan mengusung modal sebagai juara Eropa dalam pertandingan final tersebut. Sementara Belanda tidak ingin gagal lagi untuk ketiga kalinya setelah secara beruntun kalah di final pada tahun 1974 dan 1978.

Namun bukan tak mungkin, Spanyol mengikuti nasib sama seperti yang pernah dialami Belanda pada 1974. Kala itu Johan Cruyff sedang jaya-jayanya, harus menerima kenyataan pahit karena langkah mereka yang begitu mulus serta disanjung sebagai calon juara, justru tersandung di saat-saat terakhir.

Spanyol tidak ingin menganggap remeh Belanda. Sebab tim Oranye yang tidak pernah kalah sampai melangkah ke final. Sementara Spanyol di babak penyisihan, sempat dikejutkan Swiss dengan skor 0-1. Selain itu superioritas Spanyol sedikit diwarnai oleh tak bersinarnya Cesc Fabregas dan Fernando Torres.

Tidak banyak pengamat yang mengunggulkan Belanda ketika menghadapi Brasil di babak perempatfinal. Namun buktinya, Belanda berhasil menyingkirkan raksasa dari Amerika Selatan itu. Impian Brasil yang jauh-jauh hari sudah diunggulkan untuk merebut tropi juara, akhirnya musnah akibat dua gol Sneijder.

Dua gol itu melambungkan Sneijder sebagai kandidat peraih sepatu emas karena telah mengoleksi lima gol. Saingan Sneijder adalah David Villa dari Spanyol, lawan di final yang juga sudah menyumbang lima gol. Para pemain Spanyol tidak punya cara lain selain menghentikan sepak terjang Sneijder.

Setelah mengantar Inter Milan menjadi juara liga, Piala Italia, dan Liga Championsm Sneijder siap menapak lebih jauh. "Kami akan mengalahkan Spanyol. Kalau kami tidak yakin, maka kami tak akan pernah bisa melakukannya. Itu yang dikatakan pelatih, seperti yang dikatakan Jose Mourinho saat di Inter," katanya.

Bert Van Marwijk, pelatih Belanda menginginkan supaya saat berada di lapangan, para pemainlah yang akan menjadi bintang. "Saya tidak ingin memikirkan final ketika Belanda kalah pada 1974 dan 1978. Ini adalah sejarah dan sejarah itu sekarang," kata Bert Van Marwijk mantap.

Thursday, July 8, 2010

Apps on SD Card: The Details

[This post is by Suchi Amalapurapu, an engineer who worked on this feature. — Tim Bray]

Android 2.2 supports application installation on external storage devices like the SD card. This should give users room for many more apps, and will also benefit certain categories, like games, that need huge assets.

(Note that not all of the contents of an “SD-card-resident” APK are actually on the card; the dex files, private data directories, and native shared libraries remain in internal storage.)

The “Manage Applications” screen in the Settings app now has an “On SD Card” tab. The sizes listed in Manage Applications only include the space taken by the application on internal storage.

The Application Info screen now has either a “move to SD card” or “move to phone” button, but this is often disabled. Copy-protected apps and updates to system apps can’t be moved to the SD card, nor can those which are don’t specify that they work on the SD card.

Controlling Installation Preference

SD-card installation is an optional feature on Android 2.2, is under the control of the developer not the user, and will not affect any applications built prior to Android 2.2.

Application developers can set the field android:installLocation in the root manifest element to one of these values:


  • internalOnly: Install the application on internal storage only. This will result in storage errors if the device runs low on internal storage.


  • preferExternal: The android system tries to install the application on external storage. If that is full, the application is installed on internal storage.


  • auto: Let the Android system decide the best install location for the application. The default system policy is to install the application on internal storage first. If the system is running low on storage, the application is then installed on external storage.


If the installLocation is not specified (as is the case for all applications prior to Android 2.2), the application is installed on internal storage. Application updates will by default try to retain their install location, but application developers may change the installLocation field in an update. Installing an application with this new attribute on older devices will not break compatibility and these applications will be installed on internal storage only.

Application developers can also explicitly install under-development code on external storage via adb install flags, which override the installLocation field: -f for internal storage, and -s for external storage. They can also override the default install location to verify and test application installation on SD card with an adb shell pm command:

adb shell pm setInstallLocation option

Where option is one of:


  • 0 [auto] Let the system decide.


  • 1 [internal only]


  • 2 [external]


The current install location can be retrieved via
adb shell pm getInstallLocation
Note that changing this default can cause applications to misbehave if they’re not prepared to live on the SD card.

USB Mass Storage interactions

The Android system stores the SD-card-resident applications’ APKs in a secure application-specific container. A new flag FLAG_EXTERNAL_STORAGE in ApplicationInfo object indicates that an application is currently installed on the SD card. This storage is removed when an SD-card-resident app is uninstalled.

When an Android device’s SD card is unmounted, applications installed on it are no longer available. Their internal storage is still there and such apps can be uninstalled without replacing the SD card.

The Android framework provides several broadcast intents to support the (small) class of applications, such as launchers, that access other applications’ resources:


  • When the SD card is unmounted, ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE with a list of the disabled applications and a list of corresponding application uid’s via extra attributes in the broadcast intent.


  • When the SD card is mounted, ACTION_EXTERNAL_APPLICATIONS_AVAILABLE with a list of enabled applications and a list of corresponding application uid’s via extra attributes in the broadcast intent.


Applications that handle broadcast intents like ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED may also want to handle these additional notifications.

When an application gets moved between internal to external storage and vice versa, the application is disabled first (which includes broadcasting intent ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE), the asset resources are copied, and then the application is enabled (which includes broadcasting intent ACTION_EXTERNAL_APPLICATIONS_AVAILABLE).

Security and Performance Implications

Applications on SD card are mounted via Linux’s loopback interface and encrypted via a device-specific key, so they cannot be decrypted on any other device. Note that this is security measure and does not provide copy protection; the apps are world readable just like the resources of normal applications installed on the device’s internal storage. Copy-protected applications cannot be installed on external media. In the interests of stability, updates to system applications also cannot be installed on the external media. The application resources stored on external storage are read-only and hence there are no performance issues with loading or launching applications on SD card.

Swapping or Transferring SD Card Contents

It has always been the case that when you swap SD cards on an Android device, if you physically copy the contents of the old card to the new one, the system will use the data on the new card as if nothing had changed. This is also true of apps which have been installed on the SD card.

When not to install on SD card?

The advantage of installing on SD card is easy to understand: contention for storage space is reduced. There are costs, the most obvious being that your app is disabled when the SD card is either removed or in USB Mass Storage mode; this includes running Services, not just interactive Activities. Aside from this, device removal disables an application’s Widgets, Input methods, Account Managers, Device administrators, Live wallpapers, and Live folders, and may require explicit user action to re-enable them.

Android 2.2 SDK refresh

As you may have noticed, the source code for Android 2.2, which we call Froyo, has been released.

The Android 2.2 SDK that was released at Google I/O contained a preview of the Froyo system image and today, we are releasing an update to bring it into sync with the system image pushed to Nexus One devices.

I encourage all developers to use the SDK manager to update to this version.

Wednesday, July 7, 2010

Android Love at OSCON

<x>

Android developers who aren't already going should take a moment to check out the OSCON 2010 schedule, and give serious thought to a trip to Portland in a couple of weeks. OSCON is one of the world's premiere events for those who care about Open Source, and one of my personal favorite conferences, with a powerful community vibe. And this year, the Android drums are sounding.

There are a bunch of mobile and Android-related sessions, both pure and extremely impure; for example, I bet both Steve Jobs and I are dubious about Cross-Compiling Android Applications to the iPhone. There's a full-dress Android for Java Developers tutorial. And (the one I helped cook up) there's the Android Hands-On; last I heard, registration for that is approaching 200 and, since O'Reilly found us a big room, it's not full up; but it will be.

On top of which, there are going to be a herd of Googlers at OSCON, and a sub-herd of Androiders, including Dan Morrill and Justin Mattson and me. This isn't surprising; what does surprise me is that OSCON hasn't previously been an Android love-fest. Because if you're interested in mobile devices and have a hankering for Open Source, Android is for you.

</x>

Tuesday, July 6, 2010

"Gurita Sakti" Pegang Spanyol

Ramalan Gurita Masih ingat dengan Paul “si gurita sakti”. Hewan bertentakel delapan penghuni akuarium Kehidupan Laut di Oberhausen, Jerman, itu membelot untuk kedua kalinya. Ketika memilih kotak berbendera Spanyol atau Jerman untuk partai semifinal di Durban, Kamis (8/7) dini hari WIB, Paul bertengger di kotak merah-kuning-merah alias berbendera Spanyol.

Paul merupakan gurita yang dianggap punya kemampuan meramal hasil pertandingan. Jejak rekamnya selama PD 2010 ini bersih alias 100 persen benar di lima pertandingan Jerman. Si gurita dengan jitu menebak Jerman bakal menang dari Australia dan Ghana di penyisihan grup. Pun demikian ketika Jerman menyerah dari Serbia.

Ketika memasuki fase knock-out, Paul bertengger di kotak milik Jerman dan mengabaikan kotak milik Inggris dan Argentina. Hasilnya jitu lagi sehingga “Tim Panser” melaju ke semifinal. Tetapi pendukung Jerman janganlah risau. Prediksi gurita kelahiran Inggris ini salah ketika menebak hasil final Euro 2008. Ketika itu ia memegang kotak berbendera Jerman, yang pada keyantaannya Spanyol menjadi kampiun dengan gol semata wayang dari Fernando Torres.(DIM/AP Sport)

Dog

A lingering fear of mine was confirmed last night:  My dog might be slightly retarded.

I've wondered about her intelligence ever since I adopted her and subsequently discovered that she was unable to figure out how stairs worked.


Media_http2bpblogspot_hsijm

I blamed her ineptitude on the fact that she'd spent most of her life confined to a small kennel because her previous owners couldn't control her.  I figured that maybe she just hadn't been exposed to stairs yet.  Accepting the noble responsibility of educating this poor, underprivileged creature, I spent hours tenderly guiding her up and down the staircase - placing biscuits on each step to lure her and celebrating any sign of progress.  When she still couldn't successfully navigate the stairs at the end of her first week with me, I  blamed it on her extreme lack of motor control.  This dog is uncoordinated in a way that would suggest her canine lineage is tainted with traces of a species with a different number of legs - like maybe a starfish or some sort of primitive snake.

The next clue came when I started trying to train her. I am no stranger to training dogs - much of my childhood was spent working with various canines because I lacked the social skills to interact successfully with people.  With so many years of experience behind me, I was sure that training this new dog would be a very simple task.

I was wrong.  Not only is training my dog outlandishly difficult, it is also heartbreaking.  She wants so badly to please me.  Every fiber of her being quivers with the desire to do a good job.  


Media_http1bpblogspot_zsqhq

She tries really hard.    


Media_http1bpblogspot_vqyba


Media_http4bpblogspot_lndao


Media_http3bpblogspot_dadax


Media_http2bpblogspot_fjujq


Media_http1bpblogspot_hjnsi


Media_http4bpblogspot_ygrza


Media_http4bpblogspot_exjem


Media_http3bpblogspot_gikal


Media_http4bpblogspot_uzvsr


Media_http4bpblogspot_hbihf

But when turning her head at an extreme angle fails to produce a life-altering epiphany, she usually just short-circuits and rolls on her back.  

Over the past two months, she's made some progress, but it's been painfully slow and is easily forgotten.  Still, I was living under the assumption that maybe my dog just had a hidden capacity for intelligence - that all I had to do was work hard enough and maybe she'd wake up one day and be smart and capable like a normal dog.  Until last night.  

Last night I was sitting on my couch mindlessly surfing the internet when I looked up and noticed my dog licking the floor.  Just licking and licking.  At first I though maybe I'd spilled something there, but her licking did not seem to be localized to one spot.  Rather, she was walking around the room licking seemingly at random.  She lay down on her side and kept licking out of the side of her mouth while staring directly at me.  


Media_http1bpblogspot_djbxh


At that moment I realized that I needed to know for sure whether my dog was retarded or not.  

I Googled "how to tell if your dog is retarded" and after a bit of research, I found a dog IQ test that looked fairly legitimate.  It involved testing your dog's ability to solve a few very basic problems, like figuring out how to get out from underneath a blanket. 

I gathered the necessary supplies and began testing.  

The first test asked me to call my dog using a variety of words that were not her name to gauge whether she could tell the difference.  I called out "refrigerator!" and was pleased to see that my dog did not respond.  She also failed to respond to "movie," "dishwasher" and "banana."  I was beginning to feel  very proud of her.  Then came the crucial step: I called her name.  Nothing.  I called it a few more times to be sure.  Still nothing.  

The words hung like a neon sign broadcasting my dog's failure.  "It's okay," I thought.  "She'll do better on the next one."  

In the second test, I had to put a blanket over my dog and time her to see how long it took her to get out.  I threw the blanket over her and started my stopwatch.  She made some cursory attempts at freeing herself, but as the seconds ticked by, it became clear that she was not going to pass.  


Media_http1bpblogspot_devju


Media_http3bpblogspot_vgckj


Media_http4bpblogspot_mbnpt

Still, I gave her the benefit of the doubt and assumed that she just enjoyed being under there and could get out if she wanted to.  I added an extra couple points to her tally for faith's sake. 

After flagrantly failing three more tests, it came down to the final trial.  If she could score five out of five possible points on this section of the test, she could bump herself out of the bottom category into "below average."  

First, I had to make her sit, which was a test in and of itself.  Then I was supposed to show her a biscuit, let her sniff it, then - after making sure she was watching - place the biscuit on the ground and put a plastic cup over it.  If she knocked over the cup to get the biscuit within a certain amount of time, she'd pass the test.  

I put the biscuit under the cup and started the timer.  

My dog ran over to the cup and sniffed it.  She walked around it once and then looked up at me like I was some sort of wizard.  I pointed to the cup.  I knew it was cheating, but I wanted to help my dog pass her test.  


Media_http2bpblogspot_geqqu

She didn't understand, but she knew she was supposed to do something, so she just started frantically doing things because maybe - just maybe - one of those things would be the right thing and the magical wizard cup would let her know where the treat went.  


Media_http1bpblogspot_gjwfi


Media_http3bpblogspot_lwbze


Media_http1bpblogspot_baofu


Media_http2bpblogspot_mrpzi

 

Media_http3bpblogspot_fpicb



Media_http4bpblogspot_hbihf

After five minutes of watching my dog aimlessly tear around the house, I finally accepted that she was not going to pass any part of the test and yes, she was most likely mentally challenged.  But damn it, I was not going to let my poor, retarded dog feel like she failed.  


Media_http3bpblogspot_xinab


Media_http4bpblogspot_njzkb