Home | History | Annotate | Download | only in provider
      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 com.android.gallery3d.provider;
     18 
     19 import android.content.ContentProvider;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.database.Cursor;
     23 import android.database.MatrixCursor;
     24 import android.net.Uri;
     25 import android.os.Binder;
     26 import android.os.Bundle;
     27 import android.os.ParcelFileDescriptor;
     28 import android.provider.MediaStore.Images.ImageColumns;
     29 import android.util.Log;
     30 
     31 import com.android.gallery3d.app.GalleryApp;
     32 import com.android.gallery3d.common.Utils;
     33 import com.android.gallery3d.data.DataManager;
     34 import com.android.gallery3d.data.MediaItem;
     35 import com.android.gallery3d.data.MediaObject;
     36 import com.android.gallery3d.data.MtpImage;
     37 import com.android.gallery3d.data.Path;
     38 import com.android.gallery3d.picasasource.PicasaSource;
     39 import com.android.gallery3d.util.GalleryUtils;
     40 
     41 import java.io.FileNotFoundException;
     42 import java.io.IOException;
     43 import java.io.OutputStream;
     44 
     45 public class GalleryProvider extends ContentProvider {
     46     private static final String TAG = "GalleryProvider";
     47 
     48     public static final String AUTHORITY = "com.android.gallery3d.provider";
     49     public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY);
     50 
     51     public static interface PicasaColumns {
     52         public static final String USER_ACCOUNT = "user_account";
     53         public static final String PICASA_ID = "picasa_id";
     54     }
     55 
     56     private static final String[] SUPPORTED_PICASA_COLUMNS = {
     57             PicasaColumns.USER_ACCOUNT,
     58             PicasaColumns.PICASA_ID,
     59             ImageColumns.DISPLAY_NAME,
     60             ImageColumns.SIZE,
     61             ImageColumns.MIME_TYPE,
     62             ImageColumns.DATE_TAKEN,
     63             ImageColumns.LATITUDE,
     64             ImageColumns.LONGITUDE,
     65             ImageColumns.ORIENTATION};
     66 
     67     private DataManager mDataManager;
     68     private static Uri sBaseUri;
     69 
     70     public static String getAuthority(Context context) {
     71         return context.getPackageName() + ".provider";
     72     }
     73 
     74     public static Uri getUriFor(Context context, Path path) {
     75         if (sBaseUri == null) {
     76             sBaseUri = Uri.parse("content://" + context.getPackageName() + ".provider");
     77         }
     78         return sBaseUri.buildUpon()
     79                 .appendEncodedPath(path.toString().substring(1)) // ignore the leading '/'
     80                 .build();
     81     }
     82 
     83     @Override
     84     public int delete(Uri uri, String selection, String[] selectionArgs) {
     85         throw new UnsupportedOperationException();
     86     }
     87 
     88     // TODO: consider concurrent access
     89     @Override
     90     public String getType(Uri uri) {
     91         long token = Binder.clearCallingIdentity();
     92         try {
     93             Path path = Path.fromString(uri.getPath());
     94             MediaItem item = (MediaItem) mDataManager.getMediaObject(path);
     95             return item != null ? item.getMimeType() : null;
     96         } finally {
     97             Binder.restoreCallingIdentity(token);
     98         }
     99     }
    100 
    101     @Override
    102     public Uri insert(Uri uri, ContentValues values) {
    103         throw new UnsupportedOperationException();
    104     }
    105 
    106     @Override
    107     public boolean onCreate() {
    108         GalleryApp app = (GalleryApp) getContext().getApplicationContext();
    109         mDataManager = app.getDataManager();
    110         return true;
    111     }
    112 
    113     // TODO: consider concurrent access
    114     @Override
    115     public Cursor query(Uri uri, String[] projection,
    116             String selection, String[] selectionArgs, String sortOrder) {
    117         long token = Binder.clearCallingIdentity();
    118         try {
    119             Path path = Path.fromString(uri.getPath());
    120             MediaObject object = mDataManager.getMediaObject(path);
    121             if (object == null) {
    122                 Log.w(TAG, "cannot find: " + uri);
    123                 return null;
    124             }
    125             if (PicasaSource.isPicasaImage(object)) {
    126                 return queryPicasaItem(object,
    127                         projection, selection, selectionArgs, sortOrder);
    128             } else if (object instanceof MtpImage) {
    129                 return queryMtpItem((MtpImage) object,
    130                         projection, selection, selectionArgs, sortOrder);
    131             } else {
    132                     return null;
    133             }
    134         } finally {
    135             Binder.restoreCallingIdentity(token);
    136         }
    137     }
    138 
    139     private Cursor queryMtpItem(MtpImage image, String[] projection,
    140             String selection, String[] selectionArgs, String sortOrder) {
    141         Object[] columnValues = new Object[projection.length];
    142         for (int i = 0, n = projection.length; i < n; ++i) {
    143             String column = projection[i];
    144             if (ImageColumns.DISPLAY_NAME.equals(column)) {
    145                 columnValues[i] = image.getName();
    146             } else if (ImageColumns.SIZE.equals(column)){
    147                 columnValues[i] = image.getSize();
    148             } else if (ImageColumns.MIME_TYPE.equals(column)) {
    149                 columnValues[i] = image.getMimeType();
    150             } else if (ImageColumns.DATE_TAKEN.equals(column)) {
    151                 columnValues[i] = image.getDateInMs();
    152             } else {
    153                 Log.w(TAG, "unsupported column: " + column);
    154             }
    155         }
    156         MatrixCursor cursor = new MatrixCursor(projection);
    157         cursor.addRow(columnValues);
    158         return cursor;
    159     }
    160 
    161     private Cursor queryPicasaItem(MediaObject image, String[] projection,
    162             String selection, String[] selectionArgs, String sortOrder) {
    163         if (projection == null) projection = SUPPORTED_PICASA_COLUMNS;
    164         Object[] columnValues = new Object[projection.length];
    165         double latitude = PicasaSource.getLatitude(image);
    166         double longitude = PicasaSource.getLongitude(image);
    167         boolean isValidLatlong = GalleryUtils.isValidLocation(latitude, longitude);
    168 
    169         for (int i = 0, n = projection.length; i < n; ++i) {
    170             String column = projection[i];
    171             if (PicasaColumns.USER_ACCOUNT.equals(column)) {
    172                 columnValues[i] = PicasaSource.getUserAccount(getContext(), image);
    173             } else if (PicasaColumns.PICASA_ID.equals(column)) {
    174                 columnValues[i] = PicasaSource.getPicasaId(image);
    175             } else if (ImageColumns.DISPLAY_NAME.equals(column)) {
    176                 columnValues[i] = PicasaSource.getImageTitle(image);
    177             } else if (ImageColumns.SIZE.equals(column)){
    178                 columnValues[i] = PicasaSource.getImageSize(image);
    179             } else if (ImageColumns.MIME_TYPE.equals(column)) {
    180                 columnValues[i] = PicasaSource.getContentType(image);
    181             } else if (ImageColumns.DATE_TAKEN.equals(column)) {
    182                 columnValues[i] = PicasaSource.getDateTaken(image);
    183             } else if (ImageColumns.LATITUDE.equals(column)) {
    184                 columnValues[i] = isValidLatlong ? latitude : null;
    185             } else if (ImageColumns.LONGITUDE.equals(column)) {
    186                 columnValues[i] = isValidLatlong ? longitude : null;
    187             } else if (ImageColumns.ORIENTATION.equals(column)) {
    188                 columnValues[i] = PicasaSource.getRotation(image);
    189             } else {
    190                 Log.w(TAG, "unsupported column: " + column);
    191             }
    192         }
    193         MatrixCursor cursor = new MatrixCursor(projection);
    194         cursor.addRow(columnValues);
    195         return cursor;
    196     }
    197 
    198     @Override
    199     public ParcelFileDescriptor openFile(Uri uri, String mode)
    200             throws FileNotFoundException {
    201         long token = Binder.clearCallingIdentity();
    202         try {
    203             if (mode.contains("w")) {
    204                 throw new FileNotFoundException("cannot open file for write");
    205             }
    206             Path path = Path.fromString(uri.getPath());
    207             MediaObject object = mDataManager.getMediaObject(path);
    208             if (object == null) {
    209                 throw new FileNotFoundException(uri.toString());
    210             }
    211             if (PicasaSource.isPicasaImage(object)) {
    212                 return PicasaSource.openFile(getContext(), object, mode);
    213             } else if (object instanceof MtpImage) {
    214                 return openPipeHelper(uri, null, null, null,
    215                         new MtpPipeDataWriter((MtpImage) object));
    216             } else {
    217                 throw new FileNotFoundException("unspported type: " + object);
    218             }
    219         } finally {
    220             Binder.restoreCallingIdentity(token);
    221         }
    222     }
    223 
    224     @Override
    225     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    226         throw new UnsupportedOperationException();
    227     }
    228 
    229     private final class MtpPipeDataWriter implements PipeDataWriter<Object> {
    230         private final MtpImage mImage;
    231 
    232         private MtpPipeDataWriter(MtpImage image) {
    233             mImage = image;
    234         }
    235 
    236         @Override
    237         public void writeDataToPipe(ParcelFileDescriptor output,
    238                 Uri uri, String mimeType, Bundle opts, Object args) {
    239             OutputStream os = null;
    240             try {
    241                 os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
    242                 os.write(mImage.getImageData());
    243             } catch (IOException e) {
    244                 Log.w(TAG, "fail to download: " + uri, e);
    245             } finally {
    246                 Utils.closeSilently(os);
    247             }
    248         }
    249     }
    250 }
    251