X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2FTizen.Content.MediaContent%2FTizen.Content.MediaContent%2FMediaInfoCommand.cs;h=ef0303ef26a03a7057bd7644b5ef13ef4093da8b;hb=479584754c5e236c1fffa84164452535e281e0ce;hp=1e52a9721e57a34be39a29d42d03e7040491330e;hpb=7a136c6f1dfb99d3a7070f0f5b33a93372c5d232;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git diff --git a/src/Tizen.Content.MediaContent/Tizen.Content.MediaContent/MediaInfoCommand.cs b/src/Tizen.Content.MediaContent/Tizen.Content.MediaContent/MediaInfoCommand.cs index 1e52a97..ef0303e 100644 --- a/src/Tizen.Content.MediaContent/Tizen.Content.MediaContent/MediaInfoCommand.cs +++ b/src/Tizen.Content.MediaContent/Tizen.Content.MediaContent/MediaInfoCommand.cs @@ -18,14 +18,17 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Tizen.System; namespace Tizen.Content.MediaContent { /// /// Provides commands to manage the media information and query related items in the database. /// + /// 4 public class MediaInfoCommand : MediaCommand { /// @@ -33,7 +36,8 @@ namespace Tizen.Content.MediaContent /// /// The that the commands run on. /// is null. - /// has already been disposed of. + /// has already been disposed. + /// 4 public MediaInfoCommand(MediaDatabase database) : base(database) { } @@ -44,10 +48,11 @@ namespace Tizen.Content.MediaContent /// The media ID to count the bookmarks added to the media. /// The number of the bookmarks. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public int CountBookmark(string mediaId) { return CountBookmark(mediaId, null); @@ -60,10 +65,11 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The number of the bookmarks. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public int CountBookmark(string mediaId, CountArguments arguments) { ValidateDatabase(); @@ -79,10 +85,11 @@ namespace Tizen.Content.MediaContent /// The media ID to select the bookmarks added to the media. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public MediaDataReader SelectBookmark(string mediaId) { return SelectBookmark(mediaId, null); @@ -95,10 +102,11 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public MediaDataReader SelectBookmark(string mediaId, SelectArguments filter) { ValidateDatabase(); @@ -115,10 +123,11 @@ namespace Tizen.Content.MediaContent /// The media ID to count face information added to the media. /// The number of the face information. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public int CountFaceInfo(string mediaId) { return CountFaceInfo(mediaId, null); @@ -131,10 +140,12 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The number of the face information. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 + [Obsolete("Deprecated since API11; Will be removed in API13.")] public int CountFaceInfo(string mediaId, CountArguments arguments) { ValidateDatabase(); @@ -150,10 +161,12 @@ namespace Tizen.Content.MediaContent /// The media ID to select face information added to the media. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 + [Obsolete("Deprecated since API11; Will be removed in API13.")] public MediaDataReader SelectFaceInfo(string mediaId) { return SelectFaceInfo(mediaId, null); @@ -166,10 +179,12 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 + [Obsolete("Deprecated since API11; Will be removed in API13.")] public MediaDataReader SelectFaceInfo(string mediaId, SelectArguments arguments) { ValidateDatabase(); @@ -186,10 +201,11 @@ namespace Tizen.Content.MediaContent /// The number of tags. /// The media ID to count tags added to the media. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public int CountTag(string mediaId) { return CountTag(mediaId, null); @@ -202,10 +218,11 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The number of tags. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public int CountTag(string mediaId, CountArguments arguments) { ValidateDatabase(); @@ -221,10 +238,11 @@ namespace Tizen.Content.MediaContent /// The media ID to select tags added to the media. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public MediaDataReader SelectTag(string mediaId) { return SelectTag(mediaId, null); @@ -237,10 +255,11 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public MediaDataReader SelectTag(string mediaId, SelectArguments filter) { ValidateDatabase(); @@ -256,8 +275,9 @@ namespace Tizen.Content.MediaContent /// /// The number of the media information. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. + /// 4 public int CountMedia() { return CountMedia(null); @@ -269,8 +289,9 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The number of media information. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. + /// 4 public int CountMedia(CountArguments arguments) { ValidateDatabase(); @@ -284,10 +305,11 @@ namespace Tizen.Content.MediaContent /// The media ID to retrieve. /// The instance if the matched record was found in the database, otherwise null. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. + /// 4 public MediaInfo SelectMedia(string mediaId) { ValidateDatabase(); @@ -313,9 +335,10 @@ namespace Tizen.Content.MediaContent /// The column key. /// The number of groups. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. + /// 4 public int CountGroupBy(MediaInfoColumnKey columnKey) { return CountGroupBy(columnKey, null); @@ -328,9 +351,10 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The number of groups. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. + /// 4 public int CountGroupBy(MediaInfoColumnKey columnKey, CountArguments arguments) { ValidateDatabase(); @@ -350,9 +374,10 @@ namespace Tizen.Content.MediaContent /// The column key. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. + /// 4 public MediaDataReader SelectGroupBy(MediaInfoColumnKey columnKey) { return SelectGroupBy(columnKey, null); @@ -365,9 +390,10 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. + /// 4 public MediaDataReader SelectGroupBy(MediaInfoColumnKey columnKey, SelectArguments arguments) { ValidateDatabase(); @@ -394,8 +420,9 @@ namespace Tizen.Content.MediaContent /// /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. + /// 4 public MediaDataReader SelectMedia() { return SelectMedia(arguments: null); @@ -407,8 +434,9 @@ namespace Tizen.Content.MediaContent /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. + /// 4 public MediaDataReader SelectMedia(SelectArguments arguments) { ValidateDatabase(); @@ -448,18 +476,75 @@ namespace Tizen.Content.MediaContent } /// + /// Retrieves all matched ebook paths with given . + /// + /// http://tizen.org/privilege/mediastorage + /// http://tizen.org/privilege/externalstorage + /// The keyword to search. + /// A list of ebook paths which contain . + /// is null. + /// The is disconnected. + /// The has already been disposed. + /// An error occurred while executing the command. + /// The caller has no required privilege. + /// 9 + public MediaDataReader SelectEbookPath(string keyword) + { + ValidateDatabase(); + + IntPtr path = IntPtr.Zero; + uint length = 0; + + ValidationUtil.ValidateNotNullOrEmpty(keyword, nameof(keyword)); + + try + { + Interop.BookInfo.GetPathByKeyword(keyword, out path, out length). + ThrowIfError("Failed to get path by keyword"); + + var list = new List(); + var current = path; + for (int i = 0; i < length; i++) + { + list.Add(Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(current))); + current = (IntPtr)((long)current + Marshal.SizeOf(typeof(IntPtr))); + } + + return new MediaDataReader(list); + } + finally + { + var current = path; + for (int i = 0; i < length; i++) + { + Interop.Libc.Free(Marshal.ReadIntPtr(current)); + current = (IntPtr)((long)current + Marshal.SizeOf(typeof(IntPtr))); + } + } + } + + /// /// Deletes the media from the database. /// /// http://tizen.org/privilege/content.write /// The media ID to delete. /// true if the matched record was found and deleted, otherwise false. - /// The or the can be used instead. - /// The is disconnected. - /// The has already been disposed of. + /// + /// The or the can be used instead.
+ /// Since API level 6, if the file related with the in DB still exists in file system before calling this method, + /// will be thrown to keep consistency in DB. + ///
+ /// + /// The is disconnected.
+ /// -or-
+ /// The file related with the in DB still exists in file system. (Since API level 6) + ///
+ /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// The caller has no required privilege. + /// 4 public bool Delete(string mediaId) { ValidateDatabase(); @@ -472,7 +557,21 @@ namespace Tizen.Content.MediaContent return false; } - CommandHelper.Delete(Interop.MediaInfo.Delete, mediaId); + Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle). + ThrowIfError("Failed to delete MediaInfo."); + + var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); + + // If we don't check file existence before calling `ScanFile` method, + // The inconsistency between DB and file system could be occurred. + if (File.Exists(path)) + { + throw new InvalidOperationException("File still exists in file system. Remove it first."); + } + + // Native 'delete' function was deprecated, so we need to use 'scan file' function instead of it. + Database.ScanFile(path); + return true; } @@ -487,13 +586,16 @@ namespace Tizen.Content.MediaContent /// The or the can be used instead.
///
/// If you want to access internal storage, you should add privilege http://tizen.org/privilege/mediastorage.
- /// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage. + /// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage.
+ ///
+ /// If http://tizen.org/feature/content.scanning.others feature is not supported and the specified file is other-type, + /// will be thrown. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// @@ -505,6 +607,8 @@ namespace Tizen.Content.MediaContent /// /// does not exists. /// The caller has no required privilege. + /// The required feature is not supported. + /// 4 public MediaInfo Add(string path) { ValidateDatabase(); @@ -573,7 +677,10 @@ namespace Tizen.Content.MediaContent /// At most 300 items can be added at once.
///
/// If you want to access internal storage, you should add privilege http://tizen.org/privilege/mediastorage.
- /// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage. + /// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage.
+ ///
+ /// If http://tizen.org/feature/content.scanning.others feature is not supported and the specified file is other-type, + /// will be thrown. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage @@ -581,7 +688,7 @@ namespace Tizen.Content.MediaContent /// The paths of the media files to add. /// A task that represents the asynchronous add operation. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// @@ -593,6 +700,8 @@ namespace Tizen.Content.MediaContent /// /// contains a path that does not exist. /// The caller has no required privilege. + /// The required feature is not supported. + /// 4 public async Task AddAsync(IEnumerable paths) { ValidateDatabase(); @@ -630,11 +739,12 @@ namespace Tizen.Content.MediaContent /// The value indicating whether the media is favorite. /// true if the matched record was found and updated, otherwise false. /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// The caller has no required privilege. + /// 4 public bool UpdateFavorite(string mediaId, bool value) { ValidateDatabase(); @@ -683,7 +793,7 @@ namespace Tizen.Content.MediaContent /// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage. /// /// The is disconnected. - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// /// is null.
@@ -701,6 +811,7 @@ namespace Tizen.Content.MediaContent ///
/// does not exists. /// The caller has no required privilege. + /// 4 public bool Move(string mediaId, string newPath) { ValidateDatabase(); @@ -753,7 +864,7 @@ namespace Tizen.Content.MediaContent /// -or-
/// An internal error occurred while executing. /// - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. @@ -764,8 +875,10 @@ namespace Tizen.Content.MediaContent /// /// The thumbnail is not available for the given media.
/// -or-
- /// The media is in the external USB storage ( is ). + /// The media is in the external USB storage. ///
+ /// 4 + [Obsolete("Deprecated since API10; Will be removed in API12. Please use CreateThumbnail instead.")] public Task CreateThumbnailAsync(string mediaId) { return CreateThumbnailAsync(mediaId, CancellationToken.None); @@ -784,7 +897,7 @@ namespace Tizen.Content.MediaContent /// -or-
/// An internal error occurred while executing. /// - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. @@ -795,8 +908,10 @@ namespace Tizen.Content.MediaContent /// /// The thumbnail is not available for the given media.
/// -or-
- /// The media is in the external USB storage ( is ). + /// The media is in the external USB storage. ///
+ /// 4 + [Obsolete("Deprecated since API10; Will be removed in API12. Please use CreateThumbnail instead.")] public Task CreateThumbnailAsync(string mediaId, CancellationToken cancellationToken) { ValidateDatabase(); @@ -811,73 +926,124 @@ namespace Tizen.Content.MediaContent var tcs = new TaskCompletionSource(); - Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).ThrowIfError("Failed to create thumbnail"); - - if (handle.IsInvalid) + using (var handle = ValidateFile(mediaId)) { - throw new RecordNotFoundException("Media does not exist."); - } + string thumbnailPath = null; + MediaContentError ret = MediaContentError.None; + Task thumbTask = null; - using (handle) - { - if (InteropHelper.GetValue(handle, Interop.MediaInfo.GetStorageType) == StorageType.ExternalUsb) + if (cancellationToken.CanBeCanceled) { - throw new UnsupportedContentException("The media is in external usb storage."); - } - - var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); + cancellationToken.Register(() => + { + if (tcs.Task.IsCompleted) + { + return; + } - if (File.Exists(path) == false) - { - throw new FileNotFoundException($"The media file does not exist. Path={path}.", path); + tcs.TrySetCanceled(); + }); } - using (RegisterCancelThumbnail(cancellationToken, tcs, handle)) - using (var cbKeeper = ObjectKeeper.Get(GetCreateThumbnailCallback(tcs))) + thumbTask = Task.Factory.StartNew( () => { - Interop.MediaInfo.CreateThumbnail(handle, cbKeeper.Target).ThrowIfError("Failed to create thumbnail"); + ret = Interop.MediaInfo.GenerateThumbnail(handle); - return await tcs.Task; - } + if (ret != MediaContentError.None) + { + tcs.TrySetException(ret.AsException("Failed to create thumbnail")); + } + else + { + thumbnailPath = InteropHelper.GetString(handle, Interop.MediaInfo.GetThumbnailPath, true); + tcs.TrySetResult(thumbnailPath); + } + }, cancellationToken, + TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, + TaskScheduler.Default); + + return await tcs.Task; } } + #endregion - private static Interop.MediaInfo.ThumbnailCompletedCallback GetCreateThumbnailCallback( - TaskCompletionSource tcs) + /// + /// Creates the thumbnail image for the given media. + /// If the thumbnail already exists for the given media, the existing path will be returned. + /// + /// http://tizen.org/privilege/content.write + /// http://tizen.org/privilege/mediastorage + /// http://tizen.org/privilege/externalstorage + /// The ID of the media for which the thumbnail will be created. + /// A created thumbnail path. + /// + /// The is disconnected.
+ /// -or-
+ /// An internal error occurred while executing. + ///
+ /// The has already been disposed. + /// An error occurred while executing the command. + /// is null. + /// does not exist in the database. + /// + /// is a zero-length string, contains only white space. + /// + /// The file of the media does not exists; moved or deleted. + /// + /// The thumbnail is not available for the given media.
+ /// -or-
+ /// The media is in the external USB storage. + ///
+ /// The caller has no required privilege. + /// 10 + public string CreateThumbnail(string mediaId) { - return (error, path, _) => + ValidateDatabase(); + + ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); + + using (var handle = ValidateFile(mediaId)) { - if (error != MediaContentError.None) - { - tcs.TrySetException(error.AsException("Failed to create thumbnail")); - } - else - { - tcs.TrySetResult(path); - } - }; + Interop.MediaInfo.GenerateThumbnail(handle).ThrowIfError("Failed to create thumbnail"); + + return InteropHelper.GetString(handle, Interop.MediaInfo.GetThumbnailPath, true); + } } - private static IDisposable RegisterCancelThumbnail(CancellationToken cancellationToken, - TaskCompletionSource tcs, Interop.MediaInfoHandle handle) + private Interop.MediaInfoHandle ValidateFile(string mediaId) { - if (cancellationToken.CanBeCanceled == false) + Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).ThrowIfError("Failed to create thumbnail"); + + if (handle.IsInvalid) { - return null; + throw new RecordNotFoundException("Media does not exist."); } - return cancellationToken.Register(() => + try { - if (tcs.Task.IsCompleted) + var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); + + if (String.IsNullOrEmpty(path) || File.Exists(path) == false) { - return; + throw new FileNotFoundException($"The media file does not exist. Path={path}.", path); } - Interop.MediaInfo.CancelThumbnail(handle).ThrowIfError("Failed to cancel"); - tcs.TrySetCanceled(); - }); + foreach (var extendedInternal in StorageManager.Storages.Where(s => s.StorageType == StorageArea.ExtendedInternal)) + { + if (path.Contains(extendedInternal.RootDirectory)) + { + throw new UnsupportedContentException("The media is in external usb storage."); + } + } + } + catch (Exception ex) + { + handle.Dispose(); + throw ex; + } + + return handle; } - #endregion #region DetectFaceAsync /// @@ -893,7 +1059,7 @@ namespace Tizen.Content.MediaContent /// -or-
/// An internal error occurred while executing. /// - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. @@ -904,6 +1070,8 @@ namespace Tizen.Content.MediaContent /// Face detection is not available for the given media. /// The required feature is not supported. /// The caller has no required privilege. + /// 4 + [Obsolete("Deprecated since API11; Will be removed in API13.")] public Task DetectFaceAsync(string mediaId) { return DetectFaceAsync(mediaId, CancellationToken.None); @@ -915,6 +1083,7 @@ namespace Tizen.Content.MediaContent ///
/// /// Media in the external storage is not supported, with the exception of MMC. + /// Only JPEG, PNG, BMP images are supported. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/feature/vision.face_recognition @@ -926,7 +1095,7 @@ namespace Tizen.Content.MediaContent /// -or-
/// An internal error occurred while executing. /// - /// The has already been disposed of. + /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. @@ -937,9 +1106,11 @@ namespace Tizen.Content.MediaContent /// /// Face detection is not available for the given media.
/// -or-
- /// The media is in the external USB storage ( is ). + /// The media is in the external USB storage. ///
/// The required feature is not supported. + /// 4 + [Obsolete("Deprecated since API11; Will be removed in API13.")] public Task DetectFaceAsync(string mediaId, CancellationToken cancellationToken) { if (Features.IsSupported(Features.FaceRecognition) == false) @@ -968,14 +1139,17 @@ namespace Tizen.Content.MediaContent using (handle) { - if (InteropHelper.GetValue(handle, Interop.MediaInfo.GetStorageType) == StorageType.ExternalUsb) + if (InteropHelper.GetValue(handle, Interop.MediaInfo.GetMediaType) != MediaType.Image) { - throw new UnsupportedContentException("The media is in external usb storage."); + throw new UnsupportedContentException("Only image is supported."); } - if (InteropHelper.GetValue(handle, Interop.MediaInfo.GetMediaType) != MediaType.Image) + // Native P/Invoke function also check below case, but it returns invalid operation error. + // So we check it here to throw more proper exception. + string mimeType = InteropHelper.GetString(handle, Interop.MediaInfo.GetMimeType); + if (!mimeType.Equals("image/jpeg") && !mimeType.Equals("image/png") && !mimeType.Equals("image/bmp")) { - throw new UnsupportedContentException("Only image is supported."); + throw new UnsupportedContentException($"{mimeType} is not supported. Only JPEG, PNG, BMP is supported."); } var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); @@ -988,7 +1162,13 @@ namespace Tizen.Content.MediaContent using (RegisterCancelFaceDetection(cancellationToken, tcs, handle)) using (var cbKeeper = ObjectKeeper.Get(GetFaceDetectionCallback(tcs))) { - Interop.MediaInfo.StartFaceDetection(handle, cbKeeper.Target).ThrowIfError("Failed to detect faces"); + var ret = Interop.MediaInfo.StartFaceDetection(handle, cbKeeper.Target); + if (ret == MediaContentError.InvalidParameter) + { + throw new UnsupportedContentException("The media is in external usb storage."); + } + + ret.ThrowIfError("Failed to detect faces"); return await tcs.Task; }