1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util; 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver; 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.res.AssetFileDescriptor; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.media.MediaMetadataRetriever; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.ParcelFileDescriptor; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.MediaStore; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.annotation.NonNull; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.MediaScratchFileProvider; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert.DoesNotRunOnMainThread; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.io.ByteStreams; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.BufferedInputStream; 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.File; 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileNotFoundException; 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.IOException; 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.InputStream; 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.OutputStream; 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.net.URL; 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.net.URLConnection; 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Arrays; 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.HashSet; 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class UriUtil { 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String SCHEME_SMS = "sms"; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String SCHEME_SMSTO = "smsto"; 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String SCHEME_MMS = "mms"; 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String SCHEME_MMSTO = "smsto"; 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final HashSet<String> SMS_MMS_SCHEMES = new HashSet<String>( 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Arrays.asList(SCHEME_SMS, SCHEME_MMS, SCHEME_SMSTO, SCHEME_MMSTO)); 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final String SCHEME_BUGLE = "bugle"; 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final HashSet<String> SUPPORTED_SCHEME = new HashSet<String>( 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Arrays.asList(ContentResolver.SCHEME_ANDROID_RESOURCE, 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ContentResolver.SCHEME_CONTENT, 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ContentResolver.SCHEME_FILE, 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd SCHEME_BUGLE)); 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final String SCHEME_TEL = "tel:"; 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Get a Uri representation of the file path of a resource file. 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri getUriForResourceFile(final String path) { 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtils.isEmpty(path) ? null : Uri.fromFile(new File(path)); 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Extract the path from a file:// Uri, or null if the uri is of other scheme. 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String getFilePathFromUri(final Uri uri) { 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!isFileUri(uri)) { 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return uri.getPath(); 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Returns whether the given Uri is local or remote. 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isLocalResourceUri(final Uri uri) { 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String scheme = uri.getScheme(); 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtils.equals(scheme, ContentResolver.SCHEME_ANDROID_RESOURCE) || 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd TextUtils.equals(scheme, ContentResolver.SCHEME_CONTENT) || 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd TextUtils.equals(scheme, ContentResolver.SCHEME_FILE); 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Returns whether the given Uri is part of Bugle's app package 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isBugleAppResource(final Uri uri) { 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String scheme = uri.getScheme(); 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtils.equals(scheme, ContentResolver.SCHEME_ANDROID_RESOURCE); 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isFileUri(final Uri uri) { 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return uri != null && TextUtils.equals(uri.getScheme(), ContentResolver.SCHEME_FILE); 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Constructs an android.resource:// uri for the given resource id. 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri getUriForResourceId(final Context context, final int resId) { 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new Uri.Builder() 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .authority(context.getPackageName()) 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .appendPath(String.valueOf(resId)) 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .build(); 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Returns whether the given Uri string is local. 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isLocalUri(@NonNull final Uri uri) { 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.notNull(uri); 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return SUPPORTED_SCHEME.contains(uri.getScheme()); 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String MEDIA_STORE_URI_KLP = "com.android.providers.media.documents"; 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Check if a URI is from the MediaStore 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isMediaStoreUri(final Uri uri) { 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String uriAuthority = uri.getAuthority(); 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtils.equals(ContentResolver.SCHEME_CONTENT, uri.getScheme()) 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd && (TextUtils.equals(MediaStore.AUTHORITY, uriAuthority) || 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // KK changed the media store authority name 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd TextUtils.equals(MEDIA_STORE_URI_KLP, uriAuthority)); 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Gets the size in bytes for the content uri. Currently we only support content in the 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * scratch space. 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static long getContentSize(final Uri uri) { 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isNotMainThread(); 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (isLocalResourceUri(uri)) { 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ParcelFileDescriptor pfd = null; 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd pfd = Factory.get().getApplicationContext() 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .getContentResolver().openFileDescriptor(uri, "r"); 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return Math.max(pfd.getStatSize(), 0); 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final FileNotFoundException e) { 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error getting content size", e); 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (pfd != null) { 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd pfd.close(); 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Do nothing. 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.fail("Unsupported uri type!"); 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return 0; 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** @return duration in milliseconds or 0 if not able to determine */ 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static int getMediaDurationMs(final Uri uri) { 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final MediaMetadataRetrieverWrapper retriever = new MediaMetadataRetrieverWrapper(); 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd retriever.setDataSource(uri); 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return retriever.extractInteger(MediaMetadataRetriever.METADATA_KEY_DURATION, 0); 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Unable extract duration from media file: " + uri, e); 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return 0; 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd retriever.release(); 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Persist a piece of content from the given input stream, byte by byte to the scratch 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * directory. 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return the output Uri if the operation succeeded, or null if failed. 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri persistContentToScratchSpace(final InputStream inputStream) { 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Uri scratchSpaceUri = MediaScratchFileProvider.buildMediaScratchSpaceUri(null); 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return copyContent(context, inputStream, scratchSpaceUri); 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Persist a piece of content from the given sourceUri, byte by byte to the scratch 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * directory. 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return the output Uri if the operation succeeded, or null if failed. 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri persistContentToScratchSpace(final Uri sourceUri) { 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd InputStream inputStream = null; 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (UriUtil.isLocalResourceUri(sourceUri)) { 199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream = context.getContentResolver().openInputStream(sourceUri); 200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // The content is remote. Download it. 202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final URL url = new URL(sourceUri.toString()); 203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final URLConnection ucon = url.openConnection(); 204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream = new BufferedInputStream(ucon.getInputStream()); 205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return persistContentToScratchSpace(inputStream); 207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final Exception ex) { 208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error while retrieving media ", ex); 209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (inputStream != null) { 212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream.close(); 214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "error trying to close the inputStream", e); 216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Persist a piece of content from the given input stream, byte by byte to the specified 223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * directory. 224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return the output Uri if the operation succeeded, or null if failed. 225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri persistContent( 228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final InputStream inputStream, final File outputDir, final String contentType) { 229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!outputDir.exists() && !outputDir.mkdirs()) { 230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error creating " + outputDir.getAbsolutePath()); 231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Uri targetUri = Uri.fromFile(FileUtil.getNewFile(outputDir, contentType)); 237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return copyContent(context, inputStream, targetUri); 238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error creating file in " + outputDir.getAbsolutePath()); 240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Persist a piece of content from the given sourceUri, byte by byte to the 246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * specified output directory. 247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return the output Uri if the operation succeeded, or null if failed. 248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri persistContent( 251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Uri sourceUri, final File outputDir, final String contentType) { 252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd InputStream inputStream = null; 253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (UriUtil.isLocalResourceUri(sourceUri)) { 256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream = context.getContentResolver().openInputStream(sourceUri); 257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // The content is remote. Download it. 259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final URL url = new URL(sourceUri.toString()); 260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final URLConnection ucon = url.openConnection(); 261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream = new BufferedInputStream(ucon.getInputStream()); 262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return persistContent(inputStream, outputDir, contentType); 264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final Exception ex) { 265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error while retrieving media ", ex); 266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (inputStream != null) { 269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inputStream.close(); 271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "error trying to close the inputStream", e); 273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** @return uri of target file, or null on error */ 279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @DoesNotRunOnMainThread 280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static Uri copyContent( 281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context, final InputStream inputStream, final Uri targetUri) { 282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isNotMainThread(); 283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd OutputStream outputStream = null; 284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd outputStream = context.getContentResolver().openOutputStream(targetUri); 286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ByteStreams.copy(inputStream, outputStream); 287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final Exception ex) { 288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "Error while copying content ", ex); 289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (outputStream != null) { 292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd outputStream.flush(); 294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(LogUtil.BUGLE_TAG, "error trying to flush the outputStream", e); 296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd outputStream.close(); 300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Do nothing. 302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return targetUri; 307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isSmsMmsUri(final Uri uri) { 310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return uri != null && SMS_MMS_SCHEMES.contains(uri.getScheme()); 311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Extract recipient destinations from Uri of form 315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * SCHEME:destionation[,destination]?otherstuff 316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * where SCHEME is one of the supported sms/mms schemes. 317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param uri sms/mms uri 319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return recipient destinations or null 320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String[] parseRecipientsFromSmsMmsUri(final Uri uri) { 322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!isSmsMmsUri(uri)) { 323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] parts = uri.getSchemeSpecificPart().split("\\?"); 326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (TextUtils.isEmpty(parts[0])) { 327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // replaceUnicodeDigits will replace digits typed in other languages (i.e. Egyptian) with 330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // the usual ascii equivalents. 331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtil.replaceUnicodeDigits(parts[0]).replace(';', ',').split(","); 332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Return the length of the file to which contentUri refers 336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param contentUri URI for the file of which we want the length 338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return Length of the file or AssetFileDescriptor.UNKNOWN_LENGTH 339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static long getUriContentLength(final Uri contentUri) { 341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd AssetFileDescriptor afd = null; 343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd afd = context.getContentResolver().openAssetFileDescriptor(contentUri, "r"); 345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return afd.getLength(); 346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final FileNotFoundException e) { 347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(LogUtil.BUGLE_TAG, "Failed to query length of " + contentUri); 348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (afd != null) { 350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd afd.close(); 352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (final IOException e) { 353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(LogUtil.BUGLE_TAG, "Failed to close afd for " + contentUri); 354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return AssetFileDescriptor.UNKNOWN_LENGTH; 358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** @return string representation of URI or null if URI was null */ 361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String stringFromUri(final Uri uri) { 362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return uri == null ? null : uri.toString(); 363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** @return URI created from string or null if string was null or empty */ 366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Uri uriFromString(final String uriString) { 367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return TextUtils.isEmpty(uriString) ? null : Uri.parse(uriString); 368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 370