Home | History | Annotate | Download | only in assetprovider
      1 /*
      2 * Copyright (C) 2013 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 com.example.android.common.assetprovider;
     18 
     19 import android.content.ContentProvider;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.content.res.AssetFileDescriptor;
     23 import android.content.res.AssetManager;
     24 import android.database.Cursor;
     25 import android.net.Uri;
     26 
     27 import java.io.FileNotFoundException;
     28 import java.io.IOException;
     29 
     30 import static java.net.URLConnection.guessContentTypeFromName;
     31 
     32 /**
     33  * Generic content provider, which makes any files available in this app's "assets" directory
     34  * available publicly.
     35  *
     36  * <p>To use, add the following to your AndroidManifest.xml:
     37  *
     38  * <code><pre>
     39  * <provider
     40  *   android:name=".AssetProvider"
     41  *   android:authorities="[YOUR CONTENT PROVIDER DOMAIN HERE]"
     42  *   android:exported="true"/>
     43  * </pre></code>
     44  */
     45 public class AssetProvider extends ContentProvider {
     46     AssetManager mAssets;
     47 
     48     @Override
     49     public boolean onCreate() {
     50         Context ctx = getContext();
     51         if (ctx == null) {
     52             // Context not available. Give up.
     53             return false;
     54         }
     55         mAssets = ctx.getAssets();
     56         return true;
     57     }
     58 
     59     @Override
     60     public String getType(Uri uri){
     61         // Returns the MIME type for the selected URI, in conformance with the ContentProvider
     62         // interface. Looks up the file indicated by /res/assets/{uri.path}, and returns the MIME
     63         // type for that file as guessed by the URLConnection class.
     64 
     65         // Setup
     66         String path = uri.getPath();
     67 
     68         // Check if file exists
     69         if (!fileExists(path)) {
     70             return null;
     71         }
     72 
     73         // Determine MIME-type based on filename
     74         return guessContentTypeFromName(uri.toString());
     75     }
     76 
     77 
     78     @Override
     79     public AssetFileDescriptor openAssetFile (Uri uri, String mode)
     80             throws FileNotFoundException, SecurityException {
     81         // ContentProvider interface for opening a file descriptor by URI. This content provider
     82         // maps all URIs to the contents of the APK's assets folder, so a file handle to
     83         // /res/assets/{uri.path} will be returned.
     84 
     85         // Security check. This content provider only supports read-only access. (Also, the contents
     86         // of an APKs assets folder are immutable, so read-write access doesn't make sense here.)
     87         if (!"r".equals(mode)) {
     88             throw new SecurityException("Only read-only access is supported, mode must be [r]");
     89         }
     90 
     91         // Open asset from within APK and return file descriptor
     92         String path = uri.getPath();
     93         try {
     94             return mAssets.openFd(path);
     95         } catch (IOException e) {
     96             throw new FileNotFoundException();
     97         }
     98     }
     99 
    100     /**
    101      * Check if file exists inside APK assets.
    102      *
    103      * @param path Fully qualified path to file.
    104      * @return true if exists, false otherwise.
    105      */
    106     private boolean fileExists(String path) {
    107         try {
    108             // Check to see if file can be opened. If so, file exists.
    109             mAssets.openFd(path).close();
    110             return true;
    111         } catch (IOException e) {
    112             // Unable to open file descriptor for specified path; file doesn't exist.
    113             return false;
    114         }
    115     }
    116 
    117     // Required/unused ContentProvider methods below.
    118     @Override
    119     public Cursor query(Uri uri, String[] projection, String selection,
    120                         String[] selectionArgs, String sortOrder) {
    121         // Note: It might be worth implementing support for querying
    122         //       android.provider.OpenableColumns here in the future.
    123         throw new RuntimeException("Operation not supported");
    124     }
    125 
    126     @Override
    127     public Uri insert(Uri uri, ContentValues contentValues) {
    128         throw new RuntimeException("Operation not supported");
    129     }
    130 
    131     @Override
    132     public int delete(Uri uri, String selection, String[] selectionArgs) {
    133         throw new RuntimeException("Operation not supported");
    134     }
    135 
    136     @Override
    137     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    138         throw new RuntimeException("Operation not supported");
    139     }
    140 }
    141