/*
* This source is part of the
* _____ ___ ____
* __ / / _ \/ _ | / __/___ _______ _
* / // / , _/ __ |/ _/_/ _ \/ __/ _ `/
* \___/_/|_/_/ |_/_/ (_)___/_/ \_, /
* /___/
* repository.
*
* Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org)
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jraf.android.util.mediascanner;
import java.io.File;
import java.util.concurrent.atomic.AtomicReference;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.os.SystemClock;
import android.util.Log;
import org.jraf.android.util.Constants;
/**
* Convenience utility to add an image to the media library.<br/>
* Note: most of the code here was copied from the Android source, in order to achieve the same functionality in API level 7.
*/
public class MediaScannerUtil {
private static final String TAG = Constants.TAG + MediaScannerUtil.class.getSimpleName();
/**
* Interface for notifying clients of the result of scanning a
* requested media file.
*/
public interface OnScanCompletedListener {
/**
* Called to notify the client when the media scanner has finished
* scanning a file.
*
* @param path the path to the file that has been scanned.
* @param uri the Uri for the file if the scanning operation succeeded
* and the file was added to the media database, or null if scanning failed.
*/
public void onScanCompleted(String path, Uri uri);
}
/**
* Convenience for constructing a {@link MediaScannerConnection}, calling {@link #connect} on it, and calling {@link #scanFile} with the given
* <var>path</var> and <var>mimeType</var> when the connection is
* established.
*
* @param context The caller's Context, required for establishing a connection to
* the media scanner service.
* Success or failure of the scanning operation cannot be determined until {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is
* called.
* @param paths Array of paths to be scanned.
* @param mimeTypes Optional array of MIME types for each path.
* If mimeType is null, then the mimeType will be inferred from the file extension.
* @param callback Optional callback through which you can receive the
* scanned URI and MIME type; If null, the file will be scanned but
* you will not get a result back.
*/
public static void scanFile(Context context, String[] paths, String[] mimeTypes, OnScanCompletedListener callback) {
ClientProxy client = new ClientProxy(paths, mimeTypes, callback);
MediaScannerConnection connection = new MediaScannerConnection(context, client);
client.mConnection = connection;
connection.connect();
}
private static class ClientProxy implements MediaScannerConnectionClient {
final String[] mPaths;
final String[] mMimeTypes;
final OnScanCompletedListener mClient;
MediaScannerConnection mConnection;
int mNextPath;
ClientProxy(String[] paths, String[] mimeTypes, OnScanCompletedListener client) {
mPaths = paths;
mMimeTypes = mimeTypes;
mClient = client;
}
@Override
public void onMediaScannerConnected() {
scanNextPath();
}
@Override
public void onScanCompleted(String path, Uri uri) {
if (mClient != null) {
mClient.onScanCompleted(path, uri);
}
scanNextPath();
}
void scanNextPath() {
if (mNextPath >= mPaths.length) {
mConnection.disconnect();
return;
}
String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null;
mConnection.scanFile(mPaths[mNextPath], mimeType);
mNextPath++;
}
}
/**
* Synchronously scan a file. This will <strong>block</strong> until the underlying MediaScanner has finished processing the file.
*
* @return the Uri of the scanned file.
* @throws InterruptedException if the scan has not been completed after 5000 ms.
*/
public static Uri scanFileNow(Context context, File imageFile) throws InterruptedException {
// Scan it
final AtomicReference<Uri> scannedImageUri = new AtomicReference<Uri>();
MediaScannerUtil.scanFile(context, new String[] { imageFile.getPath() }, null, new OnScanCompletedListener() {
@Override
public void onScanCompleted(String p, Uri uri) {
Log.d(TAG, "onScanCompleted path=" + p + " uri=" + uri);
scannedImageUri.set(uri);
}
});
// Wait until the media scanner has found our file
long start = System.currentTimeMillis();
while (scannedImageUri.get() == null) {
Log.d(TAG, "scanFileNow Waiting 250ms for media scanner...");
SystemClock.sleep(250);
if (System.currentTimeMillis() - start > 6000) {
throw new InterruptedException("MediaScanner did not scan the file " + imageFile + " after 6000ms");
}
}
return scannedImageUri.get();
}
}