<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;Ck4NSX0-cSp7ImA9WhRbF0s.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832</id><updated>2012-02-09T12:16:38.359+08:00</updated><category term="Linux/Ubuntu" /><category term="OpenAlarm" /><category term="Cygwin" /><category term="Investment" /><category term="Music" /><category term="MacOS" /><category term="Tcl" /><category term="Palm" /><category term="BozaAlarm" /><category term="EDA/OpenAccess" /><category term="Programming" /><category term="Font" /><category term="C++" /><category term="倒扁" /><category term="心得" /><category term="Travel" /><category term="MindMap" /><category term="EDA" /><category term="Journal" /><category term="Qt" /><category term="Bluetooth" /><category term="Emacs" /><category term="Applications" /><category term="Book" /><category term="Android" /><category term="Boost" /><category term="Video" /><category term="India" /><category term="Blog" /><category term="Maemo" /><title>勇於改變</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://yenliangl.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://yenliangl.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>216</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ChangeAttitudeYounger" /><feedburner:info uri="changeattitudeyounger" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;Ak8ERns6fSp7ImA9WhRbE0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-396109281602876540</id><published>2012-02-04T20:29:00.004+08:00</published><updated>2012-02-04T20:33:27.515+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-04T20:33:27.515+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>Implement an AppWidget for BozaAlarm - Part I: Limitation</title><content type="html">Today, I released BozaAlarm v4.10 to the Android Market. What's new in this version is the simple AppWidget to display the next enabled alarm.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-fGyFyxTWKE8/Txe7fBlGisI/AAAAAAAAM8M/zB5CHa-Quhc/s1600/nextalarm_appwidget.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-fGyFyxTWKE8/Txe7fBlGisI/AAAAAAAAM8M/zB5CHa-Quhc/s320/nextalarm_appwidget.png" width="213" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Here, I'd like to talk about how I implemented this simple widget. Before I go too far, you probably need to take a look at least these two topics,&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/guide/topics/appwidgets/index.html#AppWidgetProvider" target="_blank"&gt;AppWidgetProvider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.android.com/guide/practices/ui_guidelines/widget_design.html#anatomy_determining_size" target="_blank"&gt;App Widget Design Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Just as I said before, there are some &lt;a href="http://yenliangl.blogspot.com/2010/06/appwidget-design-can-i-use-my-own.html" target="_blank"&gt;limitations&lt;/a&gt; in App Widget design and understand these should save you some time.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Basically, the Launcher process hosts AppWidgetHostView for each App Widget and talk with your process through RPC calls. You can image there are many RPC (binder) calls between Launcher and your process. That's why you will use RemoteViews to package your update actions in your process and apply them on the App Widget on the Launcher side. In fact, the RemoteViews is implemented as Command pattern in software terminology.&lt;/div&gt;
&lt;img src="https://docs.google.com/drawings/pub?id=1k5Oiw5SqAUPxm5YzCG7GhzC9tW6hjfrcUHIhtOfzwZ4&amp;amp;w=640&amp;amp;h=360" /&gt;

