Want to animate your activity from right to left when you click the home icon in the top left corner of your app?

Simples:


public static void goHomeTop(Activity context) {

final Intent intent = new Intent(context, HomeActivity.class);

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

context.startActivity(intent);

context.overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

}

Advertisements

Update: Please note that this tutorial was written over a year ago. ZXing has moved on quite a bit since then as have the Android Developer Tools. I haven’t had time to revisit and update the post but it should give you a good steer in the right direction. Some of the comments at the bottom may be able to help you out if you encounter any troubles.

Edit: Sean Owen, one of the developers for ZXing has posted a comment to this blog warning of the pitfalls of integrating ZXing into your own app; doing so just to avoid having your users take that extra step of installing from the market is not a good reason. I completely agree with this. There are many advantages to using the intent based approach as outlined in his comments. My motivation is for an enterprise app that does not have access to the Android market and involves my client installing zxing manually on thousands of devices before they are able to distribute to its business customers.

So to be clear, do not use this method unless it is absolutely necessary, and if you do have to – make sure that override your intent filters so that other apps that want to use zxing do not end up calling your modified version. Also, if zxing is already installed, then you should use that by default instead of your modified version.

ZXing is one of the most popular barcode scanning applications on the market. They make it very easy for you to integrate into your application via an intent but this means that your users must manually install the application from the market.

Fortunately, the app is also open source so I will show you how to cleanly build this capability into your project.

Please note that the awesome developers of this product have released the src under the Apache v2.o license so please be sure to adhere to the terms of this license and give them full credit for their work. http://www.apache.org/licenses/LICENSE-2.0

Step One: Obtain the zxing src code
The src can be found at http://code.google.com/p/zxing/source/browse/trunk. Specifically you only need the android/ and the core/ projects. Use svn to checkout these to your local hard-drive.

Step Two: Build zxing core using Apache Ant
You will need to build the core project into a jar file using apache ant (download from here http://ant.apache.org/ivy/download.cgi). Using a shell or cmd prompt navigate to the root directory of the downloaded zxing src and execute “ant -f core/build.xml”. This will produce a file core/core.jar which we will use in the next step.

Step Three: Build ZXing Android using Eclipse
Create a New Android Project (File –> New –> Android Project).
Set the project name to ZXing (or similar).
Select the “Create project from existing source” radio button
Click “Browse” and navigate to the android project that you downloaded from zxing and click “OK”
Select “Finish”

The project will not currently build. We need to add the core.jar file (that we produced in the previous step) into our project. Right-click on ZXing project –> properties –> Java Build Path –> Add External Jars –> Navigate to and select core.jar –> Open –> OK.

Actually, while we’re here we should do one more very important thing! Right-click on ZXing project –> properties –> Android –> Scroll down and check/tick the “Is Library” checkbox –> OK.

Step 4: Include ZXing Android into your project.
Within Eclipse,  Right-click on YOURPROJECTNAMEHERE project –> properties –>Android –> Scroll down to Libraries section –> Click Add –> Select ZXing (which should appear as an option as a result of completing previous step).

Next, in some trigger function e.g. button press within your code you should add:

Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
startActivityForResult(intent, 0);

In the same activity you’ll need the following to retrieve the results:

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
   if (requestCode == 0) {
      if (resultCode == RESULT_OK) {
         String contents = intent.getStringExtra("SCAN_RESULT");
         String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
         // Handle successful scan
      } else if (resultCode == RESULT_CANCELED) {
         // Handle cancel
      }
   }
}

Almost there! One of the current limitations of Android Library projects is that it will not pull anything from AndroidManifest.xml into your project.
So if we try to invoke the above code we will receive a runtime exception because your Android app has no idea how to handle the scan intent.
To fix this you just need to copy the following into your AndroidManifest.xml:

<activity android:name="com.google.zxing.client.android.CaptureActivity"
   android:screenOrientation="landscape"
   android:configChanges="orientation|keyboardHidden"
   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
   android:windowSoftInputMode="stateAlwaysHidden">
   <intent-filter>
      <action android:name="android.intent.action.MAIN"/>
      <category android:name="android.intent.category.DEFAULT"/>
   </intent-filter>
   <intent-filter>
      <action android:name="com.google.zxing.client.android.SCAN"/>
      <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

And as Columbo would say, “Just one more thing!”. Add this permission to the top of your AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA"/>

EDIT: You need to do yet one more thing! You need to add the core.jar (produced in Step two) to your new project (Right-click your project –> Properties –> Java Build Path –> Add External JARS… –> Select core.jar –> OK). Thanks to Marco and Markosys in the comments for spotting and pointing out the omission!

Maybe you’d like to perform a nice subtle animation such as fading some text in as soon as your activity launches? If you try to start this animation in onCreate() or onResume() you’ll be sorely dissapointed.

One possible solution is to set a timer in one of these methods so that the animation will spawn after a fixed interval.  This approach is problematic because if the delay is too short the animation won’t start (as before) and if it’s too long then the user experience will drop. Furthermore, such a delay might not behave quite the same on a G1 compared to a spanking new Samsung Galaxy S II for example.

