Archive

Archive for the ‘Learning’ 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: ,

Create application with Swipe gesture to navigate page like Google Play

December 26, 2012 4 comments

Android users might already have been familiar with Google Play application, which first, I think,  inspires the pattern of horizontal swipe gesture to navigate among content pages.

This article is gonna show you how to do a very very quick simple application that does the same pattern.

Swipe Pattern Sample

Swipe Pattern Sample

There will be three pages, each page will display a sample image of that page as swiping along. My sample, I put: “Girl, Dog & Cat”.

A – Requirements

– ViewPagerIndicator library, you can get it from here: http://viewpagerindicator.com/

– Android Support Package Library v4, well, you can either download the above package and use the already-had libs or get it from SDK Update. Either way is fine.

B – Project

Well, since I’m an Ant user, I prefer to do stuffs in command-line, so this tutorial will probably in command-mode.

1. Create the project

$ create project --target 2 --name Droid05 --path ./Droid05 --activity MainScreen --package pete.apps.study.droid05

Now project is ready for the next step.

2. Configure libs

– After downloading the ViewPagerIndicator package, you need to update the library in order to get Ant build.xml for the job. Please refer to my previous post: https://xjaphx.wordpress.com/2012/12/26/build-viewpagerindicator-with-ant/
– Now go to config the library reference, edit the project.properties and add this line

android.library.reference.1=../../tools/frameworks/ViewPagerIndicator/library

that is my case, you should locate to your correct directory where you put the /library of the ViewPagerIndicator.
– To test the config, you can just type to confirm

$ ant clean debug

If it succeeds, it means fine.
3. Implement the code
– Create the layout, pretty much simple, there will use a TitlePageIndicator and a ViewPager, main.xml

$ vi res/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#FFFFFFFF"
    >
    <com.viewpagerindicator.TitlePageIndicator
        android:id="@+id/titles"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFFFF"
        android:textColor="#FF000099"
        app:footerColor="#FF00FF00"
        app:footerLineHeight="3dp"
        app:footerIndicatorHeight="6dp"
        app:footerIndicatorStyle="triangle"
        app:selectedColor="#FF0000FF"
        app:selectedBold="true"
    />
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
    />
</LinearLayout>

– Create a custom Adapter inherits from PagerAdapter for controlling the ViewPager’s work, ViewPagerAdapter.java

package pete.apps.study.droid05;

import android.content.Context;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

public class ViewPagerAdapter extends PagerAdapter {

    private static String[] titles = new String[] {
        "Girl",
        "Dog",
        "Cat"
    };

    private static int[] images = new int[] {
        R.drawable.girl,
        R.drawable.dog,
        R.drawable.cat
    };

    private final Context context;

    public ViewPagerAdapter(Context context) {
        this.context = context;
    }

    @Override
    public String getPageTitle(int position) {
        return titles[position];
    }

    @Override
    public int getCount() {
        return titles.length;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView view = new ImageView(this.context);
        view.setImageResource(images[position]);
        ((ViewPager) container).addView(view, 0);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ((ViewPager) container).removeView((ImageView) object);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view.equals(object);
    }

}

– Finally the MainScreen.java

ackage pete.apps.study.droid05;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.Window;
import android.view.WindowManager;
import com.viewpagerindicator.TitlePageIndicator;

public class MainScreen extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.main);

        ViewPagerAdapter adapter = new ViewPagerAdapter(this);
        ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
        TitlePageIndicator title = (TitlePageIndicator) findViewById(R.id.titles);
        pager.setAdapter(adapter);
        title.setViewPager(pager);
    }
}

4. Execute the final
– Let’s build and run the code to see the results

$ ant clean debug install

C – Get source

– Get full source code at: Browse Source

 

Well, enjoy and create your amazing application !

Cheers,

Pete Houston

 

Build ViewPagerIndicator with Ant

December 26, 2012 Leave a comment

ViewPagerIndicator is one of the great libraries that helps to indicate the page status of when using ViewPager.

If you want to know more about it, visit the developers’ homepage: http://viewpagerindicator.com/

By default, it’s set to build with Maven, not Ant. So in order to build with Ant, you should do the following steps:

1. Download the package and extract it, you can click here to download,

or you can checkout it source code from developers’  branch: https://github.com/JakeWharton/Android-ViewPagerIndicator

Then name the directory, I named it: ~/ViewPagerIndicator

