Search This Blog

Showing posts with label live folder. Show all posts
Showing posts with label live folder. Show all posts

01 July 2010

Content Provider and Live Folder

We're going to create a basic ContentProvider example based on this tutorial.

Let's start with a multi-module project:

F:\work> mkdir ProviderTest
F:\work> cd ProviderTest

F:\work\ProviderTest> mvn archetype:generate -DarchetypeCatalog=http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml
2: http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml -> galatea-archetype (null)
Confirm properties configuration:
groupId: org.eoti.android.providertest.provider
artifactId: TestProvider
version: 1.0-SNAPSHOT
package: org.eoti.android.providertest.provider

F:\work\ProviderTest> mvn archetype:generate -DarchetypeCatalog=http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml
2: http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml -> galatea-archetype (null)
Confirm properties configuration:
groupId: org.eoti.android.providertest.consumer
artifactId: TestConsumer
version: 1.0-SNAPSHOT
package: org.eoti.android.providertest.consumer

F:\work\ProviderTest> mvn archetype:generate -DarchetypeCatalog=http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml
2: http://kallisti.eoti.org:8081/content/repositories/snapshots/archetype-catalog.xml -> galatea-archetype (null)
Confirm properties configuration:
groupId: org.eoti.android.providertest.generator
artifactId: TestGenerator
version: 1.0-SNAPSHOT
package: org.eoti.android.providertest.generator

Create a top-level pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>org.eoti.android.providertest</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>ProviderTest</artifactId>
    <packaging>pom</packaging>
    <name>ProviderTest</name>
    <description>Testing a simple Content Provider and consumer</description>

    <modules>
        <module>TestProvider</module>
        <module>TestConsumer</module>
        <module>TestGenerator</module>
    </modules>
</project>

Open the TestProvider\pom.xml and TestConsumer\pom.xml and add a parent to the pom.xml:
    <parent>
        <groupId>org.eoti.android.providertest</groupId>
        <version>1.0-SNAPSHOT</version>
        <artifactId>ProviderTest</artifactId>
    </parent>


F:\work\ProviderTest> mvn clean install

Replace TestProviderActivity.java with TestProvider.java:
package org.eoti.android.providertest.provider;

import android.app.Activity;
import android.content.*;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.LiveFolders;
import android.text.TextUtils;
import android.util.Log;

import java.util.HashMap;

