2013-02-08 10:09:55 +01:00
/ *
This file is part of Subsonic .
Subsonic is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Subsonic is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Subsonic . If not , see < http : //www.gnu.org/licenses/>.
Copyright 2009 ( C ) Sindre Mehus
* /
2015-07-26 18:15:07 +02:00
package org.moire.ultrasonic.util ;
2013-02-08 10:09:55 +01:00
2013-12-04 07:36:02 +01:00
import android.content.Context ;
import android.graphics.Bitmap ;
import android.graphics.BitmapFactory ;
2020-06-02 15:35:36 +02:00
import android.os.Build ;
2013-12-04 07:36:02 +01:00
import android.os.Environment ;
2018-02-10 20:08:57 +01:00
import android.text.TextUtils ;
2020-09-30 14:47:59 +02:00
import timber.log.Timber ;
2013-12-04 07:36:02 +01:00
2015-07-26 18:15:07 +02:00
import org.moire.ultrasonic.activity.SubsonicTabActivity ;
import org.moire.ultrasonic.domain.MusicDirectory ;
2013-12-04 07:36:02 +01:00
2013-02-08 10:09:55 +01:00
import java.io.File ;
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
import java.io.ObjectInputStream ;
import java.io.ObjectOutputStream ;
import java.io.Serializable ;
import java.util.Arrays ;
2013-12-04 07:36:02 +01:00
import java.util.Collections ;
2013-02-08 10:09:55 +01:00
import java.util.Iterator ;
import java.util.List ;
2013-12-04 07:36:02 +01:00
import java.util.SortedSet ;
import java.util.TreeSet ;
2017-06-28 11:25:04 +02:00
import java.util.regex.Pattern ;
2013-02-08 10:09:55 +01:00
/ * *
* @author Sindre Mehus
* /
2013-12-04 07:36:02 +01:00
public class FileUtil
{
private static final String [ ] FILE_SYSTEM_UNSAFE = { " / " , " \\ " , " .. " , " : " , " \" " , " ? " , " * " , " < " , " > " , " | " } ;
private static final String [ ] FILE_SYSTEM_UNSAFE_DIR = { " \\ " , " .. " , " : " , " \" " , " ? " , " * " , " < " , " > " , " | " } ;
private static final List < String > MUSIC_FILE_EXTENSIONS = Arrays . asList ( " mp3 " , " ogg " , " aac " , " flac " , " m4a " , " wav " , " wma " ) ;
2013-05-16 09:59:55 +02:00
private static final List < String > VIDEO_FILE_EXTENSIONS = Arrays . asList ( " flv " , " mp4 " , " m4v " , " wmv " , " avi " , " mov " , " mpg " , " mkv " ) ;
2013-12-04 07:36:02 +01:00
private static final List < String > PLAYLIST_FILE_EXTENSIONS = Collections . singletonList ( " m3u " ) ;
2017-06-28 11:25:04 +02:00
private static final Pattern TITLE_WITH_TRACK = Pattern . compile ( " ^ \\ d \\ d-.* " ) ;
2013-02-08 10:09:55 +01:00
2013-12-04 07:36:02 +01:00
public static File getSongFile ( Context context , MusicDirectory . Entry song )
{
2013-07-17 10:59:58 +02:00
File dir = getAlbumDirectory ( context , song ) ;
2013-12-04 07:36:02 +01:00
StringBuilder fileName = new StringBuilder ( 256 ) ;
2013-07-17 10:59:58 +02:00
Integer track = song . getTrack ( ) ;
2013-12-04 07:36:02 +01:00
2017-06-28 11:25:04 +02:00
if ( ! TITLE_WITH_TRACK . matcher ( song . getTitle ( ) ) . matches ( ) ) { //check if filename already had track number
if ( track ! = null ) {
if ( track < 10 ) {
fileName . append ( '0' ) ;
}
2013-12-04 07:36:02 +01:00
2017-06-28 11:25:04 +02:00
fileName . append ( track ) . append ( '-' ) ;
}
2013-07-17 10:59:58 +02:00
}
2013-12-04 07:36:02 +01:00
fileName . append ( fileSystemSafe ( song . getTitle ( ) ) ) . append ( '.' ) ;
2013-07-17 10:59:58 +02:00
2018-02-11 22:44:53 +01:00
if ( ! TextUtils . isEmpty ( song . getTranscodedSuffix ( ) ) ) {
2013-07-17 10:59:58 +02:00
fileName . append ( song . getTranscodedSuffix ( ) ) ;
2018-02-11 22:44:53 +01:00
} else {
2013-07-17 10:59:58 +02:00
fileName . append ( song . getSuffix ( ) ) ;
}
return new File ( dir , fileName . toString ( ) ) ;
}
2020-06-17 18:14:34 +02:00
public static File getPlaylistFile ( Context context , String server , String name )
2013-12-04 07:36:02 +01:00
{
2020-06-17 18:14:34 +02:00
File playlistDir = getPlaylistDirectory ( context , server ) ;
2013-12-04 07:36:02 +01:00
return new File ( playlistDir , String . format ( " %s.m3u " , fileSystemSafe ( name ) ) ) ;
2013-05-16 09:59:55 +02:00
}
2013-06-07 04:27:45 +02:00
2020-06-17 18:14:34 +02:00
public static File getPlaylistDirectory ( Context context )
2013-12-04 07:36:02 +01:00
{
2020-09-24 13:03:05 +02:00
File playlistDir = new File ( getUltrasonicDirectory ( context ) , " playlists " ) ;
2013-05-16 09:59:55 +02:00
ensureDirectoryExistsAndIsReadWritable ( playlistDir ) ;
return playlistDir ;
}
2013-07-17 10:59:58 +02:00
2020-06-17 18:14:34 +02:00
public static File getPlaylistDirectory ( Context context , String server )
2013-12-04 07:36:02 +01:00
{
2020-06-17 18:14:34 +02:00
File playlistDir = new File ( getPlaylistDirectory ( context ) , server ) ;
2013-07-17 10:59:58 +02:00
ensureDirectoryExistsAndIsReadWritable ( playlistDir ) ;
return playlistDir ;
}
2013-12-04 07:36:02 +01:00
public static File getAlbumArtFile ( Context context , MusicDirectory . Entry entry )
{
File albumDir = getAlbumDirectory ( context , entry ) ;
2020-06-02 15:35:36 +02:00
return getAlbumArtFile ( context , albumDir ) ;
2013-05-16 09:59:55 +02:00
}
2013-02-08 10:09:55 +01:00
2020-06-02 15:35:36 +02:00
public static File getAvatarFile ( Context context , String username )
2014-01-29 08:47:56 +01:00
{
2020-06-02 15:35:36 +02:00
File albumArtDir = getAlbumArtDirectory ( context ) ;
2014-01-29 08:47:56 +01:00
if ( albumArtDir = = null | | username = = null )
{
return null ;
}
String md5Hex = Util . md5Hex ( username ) ;
return new File ( albumArtDir , String . format ( " %s.jpeg " , md5Hex ) ) ;
}
2020-06-02 15:35:36 +02:00
public static File getAlbumArtFile ( Context context , File albumDir )
2013-12-04 07:36:02 +01:00
{
2020-06-02 15:35:36 +02:00
File albumArtDir = getAlbumArtDirectory ( context ) ;
2013-12-08 08:27:34 +01:00
if ( albumArtDir = = null | | albumDir = = null )
{
2013-12-30 09:33:39 +01:00
return null ;
2013-12-08 08:27:34 +01:00
}
String md5Hex = Util . md5Hex ( albumDir . getPath ( ) ) ;
return new File ( albumArtDir , String . format ( " %s.jpeg " , md5Hex ) ) ;
2013-12-04 07:36:02 +01:00
}
2020-06-02 15:35:36 +02:00
public static Bitmap getAvatarBitmap ( Context context , String username , int size , boolean highQuality )
2014-01-29 08:47:56 +01:00
{
if ( username = = null ) return null ;
2020-06-02 15:35:36 +02:00
File avatarFile = getAvatarFile ( context , username ) ;
2014-01-29 08:47:56 +01:00
SubsonicTabActivity subsonicTabActivity = SubsonicTabActivity . getInstance ( ) ;
Bitmap bitmap = null ;
ImageLoader imageLoader = null ;
if ( subsonicTabActivity ! = null )
{
imageLoader = subsonicTabActivity . getImageLoader ( ) ;
if ( imageLoader ! = null )
{
bitmap = imageLoader . getImageBitmap ( username , size ) ;
}
}
if ( bitmap ! = null )
{
return bitmap . copy ( bitmap . getConfig ( ) , false ) ;
}
if ( avatarFile ! = null & & avatarFile . exists ( ) )
{
final BitmapFactory . Options opt = new BitmapFactory . Options ( ) ;
if ( size > 0 )
{
opt . inJustDecodeBounds = true ;
BitmapFactory . decodeFile ( avatarFile . getPath ( ) , opt ) ;
if ( highQuality )
{
opt . inDither = true ;
opt . inPreferQualityOverSpeed = true ;
}
opt . inPurgeable = true ;
opt . inSampleSize = Util . calculateInSampleSize ( opt , size , Util . getScaledHeight ( opt . outHeight , opt . outWidth , size ) ) ;
opt . inJustDecodeBounds = false ;
}
try
{
bitmap = BitmapFactory . decodeFile ( avatarFile . getPath ( ) , opt ) ;
}
catch ( Exception ex )
{
2020-09-30 14:47:59 +02:00
Timber . e ( ex , " Exception in BitmapFactory.decodeFile() " ) ;
2014-01-29 08:47:56 +01:00
}
2020-09-30 14:47:59 +02:00
Timber . i ( " getAvatarBitmap %i " , String . valueOf ( size ) ) ;
2014-01-29 08:47:56 +01:00
if ( bitmap ! = null )
{
if ( imageLoader ! = null )
{
imageLoader . addImageToCache ( bitmap , username , size ) ;
}
}
2020-09-30 14:47:59 +02:00
return bitmap ;
2014-01-29 08:47:56 +01:00
}
return null ;
}
2013-12-30 09:33:39 +01:00
public static Bitmap getAlbumArtBitmap ( Context context , MusicDirectory . Entry entry , int size , boolean highQuality )
{
2014-01-21 07:16:24 +01:00
if ( entry = = null ) return null ;
2013-12-04 07:36:02 +01:00
File albumArtFile = getAlbumArtFile ( context , entry ) ;
2014-01-27 04:43:34 +01:00
SubsonicTabActivity subsonicTabActivity = SubsonicTabActivity . getInstance ( ) ;
Bitmap bitmap = null ;
ImageLoader imageLoader = null ;
if ( subsonicTabActivity ! = null )
{
imageLoader = subsonicTabActivity . getImageLoader ( ) ;
if ( imageLoader ! = null )
{
bitmap = imageLoader . getImageBitmap ( entry , true , size ) ;
}
}
2014-01-21 07:16:24 +01:00
if ( bitmap ! = null )
{
return bitmap . copy ( bitmap . getConfig ( ) , false ) ;
}
2013-12-30 09:33:39 +01:00
if ( albumArtFile ! = null & & albumArtFile . exists ( ) )
{
2013-12-04 07:36:02 +01:00
final BitmapFactory . Options opt = new BitmapFactory . Options ( ) ;
2013-12-30 09:33:39 +01:00
if ( size > 0 )
{
2013-12-04 07:36:02 +01:00
opt . inJustDecodeBounds = true ;
BitmapFactory . decodeFile ( albumArtFile . getPath ( ) , opt ) ;
2013-12-30 09:33:39 +01:00
if ( highQuality )
{
2013-12-04 07:36:02 +01:00
opt . inDither = true ;
opt . inPreferQualityOverSpeed = true ;
}
opt . inPurgeable = true ;
opt . inSampleSize = Util . calculateInSampleSize ( opt , size , Util . getScaledHeight ( opt . outHeight , opt . outWidth , size ) ) ;
opt . inJustDecodeBounds = false ;
}
2014-01-27 07:45:21 +01:00
try
{
bitmap = BitmapFactory . decodeFile ( albumArtFile . getPath ( ) , opt ) ;
}
catch ( Exception ex )
{
2020-09-30 14:47:59 +02:00
Timber . e ( ex , " Exception in BitmapFactory.decodeFile() " ) ;
2014-01-27 07:45:21 +01:00
}
2020-09-30 14:47:59 +02:00
Timber . i ( " getAlbumArtBitmap %i " , String . valueOf ( size ) ) ;
2013-12-04 07:36:02 +01:00
2014-01-21 07:16:24 +01:00
if ( bitmap ! = null )
{
2014-01-27 04:43:34 +01:00
if ( imageLoader ! = null )
{
imageLoader . addImageToCache ( bitmap , entry , size ) ;
}
2014-01-21 07:16:24 +01:00
}
2020-09-30 14:47:59 +02:00
return bitmap ;
2013-12-04 07:36:02 +01:00
}
return null ;
}
public static Bitmap getSampledBitmap ( byte [ ] bytes , int size , boolean highQuality )
{
final BitmapFactory . Options opt = new BitmapFactory . Options ( ) ;
2013-12-30 09:33:39 +01:00
if ( size > 0 )
{
2013-12-04 07:36:02 +01:00
opt . inJustDecodeBounds = true ;
BitmapFactory . decodeByteArray ( bytes , 0 , bytes . length , opt ) ;
2013-12-30 09:33:39 +01:00
if ( highQuality )
{
2013-12-04 07:36:02 +01:00
opt . inDither = true ;
opt . inPreferQualityOverSpeed = true ;
}
opt . inPurgeable = true ;
opt . inSampleSize = Util . calculateInSampleSize ( opt , size , Util . getScaledHeight ( opt . outHeight , opt . outWidth , size ) ) ;
opt . inJustDecodeBounds = false ;
}
2020-09-30 14:47:59 +02:00
Timber . i ( " getSampledBitmap %i " , String . valueOf ( size ) ) ;
2013-12-30 09:33:39 +01:00
return BitmapFactory . decodeByteArray ( bytes , 0 , bytes . length , opt ) ;
2013-12-04 07:36:02 +01:00
}
2020-06-02 15:35:36 +02:00
public static File getAlbumArtDirectory ( Context context )
2013-12-04 07:36:02 +01:00
{
2020-09-24 13:03:05 +02:00
File albumArtDir = new File ( getUltrasonicDirectory ( context ) , " artwork " ) ;
2013-12-04 07:36:02 +01:00
ensureDirectoryExistsAndIsReadWritable ( albumArtDir ) ;
ensureDirectoryExistsAndIsReadWritable ( new File ( albumArtDir , " .nomedia " ) ) ;
return albumArtDir ;
}
public static File getAlbumDirectory ( Context context , MusicDirectory . Entry entry )
{
if ( entry = = null )
{
return null ;
}
File dir ;
2020-06-02 15:35:36 +02:00
if ( ! TextUtils . isEmpty ( entry . getPath ( ) ) )
{
2013-12-04 07:36:02 +01:00
File f = new File ( fileSystemSafeDir ( entry . getPath ( ) ) ) ;
dir = new File ( String . format ( " %s/%s " , getMusicDirectory ( context ) . getPath ( ) , entry . isDirectory ( ) ? f . getPath ( ) : f . getParent ( ) ) ) ;
2020-06-02 15:35:36 +02:00
}
else
{
2013-12-04 07:36:02 +01:00
String artist = fileSystemSafe ( entry . getArtist ( ) ) ;
2013-05-16 09:59:55 +02:00
String album = fileSystemSafe ( entry . getAlbum ( ) ) ;
2013-12-04 07:36:02 +01:00
if ( " unnamed " . equals ( album ) )
{
2013-05-16 09:59:55 +02:00
album = fileSystemSafe ( entry . getTitle ( ) ) ;
}
2013-12-04 07:36:02 +01:00
dir = new File ( String . format ( " %s/%s/%s " , getMusicDirectory ( context ) . getPath ( ) , artist , album ) ) ;
}
return dir ;
}
public static void createDirectoryForParent ( File file )
{
File dir = file . getParentFile ( ) ;
if ( ! dir . exists ( ) )
{
if ( ! dir . mkdirs ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . e ( " Failed to create directory %s " , dir ) ;
2013-12-04 07:36:02 +01:00
}
}
}
2020-06-17 18:14:34 +02:00
private static File getOrCreateDirectory ( Context context , String name )
2013-12-04 07:36:02 +01:00
{
2020-09-24 13:03:05 +02:00
File dir = new File ( getUltrasonicDirectory ( context ) , name ) ;
2013-12-04 07:36:02 +01:00
if ( ! dir . exists ( ) & & ! dir . mkdirs ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . e ( " Failed to create %s " , name ) ;
2013-12-04 07:36:02 +01:00
}
return dir ;
}
2020-09-24 13:03:05 +02:00
public static File getUltrasonicDirectory ( Context context )
2013-12-04 07:36:02 +01:00
{
2020-06-02 15:35:36 +02:00
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M )
return new File ( Environment . getExternalStorageDirectory ( ) , " Android/data/org.moire.ultrasonic " ) ;
// After Android M, the location of the files must be queried differently. GetExternalFilesDir will always return a directory which Ultrasonic can access without any extra privileges.
2020-06-17 18:14:34 +02:00
return context . getExternalFilesDir ( null ) ;
2013-12-04 07:36:02 +01:00
}
2020-06-17 18:14:34 +02:00
public static File getDefaultMusicDirectory ( Context context )
2013-12-04 07:36:02 +01:00
{
2020-06-17 18:14:34 +02:00
return getOrCreateDirectory ( context , " music " ) ;
2013-12-04 07:36:02 +01:00
}
public static File getMusicDirectory ( Context context )
{
2020-06-17 18:14:34 +02:00
File defaultMusicDirectory = getDefaultMusicDirectory ( context ) ;
String path = Util . getPreferences ( context ) . getString ( Constants . PREFERENCES_KEY_CACHE_LOCATION , defaultMusicDirectory . getPath ( ) ) ;
2013-12-04 07:36:02 +01:00
File dir = new File ( path ) ;
2020-06-02 15:35:36 +02:00
boolean hasAccess = ensureDirectoryExistsAndIsReadWritable ( dir ) ;
if ( hasAccess = = false ) PermissionUtil . handlePermissionFailed ( context , null ) ;
2020-06-17 18:14:34 +02:00
return hasAccess ? dir : defaultMusicDirectory ;
2013-12-04 07:36:02 +01:00
}
public static boolean ensureDirectoryExistsAndIsReadWritable ( File dir )
{
if ( dir = = null )
{
return false ;
}
if ( dir . exists ( ) )
{
if ( ! dir . isDirectory ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . w ( " %s exists but is not a directory. " , dir ) ;
2013-12-04 07:36:02 +01:00
return false ;
}
}
else
{
if ( dir . mkdirs ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . i ( " Created directory %s " , dir ) ;
2013-12-04 07:36:02 +01:00
}
else
{
2020-09-30 14:47:59 +02:00
Timber . w ( " Failed to create directory %s " , dir ) ;
2013-12-04 07:36:02 +01:00
return false ;
}
}
if ( ! dir . canRead ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . w ( " No read permission for directory %s " , dir ) ;
2020-06-02 15:35:36 +02:00
return false ;
2013-12-04 07:36:02 +01:00
}
if ( ! dir . canWrite ( ) )
{
2020-09-30 14:47:59 +02:00
Timber . w ( " No write permission for directory %s " , dir ) ;
2020-06-02 15:35:36 +02:00
return false ;
2013-12-04 07:36:02 +01:00
}
return true ;
}
/ * *
* Makes a given filename safe by replacing special characters like slashes ( " / " and " \" )
* with dashes ( " - " ) .
*
* @param filename The filename in question .
* @return The filename with special characters replaced by hyphens .
* /
private static String fileSystemSafe ( String filename )
{
2013-12-30 09:33:39 +01:00
if ( filename = = null | | filename . trim ( ) . isEmpty ( ) )
2013-12-04 07:36:02 +01:00
{
return " unnamed " ;
}
for ( String s : FILE_SYSTEM_UNSAFE )
{
filename = filename . replace ( s , " - " ) ;
}
return filename ;
}
/ * *
* Makes a given filename safe by replacing special characters like colons ( " : " )
* with dashes ( " - " ) .
*
* @param path The path of the directory in question .
* @return The the directory name with special characters replaced by hyphens .
* /
private static String fileSystemSafeDir ( String path )
{
2013-12-30 09:33:39 +01:00
if ( path = = null | | path . trim ( ) . isEmpty ( ) )
2013-12-04 07:36:02 +01:00
{
return " " ;
}
for ( String s : FILE_SYSTEM_UNSAFE_DIR )
{
path = path . replace ( s , " - " ) ;
}
return path ;
}
/ * *
* Similar to { @link File # listFiles ( ) } , but returns a sorted set .
* Never returns { @code null } , instead a warning is logged , and an empty set is returned .
* /
public static SortedSet < File > listFiles ( File dir )
{
File [ ] files = dir . listFiles ( ) ;
if ( files = = null )
{
2020-09-30 14:47:59 +02:00
Timber . w ( " Failed to list children for %s " , dir . getPath ( ) ) ;
2013-12-04 07:36:02 +01:00
return new TreeSet < File > ( ) ;
}
return new TreeSet < File > ( Arrays . asList ( files ) ) ;
}
public static SortedSet < File > listMediaFiles ( File dir )
{
SortedSet < File > files = listFiles ( dir ) ;
Iterator < File > iterator = files . iterator ( ) ;
while ( iterator . hasNext ( ) )
{
File file = iterator . next ( ) ;
if ( ! file . isDirectory ( ) & & ! isMediaFile ( file ) )
{
iterator . remove ( ) ;
}
}
return files ;
}
private static boolean isMediaFile ( File file )
{
String extension = getExtension ( file . getName ( ) ) ;
return MUSIC_FILE_EXTENSIONS . contains ( extension ) | | VIDEO_FILE_EXTENSIONS . contains ( extension ) ;
}
public static boolean isPlaylistFile ( File file )
{
2013-05-16 09:59:55 +02:00
String extension = getExtension ( file . getName ( ) ) ;
return PLAYLIST_FILE_EXTENSIONS . contains ( extension ) ;
}
2013-12-04 07:36:02 +01:00
/ * *
* Returns the extension ( the substring after the last dot ) of the given file . The dot
* is not included in the returned extension .
*
* @param name The filename in question .
* @return The extension , or an empty string if no extension is found .
* /
public static String getExtension ( String name )
{
int index = name . lastIndexOf ( '.' ) ;
return index = = - 1 ? " " : name . substring ( index + 1 ) . toLowerCase ( ) ;
}
/ * *
* Returns the base name ( the substring before the last dot ) of the given file . The dot
* is not included in the returned basename .
*
* @param name The filename in question .
* @return The base name , or an empty string if no basename is found .
* /
public static String getBaseName ( String name )
{
int index = name . lastIndexOf ( '.' ) ;
return index = = - 1 ? name : name . substring ( 0 , index ) ;
}
public static < T extends Serializable > boolean serialize ( Context context , T obj , String fileName )
{
File file = new File ( context . getCacheDir ( ) , fileName ) ;
ObjectOutputStream out = null ;
try
{
out = new ObjectOutputStream ( new FileOutputStream ( file ) ) ;
out . writeObject ( obj ) ;
2020-09-30 14:47:59 +02:00
Timber . i ( " Serialized object to %s " , file ) ;
2013-12-04 07:36:02 +01:00
return true ;
}
catch ( Throwable x )
{
2020-09-30 14:47:59 +02:00
Timber . w ( " Failed to serialize object to %s " , file ) ;
2013-12-04 07:36:02 +01:00
return false ;
}
finally
{
Util . close ( out ) ;
}
}
2013-12-08 08:27:34 +01:00
@SuppressWarnings ( { " unchecked " } )
2013-12-04 07:36:02 +01:00
public static < T extends Serializable > T deserialize ( Context context , String fileName )
{
File file = new File ( context . getCacheDir ( ) , fileName ) ;
if ( ! file . exists ( ) | | ! file . isFile ( ) )
{
return null ;
}
ObjectInputStream in = null ;
try
{
in = new ObjectInputStream ( new FileInputStream ( file ) ) ;
2013-12-08 08:27:34 +01:00
Object object = in . readObject ( ) ;
T result = ( T ) object ;
2020-09-30 14:47:59 +02:00
Timber . i ( " Deserialized object from %s " , file ) ;
2013-12-04 07:36:02 +01:00
return result ;
}
catch ( Throwable x )
{
2020-09-30 14:47:59 +02:00
Timber . w ( x , " Failed to deserialize object from %s " , file ) ;
2013-12-04 07:36:02 +01:00
return null ;
}
finally
{
Util . close ( in ) ;
}
}
2013-02-08 10:09:55 +01:00
}