2010年9月20日 星期一

[Android] ContentProvider的權限設定

看起來沒啥, 結果快搞死我了...
廢話不多說, 情境就是如果Android的process間要共享資源, 通常會實做ContentProvider+SQLite, 再export出適合的uri
如果想要對ContentProvider設定讀/寫的權限, 要從Manifest.xml下手, 以下範例:

ContentProvider(提供讀/寫的權限)
<manifest ...>
  <application ...>
  <provider 
    android:name="{PROVIDER_CLASS}"
    android:authorities="{AUTHORITY}"
    android:multiprocess="true"                
    android:readPermission="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}"
    android:writePermission="{CONTENTPROVIDER_PACKAGE}.{WRITE_PERMISSION}>
  </provider>
  <activity ...></activity>
</application>
</manifest> 

ContentResolver(設定為只有讀的權限)
<manifest ...>
  <application ...>
    <activity ...></activity>
  </application>
  <uses-permission android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
  <permission-tree android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
  <permission 
  android:protectionLevel="dangerous" 
  android:name="{CONTENTPROVIDER_PACKAGE}.{READ_PERMISSION}" />
</manifest>


實例說明:
ContentProvider.apk
/src/demo/content/provider/myObj.java
/src/demo/content/provider/myObjProvider.java
/src/demo/content/provider/myContentProvider.java
/res/main.xml
AndroidManifest.xml

myObj.java
package demo.content.provider;

import android.net.Uri;
import android.provider.BaseColumns;

public class myObj implements BaseColumns {
  public static final String AUTHORITY = "demo.content.provider";
  public static final String PATH_SINGLE = "obj/";
  public static final String PATH_MULTIPLE = "objs";

  public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" +  PATH_MULTIPLE);
  public static final String NAME = "name";
}

myObjProvider.java
package demo.content.provider;

import java.util.HashMap;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;

public class myObjProvider extends ContentProvider {
  private static final int OBJS = 1;
  private static final int OBJ = 2;
  public static final String DATABASE_NAME = "ContentProvider.db";
  public static final String TABLE_NAME = "obj";
  public static final int DATABASE_VERSION = 1;

  private static UriMatcher URI_MATCHER = null;
  private static HashMap<String, String> PROJECTION_MAP;
  private static SQLiteDatabase db;

  static {
    URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    URI_MATCHER.addURI(myObj.AUTHORITY, myObj.PATH_MULTIPLE, OBJS);
    URI_MATCHER.addURI(myObj.AUTHORITY, myObj.PATH_SINGLE, OBJ);
    PROJECTION_MAP  = new HashMap<String, String>();
    PROJECTION_MAP.put(BaseColumns._ID, "_id");
    PROJECTION_MAP.put(myObj.NAME, "name");
  }

  @Override
  public boolean onCreate() {
    DbHelper mDbHelper = new DbHelper(getContext());
    return (db = mDbHelper.getWritableDatabase()) != null ? true : false;
  }


  //
  // DbHelper
  //
  private static class DbHelper extends SQLiteOpenHelper {
    private static final String DATABASE_CREATE = "CREATE TABLE " +
      myObjProvider.TABLE_NAME +
      "(_id INTEGER PRIMARY KEY, " +
      "name TEXT UNIQUE NOT NULL)";

    public DbHelper(Context context) {
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
      db.execSQL(DbHelper.DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

    @Override
    public void onOpen(SQLiteDatabase db) {
      super.onOpen(db);
    }
  }

  //
  // implement abstract methods
  //
  public int delete(Uri uri, String selection, String[] selectionArgs) {
    int count = 0;

    switch (myObjProvider.URI_MATCHER.match(uri)) {
      case OBJS:
        count = db.delete(TABLE_NAME, selection, selectionArgs);
      break;
      case OBJ:
        String segment = uri.getPathSegments().get(1);
        String where = "";

        if (selection.length() != 0) {
          where = " AND (" + selection + ");";
        }
        count = db.delete(TABLE_NAME, "_id=" + segment + where, selectionArgs);
      break;
      default:
    }

    return count;
  }


  public String getType(Uri uri) {
    return null;
  }

  public Uri insert(Uri uri, ContentValues values) {
    long rowId = 0L;
    ContentValues cv = null;

    if (values != null) {
      cv = new ContentValues(values);
    } else {
      cv = new ContentValues();
    }

    rowId = db.insert(TABLE_NAME, null, cv);
    Uri result = ContentUris.withAppendedId(uri, rowId);

    return result;
  }

  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    String orderBy = null;

    switch (myObjProvider.URI_MATCHER.match(uri)) {
      case OBJS:
        queryBuilder.setTables(myObjProvider.TABLE_NAME);
        queryBuilder.setProjectionMap(myObjProvider.PROJECTION_MAP);
      break;
      case OBJ:
        queryBuilder.setTables(myObjProvider.TABLE_NAME);
        queryBuilder.appendWhere("_id=" + uri.getPathSegments().get(1));
      break;
      default:
    }

    Cursor c = queryBuilder.query(db, projection, selection, selectionArgs, null, null, orderBy);
    c.setNotificationUri(this.getContext().getContentResolver(), uri);
  
    return c;
  }

  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    /*
    int count = 0;
    switch (myObjProvider.URI_MATCHER.match(uri)) {
    case OBJ:
    count = db.update(myObjProvider.TABLE_NAME, values, selection, selectionArgs);
    break;
    case OBJS:
    String segment = uri.getPathSegments().get(1);
    String where = ""; 
    if (!TextUtils.isEmpty(selection)) {
    where = " AND (" + selection + ")";
    }   
    count = db.update(myObjProvider.TABLE_NAME, values, "_id=" + segment + where, selectionArgs);
    break;
    default:
    }   

    return count;
    */
    return 0;
  }
}

