Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content;
     18 
     19 import android.database.Cursor;
     20 import android.net.Uri;
     21 import android.os.Bundle;
     22 import android.os.CancellationSignal;
     23 import android.os.DeadObjectException;
     24 import android.os.ICancellationSignal;
     25 import android.os.RemoteException;
     26 import android.os.ParcelFileDescriptor;
     27 import android.content.res.AssetFileDescriptor;
     28 
     29 import java.io.FileNotFoundException;
     30 import java.util.ArrayList;
     31 
     32 /**
     33  * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
     34  * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
     35  * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
     36  * no longer needed and can be killed to free up resources.
     37  *
     38  * <p>Note that you should generally create a new ContentProviderClient instance
     39  * for each thread that will be performing operations.  Unlike
     40  * {@link ContentResolver}, the methods here such as {@link #query} and
     41  * {@link #openFile} are not thread safe -- you must not call
     42  * {@link #release()} on the ContentProviderClient those calls are made from
     43  * until you are finished with the data they have returned.
     44  */
     45 public class ContentProviderClient {
     46     private final IContentProvider mContentProvider;
     47     private final ContentResolver mContentResolver;
     48     private final String mPackageName;
     49     private final boolean mStable;
     50     private boolean mReleased;
     51 
     52     /**
     53      * @hide
     54      */
     55     ContentProviderClient(ContentResolver contentResolver,
     56             IContentProvider contentProvider, boolean stable) {
     57         mContentProvider = contentProvider;
     58         mContentResolver = contentResolver;
     59         mPackageName = contentResolver.mPackageName;
     60         mStable = stable;
     61     }
     62 
     63     /** See {@link ContentProvider#query ContentProvider.query} */
     64     public Cursor query(Uri url, String[] projection, String selection,
     65             String[] selectionArgs, String sortOrder) throws RemoteException {
     66         try {
     67             return query(url, projection, selection,  selectionArgs, sortOrder, null);
     68         } catch (DeadObjectException e) {
     69             if (!mStable) {
     70                 mContentResolver.unstableProviderDied(mContentProvider);
     71             }
     72             throw e;
     73         }
     74     }
     75 
     76     /** See {@link ContentProvider#query ContentProvider.query} */
     77     public Cursor query(Uri url, String[] projection, String selection,
     78             String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
     79                     throws RemoteException {
     80         ICancellationSignal remoteCancellationSignal = null;
     81         if (cancellationSignal != null) {
     82             remoteCancellationSignal = mContentProvider.createCancellationSignal();
     83             cancellationSignal.setRemote(remoteCancellationSignal);
     84         }
     85         try {
     86             return mContentProvider.query(mPackageName, url, projection, selection,  selectionArgs,
     87                     sortOrder, remoteCancellationSignal);
     88         } catch (DeadObjectException e) {
     89             if (!mStable) {
     90                 mContentResolver.unstableProviderDied(mContentProvider);
     91             }
     92             throw e;
     93         }
     94     }
     95 
     96     /** See {@link ContentProvider#getType ContentProvider.getType} */
     97     public String getType(Uri url) throws RemoteException {
     98         try {
     99             return mContentProvider.getType(url);
    100         } catch (DeadObjectException e) {
    101             if (!mStable) {
    102                 mContentResolver.unstableProviderDied(mContentProvider);
    103             }
    104             throw e;
    105         }
    106     }
    107 
    108     /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
    109     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
    110         try {
    111             return mContentProvider.getStreamTypes(url, mimeTypeFilter);
    112         } catch (DeadObjectException e) {
    113             if (!mStable) {
    114                 mContentResolver.unstableProviderDied(mContentProvider);
    115             }
    116             throw e;
    117         }
    118     }
    119 
    120     /** See {@link ContentProvider#insert ContentProvider.insert} */
    121     public Uri insert(Uri url, ContentValues initialValues)
    122             throws RemoteException {
    123         try {
    124             return mContentProvider.insert(mPackageName, url, initialValues);
    125         } catch (DeadObjectException e) {
    126             if (!mStable) {
    127                 mContentResolver.unstableProviderDied(mContentProvider);
    128             }
    129             throw e;
    130         }
    131     }
    132 
    133     /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
    134     public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
    135         try {
    136             return mContentProvider.bulkInsert(mPackageName, url, initialValues);
    137         } catch (DeadObjectException e) {
    138             if (!mStable) {
    139                 mContentResolver.unstableProviderDied(mContentProvider);
    140             }
    141             throw e;
    142         }
    143     }
    144 
    145     /** See {@link ContentProvider#delete ContentProvider.delete} */
    146     public int delete(Uri url, String selection, String[] selectionArgs)
    147             throws RemoteException {
    148         try {
    149             return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
    150         } catch (DeadObjectException e) {
    151             if (!mStable) {
    152                 mContentResolver.unstableProviderDied(mContentProvider);
    153             }
    154             throw e;
    155         }
    156     }
    157 
    158     /** See {@link ContentProvider#update ContentProvider.update} */
    159     public int update(Uri url, ContentValues values, String selection,
    160             String[] selectionArgs) throws RemoteException {
    161         try {
    162             return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
    163         } catch (DeadObjectException e) {
    164             if (!mStable) {
    165                 mContentResolver.unstableProviderDied(mContentProvider);
    166             }
    167             throw e;
    168         }
    169     }
    170 
    171     /**
    172      * See {@link ContentProvider#openFile ContentProvider.openFile}.  Note that
    173      * this <em>does not</em>
    174      * take care of non-content: URIs such as file:.  It is strongly recommended
    175      * you use the {@link ContentResolver#openFileDescriptor
    176      * ContentResolver.openFileDescriptor} API instead.
    177      */
    178     public ParcelFileDescriptor openFile(Uri url, String mode)
    179             throws RemoteException, FileNotFoundException {
    180         try {
    181             return mContentProvider.openFile(mPackageName, url, mode);
    182         } catch (DeadObjectException e) {
    183             if (!mStable) {
    184                 mContentResolver.unstableProviderDied(mContentProvider);
    185             }
    186             throw e;
    187         }
    188     }
    189 
    190     /**
    191      * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
    192      * Note that this <em>does not</em>
    193      * take care of non-content: URIs such as file:.  It is strongly recommended
    194      * you use the {@link ContentResolver#openAssetFileDescriptor
    195      * ContentResolver.openAssetFileDescriptor} API instead.
    196      */
    197     public AssetFileDescriptor openAssetFile(Uri url, String mode)
    198             throws RemoteException, FileNotFoundException {
    199         try {
    200             return mContentProvider.openAssetFile(mPackageName, url, mode);
    201         } catch (DeadObjectException e) {
    202             if (!mStable) {
    203                 mContentResolver.unstableProviderDied(mContentProvider);
    204             }
    205             throw e;
    206         }
    207     }
    208 
    209     /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
    210     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
    211             String mimeType, Bundle opts)
    212             throws RemoteException, FileNotFoundException {
    213         try {
    214             return mContentProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
    215         } catch (DeadObjectException e) {
    216             if (!mStable) {
    217                 mContentResolver.unstableProviderDied(mContentProvider);
    218             }
    219             throw e;
    220         }
    221     }
    222 
    223     /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
    224     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
    225             throws RemoteException, OperationApplicationException {
    226         try {
    227             return mContentProvider.applyBatch(mPackageName, operations);
    228         } catch (DeadObjectException e) {
    229             if (!mStable) {
    230                 mContentResolver.unstableProviderDied(mContentProvider);
    231             }
    232             throw e;
    233         }
    234     }
    235 
    236     /** See {@link ContentProvider#call(String, String, Bundle)} */
    237     public Bundle call(String method, String arg, Bundle extras)
    238             throws RemoteException {
    239         try {
    240             return mContentProvider.call(mPackageName, method, arg, extras);
    241         } catch (DeadObjectException e) {
    242             if (!mStable) {
    243                 mContentResolver.unstableProviderDied(mContentProvider);
    244             }
    245             throw e;
    246         }
    247     }
    248 
    249     /**
    250      * Call this to indicate to the system that the associated {@link ContentProvider} is no
    251      * longer needed by this {@link ContentProviderClient}.
    252      * @return true if this was release, false if it was already released
    253      */
    254     public boolean release() {
    255         synchronized (this) {
    256             if (mReleased) {
    257                 throw new IllegalStateException("Already released");
    258             }
    259             mReleased = true;
    260             if (mStable) {
    261                 return mContentResolver.releaseProvider(mContentProvider);
    262             } else {
    263                 return mContentResolver.releaseUnstableProvider(mContentProvider);
    264             }
    265         }
    266     }
    267 
    268     /**
    269      * Get a reference to the {@link ContentProvider} that is associated with this
    270      * client. If the {@link ContentProvider} is running in a different process then
    271      * null will be returned. This can be used if you know you are running in the same
    272      * process as a provider, and want to get direct access to its implementation details.
    273      *
    274      * @return If the associated {@link ContentProvider} is local, returns it.
    275      * Otherwise returns null.
    276      */
    277     public ContentProvider getLocalContentProvider() {
    278         return ContentProvider.coerceToLocalContentProvider(mContentProvider);
    279     }
    280 }
    281