2. Navigate to this directory and start to create the project settings and build.xml for Ant build:

$ cd ViewPagerIndicator

$ android update project -p library/
Updated local.properties
No project name specified, using project folder name 'library'.
If you wish to change it, edit the first line of build.xml.
Added file ~/ViewPagerIndicator/library/build.xml
Added file ~/ViewPagerIndicator/library/proguard-project.txt

3. Build the sample source code and run it!

$ android update project -p sample/
Updated local.properties
No project name specified, using Activity name 'ListSamples'.
If you wish to change it, edit the first line of build.xml.
Added file ~/ViewPagerIndicator/sample/build.xml
Added file ~/ViewPagerIndicator/sample/proguard-project.txt

$ cd sample

$ ant clean

$ ant debug install

Now open your device and run the sample to enjoy the features that the library brings.

@p/s: Thanks Jake Wharton for this cool library and his support.

 

Cheers,
Pete Houston

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: ,

Guide to create, build and sign Android applications (using command)

September 5, 2012 3 comments

Today, I’d like to take you to a tour guide of how-to create, build and sign Android applications.

I – Setup the environment

– For building an Android app, you will need the help of Ant, for example, I use Apache Ant 1.8.4 for this tutorial, which is the current version at the time of this post written.

Download this package: http://apache.cs.utah.edu//ant/binaries/apache-ant-1.8.4-bin.zip

Extract it to [C:\Program Files\Ant]

It’s for Windows users, if you’re on Linux or Mac, just get and install it from Software Package Manager, it will install automatically for you, and you don’t need to do the following step of adding command to environment.

– For Windows users, now you need to add some commands to the PATH.

Open [Control Panel > System > tab Advanced -> button Environment Variables],

On the group [System variables], find the [Path] and add the following path to it:

+) path to JDK binary: for example, [C:\Program Files\Java\jdk1.6.0_18\bin]

+) path to Android Tools: for example, [C:\Program Files\Android\android-sdk\tools]

+) path to Android Platform-Tools: for example, [C:\Program Files\Android\android-sdk\platform-tools]

+) path to Apache Ant binary: for example, [C:\Program Files\Ant\bin]

Now, the value of my [Path] variable now is like:

C:\Perl\site\bin;C:\Perl\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\Android\android-sdk\platform-tools;C:\Program Files\Microsoft SQL Server\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Android\android-sdk\platform-tools;C:\Program Files\Android\android-sdk\tools;C:\Program Files\Ant\bin;C:\Program Files\Java\jdk1.6.0_18\bin;

Yours will be similar to mine.

Environment Variables

Environment Variables

II. Create, Build and Sign

1. Now, let’s go to create one project from command-line.

First, check for which Android platform SDK has been installed on your computer.

> android list targets

The output will list all platforms installed, for example:

Available Android targets:
----------
id: 1 or "android-15"
     Name: Android 4.0.3
     Type: Platform
     API level: 15
     Revision: 3
     Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, W
XGA720, WXGA800
     ABIs : no ABIs.

Your result might have more than mine.

It also means that I can create an Android project for platform “android-15” or id = 1. This value is required to create project.
Ok, I’m creating a sample project:

> android create project --target android-15 --name PeteApp --path ./PeteAppProject --activity MainActivity --package pete.apps.samples.peteapp

[–target] : is the target platform that your project will be running on
[–name] : indicate the name of your application, the APK created will have this name. Anyway, it’s optional, if you don’t specify this parameter, then the either project name or your first activity name will be chosen to be the name of your application. (you might wanna test this!)
[–path] : specify the directory of the project, it will use the existing directory, otherwise, create new.
[–activity] : the first screen or the entrance of your Droid app, it will be registered into [AndroidManifest.xml].
[–package] : your default package name.

That’s all, not that hard right?
The output would be…

Created project directory: E:\AndroidSamples\PeteAppProject
Created directory E:\AndroidSamples\PeteAppProject\src\pete\apps\samples\peteapp