&lt;br /&gt;
&lt;div&gt;
Now, you can imagine why AppWidget design is so restricted.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Moreover, because it's always unsafe to load classes from other process in a process, you're not allowed to use custom classes in your widget layout. Only built-in widget classes can be used in your layout xml file and only methods tagged by RemotableMethod in these classes are allowed.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-396109281602876540?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wWVZSPEXz6UxMVnUC_9QhdDd4TI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wWVZSPEXz6UxMVnUC_9QhdDd4TI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wWVZSPEXz6UxMVnUC_9QhdDd4TI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wWVZSPEXz6UxMVnUC_9QhdDd4TI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/48KM3vgYN_c" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/396109281602876540?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/396109281602876540?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/48KM3vgYN_c/implement-appwidget-for-bozaalarm-part.html" title="Implement an AppWidget for BozaAlarm - Part I: Limitation" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-fGyFyxTWKE8/Txe7fBlGisI/AAAAAAAAM8M/zB5CHa-Quhc/s72-c/nextalarm_appwidget.png" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2012/02/implement-appwidget-for-bozaalarm-part.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8BSXw7cSp7ImA9WhRbE0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-5348984493781244072</id><published>2012-02-04T14:09:00.000+08:00</published><updated>2012-02-04T20:34:18.209+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-04T20:34:18.209+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenAlarm" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>Experiment the Tips for reducing APK file size</title><content type="html">I came across &lt;a href="http://developer.sonyericsson.com/wp/2012/01/31/tips-for-reducing-apk-file-size/#comments" target="_blank"&gt;this article:&amp;nbsp;Tips for reducing APK file size&lt;/a&gt; at SonyEricsson Developer blog.&amp;nbsp;Among them, the one I am aware of is the PNG file optimization. So, I took some time to experiment it.&lt;br /&gt;
&lt;br /&gt;
First, I downloaded the GUI wrapper of command-line optimizer &lt;a href="http://imageoptim.pornel.net/" target="_blank"&gt;ImageOptim&lt;/a&gt;&amp;nbsp;and optimize the PNG files at res/ directory.&amp;nbsp;According to the result, it reduce total file size from 748K bytes to 700K bytes.&lt;br /&gt;
&lt;br /&gt;
Second, I recompile the release binary of my application. But, the size of APK file remains the same as the one w/o PNG optimization.&lt;br /&gt;
&lt;br /&gt;
Hmm. I repeated this process some times to make sure I didn't miss some important steps. While I was wondering, I noticed some messages spewed out during compilation like,&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
&amp;nbsp; [crunch] Processing image to cache: /Users/yenliangl/Work/Android/bozaalarm-android/res/drawable-hdpi/handler_app.png =&amp;gt; /Users/yenliangl/Work/Android/bozaalarm-android/bin/res/drawable-hdpi/handler_app.png&lt;/blockquote&gt;
&lt;i&gt;Looks like PNG optimization has been included in the standard Android tool v14??&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
This should confirm my guess. &lt;a href="http://www.blogger.com/(http://tools.android.com/recent/buildchangesinrevision14" target="_blank"&gt;From official site of Android tool&lt;/a&gt;, it says that in revision 14, aapt optimizes PNG during compilation. &lt;br /&gt;
&lt;br /&gt;
&lt;i style="background-color: white; color: #444444; font-family: Arial, Verdana, sans-serif; font-size: 13px; line-height: 21px; text-align: left;"&gt;png processing in aapt.&lt;/i&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #444444; font-family: Arial, Verdana, sans-serif; font-size: 13px; line-height: 21px; text-align: left;"&gt;When aapt packages the resources, its main goal is to compile the XML to binary format and to create a resource table with all the resource values (string, color, ids, etc...). &lt;b&gt;Additionally, it processes the png files to optimize them (for instance, pre-processing of 9-patches).&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #444444; font-family: Arial, Verdana, sans-serif; font-size: 13px; line-height: 21px; text-align: left;"&gt;Because the aapt process is not incremental, this means every build goes through all png files and processes them always. For large projects with numerous (and/or large) png this process could take a long time.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #444444; font-family: Arial, Verdana, sans-serif; font-size: 13px; line-height: 21px; text-align: left;"&gt;Revision 14 now processes the png files outside of the aapt packaging step and caches them. Only modified png files are re-processed.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-5348984493781244072?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uO7wrGD_f6HxEToAtZ5JdQ28sos/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uO7wrGD_f6HxEToAtZ5JdQ28sos/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uO7wrGD_f6HxEToAtZ5JdQ28sos/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uO7wrGD_f6HxEToAtZ5JdQ28sos/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/PA_qvnYZru4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/5348984493781244072?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/5348984493781244072?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/PA_qvnYZru4/experiment-tips-for-reducing-apk-file.html" title="Experiment the Tips for reducing APK file size" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2012/02/experiment-tips-for-reducing-apk-file.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UFQX0zeip7ImA9WhRWGEg.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-7042235328717517206</id><published>2012-01-06T21:01:00.000+08:00</published><updated>2012-01-06T21:06:50.382+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-06T21:06:50.382+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenAlarm" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>TimePicker/DatePicker with keyboard input problem</title><content type="html">I got some complaints from users saying they can't use keyboard to input in TimePicker or DatePicker widgets and found that this bug has been posted on Android developer forum for some time.&lt;br /&gt;
&lt;br /&gt;
The quick workaround for this bug is,
&lt;script src="https://gist.github.com/1570501.js"&gt; &lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-7042235328717517206?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/a5e7IiuLgrDwUfMFfZNnJGDrLlU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a5e7IiuLgrDwUfMFfZNnJGDrLlU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/a5e7IiuLgrDwUfMFfZNnJGDrLlU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a5e7IiuLgrDwUfMFfZNnJGDrLlU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/3dumgt9Hgg4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7042235328717517206?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7042235328717517206?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/3dumgt9Hgg4/timepickerdatepicker-with-keyboard.html" title="TimePicker/DatePicker with keyboard input problem" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2012/01/timepickerdatepicker-with-keyboard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIEQH05eSp7ImA9WhRWF0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-963188341923263554</id><published>2012-01-05T16:34:00.001+08:00</published><updated>2012-01-05T16:35:01.321+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-05T16:35:01.321+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Emacs" /><title>Publish org to remote host through ssh</title><content type="html">&lt;p&gt;I've used Emacs org-mode to manage my personal notes and work stuff for a while. Its flexibility always amazes me.&lt;/p&gt;&lt;p&gt;Normally, I keep my personal notes in a Dropbox directory that are synced automatically. But, for work stuff, I created a local directory for them in intranet and published them to a secured remote host through ssh. The org-publish supports this feature well after you've configured ssh.&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1564238.js"&gt; &lt;/script&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-963188341923263554?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oq-VeE7fwLIhpzWZ8_887eQgfzs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oq-VeE7fwLIhpzWZ8_887eQgfzs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oq-VeE7fwLIhpzWZ8_887eQgfzs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oq-VeE7fwLIhpzWZ8_887eQgfzs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/YM6wIcNm1J0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/963188341923263554?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/963188341923263554?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/YM6wIcNm1J0/publish-org-to-remote-host-through-ssh.html" title="Publish org to remote host through ssh" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2012/01/publish-org-to-remote-host-through-ssh.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkACQHYyeyp7ImA9WhRWF0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-8951431217608365785</id><published>2012-01-05T16:04:00.002+08:00</published><updated>2012-01-05T16:06:01.893+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-05T16:06:01.893+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Emacs" /><title>Customize Emacs compile</title><content type="html">&lt;div&gt;At work, I use &lt;span style="font-family: 'courier new', courier;"&gt;M-x compile&lt;/span&gt;&lt;span style="font-family: arial, helvetica, sans-serif;"&gt;&amp;nbsp;to build the project I'm working on. Chances are that default &lt;span style="font-family: 'courier new', courier;"&gt;compile-command&lt;/span&gt; is not what you want. You can customize it and bind it to hotkeys as follows,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;script src="https://gist.github.com/1564186.js"&gt;
haha
&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Now, you can use F8, F9 to build the optimized and debug version.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-8951431217608365785?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/QHpIurJlLru7L49uciFPG7Q1EH0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QHpIurJlLru7L49uciFPG7Q1EH0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/QHpIurJlLru7L49uciFPG7Q1EH0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/QHpIurJlLru7L49uciFPG7Q1EH0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/g85WhZIy594" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/8951431217608365785?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/8951431217608365785?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/g85WhZIy594/customize-emacs-compile.html" title="Customize Emacs compile" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2012/01/customize-emacs-compile.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cDR3s5cCp7ImA9WhRWF0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-3714673303192608391</id><published>2011-12-27T15:21:00.007+08:00</published><updated>2012-01-05T16:11:16.528+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-05T16:11:16.528+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Linux/Ubuntu" /><category scheme="http://www.blogger.com/atom/ns#" term="Emacs" /><title>Create Emacs server for each GNU Screen automatically</title><content type="html">I am a heavy user of GNU screen and Emacs at work and home. In the past, I created different GNU Screen instances for different projects and only one instance of Emacs server in one machine. For instance, you are aked to fix bugs in threee code branches and some fixes can't go into certain branches, I need to be very careful when I edit and switch buffers because only once emacs server out there.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-7gzP9mffGbU/TvlytowNC2I/AAAAAAAAM1U/nq3xlk7DhxI/s1600/emacs_screen_work_model_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="197" src="http://4.bp.blogspot.com/-7gzP9mffGbU/TvlytowNC2I/AAAAAAAAM1U/nq3xlk7DhxI/s320/emacs_screen_work_model_1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
What I really need to have setup like this,&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-JRZs1zLr2vA/TvlyrQwLftI/AAAAAAAAM1M/P77D6Th4bn8/s1600/emacs_screen_work_model_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="188" src="http://1.bp.blogspot.com/-JRZs1zLr2vA/TvlyrQwLftI/AAAAAAAAM1M/P77D6Th4bn8/s320/emacs_screen_work_model_2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Now, whenever you edit or switch files in a GNU screen by emacsclient, you can sit back and relax for a while. But, the problem is how do I make this a bit automatic? If you need to execute 'emacs --daemon=serverN' for every created GNU Screen, that will be very troublesome.&lt;br /&gt;
Here is what I have done to make this happen,&lt;br /&gt;
&lt;br /&gt;
&lt;script src="https://gist.github.com/1564216.js"&gt; &lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Now, when you instantiate GNU Screen by 'ws_XXX' aliases, an Emacs server identified by 'XXX' is created for you. And then you can use 'et' to edit a file in the proper Emacs server.&lt;br /&gt;
&lt;br /&gt;
The only thing I don't like is that I am compelled to use another alias 'kill-emacs' to kill Emacs server. I often 'pkill' to kill process, but this will kill &lt;b&gt;all&lt;/b&gt; Emacs servers in the same machine which is absolutely not the behavior I want.&lt;br /&gt;
&lt;br /&gt;
The last thing to do is to patch the source code of emacsclient. In my experiment, emacsclient in the latest stable release (23.3b) doesn't pass correct argument for Emacs to start its daemon mode. So, I made minor changes to make it right.&lt;br /&gt;
&lt;br /&gt;
&lt;script src="https://gist.github.com/1523697.js"&gt; &lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
After recompile and install, you can start using these two power tools in this way as I do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-3714673303192608391?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Yv-It99i6zoYcz9B3_2FGjzeVOg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Yv-It99i6zoYcz9B3_2FGjzeVOg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Yv-It99i6zoYcz9B3_2FGjzeVOg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Yv-It99i6zoYcz9B3_2FGjzeVOg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/9iVOmAsMm_s" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/3714673303192608391?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/3714673303192608391?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/9iVOmAsMm_s/create-emacs-server-for-each-gnu-screen.html" title="Create Emacs server for each GNU Screen automatically" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-7gzP9mffGbU/TvlytowNC2I/AAAAAAAAM1U/nq3xlk7DhxI/s72-c/emacs_screen_work_model_1.png" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2011/12/create-emacs-server-for-each-gnu-screen.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4MRXoycSp7ImA9WhZVFEQ.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6111163818138870870</id><published>2011-05-27T18:43:00.000+08:00</published><updated>2011-05-27T18:43:04.499+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-27T18:43:04.499+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Linux/Ubuntu" /><category scheme="http://www.blogger.com/atom/ns#" term="MacOS" /><title>Load machine-dependent bash setting</title><content type="html">I own several computers and each is running different OS on it. We all know that maintaining different settings for different OS is very cumbersome. A simple solution for this is to separate common settings and machine-dependent settings into different files like this,&lt;br /&gt;
&lt;pre class="brush:bash"&gt;MNAME=`uname -s`
MBASHRC=$HOME/Settings/bashrc.${MNAME,,}
if [ -f $MBASHRC ]; then
    echo "==&amp;gt; loading $MBASHRC"
    . $MBASHRC
fi
&lt;/pre&gt;In this way, all you need to do is to write your machine-dependent settings in the bashrc.darwin or bashrc.linux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6111163818138870870?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/NuppNUzQ-LKOXHyVsbNdgB2wUd4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NuppNUzQ-LKOXHyVsbNdgB2wUd4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/NuppNUzQ-LKOXHyVsbNdgB2wUd4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NuppNUzQ-LKOXHyVsbNdgB2wUd4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/E6tZn4yDqB4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6111163818138870870?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6111163818138870870?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/E6tZn4yDqB4/load-machine-dependent-bash-setting.html" title="Load machine-dependent bash setting" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/05/load-machine-dependent-bash-setting.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcDRX84eyp7ImA9WhRWGEg.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-7073648006706006598</id><published>2011-05-27T18:25:00.002+08:00</published><updated>2012-01-06T20:14:34.133+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-06T20:14:34.133+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Linux/Ubuntu" /><category scheme="http://www.blogger.com/atom/ns#" term="MacOS" /><title>MacOSX-like open command in Ubuntu and Windows/Cygwin.</title><content type="html">I always find 'open' command in MacOSX is very useful for people always hanging around in the Terminal. To get the similar behavior in Ubuntu or other Linux system, we can create an alias such as,&lt;br /&gt;