public class TestProvider
extends ContentProvider
{
    // Derived from http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NotePadProvider.html
   
    public static final String AUTHORITY = "org.eoti.android.providertest";
    private static class Logs implements BaseColumns
    {
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/logs");
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.eoti.logs";
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.eoti.log";
        public static final String DEFAULT_SORT_ORDER = "modified DESC";
        public static final String LOG = "log";
        public static final String TIMESTAMP = "timestamp";
    }

    private static String TAG = "TestProvider";
    private static final String DATABASE_NAME = "providertest.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_NAME = "logs";
    private static final int LOGS = 1;
    private static final int LOG_ID = 2;
    private static final int LIVE_FOLDER_LOGS = 3;
    private static HashMap<String, String> logsProjectionMap;
    private static HashMap<String, String> folderProjectionMap;
    private static final UriMatcher uriMatcher;


    private static class DatabaseHelper extends SQLiteOpenHelper
    {
        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
           
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + TABLE_NAME + " ("
                + Logs._ID + " INTEGER PRIMARY KEY,"
                + Logs.LOG + " TEXT,"
                + Logs.TIMESTAMP + " INTEGER"
                + ");");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS notes");
            onCreate(db);
        }
    }
    private DatabaseHelper dbHelper;
   

    @Override
    public boolean onCreate() {
        dbHelper = new DatabaseHelper(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(TABLE_NAME);

        switch (uriMatcher.match(uri)) {
            case LOGS:
                qb.setProjectionMap(logsProjectionMap);
                break;
            case LOG_ID:
                qb.setProjectionMap(logsProjectionMap);
                qb.appendWhere(Logs._ID + "=" + uri.getPathSegments().get(1));
                break;
            case LIVE_FOLDER_LOGS:
                qb.setProjectionMap(folderProjectionMap);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        String orderBy = (TextUtils.isEmpty(sortOrder) ? Logs.DEFAULT_SORT_ORDER : sortOrder);

        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case LOGS:
            case LIVE_FOLDER_LOGS:
                return Logs.CONTENT_TYPE;
            case LOG_ID:
                return Logs.CONTENT_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        if (uriMatcher.match(uri) != LOGS)
            throw new IllegalArgumentException("Unknown URI " + uri);

        ContentValues values = (initialValues == null) ? new ContentValues() : new ContentValues(initialValues);

        if(!values.containsKey(Logs.TIMESTAMP))
            values.put(Logs.TIMESTAMP, System.currentTimeMillis());

        if(!values.containsKey(Logs.LOG))
            values.put(Logs.LOG, "");

        SQLiteDatabase db = dbHelper.getWritableDatabase();
        long rowId = db.insert(TABLE_NAME, Logs.LOG, values);
        if (rowId > 0) {
            Uri noteUri = ContentUris.withAppendedId(Logs.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(noteUri, null);
            return noteUri;
        }

        throw new SQLException("Failed to insert row into " + uri);
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int count;
        switch (uriMatcher.match(uri)) {
            case LOGS:
                count = db.delete(TABLE_NAME, where, whereArgs);
                break;
            case LOG_ID:
                String noteId = uri.getPathSegments().get(1);
                count = db.delete(TABLE_NAME, Logs._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int count;
        switch (uriMatcher.match(uri)) {
            case LOGS:
                count = db.update(TABLE_NAME, values, where, whereArgs);
                break;
            case LOG_ID:
                String noteId = uri.getPathSegments().get(1);
                count = db.update(TABLE_NAME, values, Logs._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;   
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "logs", LOGS);
        uriMatcher.addURI(AUTHORITY, "logs/#", LOG_ID);
        uriMatcher.addURI(AUTHORITY, "livefolders/logs", LIVE_FOLDER_LOGS);

        logsProjectionMap = new HashMap<String,String>();
        logsProjectionMap.put(Logs._ID, Logs._ID);
        logsProjectionMap.put(Logs.LOG, Logs.LOG);
        logsProjectionMap.put(Logs.TIMESTAMP, Logs.TIMESTAMP);

        folderProjectionMap = new HashMap<String, String>();
        folderProjectionMap.put(LiveFolders._ID, Logs._ID + " AS " + LiveFolders._ID);
        folderProjectionMap.put(LiveFolders.NAME, Logs.LOG + " AS " + LiveFolders.NAME);
    }
}


Change your TestProvider\AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.eoti.android.providertest.provider">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name="TestProvider" android:authorities="org.eoti.android.providertest"/>
    </application>
</manifest>


Replace TestConsumerActivity.java with TestConsumer.java:
package org.eoti.android.providertest.consumer;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.LiveFolders;

public class TestConsumer extends Activity
{
    public static final String AUTHORITY = "org.eoti.android.providertest";

    private static String TAG = "TestConsumer";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/livefolders/logs");
    public static final Uri LOG_URI = Uri.parse("content://" + AUTHORITY + "/logs/#");

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

        final Intent intent = getIntent();
        final String action = intent.getAction();

        if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action))
        {
            final Intent liveFolderIntent = new Intent();

            liveFolderIntent.setData(CONTENT_URI);
            liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, getString(R.string.app_name));
            liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON, Intent.ShortcutIconResource.fromContext(this, R.drawable.icon));
            liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);
            liveFolderIntent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT, new Intent(Intent.ACTION_EDIT, LOG_URI));
            setResult(RESULT_OK, liveFolderIntent);
        } else {
            setResult(RESULT_CANCELED);
        }

        finish();
    }
}



Change your TestConsumer\AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.eoti.android.providertest.consumer">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="TestConsumer" android:label="@string/app_name" android:icon="@drawable/icon">
            <intent-filter>
                <action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>


Update your TestGeneratorActivity:
package org.eoti.android.providertest.generator;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestGeneratorActivity extends Activity {
    public static final String AUTHORITY = "org.eoti.android.providertest";
    private static String TAG = "TestGenerator";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/logs");
    private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ContentValues values = new ContentValues();
        long time = System.currentTimeMillis();
        values.put("timestamp", time);
        values.put("log", sdf.format(new Date(time)));

        Uri uri = getContentResolver().insert(CONTENT_URI, values);
        Toast.makeText(getApplicationContext(), (uri == null) ? " null " : uri.toString(), Toast.LENGTH_SHORT).show();
        finish();
    }
}


Redeploy (mvn clean install).  Launch the generator app.  Add the live folder to your desktop.  Launch it.  Run the generator a few more times. Launch the folder again.