OSDN Git Service

CMFileManager : Pass appropriate media type uri when ACTION_VIEW
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / util / MediaHelper.java
1 /*
2  * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.filemanager.util;
18
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.net.Uri;
23 import android.os.UserHandle;
24 import android.provider.BaseColumns;
25 import android.provider.MediaStore;
26 import android.provider.MediaStore.MediaColumns;
27 import android.text.TextUtils;
28
29 import java.io.File;
30 import java.util.HashMap;
31 import java.util.Map;
32
33 /**
34  * A helper class with useful methods to extract media data.
35  */
36 public final class MediaHelper {
37
38     private static final String EMULATED_STORAGE_SOURCE = System.getenv("EMULATED_STORAGE_SOURCE");
39     private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET");
40     private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE");
41
42     private static final String INTERNAL_VOLUME = "internal";
43     private static final String EXTERNAL_VOLUME = "external";
44
45     /**
46      * URIs that are relevant for determining album art;
47      * useful for content observer registration
48      */
49     public static final Uri[] RELEVANT_URIS = new Uri[] {
50         MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
51         MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI
52     };
53
54     /**
55      * Method that returns an array with all the unique albums paths and ids.
56      *
57      * @param cr The ContentResolver
58      * @return Map<String, Long> The albums map
59      */
60     public static Map<String, Long> getAllAlbums(ContentResolver cr) {
61         Map<String, Long> albums = new HashMap<String, Long>();
62         final String[] projection =
63                 {
64                     "distinct " + MediaStore.Audio.Media.ALBUM_ID,
65                     "substr(" + MediaStore.Audio.Media.DATA + ", 0, length(" +
66                             MediaStore.Audio.Media.DATA + ") - length(" +
67                             MediaStore.Audio.Media.DISPLAY_NAME + "))"
68                 };
69         final String where = MediaStore.Audio.Media.IS_MUSIC + " = ?";
70         Cursor c = cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
71                 projection, where, new String[]{"1"}, null);
72         if (c != null) {
73             try {
74                 while (c.moveToNext()) {
75                     long albumId = c.getLong(0);
76                     String albumPath = c.getString(1);
77                     albums.put(albumPath, albumId);
78                 }
79             } finally {
80                 c.close();
81             }
82         }
83         return albums;
84     }
85
86     /**
87      * Method that returns the album thumbnail path by its identifier.
88      *
89      * @param cr The ContentResolver
90      * @param albumId The album identifier to search
91      * @return String The album thumbnail path
92      */
93     public static String getAlbumThumbnailPath(ContentResolver cr, long albumId) {
94         final String[] projection = {MediaStore.Audio.Albums.ALBUM_ART};
95         final String where = BaseColumns._ID + " = ?";
96         Cursor c = cr.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
97                 projection, where, new String[]{String.valueOf(albumId)}, null);
98         try {
99             if (c != null && c.moveToNext()) {
100                 return c.getString(0);
101             }
102         } finally {
103             if (c != null) {
104                 c.close();
105             }
106         }
107         return null;
108     }
109
110     /**
111      * Method that converts a file reference to a content uri reference
112      *
113      * @param cr A content resolver
114      * @param file The file reference
115      * @return Uri The content uri or null if file not exists in the media database
116      */
117     public static Uri fileToContentUri(Context context, File file) {
118         // Normalize the path to ensure media search
119         final String normalizedPath = normalizeMediaPath(file.getAbsolutePath());
120
121         // Check in external and internal storages
122         Uri uri = fileToContentUri(context, normalizedPath, EXTERNAL_VOLUME);
123         if (uri != null) {
124             return uri;
125         }
126         uri = fileToContentUri(context, normalizedPath, INTERNAL_VOLUME);
127         if (uri != null) {
128             return uri;
129         }
130         return null;
131     }
132
133     /**
134      * Method that converts a file reference to a content uri reference
135      *
136      * @param cr A content resolver
137      * @param path The path to search
138      * @param volume The volume
139      * @return Uri The content uri or null if file not exists in the media database
140      */
141     private static Uri fileToContentUri(Context context, String path, String volume) {
142         String[] projection = null;
143         final String where = MediaColumns.DATA + " = ?";
144         File file = new File(path);
145         Uri baseUri = MediaStore.Files.getContentUri(volume);
146         boolean isMimeTypeImage = false, isMimeTypeVideo = false, isMimeTypeAudio = false;
147         isMimeTypeImage = MimeTypeHelper.KnownMimeTypeResolver.isImage(context, file);
148         if (!isMimeTypeImage) {
149             isMimeTypeVideo = MimeTypeHelper.KnownMimeTypeResolver.isVideo(context, file);
150             if (!isMimeTypeVideo) {
151                 isMimeTypeAudio = MimeTypeHelper.KnownMimeTypeResolver.isAudio(context, file);
152             }
153         }
154         if (isMimeTypeImage || isMimeTypeVideo || isMimeTypeAudio) {
155             projection = new String[]{BaseColumns._ID};
156             if (isMimeTypeImage) {
157                 baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
158             } else if (isMimeTypeVideo) {
159                 baseUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
160             } else if (isMimeTypeAudio) {
161                 baseUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
162             }
163         } else {
164             projection = new String[]{BaseColumns._ID, MediaStore.Files.FileColumns.MEDIA_TYPE};
165         }
166         ContentResolver cr = context.getContentResolver();
167         Cursor c = cr.query(baseUri, projection, where, new String[]{path}, null);
168         try {
169             if (c != null && c.moveToNext()) {
170                 boolean isValid = false;
171                 if (isMimeTypeImage || isMimeTypeVideo || isMimeTypeAudio) {
172                     isValid = true;
173                 } else {
174                     int type = c.getInt(c.getColumnIndexOrThrow(
175                         MediaStore.Files.FileColumns.MEDIA_TYPE));
176                     isValid = type != 0;
177                 }
178                 if (isValid) {
179                     // Do not force to use content uri for no media files
180                     long id = c.getLong(c.getColumnIndexOrThrow(BaseColumns._ID));
181                     return Uri.withAppendedPath(baseUri, String.valueOf(id));
182                 }
183             }
184         } finally {
185             if (c != null) {
186                 c.close();
187             }
188         }
189         return null;
190     }
191
192     /**
193      * Method that converts a content uri to a file system path
194      *
195      * @param cr The content resolver
196      * @param uri The content uri
197      * @return File The file reference
198      */
199     public static File contentUriToFile(ContentResolver cr, Uri uri) {
200         // Sanity checks
201         if (uri == null || uri.getScheme() == null || uri.getScheme().compareTo("content") != 0) {
202             return null;
203         }
204
205         // Retrieve the request id
206         long id = 0;
207         try {
208             id = Long.parseLong(new File(uri.getPath()).getName());
209         } catch (NumberFormatException nfex) {
210             return null;
211         }
212
213         // Check in external and internal storages
214         File file = mediaIdToFile(cr, id, EXTERNAL_VOLUME);
215         if (file != null) {
216             return file;
217         }
218         file = mediaIdToFile(cr, id, INTERNAL_VOLUME);
219         if (file != null) {
220             return file;
221         }
222         return null;
223     }
224
225     /**
226      * Method that converts a content uri to a file system path
227      *
228      * @param cr The content resolver
229      * @param id The media database id
230      * @param volume The volume
231      * @return File The file reference
232      */
233     private static File mediaIdToFile(ContentResolver cr, long id, String volume) {
234         final String[] projection = {MediaColumns.DATA};
235         final String where = MediaColumns._ID + " = ?";
236         Uri baseUri = MediaStore.Files.getContentUri(volume);
237         Cursor c = cr.query(baseUri, projection, where, new String[]{String.valueOf(id)}, null);
238         try {
239             if (c != null && c.moveToNext()) {
240                 return new File(c.getString(c.getColumnIndexOrThrow(MediaColumns.DATA)));
241             }
242         } finally {
243             if (c != null) {
244                 c.close();
245             }
246         }
247         return null;
248     }
249
250     /**
251      * Method that converts a not standard media mount path to a standard media path
252      *
253      * @param path The path to normalize
254      * @return String The normalized media path
255      */
256     public static String normalizeMediaPath(String path) {
257         // Retrieve all the paths and check that we have this environment vars
258         if (TextUtils.isEmpty(EMULATED_STORAGE_SOURCE) ||
259                 TextUtils.isEmpty(EMULATED_STORAGE_TARGET) ||
260                 TextUtils.isEmpty(EXTERNAL_STORAGE)) {
261             return path;
262         }
263
264         // We need to convert EMULATED_STORAGE_SOURCE -> EMULATED_STORAGE_TARGET
265         if (path.startsWith(EMULATED_STORAGE_SOURCE)) {
266             path = path.replace(EMULATED_STORAGE_SOURCE, EMULATED_STORAGE_TARGET);
267         }
268         // We need to convert EXTERNAL_STORAGE -> EMULATED_STORAGE_TARGET / userId
269         if (path.startsWith(EXTERNAL_STORAGE)) {
270             final String userId = String.valueOf(UserHandle.myUserId());
271             final String target = new File(EMULATED_STORAGE_TARGET, userId).getAbsolutePath();
272             path = path.replace(EXTERNAL_STORAGE, target);
273         }
274         return path;
275     }
276 }