myContentProvider.java
package demo.content.provider;

import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SimpleCursorAdapter;

public class myContentProvider extends ListActivity {
  private EditText addName;
  private Button addButton;

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

    addName = (EditText) findViewById(R.id.add_name);
    addButton = (Button) findViewById(R.id.add_button);
    addButton.setOnClickListener(new OnClickListener() {
      public void onClick(View v){
        add();
        fillAdapter();
      }
    });
  }

  @Override
  public void onStart() {
    super.onStart();
    fillAdapter();
   }

  private void fillAdapter() {
    String[] projection = new String[]{myObj._ID, myObj.NAME};
    ContentResolver resolver = this.getContentResolver();
    Cursor mCursor = resolver.query(myObj.CONTENT_URI, projection, null, null, null);
    startManagingCursor(mCursor);
    String[] from = new String[]{myObj.NAME};
    int[] to = new int[]{android.R.id.text1};

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, mCursor, from, to);
    setListAdapter(adapter);
  }

  private void add() {
    ContentValues cv = new ContentValues();
    cv.put(myObj.NAME, addName.getText().toString());
    getContentResolver().insert(myObj.CONTENT_URI, cv);
  }
}

main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="wrap_content"
  android:scrollbars="none">

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

   <TextView android:layout_width="wrap_content"
     android:layout_height="wrap_content" android:layout_marginLeft="10px"
     android:layout_marginBottom="5px" android:text="-Add NEW Item-" />
   <EditText android:id="@+id/add_name"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content" android:layout_marginLeft="10px"
     android:layout_marginBottom="5px" android:text="" />
   <Button android:id="@+id/add_button"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content" android:layout_marginLeft="10px"
     android:layout_marginBottom="15px" android:text="Add" />
   <ListView
     android:id="@+id/android:list"  
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" />
  </LinearLayout>
</ScrollView>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="demo.content.provider"
  android:versionCode="1"
  android:versionName="1.0">
  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <provider android:name="myObjProvider"
      android:authorities="demo.content.provider"
      android:multiprocess="true"
      android:readPermission="demo.content.provider.PERMISSION.READ"
      android:writePermission="demo.content.provider.PERMISSION.WRITE">
    </provider>

    <activity android:name=".myContentProvider"
      android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
</manifest> 


ContentResolver.apk(設定為有讀/寫的權限)
package demo.content.resolver;

import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.widget.SimpleCursorAdapter;

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

    String[] projection = new String[]{"_id", "name"};
    Uri uri = Uri.parse("content://demo.content.provider/objs");

    ContentResolver resolver = this.getContentResolver();

    //
    // insert
    //
    ContentValues cv = new ContentValues();
    cv.put("name", "insert_value_by_content_resolver");
    resolver.insert(uri, cv);

    //
    // query
    // 
    Cursor mCursor = resolver.query(uri, projection, null, null, null);
    startManagingCursor(mCursor);
    String[] from = new String[]{"name"};
    int[] to = new int[]{android.R.id.text1};
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, mCursor, from, to);
    setListAdapter(adapter);
  }
}

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <ListView
    android:id="@+id/android:list"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"  />
</LinearLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="demo.content.resolver"
  android:versionCode="1"
  android:versionName="1.0">
  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".myContentResolver"
      android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
  <uses-permission android:name="demo.content.provider.PERMISSION.READ"></uses-permission>
  <uses-permission android:name="demo.content.provider.PERMISSION.WRITE"></uses-permission>
  <permission-tree android:name="demo.content.provider.PERMISSION.READ"></permission-tree>
  <permission-tree android:name="demo.content.provider.PERMISSION.WRITE"></permission-tree>
  <permission android:protectionLevel="dangerous" android:name="demo.content.provider.PERMISSION.READ"></permission>
  <permission android:protectionLevel="dangerous" android:name="demo.content.provider.PERMISSION.WRITE"></permission>
</manifest>


* myContentProvider.apk here
* myContentResolver.apk here

沒有留言: