Monday, October 05, 2009

ReaderScope 1.2.1 - Auto Login

Today I came across this excellent article "5 Nice Apps I refuse to use" by Chuck Falzone. It talks about how all the Google Reader apps (or android app that needs access to Google services) ask for passwords to the user's Google account. As you know ReaderScope does it too. But I completely empathized with the author's point of view. For many like me, Google is the biggest closet in their wired home. Giving the key to this closet to any random app is scary for sure.

However, of all the login mechanisms I found out, the only supported method for a desktop/mobile app is asking user to enter his/her username and password. Google supports OAuth, but only for web apps. I wish they implement version of OAuth for desktop/mobile apps, just like Twitter. Another way, is to get the login tokens from Android platform. Although, it should be available as platform API, it is not. I guess the reason is, it will be limited only to 'Google experience' phones, hence it cannot be part of the platform.

But, thanks to the article I mentioned above, more info came out on this discussion. From the article I learnt, that a Google Reader widget accesses Google Account info available on phone. I went through the comments, and one of them gave a pointer to how this might be done. After following the email thread, I found a way to do this. The solution is not perfect/ideal. It uses a library put together by a Google engineer (@jbqueru), but it is not an official part of platform. With the help of ubikdroid's example code from the thread, I put together an "AutoLogin" feature for ReaderScope (as of v1.2.1)


If you are using a 'Google Experience' phone (or a ROM with Google Apps), then you don't have to give your password to ReaderScope. Just press AutoLogin and you are in.

If the existing users want to remove their password (which by the way is encoded before storage) from ReaderScope and use this new auth mechanism, then you can do so without loosing your cached items. Go to Settings->Credentials Management. Press "Logout". Choose "No" to the prompt of deleting cache. The app will exit. Start it again, you will be taken to Login screen. Now choose AutoLogin.

If your phone is not 'Google Experience' phone, this will not work. You will get an error message.

I put this together in past few hours. Although it has passed my automated regression tests, there might be some rough edges. Let me know if you see any problems.

Saturday, October 03, 2009

ReaderScope v1.2

After 1 week of reimplementation of news cache, 1 day of testing and 1 last hour of crazy epiphanies and patches... v1.2 is out.

Here is what is new.

With the brand new caching scheme, you can store your bulky news cache on SDCard. Right now my HTC magic is pulling about 1000 images from web (which must be total 10-20MB in size), but the app manager shows ReaderScope only taking 588KB on phone. Because all the content is going to the SDCard.


Also if you do periodic downloads with caching the content, you will notice that the subsequent downloads will take significantly shorter times. This is because, the new caching mechanism accurately downloads only the content that's not in the cache.

In addition, there are few new features that users have been asking for.

Mark All As Read


You can mark all the items in a feed read. Does the same function as its counterpart in Google Reader web interface.

Share with note


You can just "Share", or you can add a note if you wish. Again same job as its counterpart in Google Reader web interface.

Manual override to go offline


One loyal user of ReaderScope has been asking for this feature for a while. It has very practical use for certain. I finally got around to implementing it in v1.2. There are situations when you are online, but you don't want ReaderScope to use the network (because it costs $$). You could already customize the periodic background downloads to not use such specific network. But, you may want to restrict GUI's access to the network too. While you are reading the news, ReaderScope marks the items read, stars/shares them if you choose - this is synced with Google Reader over network.

With the "Go Offline" button, all these front-end actions will be batched instead of doing instant sync over the network (and you will see them in the Pending notification at the top, the one you see when you are actually offline). When you want to go online with the right kind of network, choose "Go Online" and tap on the notification, it will sync your actions.

Moreover, some bug fixes have also gone in.

Hopefully you will enjoy the new version. It's not unlikely that some silly bugs went unnoticed during this big rewrite of the caching mechanism. If you see any problems or hit any crashes, please email me the crash report (using the in built crash reporter).

Enjoy!

Saturday, September 19, 2009

Crash report for Android App

To err is human and to crash is the software created by human (even if it is made for Android ;)

So when your app crashes on your users' phones, it's a good idea to collect the details of the crash and prompt the user to send them to you. I recently wrote one such scheme for ReaderScope and it has been very helpful. Here is how I am doing it.

I found the code snippets after googling around. Mainly from this stackoverflow article. This morning however, I added few more bits to work well with exceptions that take place in background threads.

The way to do this is to implement the Thread.UncaughtExceptionHandler interface and pass it to Thread.setDefaultUncaughtExceptionHandler() at the beginning of your Activity's onCreate(). Here is the implementation class TopExceptionHandler.
package com.altcanvas.readerscope;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Context;
import java.io.*;

public class TopExceptionHandler implements Thread.UncaughtExceptionHandler {

private Thread.UncaughtExceptionHandler defaultUEH;

private Activity app = null;

public TopExceptionHandler(Activity app) {
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
this.app = app;
}

public void uncaughtException(Thread t, Throwable e)
{
StackTraceElement[] arr = e.getStackTrace();
String report = e.toString()+"\n\n";
report += "--------- Stack trace ---------\n\n";
for (int i=0; i<arr.length; i++)
{
report += "    "+arr[i].toString()+"\n";
}
report += "-------------------------------\n\n";

// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
report += "--------- Cause ---------\n\n";
Throwable cause = e.getCause();
if(cause != null) {
report += cause.toString() + "\n\n";
arr = cause.getStackTrace();
for (int i=0; i<arr.length; i++)
{
report += "    "+arr[i].toString()+"\n";
}
}
report += "-------------------------------\n\n";

try {
FileOutputStream trace = app.openFileOutput(
"stack.trace", Context.MODE_PRIVATE);
trace.write(report.getBytes());
trace.close();
} catch(IOException ioe) {
// ...
}

defaultUEH.uncaughtException(t, e);
}
}

Note that we are not consuming the exception. We let the Android framework's defaultUEH to handle it. If you don't do this, bad things may happen.

At the top of your Activity register an instance of above class like this:
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

Thread.setDefaultUncaughtExceptionHandler(new TopExceptionHandler(this));
...

This exception handler saves the trace in a file. When ReaderScope restarts next time, it detects the file and prompts the user if he/she wants to email it to the developer.

Emailing the stack trace with user's consent is so much easier on Android, than setting up a crash report server. Somewhere near the beginning of your activity just check if stack.trace file is present. If so, execute following code to pack it in an email.
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(ReaderScopeActivity.this
.openFileInput("stack.trace")));
while((line = reader.readLine()) != null) {
trace += line+"\n";
}
} catch(FileNotFoundException fnfe) {
// ...
} catch(IOException ioe) {
// ...
}

Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = "Error report";
String body =
"Mail this to readerscope@altcanvas.com: "+
"\n\n"+
trace+
"\n\n";

sendIntent.putExtra(Intent.EXTRA_EMAIL,
new String[] {"readerscope@altcanvas.com"});
sendIntent.putExtra(Intent.EXTRA_TEXT, body);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");

ReaderScopeActivity.this.startActivity(
Intent.createChooser(sendIntent, "Title:"));

ReaderScopeActivity.this.deleteFile("stack.trace");

Hope this helps! If you have suggestions for improvements, please do let me know in comments.

ReaderScope 1.1.3 - SDCard storage

Update: Just released 1.1.3a. Thanks to Fernando, found a hidden bug in a background thread. the 'a' version fixes it.

As the time goes by, ReaderScope accumulates lot of news and metadata. It resides in a SQLite database on the phone. The cached webpages reside in a separate WebView cache - also on the phone. After a few days with the device, everyone comes to know how scarce the phone memory is. So it's a good practice for an app to store its data store on the external SDCard. In v1.1.3 ReaderScope facilitates putting the database on the SDCard. Just head to Settings -> Storage Management. Choose the "Database Storage Location" to be "SDCard".



You will also be prompted if you want to migrate your current database contents to the new location. In future, if you want to move the database back to the phone (maybe to replace the existing SDCard with a new one); that is possible too.

This should help saving some space on the phone. However this is only half the job. The WebView cache has a sizable footprint on the phone storage. The work to get it to SDCard is in progress.

Another addition in this version is the "Feed Filter" option. I hope it will improve the usability for the people who prefer to read only the latest downloaded news.





I have also set up a Google Group to discuss the issues and feature requests for the ReaderScope. Please do join.


Thursday, September 17, 2009

Wifi and Battery

Although I didn't dedicate a blog post to my latest beloved gadget purchase - I have been a happy owner of HTC magic for about three weeks now. I used it for first two weeks with the factory ROM. It worked quite well - except for the Google apps and access to Android market. To my delight I found that it had very good battery life. After around 6-7 hours away from the USB charger, it would loose 10-15% battery. Remembering people's experiences of 24-hr battery life, this seemed quite impressive. However to my annoyance, I found a problem. When the phone was not in use, its wifi would be off. I had ReaderScope on it downloading news every 1 hr. It cancelled the downloads because it didn't find any wifi (and I had set it to use wifi only). Moreover, some apps (which I never found out) would go over the Mobile network if they didn't find wifi. I use a prepaid SIM card. So after every usage of Mobile network, I get a message showing me how much credit was used in last call and what's the balance remaining. So after leaving phone unused for the night, I would find some of these messages in the morning. Using Rs. 0.30 to 9.00 at times. This really bugged me. Loosing money for no reason.

Last week I rooted the phone and installed a different ROM (Amon_RA), the one with all the good stuff (Google apps and access to market). With this ROM, I do not see the wifi getting turned off when the phone is not in use and the screen is off. The ReaderScope periodic downloads go on without any problem over wifi. However now the battery life has much deteriorated. Over night, when the phone is not hooked to a USB charger, it looses about 40-50% or more charge.

My conclusion, always ON wifi is sipping the juice out of battery.

What I find more interesting however, is HTC's default setting to turn off the wifi when device is unused and screen times out. (And I couldn't find any way to change that setting at all.)

I wonder if they had a noble motive of giving the user longer battery life OR was it to boost revenue of Airtel (partner carrier) by favoring Mobile traffic over Wifi, even when the later is available.

Anyhow... Glad to be with the new ROM!!