Archive

Archive for the ‘Tricks & Tips’ Category

A Note when Using Jsoup: User-Agent

January 29, 2013 1 comment

Several days ago, I’ve tried to run Jsoup on mobile testing for data parsing. My goal is to parse all questions posted on stackoverflow.com.

However, the result doesn’t fit me well.

First run on simple Android code:

public class MainScreen extends Activity
{
    ArrayList<String> mData =  new ArrayList<String>();
    ListView mListView;
    ArrayAdapter<String> mAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mListView = (ListView) findViewById(R.id.listView);

        processData();

        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, mData);
        mListView.setAdapter(mAdapter);
    }

    private void processData() {
        String URL = "http://stackoverflow.com/questions/tagged/android";
        try {
            Document doc = Jsoup.connect(URL).get();
            Elements questions = doc.select(".summary h3 a");
            for(Element question: questions) {
                mData.add(question.text());
            }

            if(mData.size() == 0) {
                mData.add("Empty result");
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            mData.clear();
            mData.add("Exception: " + ex.toString());
        }
    }
}

The result is empty. Well, thought of something else, so my next try is to print HTML from “doc” object, it outputs parts of full expected HTML results. So I parse with this selector: “div.nav li a”. The results show up but not for “.summary h3 a”.

After two days, working with Johnathan Hedley on GitHub, finally, found the problem is that: the mobile browser user-agent differs from the desktop browser; therefore, the HTML responses differ.

Make a note to mobile developers that use Jsoup:

+ always set a desktop user-agent

+ set a timeout

That’s good practice to avoid unexpectation.

This is the update working line:

Document doc = Jsoup.connect(URL).userAgent("Mozilla/5.0 (Macintosh; U; Intel Mac OS X; de-de) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10").get(
);

This issue was discussed here in GitHub: https://github.com/jhy/jsoup/issues/287

 

Cheers,
Pete Houston

Advertisements
Categories: Tricks & Tips Tags: , , , , ,

Detect if an application is installed or not

January 3, 2013 Leave a comment

There will be a situation where your applications require a pre-installed application in order to use their libraries or functions, for example, sharing on Facebook or Twitter, watch video on Youtube, scanning barcode from ZXing, launch casts on Sopcast

What need to implement is to detect whether those required applications are installed or not, if not, redirect users to market and get it installed.

1. First, check if the required app is installed.

There are two ways:

+) List all installed apps and find if it is installed. (refer: Retrieve list of installed applications)

+) Fire the intent of the required app to see if it runs. (refer: Launch an activity)

Well, the first way seems to be the classical one, in case lots of apps installed on device, it might reduce performance.

The second way looks better, and if it throws an exception if app not installed,  NameNotFoundException, it is the proper time to trigger the market to install.

2. Implementation on firing Intent.

This is how I work it out:

ackage pete.apps.study.droid10;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;

public class Utils {

    /** handle the required pre-installed app */
    public static boolean handleRequiredApp(Context context, PackageManager pm, String packageName)
    {
        Intent iApp = pm.getLaunchIntentForPackage(packageName);
        try {
            // this line will trigger exception if not found
            pm.getApplicationInfo(packageName, 0);
            return true;
        } catch (Exception ex) {
            // launch the market for installation
            launchMarket(context, packageName);
            return false;
        }
    }

    /** launch market to certain app */
    public static void launchMarket(Context context, String packageName)
    {
        Uri uri = Uri.parse("market://details?id=" + packageName);
        Intent iDown = new Intent(Intent.ACTION_VIEW, uri);
        context.startActivity(iDown);
    }
}

Note that: the Exception will fire either when application is not installed (NameNotFoundException) or installed but having no real launching Acitivity (ActivityNotFoundException). 

This is the sample project if you cannot run the code: Demo code – Droid 10

Cheers,

Pete Houston

Categories: Tricks & Tips Tags: ,

Compress file using Zip utitliy

October 12, 2012 Leave a comment

The Android platform by default supports the compression method by using Zip utility, in case you want to do something with it. It’s on the package __java.util.zip__

This is one sample usage:

1. Utils.java

package pete.apps.samples.compressionzip;

import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.String;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class Utils {
	public static final int BUFFER = 2048;

	/**
	* to compress file
	*
	* @param	file    the input file to compress
	* @param    zipFile	name of the compressed file
	*
	*/
	public static void compress(String file, String zipFile) {
		try {

			BufferedInputStream inBufferStream = new BufferedInputStream(new FileInputStream(file), BUFFER);;
			FileOutputStream targetOutputStream = new FileOutputStream(zipFile);
			ZipOutputStream outZipStream = new ZipOutputStream(new BufferedOutputStream(targetOutputStream));

			byte data[] = new byte[BUFFER];

			ZipEntry entry = new ZipEntry(file.substring(file.lastIndexOf("/") + 1));
			outZipStream.putNextEntry(entry);
			int count;
			while((count = inBufferStream.read(data, 0, BUFFER)) != -1) {
				outZipStream.write(data, 0, count);
			}

			inBufferStream.close();
			outZipStream.close();

		} catch (Exception ex) {
			Log.d("Error", ex.getMessage());
		}
	}
}

