Simple XML with Android and Box.net

Continued on my experiment with Box.net’s API using Spring MVC, I tried the same on Android.  The source code can be found at https://github.com/barryku/SpringCloud/tree/master/BoxApp/BoxNetApp.

It uses Spring’s RestTemplate for Android to access Box’s REST API’s.  The way it works is similar to what I have done in my previous work on Android with Spring.  The main difference is that Box doesn’t generate JSON output, so I have to parse their XML response instead.  Luckily Spring already has built-in XML (Simple XML Serialization) support, and it’s not that much different than working with JSON.  However, there’s a caveat in Android’s SDK that requires a little tweak to get it working.  To keep Android SDK small, it doesn’t include everything in javax.xml.*, as a result, you will need to run dex with –core-library.  This will package those missing javax.xml into your dex file.  The fix will become available in andorid-maven-plugin 3.0 (see http://code.google.com/p/maven-android-plugin/wiki/Changelog for details.)  Before that happens, you can try my workaround I posted on StackOverflow.

This Android application has two main activities (screens), AuthActivity and BrowseActivity.  AuthActivity is the entry point when you start the application which checks for authToken’s existence.  If none was found, it present the screen with a “Sing on” button to take the user to Box.net’s authentication page.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

    Intent intent = getIntent();
    if (AUTH_INTENT_SCHEME.equals(intent.getScheme())) {
        Uri uri = intent.getData();
        Log.d(LOG_TAG, "processing auth callback: " + uri);
        String authToken = uri.getQueryParameter("auth_token");
        if (authToken != null) {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString(AUTH_TOKEN_KEY, authToken);
            editor.commit();
        }
    }
    Button login = (Button) findViewById(R.id.btnLogin);
    login.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            String requestToken = getRequestToken();
            Log.d(LOG_TAG, requestToken);
            Intent authIntent = new Intent("android.intent.action.VIEW",
                    Uri.parse(getString(R.string.auth_uri) + requestToken));
            startActivity(authIntent);
        }

        private String getRequestToken() {
            RestTemplate restTemplate = RestUtil.getRestTemplate();
            RequestToken resp = restTemplate.getForObject(getString(R.string.request_uri), RequestToken.class, getString(R.string.api_key));
            return resp.getRequestToken();
        }
    });
}

Once authenticated, the authToken is stored in SharedPreference for use till it expires.  BrowseActivity takes in the folder ID, and then does REST call, get_account_tree, to render result in a WebView.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.browse);
    restUri = getString(R.string.rest_uri);
    apiKey = getString(R.string.api_key);

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    String folderId = prefs.getString(LAST_VIEWED_FOLDER, "0");
    authToken = prefs.getString(AUTH_TOKEN_KEY, "");

    Uri uri = this.getIntent().getData();
    if (uri != null) {
        folderId = uri.getPath().substring(1);
    }
    Log.d(LOG_TAG, "loading folder from onCreate()");
    loadFolder(folderId);

}

BrowseActivity also has a menu which allows users to log out Box to clear the authToken

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.logout:
        RestTemplate rest = RestUtil.getRestTemplate();
        RestResponse response = rest.getForObject(getString(R.string.logout_uri), RestResponse.class, apiKey, authToken);
        Log.d(LOG_TAG, "log out with status:" + response.getStatus());
        clearPreferences(PreferenceManager.getDefaultSharedPreferences(this));
        break;
    }
    return super.onOptionsItemSelected(item);
}

The following is a sample XML and its corresponding binding Java class,

<?xml version='1.0' encoding='UTF-8' ?>
<response>
    <status>listing_ok</status>
    <tree>
        <folder id="0" name="" description="" user_id="12001548"
            shared="" shared_link="" permissions="dcouv" size="320908"
            file_count="" created="" updated="">
            <tags></tags>
            <folders>
                <folder id="85546770" name="test1" description="" user_id="12001548"
                    shared="1" shared_link="https://www.box.net/shared/syquihyigb"
                    permissions="kcgtedopnsuv" size="247783" file_count="9" created="1305389671"
                    updated="1305934225">
                    <tags></tags>
                </folder>
                <folder id="86461258" name="test2" description="" user_id="12001548"
                    shared="0" shared_link="" permissions="kcgtedopnsuv" size="6200"
                    file_count="3" created="1305752928" updated="1305942446">
                    <tags></tags>
                </folder>
            </folders>
            <files>
                <file id="748234686" file_name="assetList.jsp" shared="0"
                    ...">
                    <tags></tags>
                </file>
            </files>
        </folder>
    </tree>
</response>
@Root(name="response", strict=false)
public class AccountTree {
    @Element
    private String status;

    @ElementList(required=false)
    @Path("tree/folder")
    private List<FolderItem> folders;

    @ElementList(required=false)
    @Path("tree/folder")
    private List<FileItem> files;

    public List<FolderItem> getFolders() {
        return folders;
    }
    public void setFolders(List<FolderItem> folders) {
        this.folders = folders;
    }
    public List<FileItem> getFiles() {
        return files;
    }
    public void setFiles(List<FileItem> files) {
        this.files = files;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    public String getStatus() {
        return status;
    }
}

A few screenshots of this application in action.

This entry was posted in Android, Cloud and tagged , , . Bookmark the permalink.

One Response to Simple XML with Android and Box.net

  1. Pingback: Upload file in Android with Spring RestTemplate | Agile SOA Cloud

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>