- browser dims by itself - even after you manually set the colors settings and disable the system's auto-adjust brightness, the browser will still dim the screen next time you start it. Plenty of S3 users are suffering from it. My workaround it to install Dolphin browser instead. I also tried Chrome, but it freezes sometimes, so I replaced it with Dolphin.
- Samsung has stuffed up the docking bar at the bottom of the home screen with its latest firmware upgrade. You can no longer configure this docking bar. If you have uninstalled the app in the docking bar, you will not be able to put another app there. So you are left with an ungly gap. What is Samsung's solution for that? - to factory reset your phone! Oh, in Samsung's response letter, they forgot to mention to do a back up of your installed applications or downloads.
Wednesday, 14 November 2012
Sucky Samsung
Friday, 16 September 2011
Oracle vs. Google Lawsuit
I have read news about Oracle’s lawsuit against Google regarding its Android platform, alleging that Google is copying from Java. Some had even concluded that Android is in jeopardy. I had not paid much attention to the details of the lawsuit, until today when I came across Google’s rebuttal by a technical expert Prof. Owen Astrachan of Duke University. The report is published on Groklaw - it’s really fun to read.
The central issue of the lawsuit seems to be whether the Java API (or API of any language, library, even C-header files) are copyrightable. Google’s argument is that APIs are not creative expression, hence not copyrightable; but the implementation of the APIs are. Prof. Owen gave strong arguments backed by facts and through analogies.
Surely, anyone who has done software programming would not consider interfaces copyrightable. What do you think? – click your preference in the poll on the upper right hand corner of this page to express your view.
Updated 2011-10-30: the verdict is out. Total votes: 6; Yes vote: 5 (83%); No vote: 1 (16%).
Friday, 22 January 2010
Rise of the Droid
Traffic to this blog had been pretty flat in the last couple of months. It was not surprising considering the holiday season. However, I noticed an unusual surge of traffic in the last three weeks creating new record highs. I was a bit baffled. The only thing mildly interesting (to me) that I wrote after the New Year was about hacking LinkedIn API. I don't think many netizens are that interested in LinkedIn, let alone LinkedIn API.
A little digging in my custom reports in Google Analytics revealed that my No. 1 visited blog was Consumer Web Services from Android that I wrote in 2008 when the Android 0.9 SDK Beta was released. For about 12 months, that post was not among the top 5 list. Yet soon after Google announced its launch of Android phone people are are beefed up about development for Android platform. Judging from the developer community’s enthusiasm, it won’t take long before tons of Android applications to be available, helping Android’s market share. So I expect to see Android to catch up with iPhone in the next 12-24 months. It will be interesting to see how the multi-vendor strategy work out against Apple’s iPhone.
Kudos to Google!
Friday, 22 August 2008
Consuming Web Services from Android
Earlier this week, Google released Android 0.9 SDK Beta. As usual, I couldn't wait to try it out.
Unlike JavaME (especially MIDP 1.0), Android is targetting mobile devices with more grunt - it's bundled with many open source libraries, such as Apache Harmony (open source Java SE), Unicode library, JUnit, Apache Commons, ASN.1 libarary and more from Bouncy Castle, kXML, etc. The android.jar file is 11MB!
It is time to write a web service consumer on Android, to consume my WCF web service as well as RESTful service that I developed for a demo.
The Android does not contain any tools to help building SOAP based web service clients. Google is a proponent of REST services. It is no surprise that the SDK is not bundled with any SOAP-related tools. An alternative is to add kSOAP 2 to my test project. But I quickly dismissed the idea as my web service built in WCF is not JSR-172 compliant.
Like my exercise in JavaME, I decided to call the RESTful version of the same service built in NetBeans 6.1 instead.
I created a new Android project - SvdemoAndroid, using Eclipse 3.4 with the Android plugin installed. Because my Android Activity will be accessing the internet for the HTTP connection (although it's hosted on my machine), I had to add the line <uses-permission android:name="android.permission.INTERNET" /> to my AndroidManifest.xml file. Now the file looks something like:
<uses-permission android:name="android.permission.INTERNET" /> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
Android is bundled with Apache HttpClient 4. So invoking a REST service is simply a matter of openning up a HTTP link using the HttpClient and process the response. The following two methods show the consumption of two different RESTful services. The first method getKeywords() calls a service returning a plain text on HTTP.
static String SERVER_HOST="192.168.2.100";
static int SERVER_PORT = 8080;
static String URL1 = "/SvdemoRestful/resources/mySpace?url=http://wpickup02/MySpace_Com_John.htm";
static String URL2 = "/SvdemoRestful/resources/promo";
/**
* Call the RESTful service to get a list of keywords from the web page.
* @param target - the target HTTP host for the RESTful service.
* @return - comma delimited keywords. May contain spaces. If no keywords found, return null.
*/
private String getKeywords(HttpHost target) {
String keywords=null;
HttpEntity entity = null;
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(URL1);
try {
HttpResponse response=client.execute(target, get);
entity = response.getEntity();
keywords = EntityUtils.toString(entity);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (entity!=null)
try {
entity.consumeContent();
} catch (IOException e) {}
}
return keywords;
}
The second method calls another service (on URL2). This service returns a XML string containing the details of a Promotion. Unlike JavaME, Android SDK is bundled with DOM parser. Since my XML string is pretty short I decided to use DOM instead of kXML's pull parser. Note that PromoInfo is just a data object holding all the promotion information in its fields.
/**
* Call the REST service to retrieve the first matching promotion based
* on the give keywords. If none found, return null.
* @param target - the target HTTP host for the REST service.
* @param keywords - comma delimited keywords. May contain spaces.
* @return - PromoInfo that matches the keywords. If error or no match, return null.
*/
private PromoInfo searchPromo(HttpHost target, String keywords) {
if(keywords==null)
return null;
PromoInfo promo=null;
Document doc = null;
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(URL2+"/"+keywords.replaceAll(" ", "%20"));
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
HttpEntity entity = client.execute(target, get).getEntity();
doc = builder.parse(entity.getContent());
NodeList promotions = doc.getElementsByTagName("Promotion");
if(promotions!=null) {
Node promoNode = promotions.item(0);
if (promoNode!=null) {
promo=new PromoInfo();
NodeList nodeList = promoNode.getChildNodes();
int len = nodeList.getLength();
for(int i=0; i<len; i++) {
Node node = nodeList.item(i);
String value = this.getNodeValue(node);
if("Name".equals(node.getNodeName())) {
promo.setName(value);
} else if("Description".equals(node.getNodeName())) {
promo.setDescription(value);
} else if("Venue".equals(node.getNodeName())) {
promo.setVenue(value);
} else if("Name".equals(node.getNodeName())) {
promo.setName(value);
} else if("DateTime".equals(node.getNodeName())) {
promo.setDateTime(value);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
promo=null;
} finally {
}
return promo;
}
private String getNodeValue(Node node) {
NodeList children = node.getChildNodes();
if(children.getLength()>0) {
return children.item(0).getNodeValue();
} else
return null;
}
Now that I have invoked the web services and got the data back to my Android phone, it is time to display them on screen. Android adopts a similar approach to Microsoft WPF, where you can define the view layout and styles in a XML file, so that the Java code is freed up from screen rendering code and can focus more on the business logic.
I created a style.xml file under the {project}/res/values directory to define the styles for my screen widgets.
<style name="LabelText"> - 18sp
- #fff
- fill_parent
- wrap_content
- 5px
</style> <style name="ContentText">- 14sp
- #000
- #e81
- true
- fill_parent
- wrap_content
</style>
Then my view layout XML can use the styles. Here is the {project}/res/layout/main.xml file:
<TextView style="@style/LabelText" android:text="Name:"/> <TextView style="@style/ContentText" android:id="@+id/tvName" /> <TextView style="@style/LabelText" android:text="Description:"/> <TextView style="@style/ContentText" android:id="@+id/tvDescription" /> <TextView style="@style/LabelText" android:text="Venue:"/> <TextView style="@style/ContentText" android:id="@+id/tvVenue" /> <TextView style="@style/LabelText" android:text="Date:"/> <TextView style="@style/ContentText" android:id="@+id/tvDate" />
Note that by adding the android:text="@+id/tvName", the Android Eclipse Plugin will automatically regenerate the R.java file to add fields into the id class, so that you can reference the widget from Java code using findViewById(R.id.tvName). Here is the code for the onCreate() method:
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HttpHost target = new HttpHost(SERVER_HOST, SERVER_PORT, "http");
String keywords = getKeywords(target);
setContentView(R.layout.main);
if(keywords!=null) {
PromoInfo promo = searchPromo(target, keywords);
if(promo!=null) {
((TextView)this.findViewById(R.id.tvName)).setText(promo.getName());
((TextView)this.findViewById(R.id.tvDescription)).setText(promo.getDescription());
((TextView)this.findViewById(R.id.tvDate)).setText(promo.getDateTime());
((TextView)this.findViewById(R.id.tvVenue)).setText(promo.getVenue());
}
}
}
Running the application:
Related Posts:
