Home | History | Annotate | Download | only in justforus
      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.justforus;
     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.database.MatrixCursor;
     26 import android.net.Uri;
     27 import android.provider.OpenableColumns;
     28 import android.util.Log;
     29 
     30 import java.io.FileNotFoundException;
     31 import java.io.IOException;
     32 
     33 import static java.net.URLConnection.guessContentTypeFromName;
     34 
     35 /**
     36  * Generic content provider, which makes any files available in this app's "assets" directory
     37  * available publicly.
     38  *
     39  * <p>To use, add the following to your AndroidManifest.xml:
     40  *
     41  * <code><pre>
     42  * <provider
     43  *   android:name=".AssetProvider"
     44  *   android:authorities="[YOUR CONTENT PROVIDER DOMAIN HERE]"
     45  *   android:grantUriPermissions="true"
     46  *   android:exported="true"/>
     47  * </pre></code>
     48  */
     49 public class AssetProvider extends ContentProvider {
     50 
     51     /**
     52      * Content provider authority that identifies data that is offered by this
     53      * {@link AssetProvider}.
     54      */
     55     public static String CONTENT_URI = "com.example.android.justforus";
     56 
     57     private static final String TAG = "AssetProvider";
     58 
     59     AssetManager mAssets;
     60 
     61     @Override
     62     public boolean onCreate() {
     63         Context ctx = getContext();
     64         if (ctx == null) {
     65             // Context not available. Give up.
     66             return false;
     67         }
     68         mAssets = ctx.getAssets();
     69         return true;
     70     }
     71 
     72     @Override
     73     public String getType(Uri uri){
     74         // Returns the MIME type for the selected URI, in conformance with the ContentProvider
     75         // interface. Looks up the file indicated by /res/assets/{uri.path}, and returns the MIME
     76         // type for that file as guessed by the URLConnection class.
     77 
     78         // Setup
     79         String path = uri.getLastPathSegment();
     80 
     81         // Check if file exists
     82         if (!fileExists(path)) {
     83             return null;
     84         }
     85 
     86         // Determine MIME-type based on filename
     87         return guessContentTypeFromName(uri.toString());
     88     }
     89 
     90 
     91     @Override
     92     public AssetFileDescriptor openAssetFile (Uri uri, String mode)
     93             throws FileNotFoundException, SecurityException {
     94         // ContentProvider interface for opening a file descriptor by URI. This content provider
     95         // maps all URIs to the contents of the APK's assets folder, so a file handle to
     96         // /res/assets/{uri.path} will be returned.
     97 
     98         // Security check. This content provider only supports read-only access. (Also, the contents
     99         // of an APKs assets folder are immutable, so read-write access doesn't make sense here.)
    100         if (!"r".equals(mode)) {
    101             throw new SecurityException("Only read-only access is supported, mode must be [r]");
    102         }
    103 
    104         // Open asset from within APK and return file descriptor
    105         String path = uri.getLastPathSegment();
    106         try {
    107             return mAssets.openFd(path);
    108         } catch (IOException e) {
    109             throw new FileNotFoundException();
    110         }
    111     }
    112 
    113     /**
    114      * Check if file exists inside APK assets.
    115      *
    116      * @param path Fully qualified path to file.
    117      * @return true if exists, false otherwise.
    118      */
    119     private boolean fileExists(String path) {
    120         try {
    121             // Check to see if file can be opened. If so, file exists.
    122             mAssets.openFd(path).close();
    123             return true;
    124         } catch (IOException e) {
    125             // Unable to open file descriptor for specified path; file doesn't exist.
    126             return false;
    127         }
    128     }
    129 
    130     @Override
    131     public Cursor query(Uri uri, String[] projection, String selection,
    132                         String[] selectionArgs, String sortOrder) {
    133         String path = uri.getLastPathSegment();
    134         if (!fileExists(path)) {
    135             Log.e(TAG, "Requested file doesn't exist at " + path);
    136             return null;
    137         }
    138 
    139         // Create matrix cursor
    140         if (projection == null) {
    141             projection = new String[]{
    142                     OpenableColumns.DISPLAY_NAME,
    143                     OpenableColumns.SIZE,
    144             };
    145         }
    146 
    147         MatrixCursor matrixCursor = new MatrixCursor(projection, 1);
    148         Object[] row = new Object[projection.length];
    149         for (int col = 0; col < projection.length; col++) {
    150             if (OpenableColumns.DISPLAY_NAME.equals(projection[col])) {
    151                 row[col] = path;
    152             } else if (OpenableColumns.SIZE.equals(projection[col])) {
    153                 try {
    154                     AssetFileDescriptor afd = openAssetFile(uri, "r");
    155                     if (afd != null) {
    156                         row[col] = Long.valueOf(afd.getLength());
    157                     }
    158                     afd.close();
    159                 } catch (IOException e) {
    160                     Log.e(TAG, e.toString());
    161                 }
    162             }
    163         }
    164         matrixCursor.addRow(row);
    165         return matrixCursor;
    166     }
    167 
    168     // Required/unused ContentProvider methods below.
    169     @Override
    170     public Uri insert(Uri uri, ContentValues contentValues) {
    171         throw new RuntimeException("Operation not supported");
    172     }
    173 
    174     @Override
    175     public int delete(Uri uri, String selection, String[] selectionArgs) {
    176         throw new RuntimeException("Operation not supported");
    177     }
    178 
    179     @Override
    180     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    181         throw new RuntimeException("Operation not supported");
    182     }
    183 }
    184