2. MainScreen.java

package pete.apps.samples.compressionzip;

import android.app.Activity;
import android.os.Bundle;
import pete.apps.samples.compressionzip.Utils;

public class MainScreen extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        doCompress();
    }

    public void doCompress() {
    	final String FILE_TARGET = "/sdcard/Download/target.txt";
    	final String FILE_ZIP = "/sdcard/Download/target.zip";

    	Utils.compress(FILE_TARGET, FILE_ZIP);
    }
}

Here in my sample, I try to compress the file __target.txt__ which stored in SDCcard and try to compress it in put in the same directory __target.zip__

– In case of you have some files in your packages APK stored in __/res__ or __/raw__ or __/assets__, you need to take them out and use a __BufferedInputStream__ to write it to internal directory (local directory of your package), then get its location to compress.

 

Cheers,

Pete Houston

Categories: Tricks & Tips Tags: ,

Launch your applications on custom secret code

August 13, 2012 8 comments

You might know about some of Android Secret Number or Code, right?

For sample, on the dial pad, type this code: *#*#4636#*#*, the a Testing screen will appear; it’s a secret screen that you do/don’t know about it before.

Dial Pad on SecretCode

Dial Pad on SecretCode

The interesting point here is that you absolutely want to do the same thing, type your custom secret code and your app is launched immediately.

This is what you need to do for it.

1. Create a custom BroadcastReceiver for Secret Code entering; for sample, I named it MySecretCodeReceiver.

This receiver will launch my Activity on detection.

public class MySecretCodeReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		if(intent.getAction().equals("android.provider.Telephony.SECRET_CODE")) {
			Intent i = new Intent(context, MainActivity.class);
			i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			context.startActivity(i);
		}
	}

}

2. Register the MySecretCodeReceiver properly, like below:

        <receiver android:name=".MySecretCodeReceiver">
    	 	<intent-filter>
          		<action android:name="android.provider.Telephony.SECRET_CODE" />
         		<data android:scheme="android_secret_code" android:host="1711" />
   		</intent-filter>
        </receiver>

You need to make sure that the tag <action> should be like exactly same as above, since it’s the pre-defined action for SECRET_CODE handling. Also, pick a number in attribute “android:host” to your application. For sample here, I pick my lucky number 1711.

That’s pretty much straightforward. Have fun anyway!

Cheers,

Pete Houston

Categories: Tricks & Tips Tags: , , ,

Launch Home Chooser Dialog


After long time digging in Android source code, I’ve found a way to pop-up the Home Chooser dialog.

Home Chooser Dialog

Home Chooser Dialog

Above is how it displays on my phone. Anyway, here the way how to do it:

    static final String HOME_CHOOSER_PACKAGE_NAME = "android";
    static final String HOME_CHOOSER_CLASS_NAME = "com.android.internal.app.ResolverActivity";

    private void launchHomeChooser() {
    	Intent i = new Intent(Intent.ACTION_MAIN);
    	i.addCategory(Intent.CATEGORY_HOME);
    	i.setClassName(HOME_CHOOSER_PACKAGE_NAME, HOME_CHOOSER_CLASS_NAME);
    	startActivity(i);
    }

If you search over Internet, there might be many other ways to create a similar Home Chooser dialog, however, it takes lots of coding and customization. Well, I prefer to call the framework one.

One more thing, it works on my device Galaxy SII, running ROM Resurrection Remix v2.5.3 (Android ICS v4.0.4); so I’m not really certain that it would work for every device, but it should work for most of devices then. It runs fine on Android 2.3.x devices, too.

Cheers,
Pete Houston

Categories: Tricks & Tips Tags: , ,

Get date time in custom format


Basically, I use [Date] class to get current time and use [SimpleDateFormat] to format my own output.

Just a sample format:

private String getDateTime() {
    // get date time in custom format
    SimpleDateFormat sdf = new SimpleDateFormat("[yyyy/MM/dd - HH:mm:ss]");
    return sdf.format(new Date(appInfo.firstInstallTime));
}

Cheers,
Pete Houston

Categories: Tricks & Tips Tags: , ,

Launch Youtube app to play video

July 7, 2012 1 comment

A simple snippet for launching Youtube app to play video.

	// constant value of package & class name of YouTube app
	public static final String YOUTUBE_PACKAGE_NAME = "com.google.android.youtube";
	public static final String YOUTUBE_CLASS_NAME = "com.google.android.youtube.WatchActivity";
	
	/**
	 * Launch Youtube to watch an URL
	 * @param context
	 * @param url
	 */
	public static void launchYoutube(Context context, String url) {
		Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(url));        
        intent.setClassName(YOUTUBE_PACKAGE_NAME, YOUTUBE_CLASS_NAME);        
        context.startActivity(intent);
	}

Cheers,
Pete Houston

Categories: Tricks & Tips Tags: ,