&lt;script src="https://gist.github.com/1570314.js"&gt; &lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-7073648006706006598?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/y2Mnec2T055rJm1KPF_7s4z8dJk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/y2Mnec2T055rJm1KPF_7s4z8dJk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/y2Mnec2T055rJm1KPF_7s4z8dJk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/y2Mnec2T055rJm1KPF_7s4z8dJk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/Xv7Q4eKqwdA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7073648006706006598?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7073648006706006598?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/Xv7Q4eKqwdA/macosx-like-open-command-in-ubuntu.html" title="MacOSX-like open command in Ubuntu and Windows/Cygwin." /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/05/macosx-like-open-command-in-ubuntu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcDRHk6eSp7ImA9WhZVFEQ.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6672119044712374886</id><published>2011-05-16T21:24:00.001+08:00</published><updated>2011-05-27T18:27:55.711+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-27T18:27:55.711+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>My new Android application TallyCounter</title><content type="html">I've published a new application, TallyCounter, on the Android Market.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-A8mB6sVLJVo/TdD_HGxmpvI/AAAAAAAAKyM/5n08kfmbxnU/s1600/main_screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-A8mB6sVLJVo/TdD_HGxmpvI/AAAAAAAAKyM/5n08kfmbxnU/s320/main_screen.png" width="192" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
It's very easy to use. You can download it on this &lt;a href="https://market.android.com/details?id=org.startsmall.tallycounter"&gt;link&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6672119044712374886?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UOZ-A46wR7tq1BdLIBRRXb_8x24/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UOZ-A46wR7tq1BdLIBRRXb_8x24/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UOZ-A46wR7tq1BdLIBRRXb_8x24/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UOZ-A46wR7tq1BdLIBRRXb_8x24/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/3XbKe-XEUiI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6672119044712374886?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6672119044712374886?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/3XbKe-XEUiI/my-new-android-application-tallycounter.html" title="My new Android application TallyCounter" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-A8mB6sVLJVo/TdD_HGxmpvI/AAAAAAAAKyM/5n08kfmbxnU/s72-c/main_screen.png" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2011/05/my-new-android-application-tallycounter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08HQXkzeip7ImA9WhZXFEo.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-7410972363210795224</id><published>2011-05-04T11:30:00.000+08:00</published><updated>2011-05-04T11:30:30.782+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-04T11:30:30.782+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Run Android CTS</title><content type="html">Recently, I was asked to look into CTS report of my work. So, I downloaded CTS on &lt;a href="http://source.android.com/compatibility/cts-intro.html"&gt;Android website&lt;/a&gt; and started running it. After hours of experiments, these are my experiences that should save you some time.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Use SDK 1.6r1 against your CTS. Don't use SDK r10. &lt;/li&gt;
&lt;li&gt;Modify &lt;b&gt;maxTestCount&lt;/b&gt; to -1 in your $CTS_ROOT/repository/host_config.xml&lt;/li&gt;
&lt;li&gt;Don't run large test plan. Predefined test plans in the CTS are,&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;CTS&lt;/b&gt; plan&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;VM&lt;/b&gt; plan&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java&lt;/b&gt; plan&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Android&lt;/b&gt; plan&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;RefApp&lt;/b&gt; plan&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AppSecurity&lt;/b&gt; plan&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Signature&lt;/b&gt; plan&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Performance&lt;/b&gt; plan&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;If you run into errors complaining this "&lt;i&gt;Installing met .... due to unknown reasons&lt;/i&gt;", try to run a customized smaller test plan composed of nonExecuted packages.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt; &lt;i&gt;add --plan reset_of_packages&lt;/i&gt;. It prompts you available packages to add into this plan and you can add packages that haven't run yet since the error happens.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;You can run CTS in Linux, Windows or Ubuntu. The whole CTS suite is just a script wrapped on top of "java -cp". It should be platform-independent. If you are running CTS on Windows/cygwin system,&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Move the definition of ${JARS} in your &lt;i&gt;startcts&lt;/i&gt; to the following, &lt;pre class="brush:bash"&gt;JARS=`cygpath -w -p ${CTS_LIB}:${DDM_LIB}:${JUNIT_LIB}:${HOSTTEST_LIB}`&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;and, this line &lt;pre class="brush:bash"&gt;java ${JAVA_OPTS} -cp ${JARS} com.android.cts.TestHost `cygpath -w ${CONFIG}` "$@" ${DDCONFIG}&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;i&gt; &lt;/i&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-7410972363210795224?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eTKi6x9HJjTj9Dvuy9FE9WSBYak/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eTKi6x9HJjTj9Dvuy9FE9WSBYak/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eTKi6x9HJjTj9Dvuy9FE9WSBYak/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eTKi6x9HJjTj9Dvuy9FE9WSBYak/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/DndKNlAB2Xg" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7410972363210795224?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/7410972363210795224?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/DndKNlAB2Xg/run-android-cts.html" title="Run Android CTS" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/05/run-android-cts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYASHk7cCp7ImA9WhZQGUw.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6063831843272092523</id><published>2011-04-27T22:22:00.000+08:00</published><updated>2011-04-27T22:22:29.708+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-27T22:22:29.708+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>New alpha version for features I've implemented since v3.07b</title><content type="html">I've compiled a new alpha version that includes features I've implemented since the release of v3.07b on the Android Market. These features include,&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;New alarm action for launching application.&lt;/li&gt;
&lt;li&gt; New equation mode on the AlarmAlert activity to unlock snooze/dismiss buttons.&lt;/li&gt;
&lt;li&gt;The redesigned password input widget. &lt;/li&gt;
&lt;/ol&gt;Screenshots are uploaded to my Picasa space.&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Q4OPZ4HJ6_4/TbbQmcWDfMI/AAAAAAAAKu8/cMlU0k0Cf08/s1600/select_application.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-Q4OPZ4HJ6_4/TbbQmcWDfMI/AAAAAAAAKu8/cMlU0k0Cf08/s320/select_application.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Select an application to launch&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-QKE-83KtWLU/TbgdKOD3qTI/AAAAAAAAKvE/XurXM9XVoeg/s1600/enter_password_for_an_alert.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-QKE-83KtWLU/TbgdKOD3qTI/AAAAAAAAKvE/XurXM9XVoeg/s320/enter_password_for_an_alert.png" width="213" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Set password for an alert&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-QRV7orzu7qs/TbgiyXicVkI/AAAAAAAAKvU/-FyD3gMzaUU/s1600/answer_math_equatioin_to_snooze_or_dismiss.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-QRV7orzu7qs/TbgiyXicVkI/AAAAAAAAKvU/-FyD3gMzaUU/s320/answer_math_equatioin_to_snooze_or_dismiss.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Solve a simple equation to unlock snooze/dismiss buttons&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-RNj6TnuSxSQ/Tbgi1OIoa-I/AAAAAAAAKvY/Zdtj7LIpUi4/s1600/enter_password_to_snooze_or_dismiss.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-RNj6TnuSxSQ/Tbgi1OIoa-I/AAAAAAAAKvY/Zdtj7LIpUi4/s320/enter_password_to_snooze_or_dismiss.png" width="192" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Enter specified or random-generated password to unlock snooze/dismiss buttons&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;You can install this new alpha version &lt;a href="http://dl.dropbox.com/u/946518/BozaAlarm-release.free.v3.12a.apk"&gt;from my Dropbox space&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6063831843272092523?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ln6IngzQkWI6gg-a4KF0dliBeDA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ln6IngzQkWI6gg-a4KF0dliBeDA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ln6IngzQkWI6gg-a4KF0dliBeDA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ln6IngzQkWI6gg-a4KF0dliBeDA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/1VuyUfxDT4c" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6063831843272092523?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6063831843272092523?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/1VuyUfxDT4c/new-alpha-version-for-features-ive.html" title="New alpha version for features I've implemented since v3.07b" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-Q4OPZ4HJ6_4/TbbQmcWDfMI/AAAAAAAAKu8/cMlU0k0Cf08/s72-c/select_application.png" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/new-alpha-version-for-features-ive.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4BQH0yfCp7ImA9WhZQGE8.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-4510720166661509713</id><published>2011-04-26T22:09:00.000+08:00</published><updated>2011-04-26T22:09:11.394+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-26T22:09:11.394+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>New alarm action to launch an application main activity</title><content type="html">I was struggling to add this feature my application because I believe it won't do much help. Still, I tried to implement this as a practice. It's pretty easy to get all installed applications on the phone by these lines.&lt;br /&gt;
&lt;br /&gt;
&lt;script class="brush: java" type="syntaxhighlighter"&gt;
&lt;![CDATA[
private void loadInstalledApplications() {
    final PackageManager pm = getPackageManager();
    List&lt;applicationinfo&gt; appInfos = pm.getInstalledApplications(PackageManager.GET_META_DATA);
    Collections.sort(appInfos,                     
                     new Comparator&lt;applicationinfo&gt;() {
                          public int compare(ApplicationInfo obj1, ApplicationInfo obj2) {
                              String s1 = obj1.loadLabel(pm).toString();
                              String s2 = obj2.loadLabel(pm).toString();
                              return s1.compareTo(s2);
                          }
                     });
]]&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
and you can launch the main activity of an application by &lt;br /&gt;
&lt;pre class="brush:java"&gt;Intent launchIntent = pm.getLaunchIntentForPackage(packageName);
launchIntent.setFlags(Intent.FLAG_ACTIVIY_NEW_TASK|Intent.FLAG_ACTIVITY_NO_USER_ACTION);
context.startActivity(launchIntent);
&lt;/pre&gt;&lt;br /&gt;
What I said it doesn't do much help is that you can only bring up an activity unless you know how to talk to it through its public interface.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-4510720166661509713?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GSr51kkXUSRN_RWEay1NywFD2TA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GSr51kkXUSRN_RWEay1NywFD2TA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GSr51kkXUSRN_RWEay1NywFD2TA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GSr51kkXUSRN_RWEay1NywFD2TA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/4umCinzw9ts" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/4510720166661509713?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/4510720166661509713?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/4umCinzw9ts/new-alarm-action-to-launch-application.html" title="New alarm action to launch an application main activity" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/new-alarm-action-to-launch-application.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QDQno5fyp7ImA9WhZQFEs.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-74186377938657168</id><published>2011-04-22T17:42:00.000+08:00</published><updated>2011-04-22T17:42:53.427+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-22T17:42:53.427+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>How to toggle power controls (Wi-Fi, GPS, bluetooth, brightness, sync)</title><content type="html">This topic has been asked on Android forums regularly and sometimes you are told not to turn on/off GPS/Bluetooth without consents from users. That's true.&lt;br /&gt;
&lt;br /&gt;
Despite this consent issue, what is the simplest way to toggle power controls programmatically? For Android 2.1+, my opinion is to take advantage of the code Settings already provides.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;Intent intent = new Intent();
intent.setClassName("com.android.settings","com.android.settings.widget.SettingsAppWidgetProvider");
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
intent.setData(Uri.parse("custom:" + getButtonId()));
context.sendBroadcast(intent);
&lt;/pre&gt;&lt;br /&gt;
The getButtonId() returns the button id on the PowerControl widget. You can try to put this widget on your device. It is not impossible that these button ids are changed in the future Android release or by vendors. But, I have to say it's not very likely to happen.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Wi-Fi: &amp;nbsp;0&lt;/li&gt;
&lt;li&gt;Brightness: 1&lt;/li&gt;
&lt;li&gt;Sync: 2&lt;/li&gt;
&lt;li&gt;GPS: 3&lt;/li&gt;
&lt;li&gt;Bluetooth: 4&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Another advantage of using this is the reduction of hardware permissions you have to declare.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-74186377938657168?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Q_F4KHexbTorUg7fPfQOGvqWqYo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q_F4KHexbTorUg7fPfQOGvqWqYo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Q_F4KHexbTorUg7fPfQOGvqWqYo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q_F4KHexbTorUg7fPfQOGvqWqYo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/3PFpI8b_Hr0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/74186377938657168?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/74186377938657168?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/3PFpI8b_Hr0/how-to-toggle-power-controls-wi-fi-gps.html" title="How to toggle power controls (Wi-Fi, GPS, bluetooth, brightness, sync)" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/how-to-toggle-power-controls-wi-fi-gps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIBSX0zeCp7ImA9WhZQE0o.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6853869998582569327</id><published>2011-04-21T16:12:00.000+08:00</published><updated>2011-04-21T16:12:38.380+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-21T16:12:38.380+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>New alpha version of BozaAlarm v3.01a</title><content type="html">I've implemented these experimental changes into this new alpha version - v3.01a.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;GPS and Bluetooth toggling action.&lt;/li&gt;
&lt;li&gt;Wi-Fi action has no toggling option any more. It toggles current Wi-Fi state.&lt;/li&gt;
&lt;li&gt;Honor user's group-by setting when viewing alarms through View/All.&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;This new test release can be downloaded &lt;a href="http://dl.dropbox.com/u/946518/BozaAlarm-release.free-v3.01a.apk"&gt;here in my Dropbox space.&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6853869998582569327?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9j1ytLOPTyJgwgLdwPIFBl2yd3g/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9j1ytLOPTyJgwgLdwPIFBl2yd3g/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9j1ytLOPTyJgwgLdwPIFBl2yd3g/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9j1ytLOPTyJgwgLdwPIFBl2yd3g/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/O_Q3IJA7mV4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6853869998582569327?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6853869998582569327?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/O_Q3IJA7mV4/new-alpha-version-of-bozaalarm-v301a.html" title="New alpha version of BozaAlarm v3.01a" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/new-alpha-version-of-bozaalarm-v301a.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8ERno9eSp7ImA9WhZRE04.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6685742520669222085</id><published>2011-04-09T15:07:00.002+08:00</published><updated>2011-04-09T15:40:07.461+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-09T15:40:07.461+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Journal" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>How CursorAdapter works</title><content type="html">For people who are new to Android development, sometimes, they are wondering why &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CursorAdapter&lt;/span&gt; know when to refresh your UI and how the connection between your model and view is set?&lt;br /&gt;
&lt;br /&gt;
I looked into the Android source code and learned that &lt;b&gt;&lt;i&gt;two key method calls&lt;/i&gt;&lt;/b&gt; will establish this connection. This following diagram was drawn in order to understand how your model (Database) and View (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AdapterView&lt;/span&gt;) are bound together. From this diagram, we can see&lt;br /&gt;
&lt;ol&gt;&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Cursor.setNotificationUri(ContentResolver, Uri)&lt;/li&gt;
&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentResolver.notifyChange(...)&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;The first call will insert an hash entry (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Uri&lt;/span&gt;, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Cursor&lt;/span&gt;) into the hash map hold by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentResolver&lt;/span&gt; (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentService&lt;/span&gt;) so that &lt;u&gt;&lt;i&gt;whenever the data pointed by this &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Uri&lt;/span&gt; object is changed, it will requery the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Cursor&lt;/span&gt; object.&lt;/i&gt;&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
But the question is how &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentResolver &lt;/span&gt;knows your data is changed? It's your responsibility to tell it. In your implementation of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentProvider&lt;/span&gt; or &lt;i&gt;&lt;b&gt;internal database&lt;/b&gt;&lt;/i&gt;, when you insert, delete, update the data successfully, you need to call &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentResolver.notifyChange(Uri, ...)&lt;/span&gt; to let &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentResolver&lt;/span&gt; know it should requery the hosted &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Cursor&lt;/span&gt; object keyed by the passed &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Uri&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
As for the internal database, if it is &lt;span style="font-family: &amp;quot;Inconsolata&amp;quot;,Courier,monospace;"&gt;SQLiteDatabase&lt;/span&gt;, I prefer using &lt;i&gt;&lt;b&gt;non-exported&lt;/b&gt;&lt;/i&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContentProvider&lt;/span&gt; because its well-established interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;iframe frameborder="0" height="560px" src="https://docs.google.com/viewer?a=v&amp;amp;pid=explorer&amp;amp;chrome=false&amp;amp;embedded=true&amp;amp;srcid=0B0ZUw6inr9WXYzZiODA2ZTktYTc3Ny00MTk5LTlkYjEtZTQ5MDc5MDQ4MjZm&amp;amp;authkey=CJGVvOUJ&amp;amp;hl=en" width="100%"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6685742520669222085?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tSwyuo0iaOsm_1Y8ADbhxUY0QCg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tSwyuo0iaOsm_1Y8ADbhxUY0QCg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tSwyuo0iaOsm_1Y8ADbhxUY0QCg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tSwyuo0iaOsm_1Y8ADbhxUY0QCg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/OTFdwxjSxkU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6685742520669222085?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6685742520669222085?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/OTFdwxjSxkU/for-people-who-are-new-to-android.html" title="How CursorAdapter works" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/for-people-who-are-new-to-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUGQX0yeSp7ImA9WhZRE08.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6513507609414037057</id><published>2011-04-09T11:37:00.000+08:00</published><updated>2011-04-09T11:37:00.391+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-09T11:37:00.391+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Journal" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>Customize the layout of PreferenceActivity</title><content type="html">In my application, I'd like to have non-&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Preference&lt;/span&gt; items shown on a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PreferenceActivity&lt;/span&gt; like the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;TimePicker&lt;/span&gt; widget below,&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-7cGCVUDNaVU/TYjbts7uYTI/AAAAAAAAKfU/nMmfM4FmziM/s1600/5547258826_4c5fc2c9d0_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-7cGCVUDNaVU/TYjbts7uYTI/AAAAAAAAKfU/nMmfM4FmziM/s320/5547258826_4c5fc2c9d0_b.jpg" width="192" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Actually, it is easy to get this. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PreferenceActivity&lt;/span&gt; sets its content view to a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ListView&lt;/span&gt; with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;list&lt;/span&gt; as its view id.&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(com.android.internal.R.layout.preference_list_content);
        
        mPreferenceManager = onCreatePreferenceManager();
        getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
    }