Added file E:\AndroidSamples\PeteAppProject\src\pete\apps\samples\peteapp\MainAc
tivity.java
Created directory E:\AndroidSamples\PeteAppProject\res
Created directory E:\AndroidSamples\PeteAppProject\bin
Created directory E:\AndroidSamples\PeteAppProject\libs
Created directory E:\AndroidSamples\PeteAppProject\res\values
Added file E:\AndroidSamples\PeteAppProject\res\values\strings.xml
Created directory E:\AndroidSamples\PeteAppProject\res\layout
Added file E:\AndroidSamples\PeteAppProject\res\layout\main.xml
Created directory E:\AndroidSamples\PeteAppProject\res\drawable-hdpi
Created directory E:\AndroidSamples\PeteAppProject\res\drawable-mdpi
Created directory E:\AndroidSamples\PeteAppProject\res\drawable-ldpi
Added file E:\AndroidSamples\PeteAppProject\AndroidManifest.xml
Added file E:\AndroidSamples\PeteAppProject\build.xml
Added file E:\AndroidSamples\PeteAppProject\proguard-project.txt

Just add source files or whatever stuffs you need…that’s done for the creation.

2. Build it!!!
– There are two build mode in development, [Debug] and [Release]
– You can use these command to build depending on your mode.

> ant debug
> ant release

The [bin] directory will be created including your [***-debug-unaligned.apk] or [***-release-unaligned.apk].
– If you ever change anything in [res] (resources) directory, you should remove all stuffs in [bin] and [gen] directory, otherwise, it might cause bug in run-time, due to “fail to load resources”. This is one of very common mistake, so you should be aware of this. However, if you don’t want to work handy, you can use this robo-command:

> ant clean

– In order to install your application, there are many ways, but I show you two common methods:
+) use [Ant] for work, this depend on your mode:

> ant debug install
> ant release install

+) use [ADB], navigate to your [bin] directory:

> adb install AppName.apk

3. Release It!!!
– Got your APK work now, but it’s not ready for distribution on Market/Google Play. What you need to do next is to sign and align your release APK. The step is: create keystore > sign APK with key > align final package.

+) Create Key:
Look at my command:

> keytool -genkey -v -keystore peteapp.keystore -alias peteapp -keyalg RSA -keysize 2048 -validity 10000

Here the output

Enter keystore password:
Re-enter new password:
What is your first and last name?
  [Unknown]:  Pete Houston
What is the name of your organizational unit?
  [Unknown]:  Nowhere
What is the name of your organization?
  [Unknown]:  Noname
What is the name of your City or Locality?
  [Unknown]:  Seoul
What is the name of your State or Province?
  [Unknown]:  Kangnam
What is the two-letter country code for this unit?
  [Unknown]:  KR
Is CN=Pete Houston, OU=Nowhere, O=Noname, L=Seoul, ST=Kangnam, C=KR correct?
  [no]:  yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10,000 days
        for: CN=Pete Houston, OU=Nowhere, O=Noname, L=Seoul, ST=Kangnam, C=KR
Enter key password for <peteapp>
        (RETURN if same as keystore password):
[Storing peteapp.keystore]

For details, please visit this link: Obtain a key

+) Sign the APK:
– Remember, you must create the APK in [Release] mode before doing this.

> jarsigner -verbose -sigalg MD5withRSA -digestal
g SHA1 -keystore peteapp.keystore bin\PeteApp-release-unsigned.apk peteapp

The result:

Enter Passphrase for keystore:
   adding: META-INF/MANIFEST.MF
   adding: META-INF/PETEAPP.SF
   adding: META-INF/PETEAPP.RSA
  signing: res/layout/main.xml
  signing: AndroidManifest.xml
  signing: resources.arsc
  signing: res/drawable-hdpi/ic_launcher.png
  signing: res/drawable-ldpi/ic_launcher.png
  signing: res/drawable-mdpi/ic_launcher.png
  signing: classes.dex

– Now verify whether the signing process was OK.

> jarsigner -verify -verbose -certs bin\PeteApp-release-unsigned.apk

[-certs] : will display the validation of each and every signed file.
[-verbose] : to display the output, there you can check.

+) Align the final:

> zipalign -v 4 bin\PeteApp-release-unsigned.apk PeteApp.apk

The final signed and aligned package [PeteApp.apk] will be created under the main directory of the project.

Now you can use this APK to distribute on Market/Google Play 🙂

III – References
If you do a search over Internet, there are some good articles about this work, I also do refer from them as well. IF you feel any hard part, try to refer to them all and get the idea how it works.

Android Developers – Building and Running from Command Line

Android Developers – Sign Your Application

Android Engineer – Using Ant to Automate Building Android 

 

IV – Final Words

Well, enjoy and have fun!

 

Cheers,

Pete Houston

Categories: Tutorials 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: , , ,