A better way is to start the animation in the onWindowFocussedChanged method which is called when the current window of the activity gains or loses focus and gives the best indicator whether the activity is visible to the user. You can use the *hasFocus* parameter to distinguish between gaining or losing focus. Example below:

   private TextView myTextView;

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

        myTextView= (TextView)findViewById(R.id.my_textview);

        anim = AnimationUtils.loadAnimation(this, R.anim.fade_in);
    }

   @Override
   public void onWindowFocusChanged (boolean hasFocus) {
      super.onWindowFocusChanged(hasFocus);
      if (hasFocus)
         myTextView.startAnimation(anim);
   }

The animation itself is defined in an xml file in res/anim/fade_in.xml:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromAlpha="0.0" android:toAlpha="1.0"
       android:duration="1500" />

This may be obvious to some but not me. ..

Like a good little programmer, I use strings.xml all the time in my Android applications which means that this file can get quite large. For a customer that wanted to be able to modify some settings before recompiling and distributing to their customers, I wanted to extract those variable “settings” into a different file for clarity.

It’s actually extremely easy to do. So easy that I thought it couldn’t possibly be that easy and started exploring more complicated routes.

All you have to do is create a new xml file e.g. “settings.xml” and then move your string value (e.g. <string name=”default_retry_time_value”>10</string>) from “strings.xml” into this new file.  That’s it!

You don’t need to update any views in your layouts to do to something like this android:text=”@settings/default_mcode_value”.

You just need to make sure that your settings.xml file is in res/values (same place as strings.xml) and Android will pick it up.

The new Android market is a great step forward. Finally, we are able to provide links to our apps on the web, customers can browse and search for applications and install them directly to their devices from the web.  Overall, it looks great.

There are some improvements that could be made though and I’m sure that Google will iterate on the user experience over the coming months. Here are some constructive criticisms / suggestions for improvements that I hope they will take into consideration

  1. The beautiful styling of the page is somewhat ruined by the default Google navbar at the top of the page which looks like it was constructed in FrontPage.
  2. When viewing a screenshot for an app, I would like to be able to view the next image in the sequence without having to close the one that I’m currently looking at and manually selecting the next image! That is a useability fail.
  3. I know (because I’m a savvy Android user/developer) that the Square app (squareup.com) is only available in the U.S. With the new market, I can search and view details for the square app but I’m not able to install it. For a general user I think that it would be nice if an explanation was given as to why this app is not available for installation rather than a bog standard message that says “This item is not available on your carrier”. Or better yet, since I’m logged in and you already know that I can’t download the app – why not just hide it from my search results like you do on the phone?
  4. Android buyer currency support is most welcome, but I feel that Google are trying to be too flexible. Apple have really nailed this one by providing tiers of charges so if you set your price at £0.59 then in the U.S. it will be charged at $0.99 and so on.  Enabling Android devs to set their own prices for each country gives total flexibility but adds way too much complexity.

An interesting blog post on the subject here:

http://goldengekko.blogspot.com/2010/09/what-are-costs-of-developing-mobile-app.html

NB. The numbers are pretty accurate in my opinion.

Update: Also of interest are some of the comments in this stackoverflow question. Some frank estimates of time by some of the developers for well known apps such as twitterific.

http://stackoverflow.com/questions/209170/how-much-does-it-cost-to-develop-an-iphone-application/3926493#3926493

I recently encountered this problem while trying to develop a WebView that is supported on Doughnut (1.6) and above. When presented with a https url the WebView just renders a blank page.

It seems that until Froyo, Android didn’t provide a public API to let you manually decide if you wanted to proceed to an untrusted web site via a WebView.

Note that in this case it is not even that the web site was untrusted (in the conventional sense) – it is because Thawte is not in the default list of trusted certificate authorities on Android. If you use the standard web browser on Android, the browser presents a typical warning dialog (as presented below) that enables you to accept the certificate and carry on.

Invalid certificate warning

If you are using Froyo as the target SDK then you can use:

engine = (WebView) findViewById(R.id.my_webview);
engine.setWebViewClient(new WebViewClient() {
 public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
 handler.proceed() ;
 }
}

However, if you are not using Froyo then it seems you are out of luck. After some research, I concluded that I had the following options:

a) intercept all page requests and forward to external web browser if url begins with https (not a clean or nice user experience and totally unnecessary for Froyo and above)
b) add certificate of website to local keystore (in this case I am serving multiple web pages and the origin of many of these is not known until runtime)
c) make Froyo the minSDK and discard previous versions of Android (not a suitable option)
d) hack and use some private apis (the option described below)

To solve this problem we have to use a private interface (not published on SDK but present in real SDK runtime). As you can see in the Android src tree, the onReceivedSslError is indeed present (and used – it simply cancels the request) in Doughnut. However, this method is not presented to us in the SDK  – it is hidden because it contains a parameter type SslError which is located in a hidden package.  Therefore, we need to copy these src files into our project so that we can access them:

1) Copy WebViewClient.java into the package “android.webkit” within your src folder.
2) Copy SslError.java into the package “android.net.http” within your src folder.

Src files

3) Since we replicated the paths to the src files in the SDK, our code to override onSslError above now works on Android 1.6.

Caution: bear in mind that we are using a private API and Google reserve the right to change private APIs at any time – though in this case it is unlikely since they’ve now made this available in Froyo.