&lt;/pre&gt;and this &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;preference_list_content&lt;/span&gt; is just a ListView,&lt;br /&gt;
&lt;script class="brush: xml" type="syntaxhighlighter"&gt;
&lt;![CDATA[
&lt;listview xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
    android:layout_width="match_parent" 
    android:layout_height="match_parent"
    android:drawSelectorOnTop="false"
    android:scrollbarAlwaysDrawVerticalTrack="true"
    /&gt;
]]&gt;
&lt;/script&gt;&lt;br /&gt;
which can be replaced by your own layout xml file as long as it contains one &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ListView&lt;/span&gt; with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;android:id/list&lt;/span&gt; as its id. You can put as many widgets as you want in this layout xml file and use &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;setContentView()&lt;/span&gt; to use it in your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;onCreate()&lt;/span&gt; method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6513507609414037057?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6MX-8AiDKzfq-Hd1l-d9D59Q8k4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6MX-8AiDKzfq-Hd1l-d9D59Q8k4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6MX-8AiDKzfq-Hd1l-d9D59Q8k4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6MX-8AiDKzfq-Hd1l-d9D59Q8k4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/nlz_JgFvwms" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6513507609414037057?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6513507609414037057?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/nlz_JgFvwms/customize-layout-of-preferenceactivity.html" title="Customize the layout of PreferenceActivity" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-7cGCVUDNaVU/TYjbts7uYTI/AAAAAAAAKfU/nMmfM4FmziM/s72-c/5547258826_4c5fc2c9d0_b.jpg" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/customize-layout-of-preferenceactivity.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EMQXw_fCp7ImA9WhZREkk.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-5472773408994633393</id><published>2011-04-08T14:54:00.000+08:00</published><updated>2011-04-08T14:54:40.244+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-08T14:54:40.244+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenAlarm" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Journal" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>Why TaskKiller prevents my Alarm apps from working</title><content type="html">It is well-known that task killers on the Android Market prevents Alarm applications from working. But why? To understand this, we should understand how alarms in Android are handled. A hardware alarm event should go through 2 layers to bring up your software component.&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Hardware alarm event&lt;/li&gt;
&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;b&gt;AlarmManagerService&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Your application components to handle alarms &lt;/li&gt;
&lt;/ol&gt;&lt;i&gt;The AlarmManagerService stores the information required to link hardware alarm event to your application components.&lt;/i&gt; The task killer actutually removes these information from AlarmManagerService and this is why your Alarm application doesn't work after a task killer kills your application.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;For devices running Android 2.1 and below&lt;/b&gt;&lt;/i&gt;, the method the task killer uses to kill an application is &lt;a href="http://developer.android.com/reference/android/app/ActivityManager.html#restartPackage%28java.lang.String%29"&gt;ActivityManager.restartPackage(String)&lt;/a&gt; that in turn triggers the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;UninstallReceiver&lt;/span&gt; defined in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AlarmManagerService&lt;/span&gt; to remove all links registered by your application.&lt;br /&gt;
&lt;pre class="brush:java"&gt;class UninstallReceiver extends BroadcastReceiver {
        public UninstallReceiver() {
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); // &amp;lt;------ this line
            filter.addDataScheme("package");
            mContext.registerReceiver(this, filter);
        }
        
        @Override
        public void onReceive(Context context, Intent intent) {
            synchronized (mLock) {
                Uri data = intent.getData();
                if (data != null) {
                    String pkg = data.getSchemeSpecificPart();
                    removeLocked(pkg);
                    mBroadcastStats.remove(pkg);
                }
            }
        }
    }
&lt;/pre&gt;&lt;br /&gt;
But, in Android 2.2, things changed. The restartPackage method is changed to be just a wrapper of a new method &lt;a href="file:///home/yenliangl/tools/android-sdk-linux_86/docs/reference/android/app/ActivityManager.html#killBackgroundProcesses%28java.lang.String%29"&gt;killBackgroundProcesses&lt;/a&gt;. So, task killers on the Market are doing the same thing as default &lt;i&gt;&lt;b&gt;Out-Of-Memory (OOM) killer&lt;/b&gt;&lt;/i&gt;. Although we can still install them to proactively kill processes, but they are not necessary any more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-5472773408994633393?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/G4onRbU6biHOO-F-tVjth3p4mxI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/G4onRbU6biHOO-F-tVjth3p4mxI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/G4onRbU6biHOO-F-tVjth3p4mxI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/G4onRbU6biHOO-F-tVjth3p4mxI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/23lNh9ZNxqU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/5472773408994633393?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/5472773408994633393?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/23lNh9ZNxqU/why-taskkiller-prevents-my-alarm-apps.html" title="Why TaskKiller prevents my Alarm apps from working" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/why-taskkiller-prevents-my-alarm-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4ARnc7fCp7ImA9WhZREkk.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-2792097727547599323</id><published>2011-04-08T14:25:00.001+08:00</published><updated>2011-04-08T14:25:47.904+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-08T14:25:47.904+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Journal" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>A Preference that get result back from Activity it started</title><content type="html">We know that Preferences in Android don't provide &lt;i&gt;&lt;b&gt;public interface&lt;/b&gt;&lt;/i&gt; to get result back from the activities they launched. The only clue we can find is that RingtonePreference has done the exact thing in protected level. Fortunately, It is very easy to extend RingtonePreference.&lt;br /&gt;
&lt;br /&gt;
So, this is the behavior of RingtonePreference that we want to achieve, &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Click to start our activity (not RingtonePicker) &lt;/li&gt;
&lt;li&gt;Get result back from activity and store it as SharedPreference for later use. (any kind of result other than Ringtone Uri)&lt;/li&gt;
&lt;/ol&gt;you definitely need to do some modifications on RingtonePreference as I did.&lt;br /&gt;
&lt;br /&gt;
I am developing a ContactPreference in my application that starts an activity for user to pick contacts and returns them back to the ContactPreference. Here is what I did by overriding RingtonePreference,&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;public class ContactPreference extends android.preference.RingtonePreference {
    // 
    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        if (super.onActivityResult(requestCode, resultCode, data)) {
            ArrayList&lt;string&gt; addrList =null;
            if (data != null) {    
                addrList = data.getStringArrayListExtra(ContactPicker.EXTRA_ADDRESS_LIST);
            }
            onSaveAddressList(addrList);                       
            return true;                     
        }                          
        return false;             
    }

    @Override
    protected void onPrepareRingtonePickerIntent(Intent intent) {
        // Remove all extras already placed by RingtonePreference
        intent.setAction(null);
        intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
        intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT);
        intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI);
        intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT);
        intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_TYPE);

        // Set the activity we want to start.
        intent.setClass(getContext(), ContactPicker.class);

        // Addresses that was picked. So that your activity can handle it, s.t., checked them on/off.
        ArrayList&lt;string&gt; addrList = onRestoreAddressList();
        if (addrList != null) {
            intent.putStringArrayListExtra(ContactPicker.EXTRA_ADDRESS_LIST, addrList);
        }
    }
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-2792097727547599323?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Fr7BWh9BqLbfP-jCFBx1gl1BGuo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Fr7BWh9BqLbfP-jCFBx1gl1BGuo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Fr7BWh9BqLbfP-jCFBx1gl1BGuo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Fr7BWh9BqLbfP-jCFBx1gl1BGuo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/z6S9dM3j7EU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2792097727547599323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2792097727547599323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/z6S9dM3j7EU/preference-that-receives-activity.html" title="A Preference that get result back from Activity it started" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/04/preference-that-receives-activity.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4CRn48eyp7ImA9WhZREkk.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-2799198957540556612</id><published>2011-03-25T16:45:00.002+08:00</published><updated>2011-04-08T14:26:07.073+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-08T14:26:07.073+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="Journal" /><category scheme="http://www.blogger.com/atom/ns#" term="BozaAlarm" /><title>aidl file of Winamp</title><content type="html">I've been experimenting adding support for Winamp in my application that is supposed to be released soon. &amp;nbsp; But the first thing I need to consider is a correct Android interface file that describes the interface Winamp's music service has. After several trial&amp;amp;error, I have some findings,&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Winamp uses built-in MediaStore provider.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Playlists created in built-in Music application can be seen in Winamp and playlists created from Winamp can be seen in built-in Music application.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Winamp uses built-in IMediaPlaybackService.aidl which package names replaced with &lt;b&gt;com.nullsoft.winamp&lt;/b&gt;. Still, it changes some code that makes my integration difficult. Here are my steps to guess its aidl interface,&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Installed Winamp in a rooted device and debug it.&lt;/li&gt;
&lt;li&gt;Because Winamp doesn't obfuscate its code, we can use Java's reflection to see its class and method interfaces easily. In jdb,&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Run '&lt;b&gt;classes'&lt;/b&gt; to see all classes started with com.nullsoft.winamp. You can see one line for &lt;b&gt;com.nullsoft.winamp.IMediaPlaybackService&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Run '&lt;b&gt;methods&amp;nbsp;&lt;/b&gt;&lt;b&gt;com.nullsoft.winamp.IMediaPlaybackService'&lt;/b&gt;&amp;nbsp;to list all method declaration of this class. You can see it not having differences than standard IMediaPlaybackService.&lt;/li&gt;
&lt;pre class="brush:java"&gt;com.nullsoft.winamp.IMediaPlaybackService duration()
com.nullsoft.winamp.IMediaPlaybackService enqueue(long[], int)
com.nullsoft.winamp.IMediaPlaybackService getAlbumId()
com.nullsoft.winamp.IMediaPlaybackService getAlbumName()
com.nullsoft.winamp.IMediaPlaybackService getArtistId()
com.nullsoft.winamp.IMediaPlaybackService getArtistName()
com.nullsoft.winamp.IMediaPlaybackService getAudioId()
com.nullsoft.winamp.IMediaPlaybackService getMediaMountedCount()
com.nullsoft.winamp.IMediaPlaybackService getPath()
com.nullsoft.winamp.IMediaPlaybackService getQueue()
com.nullsoft.winamp.IMediaPlaybackService getQueueLen()
com.nullsoft.winamp.IMediaPlaybackService getQueuePosition()
com.nullsoft.winamp.IMediaPlaybackService getRepeatMode()
com.nullsoft.winamp.IMediaPlaybackService getShuffleMode()
com.nullsoft.winamp.IMediaPlaybackService getTrackName()
com.nullsoft.winamp.IMediaPlaybackService isPlaying()
com.nullsoft.winamp.IMediaPlaybackService moveQueueItem(int, int)
com.nullsoft.winamp.IMediaPlaybackService next()
com.nullsoft.winamp.IMediaPlaybackService open(long[], int)
com.nullsoft.winamp.IMediaPlaybackService openFile(java.lang.String, boolean)
com.nullsoft.winamp.IMediaPlaybackService openFileAsync(java.lang.String)
com.nullsoft.winamp.IMediaPlaybackService pause()
com.nullsoft.winamp.IMediaPlaybackService play()
com.nullsoft.winamp.IMediaPlaybackService position()
com.nullsoft.winamp.IMediaPlaybackService prev()
com.nullsoft.winamp.IMediaPlaybackService quit()
com.nullsoft.winamp.IMediaPlaybackService removeTrack(long)
com.nullsoft.winamp.IMediaPlaybackService removeTracks(int, int)
com.nullsoft.winamp.IMediaPlaybackService seek(long)
com.nullsoft.winamp.IMediaPlaybackService setQueuePosition(int)
com.nullsoft.winamp.IMediaPlaybackService setRepeatMode(int)
com.nullsoft.winamp.IMediaPlaybackService setShuffleMode(int)
com.nullsoft.winamp.IMediaPlaybackService stop()
&lt;/pre&gt;&lt;/ul&gt;&lt;li&gt;Duplicate IMediaPlaybackService.aidl from built-in Music code and replace its package name, include this file in your project.&lt;/li&gt;
&lt;li&gt;Although the code builds successfully, it doesn't work as expected.&lt;br /&gt;
&lt;pre class="brush:java"&gt;public void onServiceConnected(ComponentName name, IBinder binder) {
    com.nullsoft.winamp.IMediaPlaybackService s = com.nullsoft.winamp.IMediaPlaybackService.Stub.asInterface(binder);
    try {
        // s.isPlaying() and s.top() are working.
        if (s.isPlaying()) {
            s.stop();
        }

        // s.open() broadcasts com.nullsoft.winamp.queuechanged if audio ids
        // are set successfully. 
        s.open(mData, 0);

        /* s.next() works but only plays one song and causes 
           com.nullsoft.winamp.playstatechanged and com.nullsoft.winamp.metachanged
           broadcasted. */ 
        s.next();

        /* s.play() doesn't work. Guess that MediaPlayer is not initialized if Winamp doesn't 
           change too much from standard Music */
        // s.play();
    } catch (RemoteException e) {
    }
}
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;I should do more experiments to guess how it responds to different parameters and modes. &lt;/li&gt;
&lt;/ul&gt;&lt;/ol&gt;&lt;div&gt;This process (reverse engineering) is normally what authors of an application don't want people do on their applications.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;OBFUSCATE YOUR APPLICATION IF YOU DO MIND.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-2799198957540556612?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/htGNJ6JnCx7mDoLnvfd5OhUjuEs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/htGNJ6JnCx7mDoLnvfd5OhUjuEs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/htGNJ6JnCx7mDoLnvfd5OhUjuEs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/htGNJ6JnCx7mDoLnvfd5OhUjuEs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/HSbbbxVyQhg" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2799198957540556612?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2799198957540556612?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/HSbbbxVyQhg/aidl-file-of-winamp.html" title="aidl file of Winamp" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/03/aidl-file-of-winamp.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4GRX0-eSp7ImA9Wx9UE0g.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-1479971431294916733</id><published>2011-02-10T23:48:00.000+08:00</published><updated>2011-02-10T23:48:44.351+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-10T23:48:44.351+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Linux/Ubuntu" /><category scheme="http://www.blogger.com/atom/ns#" term="Font" /><category scheme="http://www.blogger.com/atom/ns#" term="MacOS" /><title>Two X11 bitmap fonts for Mac</title><content type="html">I came across these two X11 bitmap fonts, &lt;a href="http://zevv.nl/play/code/zevv-peep/"&gt;peep&lt;/a&gt; and &lt;a href="http://www.jmknoble.net/fonts/"&gt;neep-alt&lt;/a&gt;. I love what they looks in Linux, but their original sites don't provide MacOS counterparts. I used FontForge to generate their Mac dfont versions.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://dl.dropbox.com/u/946518/Mac%20fonts/NeepAltBold.dfont"&gt;NeepAltBold&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dl.dropbox.com/u/946518/Mac%20fonts/NeepAltMedium.dfont"&gt;NeepAltMedium&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dl.dropbox.com/u/946518/Mac%20fonts/NeepBold.dfont"&gt;NeepBold&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dl.dropbox.com/u/946518/Mac%20fonts/NeepMedium.dfont"&gt;NeepMedium&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dl.dropbox.com/u/946518/Mac%20fonts/peepMedium.dfont"&gt;peepMedium&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-1479971431294916733?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/itmmJFQJiKFUaFtYFrCkNj40MQE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/itmmJFQJiKFUaFtYFrCkNj40MQE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/itmmJFQJiKFUaFtYFrCkNj40MQE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/itmmJFQJiKFUaFtYFrCkNj40MQE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/eXPjvFM4VVY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/1479971431294916733?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/1479971431294916733?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/eXPjvFM4VVY/two-x11-bitmap-fonts-for-mac.html" title="Two X11 bitmap fonts for Mac" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/02/two-x11-bitmap-fonts-for-mac.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IGR3Y_fyp7ImA9Wx9WGUo.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-1506337748813293614</id><published>2011-01-25T00:36:00.021+08:00</published><updated>2011-01-26T00:05:26.847+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-26T00:05:26.847+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="MacOS" /><category scheme="http://www.blogger.com/atom/ns#" term="Emacs" /><title>Use Emacs/JDEE in Android Development</title><content type="html">Eclipse/ADT is a great tool for Android development. But for people using Emacs, it is difficult to get used to it. Fortunately, JDEE is easy to be customized to work on Android development. Here are my settings on my MacBookPro,&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:text"&gt;;; Load JDEE
(require 'jde)

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(jde-global-classpath (quote ("~/android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar" "~/android/out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar" "~/android/out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes.jar" "~/android/out/out/target/common/obj/JAVA_LIBRARIES/android.policy_intermediates/classes.jar")))
 '(jde-jdk-registry (quote (("1.5.0" . "/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0"))))
 '(jde-sourcepath (quote ("~/android/source/frameworks/base/services" "~/android/source/frameworks/base/core/java" "~/android/source/dalvik/libcore/luni/src/main/java")))
&lt;/pre&gt;&lt;br /&gt;
Here, I have android source code in ~/android/source and build in ~/android/out. If you are using SDK, you should add android.jar in SDK to jde-global-classpath. Also, you can put these settings into a per-project file prj.el in your project top directory for JDEE to load.&lt;br /&gt;
&lt;br /&gt;
For example, my prj.el in one of my project looks like,&lt;br /&gt;
&lt;pre class="brush:text"&gt;(jde-project-file-version "1.0")

;; Reset class path and source path
(jde-set-variables
 '(jde-project-name "openalarm-android")
 '(jde-gen-buffer-boilerplate
   '("/**"
     "*  OpenAlarm - an extensible alarm for Android"
     "*  Copyright (C) 2010 Liu Yen-Liang (Josh)"
     "*"
     "*"
     "*  This program is free software: you can redistribute it and/or modify"
     "*  it under the terms of the GNU General Public License as published by"
     "*  the Free Software Foundation, either version 3 of the License, or"
     "*  (at your option) any later version."
     "*"
     "*  This program is distributed in the hope that it will be useful,"
     "*  but WITHOUT ANY WARRANTY; without even the implied warranty of"
     "*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"
     "*  GNU General Public License for more details."
     "*"
     "*  You should have received a copy of the GNU General Public License"
     "*  along with this program. If not, see &lt;http: licenses="" www.gnu.org=""&gt;."
     "*/"))
 '(jde-log-max 5000)
 '(jde-enable-abbrev-mode t)
 ;; Class path for browsing files and generate code templates
 '(jde-global-classpath
   (quote ("$ANDROID_SDK_ROOT/platforms/android-7/android.jar"
           "$HOME/projects/openalarm-android/bin")))
 '(jde-sourcepath
   (quote ("$HOME/projects/openalarm-android/src"
           "$HOME/android/eclair_21/frameworks/base/core/java")
          ))
 '(jde-compile-option-directory "$HOME/projects/openalarm-android/bin") 
 '(jde-complete-function (quote jde-complete-menu)) 
 '(jde-run-working-directory "$HOME/projects/openalarm-android/bin")
 '(jde-help-docsets
   (quote (("Android SDK Doc" "$ANDROID_SDK_ROOT/docs/index.html" nil))))
 '(jde-build-function (quote (jde-ant-build)))
 '(jde-ant-args "-emacs")
 '(jde-ant-complete-target t)
 '(jde-ant-enable-find t) 
 '(jde-ant-read-args nil)
 '(jde-ant-read-buildfile nil)
 '(jde-ant-read-target nil)
 '(jde-ant-use-global-classpath nil)
 '(jde-ant-working-directory "$HOME/projects/openalarm-openalarm/bin/") 
 '(jde-built-class-path (quote ("$HOME/projects/openalarm-android/bin")))
 )
&lt;/pre&gt;These settings enable us using method completion, source browsing, etc. But, I am still experimenting if we can build android target in JDEE.&lt;br /&gt;
&lt;br /&gt;
For MacOS users: the environment variables must be defined in ~/.MacOSX/environemtn.plist&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-1506337748813293614?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kstTBCTs27gTSAxyrvLfNs94Rqk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kstTBCTs27gTSAxyrvLfNs94Rqk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kstTBCTs27gTSAxyrvLfNs94Rqk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kstTBCTs27gTSAxyrvLfNs94Rqk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/E1x__XHYg88" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/1506337748813293614?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/1506337748813293614?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/E1x__XHYg88/use-emacsjdee-in-android-development.html" title="Use Emacs/JDEE in Android Development" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2011/01/use-emacsjdee-in-android-development.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcDQXw9fSp7ImA9WxFVEEw.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-9045967987344446191</id><published>2010-06-09T00:04:00.000+08:00</published><updated>2010-06-09T00:04:30.265+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-09T00:04:30.265+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>AppWidget design - Can I use my own custom widget?</title><content type="html">The answer to the question is probably no. But, not impossible. If you take a look at the design of AppWidget class family. You should know that a class that doesn't meet all requirements below can't be inflated in the layout of an AppWidget.&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Annotated by RemoteViews&lt;/li&gt;
&lt;li&gt;Can't be found by PathClassLoader with default class path - "."&lt;/li&gt;
&lt;/ol&gt;The first one is simple because RemoteViews is not private interface. You can annotate your custom class by RemoteViews as Android widgets do.&lt;br /&gt;
&lt;br /&gt;
The second one is not easy to attack. You need to know where this dot refers to. It is actually defined as an environment variable BOOTCLASSPATH in a file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;init.rc&lt;/span&gt; wrapped in your boot.img or ramdisk.img.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/org.startsmall.widget.jar&lt;/blockquote&gt;So, you need to,&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Wrap your widget class in a jar library.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Archive classes.dex only.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Put your jar library into system.img.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;The system.img can be decompressed by unyaffs. Decompress it and put jar library into system/framework.&lt;/li&gt;
&lt;li&gt;Compress whole system/ directory back to system.img by mkyaffs2image.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Modify init.rc to add custom widget jar into BOOTCLASSPATH.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;The boot.img/ramdisk.img is just a cpio archive. Decompress&amp;nbsp; ramdisk.img, do modification to init.rc and archive it back as cpio file.&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Put the system.img and ramdisk.img to your avd directory (~/.android/avd/avd-XXX). Start emulator and use logcat to see whether your custom jar library is loaded by Android.&lt;/li&gt;
&lt;/ol&gt;Although you can use your custom widget class now, but &lt;i&gt;you may soon find you can't actually use non-RemotableViews annotated method through RemoteViews set methods.&lt;/i&gt; Defeated? Not really, if you are willing to hack Android, I guess you still can modify Android source code to make RemotableMethod visible to your custom widget class.&lt;br /&gt;
&lt;br /&gt;
If you don't want to do it, you need to make your custom widget self-handled. You can't update custom widgets by set methods of RemoteViews, but &lt;i&gt;you can send broadcasts to update it because AppWidgetHostView instantiates custom widgets in your context.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
You can see from above that it is possible to write custom widget class to be used in AppWidget design only when you have permissions to access image files. This means either you work for a phone company or you make custom ROMs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-9045967987344446191?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eqDPHGWuyfNEjEQFJlUMFoGE6MU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eqDPHGWuyfNEjEQFJlUMFoGE6MU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eqDPHGWuyfNEjEQFJlUMFoGE6MU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eqDPHGWuyfNEjEQFJlUMFoGE6MU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/e5JDDQyE0wQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/9045967987344446191?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/9045967987344446191?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/e5JDDQyE0wQ/appwidget-design-can-i-use-my-own.html" title="AppWidget design - Can I use my own custom widget?" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2010/06/appwidget-design-can-i-use-my-own.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8HQno7eSp7ImA9WxFXFko.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-2991190642885492564</id><published>2010-05-24T13:10:00.000+08:00</published><updated>2010-05-24T13:10:33.401+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-24T13:10:33.401+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Views that can be used along with RemoteViews</title><content type="html">Views must be annotated &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RemoteView&lt;/span&gt; in order to be used in the layout file inflated by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LayoutInflater&lt;/span&gt;. Look into source code of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RemoteViews&lt;/span&gt;. You can find an interface that is used to do annotation.&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoteView {
}
&lt;/pre&gt;&lt;br /&gt;
And, for views that supports &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RemoteViews&lt;/span&gt; have &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RemoteView&lt;/span&gt; annotation in the beginning of their class definition. For example,&lt;br /&gt;
&lt;pre class="brush:java"&gt;@RemoteView
public class LinearLayout extends ViewGroup {
 // ...
}
&lt;/pre&gt;&lt;br /&gt;
In the latest Android source, views that supports &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RemoteViews&lt;/span&gt; are,&lt;br /&gt;
&lt;blockquote&gt;AbsoluteLayout.java:40:@RemoteView&lt;br /&gt;
AnalogClock.java:39:@RemoteView&lt;br /&gt;
Button.java:58:@RemoteView&lt;br /&gt;
Chronometer.java:45:@RemoteView&lt;br /&gt;
FrameLayout.java:47:@RemoteView&lt;br /&gt;
ImageButton.java:71:@RemoteView&lt;br /&gt;
ImageView.java:55:@RemoteView&lt;br /&gt;
LinearLayout.java:44:@RemoteView&lt;br /&gt;
ProgressBar.java:123:@RemoteView&lt;br /&gt;
RelativeLayout.java:66:@RemoteView&lt;br /&gt;
TextView.java:186:@RemoteView&lt;br /&gt;
ViewFlipper.java:38:@RemoteView&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-2991190642885492564?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/mmpJ2ZDg5df-qlc9PEv9V2M4wUw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/mmpJ2ZDg5df-qlc9PEv9V2M4wUw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/mmpJ2ZDg5df-qlc9PEv9V2M4wUw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/mmpJ2ZDg5df-qlc9PEv9V2M4wUw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/F-FLfNYZMCE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2991190642885492564?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/2991190642885492564?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/F-FLfNYZMCE/views-that-can-be-used-along-with.html" title="Views that can be used along with RemoteViews" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2010/05/views-that-can-be-used-along-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8DQHY7eSp7ImA9WhZRE0w.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-6885748203377746643</id><published>2010-04-21T17:16:00.001+08:00</published><updated>2011-04-09T10:41:11.801+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-09T10:41:11.801+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>Android UI Prototyping</title><content type="html">If you are from Qt world which has excellent Qt-designer served as a good prototyping tool since its early version, you probably are disappointed about the lack of prototyping tools in Android world.&lt;br /&gt;
&lt;br /&gt;
We already has &lt;a href="http://www.droiddraw.org/"&gt;DroidDraw&lt;/a&gt;, but it still has a long way to go, though. I came across a website and it mentions &lt;a href="http://www.artfulbits.com/Android/Stencil.aspx"&gt;Android GUI Prototyping&lt;/a&gt; that adds Android prototyping into your Visio template sets. I am not familiar with Visio and I normally use the primitive toolkit (pen, paper and glue) to do prototyping. I don't know if this Visio stuff works for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-6885748203377746643?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xALkB-qxydN-_7VT-zS6MqOSVOA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xALkB-qxydN-_7VT-zS6MqOSVOA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xALkB-qxydN-_7VT-zS6MqOSVOA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xALkB-qxydN-_7VT-zS6MqOSVOA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/TmF4jJ-ePWo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6885748203377746643?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/6885748203377746643?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/TmF4jJ-ePWo/android-ui-prototyping.html" title="Android UI Prototyping" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><feedburner:origLink>http://yenliangl.blogspot.com/2010/04/android-ui-prototyping.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEHQ3c6eip7ImA9WxFSE0U.&quot;"><id>tag:blogger.com,1999:blog-3040027623434763832.post-8178681309121428530</id><published>2010-04-13T11:35:00.004+08:00</published><updated>2010-04-16T10:57:12.912+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-16T10:57:12.912+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenAlarm" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><title>New release of OpenAlarm</title><content type="html">A new version of OpenAlarm is released at 04/15/2010. This version has several minor bug fixes and some UI changes.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Fixed FC when no default ringtone exists.&lt;/li&gt;
&lt;li&gt;Fixed silent alarm if no ringtone specified (Play fallback ringtone instead).&lt;/li&gt;
&lt;li&gt;Fallback to normal mode if user selects password mode but no password set.&lt;/li&gt;
&lt;li&gt;Users can pull phone number directly from contact database in Phone alarms. The rule of picking a number to call is&lt;/li&gt;

&lt;ol&gt;&lt;li&gt;Default phone number if exists.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;First phone number.&lt;/li&gt;
&lt;li&gt;No phone number for this person and show "no phone number" error message along with the name of this person.&lt;/li&gt;
&lt;/ol&gt;
&lt;li&gt;Justify the position of the banner so that it is at the center of the screen.&lt;/li&gt;
&lt;li&gt;Use hardware search button to apply another search to an filtered result is NOT allowed anymore.&lt;/li&gt;
&lt;li&gt;Insert device information to the e-mail caused by the clicking on my email address in the About dialog.&lt;/li&gt;
&lt;li&gt;UI changes. Move &lt;b&gt;New&lt;/b&gt; menu item to the main screen.&lt;/li&gt;
&lt;li&gt;Add explicit on/off settings to ToggleSwitch.&lt;/li&gt;
&lt;/ul&gt;這個版本修正了一些小臭蟲以及使用者介面上的一些小改變。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;修正當沒有預設響鈴時可能發生的強制關閉。&lt;/li&gt;
&lt;li&gt;修正當沒有設定響鈴時的無聲鬧鈴。使用緊急鬧鈴。&lt;/li&gt;
&lt;li&gt;如果使用者選擇密碼模式但忘記設定密碼，則使用正常模式。&lt;/li&gt;
&lt;li&gt;在設定電話鬧鈴時，使用者可以直接從聯絡人清單挑選聯絡人。電話號碼的選擇順序為，&lt;/li&gt;
&lt;ol&gt;&lt;li&gt;預設號碼。&lt;/li&gt;
&lt;li&gt;第一組號碼。&lt;/li&gt;
&lt;li&gt;無號碼時則顯示錯誤訊息。&lt;/li&gt;
&lt;/ol&gt;&lt;li&gt;對正OpenAlarm的Banner。&lt;/li&gt;
&lt;li&gt;對搜尋出的鬧鐘再執行搜尋並無太大意義。關閉這個功能。&lt;/li&gt;
&lt;li&gt;在關於此程式中，按我的email位址寄信給我，會在郵件中插入幾行除錯資訊。&lt;/li&gt;
&lt;li&gt;使用者介面的稍許更動。將加入新鬧鈴的選單項目移到主畫面。&lt;/li&gt;
&lt;li&gt;加入明確的開關設定。 &lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/lx4qBzoNujc5JTpxbumMrg?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_4dde1sDcsB4/S8PlnkHqD5I/AAAAAAAAKag/x3WWc3__tsc/s400/openalarm_20100415_main.png" /&gt;&lt;/a&gt;&lt;/td&gt;  &lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/3abbcBr4gVM_oCh-wq0oww?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_4dde1sDcsB4/S8PloDsVjMI/AAAAAAAAKak/oIfERFwbGWg/s400/openalarm_20100415_pull_number.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/7g28TU_DdyziWLCpsyKVfg?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_4dde1sDcsB4/S8PloXnOBYI/AAAAAAAAKao/u672A6H0rbc/s400/openalarm_20100415_filtered_main.png" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/dXUWWHLB3Y4dWD2_YFUJpw?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_4dde1sDcsB4/S8WefVQ2hKI/AAAAAAAAKaw/JNk5l9mdq9o/s400/openalarm_20100415_onoff.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3040027623434763832-8178681309121428530?l=yenliangl.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FG_1Hfy0bxM08LBSGc888E2tOKo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FG_1Hfy0bxM08LBSGc888E2tOKo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FG_1Hfy0bxM08LBSGc888E2tOKo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FG_1Hfy0bxM08LBSGc888E2tOKo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ChangeAttitudeYounger/~4/V2jWZnxylRE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/8178681309121428530?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3040027623434763832/posts/default/8178681309121428530?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ChangeAttitudeYounger/~3/V2jWZnxylRE/new-release-of-openalarm.html" title="New release of OpenAlarm" /><author><name>Yenliang Liu</name><uri>https://profiles.google.com/107187526666793947237</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-KOrYpxf7hWc/AAAAAAAAAAI/AAAAAAAANIc/xxiTHcV1nL0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_4dde1sDcsB4/S8PlnkHqD5I/AAAAAAAAKag/x3WWc3__tsc/s72-c/openalarm_20100415_main.png" height="72" width="72" /><feedburner:origLink>http://yenliangl.blogspot.com/2010/04/new-release-of-openalarm.html</feedburner:origLink></entry></feed>

