2014-08-22 16:24:33 +02:00
/ *
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v . 5 . x . x .
2014-08-22 16:24:33 +02:00
* It is licensed under GNU GPL v . 2 or later .
* You should have received a copy of the license in this archive ( see LICENSE ) .
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov , 2013 - 2018 .
2014-08-22 16:24:33 +02:00
* /
2015-09-24 22:52:02 +02:00
package org.telegram.messenger ;
2014-08-22 16:24:33 +02:00
2021-06-25 02:43:10 +02:00
import android.annotation.TargetApi ;
2014-08-22 16:24:33 +02:00
import android.app.ActivityManager ;
2014-10-01 21:55:24 +02:00
import android.content.BroadcastReceiver ;
2014-08-22 16:24:33 +02:00
import android.content.Context ;
2014-10-01 21:55:24 +02:00
import android.content.Intent ;
import android.content.IntentFilter ;
2014-08-22 16:24:33 +02:00
import android.graphics.Bitmap ;
import android.graphics.BitmapFactory ;
import android.graphics.Matrix ;
import android.graphics.drawable.BitmapDrawable ;
2019-05-14 14:08:05 +02:00
import android.graphics.drawable.Drawable ;
2014-08-22 16:24:33 +02:00
import android.net.Uri ;
import android.os.AsyncTask ;
import android.os.Build ;
2014-09-25 05:54:35 +02:00
import android.os.Environment ;
2021-01-28 15:15:51 +01:00
import android.os.SystemClock ;
2014-08-22 16:24:33 +02:00
import android.provider.MediaStore ;
2017-12-08 18:35:59 +01:00
import android.text.TextUtils ;
2018-07-30 04:07:02 +02:00
import android.util.SparseArray ;
2014-08-22 16:24:33 +02:00
2021-12-30 11:52:40 +01:00
import androidx.exifinterface.media.ExifInterface ;
2021-11-05 11:06:49 +01:00
2019-01-23 18:03:33 +01:00
import org.json.JSONArray ;
import org.json.JSONObject ;
2017-07-23 14:56:38 +02:00
import org.telegram.messenger.secretmedia.EncryptedFileInputStream ;
2016-01-11 18:19:48 +01:00
import org.telegram.tgnet.ConnectionsManager ;
2015-09-24 22:52:02 +02:00
import org.telegram.tgnet.TLObject ;
import org.telegram.tgnet.TLRPC ;
2019-12-31 14:08:08 +01:00
import org.telegram.ui.Cells.ChatMessageCell ;
2016-01-11 18:19:48 +01:00
import org.telegram.ui.Components.AnimatedFileDrawable ;
2019-12-31 14:08:08 +01:00
import org.telegram.ui.Components.Point ;
2019-07-18 15:01:39 +02:00
import org.telegram.ui.Components.RLottieDrawable ;
2020-10-30 11:26:29 +01:00
import org.telegram.ui.Components.SlotsDrawable ;
2019-12-31 14:08:08 +01:00
import org.telegram.ui.Components.ThemePreviewDrawable ;
2014-08-22 16:24:33 +02:00
2021-06-25 02:43:10 +02:00
import java.io.BufferedReader ;
2014-08-22 16:24:33 +02:00
import java.io.ByteArrayOutputStream ;
import java.io.File ;
import java.io.FileInputStream ;
2016-10-11 13:57:01 +02:00
import java.io.FileNotFoundException ;
2014-08-22 16:24:33 +02:00
import java.io.FileOutputStream ;
import java.io.InputStream ;
2021-06-25 02:43:10 +02:00
import java.io.InputStreamReader ;
2014-08-22 16:24:33 +02:00
import java.io.RandomAccessFile ;
2015-01-02 23:15:07 +01:00
import java.net.HttpURLConnection ;
2016-01-11 18:19:48 +01:00
import java.net.SocketException ;
import java.net.SocketTimeoutException ;
2014-08-22 16:24:33 +02:00
import java.net.URL ;
import java.net.URLConnection ;
2015-06-29 19:12:11 +02:00
import java.net.UnknownHostException ;
2015-01-02 23:15:07 +01:00
import java.nio.ByteBuffer ;
import java.nio.channels.FileChannel ;
2021-06-25 02:43:10 +02:00
import java.nio.file.Files ;
import java.nio.file.Path ;
2014-08-22 16:24:33 +02:00
import java.util.ArrayList ;
2018-07-30 04:07:02 +02:00
import java.util.Arrays ;
2014-08-22 16:24:33 +02:00
import java.util.HashMap ;
import java.util.LinkedList ;
2016-01-11 18:19:48 +01:00
import java.util.List ;
2019-12-31 14:08:08 +01:00
import java.util.Locale ;
2016-01-11 18:19:48 +01:00
import java.util.Map ;
2014-08-22 16:24:33 +02:00
import java.util.concurrent.ConcurrentHashMap ;
2021-06-25 02:43:10 +02:00
import java.util.stream.Stream ;
import java.util.zip.GZIPInputStream ;
2014-08-22 16:24:33 +02:00
2021-11-05 11:06:49 +01:00
/ * *
* image filter types
* suffixes :
* f - image is wallpaper
* isc - ignore cache for small images
* b - need blur image
* g - autoplay
* /
2014-08-22 16:24:33 +02:00
public class ImageLoader {
2015-01-02 23:15:07 +01:00
private HashMap < String , Integer > bitmapUseCounts = new HashMap < > ( ) ;
2021-11-05 11:06:49 +01:00
private LruCache < BitmapDrawable > smallImagesMemCache ;
2019-06-04 12:14:50 +02:00
private LruCache < BitmapDrawable > memCache ;
2021-09-20 07:54:41 +02:00
private LruCache < BitmapDrawable > wallpaperMemCache ;
2019-07-18 15:01:39 +02:00
private LruCache < RLottieDrawable > lottieMemCache ;
2015-02-01 19:51:02 +01:00
private HashMap < String , CacheImage > imageLoadingByUrl = new HashMap < > ( ) ;
private HashMap < String , CacheImage > imageLoadingByKeys = new HashMap < > ( ) ;
2018-07-30 04:07:02 +02:00
private SparseArray < CacheImage > imageLoadingByTag = new SparseArray < > ( ) ;
2015-02-01 19:51:02 +01:00
private HashMap < String , ThumbGenerateInfo > waitingForQualityThumb = new HashMap < > ( ) ;
2018-07-30 04:07:02 +02:00
private SparseArray < String > waitingForQualityThumbByTag = new SparseArray < > ( ) ;
2015-01-02 23:15:07 +01:00
private LinkedList < HttpImageTask > httpTasks = new LinkedList < > ( ) ;
2019-01-23 18:03:33 +01:00
private LinkedList < ArtworkLoadTask > artworkTasks = new LinkedList < > ( ) ;
2014-09-14 01:40:36 +02:00
private DispatchQueue cacheOutQueue = new DispatchQueue ( " cacheOutQueue " ) ;
2015-02-01 19:51:02 +01:00
private DispatchQueue cacheThumbOutQueue = new DispatchQueue ( " cacheThumbOutQueue " ) ;
private DispatchQueue thumbGeneratingQueue = new DispatchQueue ( " thumbGeneratingQueue " ) ;
private DispatchQueue imageLoadQueue = new DispatchQueue ( " imageLoadQueue " ) ;
2018-07-30 04:07:02 +02:00
private HashMap < String , String > replacedBitmaps = new HashMap < > ( ) ;
2020-01-23 07:15:40 +01:00
private ConcurrentHashMap < String , long [ ] > fileProgresses = new ConcurrentHashMap < > ( ) ;
2015-02-01 19:51:02 +01:00
private HashMap < String , ThumbGenerateTask > thumbGenerateTasks = new HashMap < > ( ) ;
2017-12-08 18:35:59 +01:00
private HashMap < String , Integer > forceLoadingImages = new HashMap < > ( ) ;
2019-03-03 21:40:48 +01:00
private static ThreadLocal < byte [ ] > bytesLocal = new ThreadLocal < > ( ) ;
private static ThreadLocal < byte [ ] > bytesThumbLocal = new ThreadLocal < > ( ) ;
2015-05-21 23:27:27 +02:00
private static byte [ ] header = new byte [ 12 ] ;
private static byte [ ] headerThumb = new byte [ 12 ] ;
2014-08-22 16:24:33 +02:00
private int currentHttpTasksCount = 0 ;
2019-01-23 18:03:33 +01:00
private int currentArtworkTasksCount = 0 ;
2019-03-03 21:40:48 +01:00
private boolean canForce8888 ;
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
private ConcurrentHashMap < String , WebFile > testWebFile = new ConcurrentHashMap < > ( ) ;
2015-01-02 23:15:07 +01:00
private LinkedList < HttpFileTask > httpFileLoadTasks = new LinkedList < > ( ) ;
private HashMap < String , HttpFileTask > httpFileLoadTasksByKeys = new HashMap < > ( ) ;
private HashMap < String , Runnable > retryHttpsTasks = new HashMap < > ( ) ;
private int currentHttpFileLoadTasksCount = 0 ;
2014-08-22 16:24:33 +02:00
private String ignoreRemoval = null ;
private volatile long lastCacheOutTime = 0 ;
private int lastImageNum = 0 ;
2014-09-30 00:48:11 +02:00
private File telegramPath = null ;
2019-05-14 14:08:05 +02:00
public static final String AUTOPLAY_FILTER = " g " ;
2019-03-03 21:40:48 +01:00
2021-11-05 11:06:49 +01:00
public void moveToFront ( String key ) {
if ( key = = null ) {
return ;
}
BitmapDrawable drawable = memCache . get ( key ) ;
if ( drawable ! = null ) {
memCache . moveToFront ( key ) ;
}
drawable = smallImagesMemCache . get ( key ) ;
if ( drawable ! = null ) {
smallImagesMemCache . moveToFront ( key ) ;
}
}
2019-12-31 14:08:08 +01:00
public void putThumbsToCache ( ArrayList < MessageThumb > updateMessageThumbs ) {
for ( int i = 0 ; i < updateMessageThumbs . size ( ) ; i + + ) {
2021-11-05 11:06:49 +01:00
putImageToCache ( updateMessageThumbs . get ( i ) . drawable , updateMessageThumbs . get ( i ) . key , true ) ;
2019-12-31 14:08:08 +01:00
}
}
2020-04-24 11:21:58 +02:00
private static class ThumbGenerateInfo {
2019-01-23 18:03:33 +01:00
private TLRPC . Document parentDocument ;
2015-02-01 19:51:02 +01:00
private String filter ;
2019-01-23 18:03:33 +01:00
private ArrayList < ImageReceiver > imageReceiverArray = new ArrayList < > ( ) ;
2019-07-18 15:01:39 +02:00
private ArrayList < Integer > imageReceiverGuidsArray = new ArrayList < > ( ) ;
2019-03-03 21:40:48 +01:00
private boolean big ;
2015-02-01 19:51:02 +01:00
}
2015-01-02 23:15:07 +01:00
private class HttpFileTask extends AsyncTask < Void , Void , Boolean > {
2014-08-22 16:24:33 +02:00
2015-01-02 23:15:07 +01:00
private String url ;
private File tempFile ;
private String ext ;
2016-10-11 13:57:01 +02:00
private int fileSize ;
2014-08-22 16:24:33 +02:00
private RandomAccessFile fileOutputStream = null ;
2015-01-02 23:15:07 +01:00
private boolean canRetry = true ;
2016-10-11 13:57:01 +02:00
private long lastProgressTime ;
2018-07-30 04:07:02 +02:00
private int currentAccount ;
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
public HttpFileTask ( String url , File tempFile , String ext , int currentAccount ) {
2015-01-02 23:15:07 +01:00
this . url = url ;
this . tempFile = tempFile ;
this . ext = ext ;
2018-07-30 04:07:02 +02:00
this . currentAccount = currentAccount ;
2014-08-22 16:24:33 +02:00
}
2020-01-23 07:15:40 +01:00
private void reportProgress ( long uploadedSize , long totalSize ) {
2021-01-28 15:15:51 +01:00
long currentTime = SystemClock . elapsedRealtime ( ) ;
2020-01-23 07:15:40 +01:00
if ( uploadedSize = = totalSize | | lastProgressTime = = 0 | | lastProgressTime < currentTime - 100 ) {
2016-10-11 13:57:01 +02:00
lastProgressTime = currentTime ;
2018-08-27 10:33:11 +02:00
Utilities . stageQueue . postRunnable ( ( ) - > {
2020-01-23 07:15:40 +01:00
fileProgresses . put ( url , new long [ ] { uploadedSize , totalSize } ) ;
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileLoadProgressChanged , url , uploadedSize , totalSize ) ) ;
2016-10-11 13:57:01 +02:00
} ) ;
}
}
2014-08-22 16:24:33 +02:00
protected Boolean doInBackground ( Void . . . voids ) {
InputStream httpConnectionStream = null ;
boolean done = false ;
2015-01-02 23:15:07 +01:00
URLConnection httpConnection = null ;
2014-08-22 16:24:33 +02:00
try {
2015-01-02 23:15:07 +01:00
URL downloadUrl = new URL ( url ) ;
httpConnection = downloadUrl . openConnection ( ) ;
2017-07-08 18:32:04 +02:00
httpConnection . addRequestProperty ( " User-Agent " , " Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1 " ) ;
2014-08-22 16:24:33 +02:00
httpConnection . setConnectTimeout ( 5000 ) ;
httpConnection . setReadTimeout ( 5000 ) ;
2015-05-21 23:27:27 +02:00
if ( httpConnection instanceof HttpURLConnection ) {
HttpURLConnection httpURLConnection = ( HttpURLConnection ) httpConnection ;
httpURLConnection . setInstanceFollowRedirects ( true ) ;
int status = httpURLConnection . getResponseCode ( ) ;
if ( status = = HttpURLConnection . HTTP_MOVED_TEMP | | status = = HttpURLConnection . HTTP_MOVED_PERM | | status = = HttpURLConnection . HTTP_SEE_OTHER ) {
String newUrl = httpURLConnection . getHeaderField ( " Location " ) ;
String cookies = httpURLConnection . getHeaderField ( " Set-Cookie " ) ;
downloadUrl = new URL ( newUrl ) ;
httpConnection = downloadUrl . openConnection ( ) ;
httpConnection . setRequestProperty ( " Cookie " , cookies ) ;
2017-07-08 18:32:04 +02:00
httpConnection . addRequestProperty ( " User-Agent " , " Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1 " ) ;
2015-05-21 23:27:27 +02:00
}
}
2014-08-22 16:24:33 +02:00
httpConnection . connect ( ) ;
httpConnectionStream = httpConnection . getInputStream ( ) ;
2015-01-02 23:15:07 +01:00
fileOutputStream = new RandomAccessFile ( tempFile , " rws " ) ;
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2016-10-11 13:57:01 +02:00
if ( e instanceof SocketTimeoutException ) {
2019-01-23 18:03:33 +01:00
if ( ApplicationLoader . isNetworkOnline ( ) ) {
2016-10-11 13:57:01 +02:00
canRetry = false ;
}
} else if ( e instanceof UnknownHostException ) {
canRetry = false ;
} else if ( e instanceof SocketException ) {
if ( e . getMessage ( ) ! = null & & e . getMessage ( ) . contains ( " ECONNRESET " ) ) {
canRetry = false ;
}
} else if ( e instanceof FileNotFoundException ) {
2015-06-29 19:12:11 +02:00
canRetry = false ;
2015-01-02 23:15:07 +01:00
}
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
}
2015-06-29 19:12:11 +02:00
if ( canRetry ) {
2015-05-21 23:27:27 +02:00
try {
2019-01-23 18:03:33 +01:00
if ( httpConnection instanceof HttpURLConnection ) {
2015-06-29 19:12:11 +02:00
int code = ( ( HttpURLConnection ) httpConnection ) . getResponseCode ( ) ;
if ( code ! = HttpURLConnection . HTTP_OK & & code ! = HttpURLConnection . HTTP_ACCEPTED & & code ! = HttpURLConnection . HTTP_NOT_MODIFIED ) {
canRetry = false ;
2015-05-21 23:27:27 +02:00
}
2015-06-29 19:12:11 +02:00
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-06-29 19:12:11 +02:00
}
2016-10-11 13:57:01 +02:00
if ( httpConnection ! = null ) {
try {
Map < String , List < String > > headerFields = httpConnection . getHeaderFields ( ) ;
if ( headerFields ! = null ) {
List values = headerFields . get ( " content-Length " ) ;
if ( values ! = null & & ! values . isEmpty ( ) ) {
String length = ( String ) values . get ( 0 ) ;
if ( length ! = null ) {
fileSize = Utilities . parseInt ( length ) ;
}
}
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2016-10-11 13:57:01 +02:00
}
}
2015-06-29 19:12:11 +02:00
if ( httpConnectionStream ! = null ) {
try {
2016-10-11 13:57:01 +02:00
byte [ ] data = new byte [ 1024 * 32 ] ;
int totalLoaded = 0 ;
2015-06-29 19:12:11 +02:00
while ( true ) {
if ( isCancelled ( ) ) {
2015-05-21 23:27:27 +02:00
break ;
2015-06-29 19:12:11 +02:00
}
try {
int read = httpConnectionStream . read ( data ) ;
if ( read > 0 ) {
fileOutputStream . write ( data , 0 , read ) ;
2016-10-11 13:57:01 +02:00
totalLoaded + = read ;
if ( fileSize > 0 ) {
2020-01-23 07:15:40 +01:00
reportProgress ( totalLoaded , fileSize ) ;
2016-10-11 13:57:01 +02:00
}
2015-06-29 19:12:11 +02:00
} else if ( read = = - 1 ) {
done = true ;
2016-10-11 13:57:01 +02:00
if ( fileSize ! = 0 ) {
2020-01-23 07:15:40 +01:00
reportProgress ( fileSize , fileSize ) ;
2016-10-11 13:57:01 +02:00
}
2015-06-29 19:12:11 +02:00
break ;
} else {
break ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-05-21 23:27:27 +02:00
break ;
}
2014-08-22 16:24:33 +02:00
}
2015-06-29 19:12:11 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
}
2015-06-29 19:12:11 +02:00
try {
if ( fileOutputStream ! = null ) {
fileOutputStream . close ( ) ;
fileOutputStream = null ;
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
2015-06-29 19:12:11 +02:00
try {
if ( httpConnectionStream ! = null ) {
httpConnectionStream . close ( ) ;
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
}
2015-01-02 23:15:07 +01:00
return done ;
}
@Override
protected void onPostExecute ( Boolean result ) {
runHttpFileLoadTasks ( this , result ? 2 : 1 ) ;
}
@Override
protected void onCancelled ( ) {
runHttpFileLoadTasks ( this , 2 ) ;
}
}
2019-01-23 18:03:33 +01:00
private class ArtworkLoadTask extends AsyncTask < Void , Void , String > {
private CacheImage cacheImage ;
private boolean canRetry = true ;
private HttpURLConnection httpConnection ;
private boolean small ;
public ArtworkLoadTask ( CacheImage cacheImage ) {
this . cacheImage = cacheImage ;
2019-05-14 14:08:05 +02:00
Uri uri = Uri . parse ( cacheImage . imageLocation . path ) ;
2019-01-23 18:03:33 +01:00
small = uri . getQueryParameter ( " s " ) ! = null ;
}
protected String doInBackground ( Void . . . voids ) {
ByteArrayOutputStream outbuf = null ;
InputStream httpConnectionStream = null ;
try {
2019-05-14 14:08:05 +02:00
String location = cacheImage . imageLocation . path ;
2019-02-08 03:30:32 +01:00
URL downloadUrl = new URL ( location . replace ( " athumb:// " , " https:// " ) ) ;
2019-01-23 18:03:33 +01:00
httpConnection = ( HttpURLConnection ) downloadUrl . openConnection ( ) ;
2020-07-26 10:03:38 +02:00
//httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
2019-01-23 18:03:33 +01:00
httpConnection . setConnectTimeout ( 5000 ) ;
httpConnection . setReadTimeout ( 5000 ) ;
httpConnection . connect ( ) ;
try {
if ( httpConnection ! = null ) {
int code = httpConnection . getResponseCode ( ) ;
if ( code ! = HttpURLConnection . HTTP_OK & & code ! = HttpURLConnection . HTTP_ACCEPTED & & code ! = HttpURLConnection . HTTP_NOT_MODIFIED ) {
canRetry = false ;
}
}
} catch ( Exception e ) {
2021-12-30 11:52:40 +01:00
FileLog . e ( e , false ) ;
2019-01-23 18:03:33 +01:00
}
httpConnectionStream = httpConnection . getInputStream ( ) ;
outbuf = new ByteArrayOutputStream ( ) ;
byte [ ] data = new byte [ 1024 * 32 ] ;
while ( true ) {
if ( isCancelled ( ) ) {
break ;
}
int read = httpConnectionStream . read ( data ) ;
if ( read > 0 ) {
outbuf . write ( data , 0 , read ) ;
} else if ( read = = - 1 ) {
break ;
} else {
break ;
}
}
canRetry = false ;
2019-05-14 14:08:05 +02:00
JSONObject object = new JSONObject ( new String ( outbuf . toByteArray ( ) ) ) ;
2019-01-23 18:03:33 +01:00
JSONArray array = object . getJSONArray ( " results " ) ;
if ( array . length ( ) > 0 ) {
JSONObject media = array . getJSONObject ( 0 ) ;
String artworkUrl100 = media . getString ( " artworkUrl100 " ) ;
if ( small ) {
return artworkUrl100 ;
} else {
return artworkUrl100 . replace ( " 100x100 " , " 600x600 " ) ;
}
}
} catch ( Throwable e ) {
if ( e instanceof SocketTimeoutException ) {
if ( ApplicationLoader . isNetworkOnline ( ) ) {
canRetry = false ;
}
} else if ( e instanceof UnknownHostException ) {
canRetry = false ;
} else if ( e instanceof SocketException ) {
if ( e . getMessage ( ) ! = null & & e . getMessage ( ) . contains ( " ECONNRESET " ) ) {
canRetry = false ;
}
} else if ( e instanceof FileNotFoundException ) {
canRetry = false ;
}
2021-12-07 14:02:02 +01:00
FileLog . e ( e , false ) ;
2019-01-23 18:03:33 +01:00
} finally {
try {
if ( httpConnection ! = null ) {
httpConnection . disconnect ( ) ;
}
} catch ( Throwable ignore ) {
}
try {
if ( httpConnectionStream ! = null ) {
httpConnectionStream . close ( ) ;
}
} catch ( Throwable e ) {
FileLog . e ( e ) ;
}
try {
if ( outbuf ! = null ) {
outbuf . close ( ) ;
}
} catch ( Exception ignore ) {
}
}
return null ;
}
@Override
protected void onPostExecute ( final String result ) {
if ( result ! = null ) {
2020-10-31 22:13:37 +01:00
imageLoadQueue . postRunnable ( ( ) - > {
cacheImage . httpTask = new HttpImageTask ( cacheImage , 0 , result ) ;
httpTasks . add ( cacheImage . httpTask ) ;
runHttpTasks ( false ) ;
} ) ;
2019-01-23 18:03:33 +01:00
} else if ( canRetry ) {
artworkLoadError ( cacheImage . url ) ;
}
imageLoadQueue . postRunnable ( ( ) - > runArtworkTasks ( true ) ) ;
}
@Override
protected void onCancelled ( ) {
imageLoadQueue . postRunnable ( ( ) - > runArtworkTasks ( true ) ) ;
}
}
2015-01-02 23:15:07 +01:00
private class HttpImageTask extends AsyncTask < Void , Void , Boolean > {
2018-07-30 04:07:02 +02:00
private CacheImage cacheImage ;
private RandomAccessFile fileOutputStream ;
2015-01-02 23:15:07 +01:00
private int imageSize ;
private long lastProgressTime ;
private boolean canRetry = true ;
2019-01-23 18:03:33 +01:00
private String overrideUrl ;
2018-07-30 04:07:02 +02:00
private HttpURLConnection httpConnection ;
2015-01-02 23:15:07 +01:00
public HttpImageTask ( CacheImage cacheImage , int size ) {
this . cacheImage = cacheImage ;
imageSize = size ;
}
2019-01-23 18:03:33 +01:00
public HttpImageTask ( CacheImage cacheImage , int size , String url ) {
this . cacheImage = cacheImage ;
imageSize = size ;
overrideUrl = url ;
}
2020-01-23 07:15:40 +01:00
private void reportProgress ( long uploadedSize , long totalSize ) {
2021-01-28 15:15:51 +01:00
long currentTime = SystemClock . elapsedRealtime ( ) ;
2020-01-23 07:15:40 +01:00
if ( uploadedSize = = totalSize | | lastProgressTime = = 0 | | lastProgressTime < currentTime - 100 ) {
2015-01-02 23:15:07 +01:00
lastProgressTime = currentTime ;
2018-08-27 10:33:11 +02:00
Utilities . stageQueue . postRunnable ( ( ) - > {
2020-01-23 07:15:40 +01:00
fileProgresses . put ( cacheImage . url , new long [ ] { uploadedSize , totalSize } ) ;
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( cacheImage . currentAccount ) . postNotificationName ( NotificationCenter . fileLoadProgressChanged , cacheImage . url , uploadedSize , totalSize ) ) ;
2015-01-02 23:15:07 +01:00
} ) ;
}
}
protected Boolean doInBackground ( Void . . . voids ) {
InputStream httpConnectionStream = null ;
boolean done = false ;
if ( ! isCancelled ( ) ) {
try {
2019-05-14 14:08:05 +02:00
String location = cacheImage . imageLocation . path ;
2019-02-08 03:30:32 +01:00
if ( location . startsWith ( " https://static-maps " ) | | location . startsWith ( " https://maps.googleapis " ) ) {
2018-07-30 04:07:02 +02:00
int provider = MessagesController . getInstance ( cacheImage . currentAccount ) . mapProvider ;
if ( provider = = 3 | | provider = = 4 ) {
2019-02-08 03:30:32 +01:00
WebFile webFile = testWebFile . get ( location ) ;
2018-07-30 04:07:02 +02:00
if ( webFile ! = null ) {
TLRPC . TL_upload_getWebFile req = new TLRPC . TL_upload_getWebFile ( ) ;
req . location = webFile . location ;
req . offset = 0 ;
req . limit = 0 ;
2018-08-27 10:33:11 +02:00
ConnectionsManager . getInstance ( cacheImage . currentAccount ) . sendRequest ( req , ( response , error ) - > {
2018-07-30 04:07:02 +02:00
} ) ;
}
}
}
2019-02-08 03:30:32 +01:00
URL downloadUrl = new URL ( overrideUrl ! = null ? overrideUrl : location ) ;
2017-12-08 18:35:59 +01:00
httpConnection = ( HttpURLConnection ) downloadUrl . openConnection ( ) ;
2017-07-08 18:32:04 +02:00
httpConnection . addRequestProperty ( " User-Agent " , " Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1 " ) ;
2015-01-02 23:15:07 +01:00
httpConnection . setConnectTimeout ( 5000 ) ;
httpConnection . setReadTimeout ( 5000 ) ;
2017-12-08 18:35:59 +01:00
httpConnection . setInstanceFollowRedirects ( true ) ;
2015-01-02 23:15:07 +01:00
if ( ! isCancelled ( ) ) {
httpConnection . connect ( ) ;
httpConnectionStream = httpConnection . getInputStream ( ) ;
fileOutputStream = new RandomAccessFile ( cacheImage . tempFilePath , " rws " ) ;
}
} catch ( Throwable e ) {
2021-12-07 14:02:02 +01:00
boolean sentLogs = true ;
2016-01-11 18:19:48 +01:00
if ( e instanceof SocketTimeoutException ) {
2019-01-23 18:03:33 +01:00
if ( ApplicationLoader . isNetworkOnline ( ) ) {
2016-01-11 18:19:48 +01:00
canRetry = false ;
}
2021-12-07 14:02:02 +01:00
sentLogs = false ;
2016-01-11 18:19:48 +01:00
} else if ( e instanceof UnknownHostException ) {
canRetry = false ;
2021-12-07 14:02:02 +01:00
sentLogs = false ;
2016-01-11 18:19:48 +01:00
} else if ( e instanceof SocketException ) {
if ( e . getMessage ( ) ! = null & & e . getMessage ( ) . contains ( " ECONNRESET " ) ) {
canRetry = false ;
}
2021-12-07 14:02:02 +01:00
sentLogs = false ;
2016-10-11 13:57:01 +02:00
} else if ( e instanceof FileNotFoundException ) {
canRetry = false ;
2021-12-07 14:02:02 +01:00
sentLogs = false ;
2016-01-11 18:19:48 +01:00
}
2021-12-07 14:02:02 +01:00
FileLog . e ( e , sentLogs ) ;
2015-01-02 23:15:07 +01:00
}
}
if ( ! isCancelled ( ) ) {
try {
2019-01-23 18:03:33 +01:00
if ( httpConnection ! = null ) {
2017-12-08 18:35:59 +01:00
int code = httpConnection . getResponseCode ( ) ;
2015-01-02 23:15:07 +01:00
if ( code ! = HttpURLConnection . HTTP_OK & & code ! = HttpURLConnection . HTTP_ACCEPTED & & code ! = HttpURLConnection . HTTP_NOT_MODIFIED ) {
canRetry = false ;
}
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
}
2016-01-11 18:19:48 +01:00
if ( imageSize = = 0 & & httpConnection ! = null ) {
try {
Map < String , List < String > > headerFields = httpConnection . getHeaderFields ( ) ;
if ( headerFields ! = null ) {
List values = headerFields . get ( " content-Length " ) ;
if ( values ! = null & & ! values . isEmpty ( ) ) {
String length = ( String ) values . get ( 0 ) ;
if ( length ! = null ) {
imageSize = Utilities . parseInt ( length ) ;
}
}
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2016-01-11 18:19:48 +01:00
}
}
2015-01-02 23:15:07 +01:00
2015-05-21 23:27:27 +02:00
if ( httpConnectionStream ! = null ) {
try {
2016-01-11 18:19:48 +01:00
byte [ ] data = new byte [ 1024 * 8 ] ;
2015-05-21 23:27:27 +02:00
int totalLoaded = 0 ;
while ( true ) {
if ( isCancelled ( ) ) {
2015-01-02 23:15:07 +01:00
break ;
2015-05-21 23:27:27 +02:00
}
try {
int read = httpConnectionStream . read ( data ) ;
if ( read > 0 ) {
totalLoaded + = read ;
fileOutputStream . write ( data , 0 , read ) ;
if ( imageSize ! = 0 ) {
2020-01-23 07:15:40 +01:00
reportProgress ( totalLoaded , imageSize ) ;
2015-05-21 23:27:27 +02:00
}
} else if ( read = = - 1 ) {
done = true ;
if ( imageSize ! = 0 ) {
2020-01-23 07:15:40 +01:00
reportProgress ( imageSize , imageSize ) ;
2015-05-21 23:27:27 +02:00
}
break ;
} else {
break ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
break ;
}
}
2015-05-21 23:27:27 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
}
}
}
try {
if ( fileOutputStream ! = null ) {
fileOutputStream . close ( ) ;
fileOutputStream = null ;
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
}
2017-12-08 18:35:59 +01:00
try {
if ( httpConnection ! = null ) {
httpConnection . disconnect ( ) ;
}
} catch ( Throwable ignore ) {
}
2015-01-02 23:15:07 +01:00
try {
if ( httpConnectionStream ! = null ) {
httpConnectionStream . close ( ) ;
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-01-02 23:15:07 +01:00
}
2014-08-22 16:24:33 +02:00
if ( done ) {
if ( cacheImage . tempFilePath ! = null ) {
2015-02-01 19:51:02 +01:00
if ( ! cacheImage . tempFilePath . renameTo ( cacheImage . finalFilePath ) ) {
cacheImage . finalFilePath = cacheImage . tempFilePath ;
}
2014-08-22 16:24:33 +02:00
}
}
return done ;
}
@Override
2015-01-02 23:15:07 +01:00
protected void onPostExecute ( final Boolean result ) {
if ( result | | ! canRetry ) {
2015-02-01 19:51:02 +01:00
fileDidLoaded ( cacheImage . url , cacheImage . finalFilePath , FileLoader . MEDIA_DIR_IMAGE ) ;
2015-01-02 23:15:07 +01:00
} else {
httpFileLoadError ( cacheImage . url ) ;
}
2018-08-27 10:33:11 +02:00
Utilities . stageQueue . postRunnable ( ( ) - > {
fileProgresses . remove ( cacheImage . url ) ;
AndroidUtilities . runOnUIThread ( ( ) - > {
if ( result ) {
2021-06-25 02:43:10 +02:00
NotificationCenter . getInstance ( cacheImage . currentAccount ) . postNotificationName ( NotificationCenter . fileLoaded , cacheImage . url , cacheImage . finalFilePath ) ;
2018-08-27 10:33:11 +02:00
} else {
2021-06-25 02:43:10 +02:00
NotificationCenter . getInstance ( cacheImage . currentAccount ) . postNotificationName ( NotificationCenter . fileLoadFailed , cacheImage . url , 2 ) ;
2018-08-27 10:33:11 +02:00
}
} ) ;
2015-01-02 23:15:07 +01:00
} ) ;
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > runHttpTasks ( true ) ) ;
2014-08-22 16:24:33 +02:00
}
@Override
protected void onCancelled ( ) {
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > runHttpTasks ( true ) ) ;
Utilities . stageQueue . postRunnable ( ( ) - > {
fileProgresses . remove ( cacheImage . url ) ;
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( cacheImage . currentAccount ) . postNotificationName ( NotificationCenter . fileLoadFailed , cacheImage . url , 1 ) ) ;
2015-01-02 23:15:07 +01:00
} ) ;
2014-08-22 16:24:33 +02:00
}
}
2015-02-01 19:51:02 +01:00
private class ThumbGenerateTask implements Runnable {
private File originalPath ;
private int mediaType ;
2019-01-23 18:03:33 +01:00
private ThumbGenerateInfo info ;
2015-02-01 19:51:02 +01:00
2019-01-23 18:03:33 +01:00
public ThumbGenerateTask ( int type , File path , ThumbGenerateInfo i ) {
2015-02-01 19:51:02 +01:00
mediaType = type ;
originalPath = path ;
2019-01-23 18:03:33 +01:00
info = i ;
2015-02-01 19:51:02 +01:00
}
private void removeTask ( ) {
2019-01-23 18:03:33 +01:00
if ( info = = null ) {
2015-02-01 19:51:02 +01:00
return ;
}
2019-01-23 18:03:33 +01:00
final String name = FileLoader . getAttachFileName ( info . parentDocument ) ;
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > thumbGenerateTasks . remove ( name ) ) ;
2015-02-01 19:51:02 +01:00
}
@Override
public void run ( ) {
try {
2019-01-23 18:03:33 +01:00
if ( info = = null ) {
2015-02-01 19:51:02 +01:00
removeTask ( ) ;
return ;
}
2019-01-23 18:03:33 +01:00
final String key = " q_ " + info . parentDocument . dc_id + " _ " + info . parentDocument . id ;
File thumbFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , key + " .jpg " ) ;
2015-02-01 19:51:02 +01:00
if ( thumbFile . exists ( ) | | ! originalPath . exists ( ) ) {
removeTask ( ) ;
return ;
}
2019-03-03 21:40:48 +01:00
int size = info . big ? Math . max ( AndroidUtilities . displaySize . x , AndroidUtilities . displaySize . y ) : Math . min ( 180 , Math . min ( AndroidUtilities . displaySize . x , AndroidUtilities . displaySize . y ) / 4 ) ;
2015-02-01 19:51:02 +01:00
Bitmap originalBitmap = null ;
if ( mediaType = = FileLoader . MEDIA_DIR_IMAGE ) {
originalBitmap = ImageLoader . loadBitmap ( originalPath . toString ( ) , null , size , size , false ) ;
} else if ( mediaType = = FileLoader . MEDIA_DIR_VIDEO ) {
2020-06-04 18:47:15 +02:00
originalBitmap = SendMessagesHelper . createVideoThumbnail ( originalPath . toString ( ) , info . big ? MediaStore . Video . Thumbnails . FULL_SCREEN_KIND : MediaStore . Video . Thumbnails . MINI_KIND ) ;
2015-02-01 19:51:02 +01:00
} else if ( mediaType = = FileLoader . MEDIA_DIR_DOCUMENT ) {
String path = originalPath . toString ( ) . toLowerCase ( ) ;
2019-03-03 21:40:48 +01:00
if ( path . endsWith ( " mp4 " ) ) {
2020-06-04 18:47:15 +02:00
originalBitmap = SendMessagesHelper . createVideoThumbnail ( originalPath . toString ( ) , info . big ? MediaStore . Video . Thumbnails . FULL_SCREEN_KIND : MediaStore . Video . Thumbnails . MINI_KIND ) ;
2019-03-03 21:40:48 +01:00
} else if ( path . endsWith ( " .jpg " ) | | path . endsWith ( " .jpeg " ) | | path . endsWith ( " .png " ) | | path . endsWith ( " .gif " ) ) {
originalBitmap = ImageLoader . loadBitmap ( path , null , size , size , false ) ;
2015-02-01 19:51:02 +01:00
}
}
if ( originalBitmap = = null ) {
removeTask ( ) ;
return ;
}
int w = originalBitmap . getWidth ( ) ;
int h = originalBitmap . getHeight ( ) ;
if ( w = = 0 | | h = = 0 ) {
removeTask ( ) ;
return ;
}
float scaleFactor = Math . min ( ( float ) w / size , ( float ) h / size ) ;
2019-03-03 21:40:48 +01:00
if ( scaleFactor > 1 ) {
Bitmap scaledBitmap = Bitmaps . createScaledBitmap ( originalBitmap , ( int ) ( w / scaleFactor ) , ( int ) ( h / scaleFactor ) , true ) ;
if ( scaledBitmap ! = originalBitmap ) {
originalBitmap . recycle ( ) ;
originalBitmap = scaledBitmap ;
}
2015-02-01 19:51:02 +01:00
}
FileOutputStream stream = new FileOutputStream ( thumbFile ) ;
2019-03-03 21:40:48 +01:00
originalBitmap . compress ( Bitmap . CompressFormat . JPEG , info . big ? 83 : 60 , stream ) ;
2015-02-27 20:57:58 +01:00
try {
stream . close ( ) ;
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-02-27 20:57:58 +01:00
}
2015-02-01 19:51:02 +01:00
final BitmapDrawable bitmapDrawable = new BitmapDrawable ( originalBitmap ) ;
2019-01-23 18:03:33 +01:00
final ArrayList < ImageReceiver > finalImageReceiverArray = new ArrayList < > ( info . imageReceiverArray ) ;
2019-07-18 15:01:39 +02:00
final ArrayList < Integer > finalImageReceiverGuidsArray = new ArrayList < > ( info . imageReceiverGuidsArray ) ;
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
removeTask ( ) ;
2015-02-01 19:51:02 +01:00
2018-08-27 10:33:11 +02:00
String kf = key ;
2019-01-23 18:03:33 +01:00
if ( info . filter ! = null ) {
kf + = " @ " + info . filter ;
}
for ( int a = 0 ; a < finalImageReceiverArray . size ( ) ; a + + ) {
ImageReceiver imgView = finalImageReceiverArray . get ( a ) ;
2019-07-18 15:01:39 +02:00
imgView . setImageBitmapByKey ( bitmapDrawable , kf , ImageReceiver . TYPE_IMAGE , false , finalImageReceiverGuidsArray . get ( a ) ) ;
2015-02-01 19:51:02 +01:00
}
2019-01-23 18:03:33 +01:00
2018-08-27 10:33:11 +02:00
memCache . put ( kf , bitmapDrawable ) ;
2015-02-01 19:51:02 +01:00
} ) ;
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-02-01 19:51:02 +01:00
removeTask ( ) ;
}
}
}
2021-06-25 02:43:10 +02:00
public static String decompressGzip ( File file ) {
final StringBuilder outStr = new StringBuilder ( ) ;
if ( file = = null ) {
return " " ;
}
try ( GZIPInputStream gis = new GZIPInputStream ( new FileInputStream ( file ) ) ; BufferedReader bufferedReader = new BufferedReader ( new InputStreamReader ( gis , " UTF-8 " ) ) ) {
String line ;
while ( ( line = bufferedReader . readLine ( ) ) ! = null ) {
outStr . append ( line ) ;
}
return outStr . toString ( ) ;
} catch ( Exception ignore ) {
return " " ;
}
}
2014-09-14 01:40:36 +02:00
private class CacheOutTask implements Runnable {
2015-02-01 19:51:02 +01:00
private Thread runningThread ;
2014-10-05 23:23:57 +02:00
private final Object sync = new Object ( ) ;
2014-08-22 16:24:33 +02:00
2015-02-01 19:51:02 +01:00
private CacheImage cacheImage ;
private boolean isCancelled ;
2014-08-22 16:24:33 +02:00
2015-02-01 19:51:02 +01:00
public CacheOutTask ( CacheImage image ) {
cacheImage = image ;
2014-08-22 16:24:33 +02:00
}
2014-09-14 01:40:36 +02:00
@Override
public void run ( ) {
synchronized ( sync ) {
runningThread = Thread . currentThread ( ) ;
Thread . interrupted ( ) ;
if ( isCancelled ) {
return ;
}
}
2019-05-14 14:08:05 +02:00
if ( cacheImage . imageLocation . photoSize instanceof TLRPC . TL_photoStrippedSize ) {
TLRPC . TL_photoStrippedSize photoSize = ( TLRPC . TL_photoStrippedSize ) cacheImage . imageLocation . photoSize ;
2019-12-31 14:08:08 +01:00
Bitmap bitmap = getStrippedPhotoBitmap ( photoSize . bytes , cacheImage . filter ) ;
2019-01-23 18:03:33 +01:00
onPostExecute ( bitmap ! = null ? new BitmapDrawable ( bitmap ) : null ) ;
2019-12-31 14:08:08 +01:00
} else if ( cacheImage . imageType = = FileLoader . IMAGE_TYPE_THEME_PREVIEW ) {
BitmapDrawable bitmapDrawable = null ;
try {
bitmapDrawable = new ThemePreviewDrawable ( cacheImage . finalFilePath , ( DocumentObject . ThemeDocument ) cacheImage . imageLocation . document ) ;
} catch ( Throwable e ) {
FileLog . e ( e ) ;
}
onPostExecute ( bitmapDrawable ) ;
} else if ( cacheImage . imageType = = FileLoader . IMAGE_TYPE_SVG | | cacheImage . imageType = = FileLoader . IMAGE_TYPE_SVG_WHITE ) {
int w = AndroidUtilities . dp ( 360 ) ;
int h = AndroidUtilities . dp ( 640 ) ;
if ( cacheImage . filter ! = null ) {
String [ ] args = cacheImage . filter . split ( " _ " ) ;
if ( args . length > = 2 ) {
float w_filter = Float . parseFloat ( args [ 0 ] ) ;
float h_filter = Float . parseFloat ( args [ 1 ] ) ;
w = ( int ) ( w_filter * AndroidUtilities . density ) ;
h = ( int ) ( h_filter * AndroidUtilities . density ) ;
2019-05-14 14:08:05 +02:00
}
}
2019-12-31 14:08:08 +01:00
Bitmap bitmap = null ;
try {
bitmap = SvgHelper . getBitmap ( cacheImage . finalFilePath , w , h , cacheImage . imageType = = FileLoader . IMAGE_TYPE_SVG_WHITE ) ;
} catch ( Throwable e ) {
FileLog . e ( e ) ;
}
onPostExecute ( bitmap ! = null ? new BitmapDrawable ( bitmap ) : null ) ;
} else if ( cacheImage . imageType = = FileLoader . IMAGE_TYPE_LOTTIE ) {
2019-07-18 15:01:39 +02:00
int w = Math . min ( 512 , AndroidUtilities . dp ( 170 . 6f ) ) ;
int h = Math . min ( 512 , AndroidUtilities . dp ( 170 . 6f ) ) ;
boolean precache = false ;
boolean limitFps = false ;
2019-08-22 01:53:26 +02:00
int autoRepeat = 1 ;
int [ ] colors = null ;
2020-04-24 11:21:58 +02:00
String diceEmoji = null ;
2021-12-07 14:02:02 +01:00
int fitzModifier = 0 ;
2019-07-18 15:01:39 +02:00
if ( cacheImage . filter ! = null ) {
String [ ] args = cacheImage . filter . split ( " _ " ) ;
if ( args . length > = 2 ) {
float w_filter = Float . parseFloat ( args [ 0 ] ) ;
float h_filter = Float . parseFloat ( args [ 1 ] ) ;
w = Math . min ( 512 , ( int ) ( w_filter * AndroidUtilities . density ) ) ;
h = Math . min ( 512 , ( int ) ( h_filter * AndroidUtilities . density ) ) ;
2021-12-30 11:52:40 +01:00
if ( w_filter < = 90 & & h_filter < = 90 & & ! cacheImage . filter . contains ( " nolimit " ) ) {
2019-07-18 15:01:39 +02:00
w = Math . min ( w , 160 ) ;
h = Math . min ( h , 160 ) ;
limitFps = true ;
}
2021-09-20 07:54:41 +02:00
if ( args . length > = 3 & & " pcache " . equals ( args [ 2 ] ) ) {
precache = true ;
} else {
2022-01-10 03:27:47 +01:00
precache = ! cacheImage . filter . contains ( " nolimit " ) & & SharedConfig . getDevicePerformanceClass ( ) ! = SharedConfig . PERFORMANCE_CLASS_HIGH ;
2021-09-20 07:54:41 +02:00
}
2019-07-18 15:01:39 +02:00
}
2019-12-31 14:08:08 +01:00
2019-08-22 01:53:26 +02:00
if ( args . length > = 3 ) {
if ( " nr " . equals ( args [ 2 ] ) ) {
autoRepeat = 2 ;
} else if ( " nrs " . equals ( args [ 2 ] ) ) {
autoRepeat = 3 ;
2020-03-30 14:00:09 +02:00
} else if ( " dice " . equals ( args [ 2 ] ) ) {
2020-04-24 11:21:58 +02:00
diceEmoji = args [ 3 ] ;
2020-03-30 14:00:09 +02:00
autoRepeat = 2 ;
2019-08-22 01:53:26 +02:00
}
}
if ( args . length > = 5 ) {
if ( " c1 " . equals ( args [ 4 ] ) ) {
2021-12-07 14:02:02 +01:00
fitzModifier = 12 ;
2019-08-22 01:53:26 +02:00
} else if ( " c2 " . equals ( args [ 4 ] ) ) {
2021-12-07 14:02:02 +01:00
fitzModifier = 3 ;
2019-08-22 01:53:26 +02:00
} else if ( " c3 " . equals ( args [ 4 ] ) ) {
2021-12-07 14:02:02 +01:00
fitzModifier = 4 ;
2019-08-22 01:53:26 +02:00
} else if ( " c4 " . equals ( args [ 4 ] ) ) {
2021-12-07 14:02:02 +01:00
fitzModifier = 5 ;
2019-08-22 01:53:26 +02:00
} else if ( " c5 " . equals ( args [ 4 ] ) ) {
2021-12-07 14:02:02 +01:00
fitzModifier = 6 ;
2019-08-22 01:53:26 +02:00
}
}
2019-05-14 14:08:05 +02:00
}
2020-03-30 14:00:09 +02:00
RLottieDrawable lottieDrawable ;
2020-04-24 11:21:58 +02:00
if ( diceEmoji ! = null ) {
2020-10-30 11:26:29 +01:00
if ( " \ uD83C \ uDFB0 " . equals ( diceEmoji ) ) {
lottieDrawable = new SlotsDrawable ( diceEmoji , w , h ) ;
} else {
lottieDrawable = new RLottieDrawable ( diceEmoji , w , h ) ;
}
2020-03-30 14:00:09 +02:00
} else {
2021-06-25 02:43:10 +02:00
File f = cacheImage . finalFilePath ;
RandomAccessFile randomAccessFile = null ;
boolean compressed = false ;
try {
randomAccessFile = new RandomAccessFile ( cacheImage . finalFilePath , " r " ) ;
byte [ ] bytes ;
if ( cacheImage . type = = ImageReceiver . TYPE_THUMB ) {
bytes = headerThumb ;
} else {
bytes = header ;
}
randomAccessFile . readFully ( bytes , 0 , 2 ) ;
if ( bytes [ 0 ] = = 0x1f & & bytes [ 1 ] = = ( byte ) 0x8b ) {
compressed = true ;
}
} catch ( Exception e ) {
FileLog . e ( e ) ;
} finally {
if ( randomAccessFile ! = null ) {
try {
randomAccessFile . close ( ) ;
} catch ( Exception e ) {
FileLog . e ( e ) ;
}
}
}
if ( compressed ) {
2021-12-07 14:02:02 +01:00
lottieDrawable = new RLottieDrawable ( cacheImage . finalFilePath , decompressGzip ( cacheImage . finalFilePath ) , w , h , precache , limitFps , null , fitzModifier ) ;
2021-06-25 02:43:10 +02:00
} else {
2021-12-07 14:02:02 +01:00
lottieDrawable = new RLottieDrawable ( cacheImage . finalFilePath , w , h , precache , limitFps , null , fitzModifier ) ;
2021-06-25 02:43:10 +02:00
}
2020-03-30 14:00:09 +02:00
}
2019-08-22 01:53:26 +02:00
lottieDrawable . setAutoRepeat ( autoRepeat ) ;
2019-05-14 14:08:05 +02:00
onPostExecute ( lottieDrawable ) ;
2019-12-31 14:08:08 +01:00
} else if ( cacheImage . imageType = = FileLoader . IMAGE_TYPE_ANIMATION ) {
2019-03-03 21:40:48 +01:00
AnimatedFileDrawable fileDrawable ;
2020-07-26 10:03:38 +02:00
long seekTo ;
if ( cacheImage . imageLocation ! = null ) {
seekTo = cacheImage . imageLocation . videoSeekTo ;
} else {
seekTo = 0 ;
}
2019-05-14 14:08:05 +02:00
if ( AUTOPLAY_FILTER . equals ( cacheImage . filter ) & & ! ( cacheImage . imageLocation . document instanceof TLRPC . TL_documentEncrypted ) ) {
2020-07-26 10:03:38 +02:00
TLRPC . Document document = cacheImage . imageLocation . document instanceof TLRPC . Document ? cacheImage . imageLocation . document : null ;
int size = document ! = null ? cacheImage . size : cacheImage . imageLocation . currentSize ;
fileDrawable = new AnimatedFileDrawable ( cacheImage . finalFilePath , false , size , document , document = = null ? cacheImage . imageLocation : null , cacheImage . parentObject , seekTo , cacheImage . currentAccount , false ) ;
2019-03-03 21:40:48 +01:00
} else {
2020-12-23 08:48:30 +01:00
int w = 0 ;
int h = 0 ;
if ( cacheImage . filter ! = null ) {
String [ ] args = cacheImage . filter . split ( " _ " ) ;
if ( args . length > = 2 ) {
float w_filter = Float . parseFloat ( args [ 0 ] ) ;
float h_filter = Float . parseFloat ( args [ 1 ] ) ;
w = ( int ) ( w_filter * AndroidUtilities . density ) ;
h = ( int ) ( h_filter * AndroidUtilities . density ) ;
}
}
fileDrawable = new AnimatedFileDrawable ( cacheImage . finalFilePath , " d " . equals ( cacheImage . filter ) , 0 , null , null , null , seekTo , cacheImage . currentAccount , false , w , h ) ;
2019-03-03 21:40:48 +01:00
}
2016-01-11 18:19:48 +01:00
Thread . interrupted ( ) ;
onPostExecute ( fileDrawable ) ;
} else {
Long mediaId = null ;
boolean mediaIsVideo = false ;
Bitmap image = null ;
2019-01-23 18:03:33 +01:00
boolean needInvert = false ;
int orientation = 0 ;
2016-01-11 18:19:48 +01:00
File cacheFileFinal = cacheImage . finalFilePath ;
2018-07-30 04:07:02 +02:00
boolean inEncryptedFile = cacheImage . secureDocument ! = null | | cacheImage . encryptionKeyPath ! = null & & cacheFileFinal ! = null & & cacheFileFinal . getAbsolutePath ( ) . endsWith ( " .enc " ) ;
SecureDocumentKey secureDocumentKey ;
byte [ ] secureDocumentHash ;
if ( cacheImage . secureDocument ! = null ) {
secureDocumentKey = cacheImage . secureDocument . secureDocumentKey ;
if ( cacheImage . secureDocument . secureFile ! = null & & cacheImage . secureDocument . secureFile . file_hash ! = null ) {
secureDocumentHash = cacheImage . secureDocument . secureFile . file_hash ;
} else {
secureDocumentHash = cacheImage . secureDocument . fileHash ;
}
} else {
secureDocumentKey = null ;
secureDocumentHash = null ;
}
2016-01-11 18:19:48 +01:00
boolean canDeleteFile = true ;
2019-05-14 14:08:05 +02:00
boolean useNativeWebpLoader = false ;
2016-01-11 18:19:48 +01:00
if ( Build . VERSION . SDK_INT < 19 ) {
RandomAccessFile randomAccessFile = null ;
try {
randomAccessFile = new RandomAccessFile ( cacheFileFinal , " r " ) ;
byte [ ] bytes ;
2019-12-31 14:08:08 +01:00
if ( cacheImage . type = = ImageReceiver . TYPE_THUMB ) {
2016-01-11 18:19:48 +01:00
bytes = headerThumb ;
2015-02-01 19:51:02 +01:00
} else {
2016-01-11 18:19:48 +01:00
bytes = header ;
2015-05-03 13:48:36 +02:00
}
2016-01-11 18:19:48 +01:00
randomAccessFile . readFully ( bytes , 0 , bytes . length ) ;
String str = new String ( bytes ) . toLowerCase ( ) ;
str = str . toLowerCase ( ) ;
if ( str . startsWith ( " riff " ) & & str . endsWith ( " webp " ) ) {
2019-05-14 14:08:05 +02:00
useNativeWebpLoader = true ;
2015-02-01 19:51:02 +01:00
}
2016-01-11 18:19:48 +01:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2016-01-11 18:19:48 +01:00
} finally {
if ( randomAccessFile ! = null ) {
try {
randomAccessFile . close ( ) ;
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-02-01 19:51:02 +01:00
}
}
2014-08-22 16:24:33 +02:00
}
2016-01-11 18:19:48 +01:00
}
2014-08-22 16:24:33 +02:00
2019-05-14 14:08:05 +02:00
String mediaThumbPath = null ;
if ( cacheImage . imageLocation . path ! = null ) {
String location = cacheImage . imageLocation . path ;
if ( location . startsWith ( " thumb:// " ) ) {
int idx = location . indexOf ( " : " , 8 ) ;
if ( idx > = 0 ) {
mediaId = Long . parseLong ( location . substring ( 8 , idx ) ) ;
mediaIsVideo = false ;
mediaThumbPath = location . substring ( idx + 1 ) ;
}
canDeleteFile = false ;
} else if ( location . startsWith ( " vthumb:// " ) ) {
int idx = location . indexOf ( " : " , 9 ) ;
if ( idx > = 0 ) {
mediaId = Long . parseLong ( location . substring ( 9 , idx ) ) ;
mediaIsVideo = true ;
}
canDeleteFile = false ;
} else if ( ! location . startsWith ( " http " ) ) {
canDeleteFile = false ;
}
}
BitmapFactory . Options opts = new BitmapFactory . Options ( ) ;
opts . inSampleSize = 1 ;
if ( Build . VERSION . SDK_INT < 21 ) {
opts . inPurgeable = true ;
}
float w_filter = 0 ;
float h_filter = 0 ;
int blurType = 0 ;
boolean checkInversion = false ;
boolean force8888 = canForce8888 ;
try {
2015-02-01 19:51:02 +01:00
if ( cacheImage . filter ! = null ) {
2019-05-14 14:08:05 +02:00
String [ ] args = cacheImage . filter . split ( " _ " ) ;
if ( args . length > = 2 ) {
w_filter = Float . parseFloat ( args [ 0 ] ) * AndroidUtilities . density ;
h_filter = Float . parseFloat ( args [ 1 ] ) * AndroidUtilities . density ;
}
2016-01-11 18:19:48 +01:00
if ( cacheImage . filter . contains ( " b2 " ) ) {
blurType = 3 ;
} else if ( cacheImage . filter . contains ( " b1 " ) ) {
blurType = 2 ;
} else if ( cacheImage . filter . contains ( " b " ) ) {
blurType = 1 ;
2015-02-01 19:51:02 +01:00
}
2019-01-23 18:03:33 +01:00
if ( cacheImage . filter . contains ( " i " ) ) {
checkInversion = true ;
}
2019-05-14 14:08:05 +02:00
if ( cacheImage . filter . contains ( " f " ) ) {
force8888 = true ;
}
if ( ! useNativeWebpLoader & & w_filter ! = 0 & & h_filter ! = 0 ) {
opts . inJustDecodeBounds = true ;
if ( mediaId ! = null & & mediaThumbPath = = null ) {
if ( mediaIsVideo ) {
MediaStore . Video . Thumbnails . getThumbnail ( ApplicationLoader . applicationContext . getContentResolver ( ) , mediaId , MediaStore . Video . Thumbnails . MINI_KIND , opts ) ;
} else {
MediaStore . Images . Thumbnails . getThumbnail ( ApplicationLoader . applicationContext . getContentResolver ( ) , mediaId , MediaStore . Images . Thumbnails . MINI_KIND , opts ) ;
}
} else {
if ( secureDocumentKey ! = null ) {
RandomAccessFile f = new RandomAccessFile ( cacheFileFinal , " r " ) ;
int len = ( int ) f . length ( ) ;
byte [ ] bytes = bytesLocal . get ( ) ;
byte [ ] data = bytes ! = null & & bytes . length > = len ? bytes : null ;
if ( data = = null ) {
bytes = data = new byte [ len ] ;
bytesLocal . set ( bytes ) ;
}
f . readFully ( data , 0 , len ) ;
f . close ( ) ;
EncryptedFileInputStream . decryptBytesWithKeyFile ( data , 0 , len , secureDocumentKey ) ;
byte [ ] hash = Utilities . computeSHA256 ( data , 0 , len ) ;
boolean error = false ;
if ( secureDocumentHash = = null | | ! Arrays . equals ( hash , secureDocumentHash ) ) {
error = true ;
}
int offset = ( data [ 0 ] & 0xff ) ;
len - = offset ;
if ( ! error ) {
BitmapFactory . decodeByteArray ( data , offset , len , opts ) ;
}
} else {
FileInputStream is ;
if ( inEncryptedFile ) {
is = new EncryptedFileInputStream ( cacheFileFinal , cacheImage . encryptionKeyPath ) ;
} else {
is = new FileInputStream ( cacheFileFinal ) ;
}
BitmapFactory . decodeStream ( is , null , opts ) ;
is . close ( ) ;
}
}
float photoW = opts . outWidth ;
float photoH = opts . outHeight ;
2019-06-04 12:14:50 +02:00
float scaleFactor ;
2019-09-10 12:56:11 +02:00
if ( w_filter > = h_filter & & photoW > photoH ) {
2019-06-04 12:14:50 +02:00
scaleFactor = Math . max ( photoW / w_filter , photoH / h_filter ) ;
} else {
scaleFactor = Math . min ( photoW / w_filter , photoH / h_filter ) ;
}
2019-09-10 12:56:11 +02:00
if ( scaleFactor < 1 . 2f ) {
2019-05-14 14:08:05 +02:00
scaleFactor = 1 ;
}
opts . inJustDecodeBounds = false ;
2019-09-10 12:56:11 +02:00
if ( scaleFactor > 1 . 0f & & ( photoW > w_filter | | photoH > h_filter ) ) {
int sample = 1 ;
do {
sample * = 2 ;
} while ( sample * 2 < scaleFactor ) ;
opts . inSampleSize = sample ;
} else {
opts . inSampleSize = ( int ) scaleFactor ;
}
2019-05-14 14:08:05 +02:00
}
} else if ( mediaThumbPath ! = null ) {
opts . inJustDecodeBounds = true ;
opts . inPreferredConfig = force8888 ? Bitmap . Config . ARGB_8888 : Bitmap . Config . RGB_565 ;
FileInputStream is = new FileInputStream ( cacheFileFinal ) ;
image = BitmapFactory . decodeStream ( is , null , opts ) ;
is . close ( ) ;
int photoW2 = opts . outWidth ;
int photoH2 = opts . outHeight ;
opts . inJustDecodeBounds = false ;
2020-10-30 11:26:29 +01:00
int screenSize = Math . max ( 66 , Math . min ( AndroidUtilities . getRealScreenSize ( ) . x , AndroidUtilities . getRealScreenSize ( ) . y ) ) ;
float scaleFactor = ( Math . min ( photoH2 , photoW2 ) / ( float ) screenSize ) * 6f ;
2019-05-14 14:08:05 +02:00
if ( scaleFactor < 1 ) {
scaleFactor = 1 ;
}
2019-09-10 12:56:11 +02:00
if ( scaleFactor > 1 . 0f ) {
int sample = 1 ;
do {
sample * = 2 ;
2020-10-30 11:26:29 +01:00
} while ( sample * 2 < = scaleFactor ) ;
2019-09-10 12:56:11 +02:00
opts . inSampleSize = sample ;
} else {
opts . inSampleSize = ( int ) scaleFactor ;
}
2016-01-11 18:19:48 +01:00
}
2019-05-14 14:08:05 +02:00
} catch ( Throwable e ) {
2021-12-07 14:02:02 +01:00
boolean sentLog = true ;
if ( e instanceof FileNotFoundException ) {
sentLog = false ;
}
FileLog . e ( e , sentLog ) ;
2019-05-14 14:08:05 +02:00
}
2015-02-01 19:51:02 +01:00
2019-12-31 14:08:08 +01:00
if ( cacheImage . type = = ImageReceiver . TYPE_THUMB ) {
2016-01-11 18:19:48 +01:00
try {
2021-01-28 15:15:51 +01:00
lastCacheOutTime = SystemClock . elapsedRealtime ( ) ;
2016-01-11 18:19:48 +01:00
synchronized ( sync ) {
if ( isCancelled ) {
return ;
2015-05-03 13:48:36 +02:00
}
2015-02-01 19:51:02 +01:00
}
2014-08-22 16:24:33 +02:00
2019-05-14 14:08:05 +02:00
if ( useNativeWebpLoader ) {
2015-02-01 19:51:02 +01:00
RandomAccessFile file = new RandomAccessFile ( cacheFileFinal , " r " ) ;
ByteBuffer buffer = file . getChannel ( ) . map ( FileChannel . MapMode . READ_ONLY , 0 , cacheFileFinal . length ( ) ) ;
2015-10-29 18:10:07 +01:00
BitmapFactory . Options bmOptions = new BitmapFactory . Options ( ) ;
bmOptions . inJustDecodeBounds = true ;
Utilities . loadWebpImage ( null , buffer , buffer . limit ( ) , bmOptions , true ) ;
image = Bitmaps . createBitmap ( bmOptions . outWidth , bmOptions . outHeight , Bitmap . Config . ARGB_8888 ) ;
Utilities . loadWebpImage ( image , buffer , buffer . limit ( ) , null , ! opts . inPurgeable ) ;
2015-02-01 19:51:02 +01:00
file . close ( ) ;
} else {
2018-07-30 04:07:02 +02:00
if ( opts . inPurgeable | | secureDocumentKey ! = null ) {
2015-05-03 13:48:36 +02:00
RandomAccessFile f = new RandomAccessFile ( cacheFileFinal , " r " ) ;
int len = ( int ) f . length ( ) ;
2018-07-30 04:07:02 +02:00
int offset = 0 ;
2019-03-03 21:40:48 +01:00
byte [ ] bytesThumb = bytesThumbLocal . get ( ) ;
2016-01-11 18:19:48 +01:00
byte [ ] data = bytesThumb ! = null & & bytesThumb . length > = len ? bytesThumb : null ;
2015-05-03 13:48:36 +02:00
if ( data = = null ) {
2016-01-11 18:19:48 +01:00
bytesThumb = data = new byte [ len ] ;
2019-03-03 21:40:48 +01:00
bytesThumbLocal . set ( bytesThumb ) ;
2015-05-03 13:48:36 +02:00
}
f . readFully ( data , 0 , len ) ;
2017-07-23 14:56:38 +02:00
f . close ( ) ;
2018-07-30 04:07:02 +02:00
boolean error = false ;
if ( secureDocumentKey ! = null ) {
EncryptedFileInputStream . decryptBytesWithKeyFile ( data , 0 , len , secureDocumentKey ) ;
byte [ ] hash = Utilities . computeSHA256 ( data , 0 , len ) ;
if ( secureDocumentHash = = null | | ! Arrays . equals ( hash , secureDocumentHash ) ) {
error = true ;
}
offset = ( data [ 0 ] & 0xff ) ;
len - = offset ;
} else if ( inEncryptedFile ) {
2017-07-23 14:56:38 +02:00
EncryptedFileInputStream . decryptBytesWithKeyFile ( data , 0 , len , cacheImage . encryptionKeyPath ) ;
}
2018-07-30 04:07:02 +02:00
if ( ! error ) {
image = BitmapFactory . decodeByteArray ( data , offset , len , opts ) ;
}
2015-05-03 13:48:36 +02:00
} else {
2017-07-23 14:56:38 +02:00
FileInputStream is ;
if ( inEncryptedFile ) {
is = new EncryptedFileInputStream ( cacheFileFinal , cacheImage . encryptionKeyPath ) ;
} else {
is = new FileInputStream ( cacheFileFinal ) ;
}
2015-05-03 13:48:36 +02:00
image = BitmapFactory . decodeStream ( is , null , opts ) ;
is . close ( ) ;
}
2015-02-01 19:51:02 +01:00
}
2016-01-11 18:19:48 +01:00
if ( image = = null ) {
if ( cacheFileFinal . length ( ) = = 0 | | cacheImage . filter = = null ) {
cacheFileFinal . delete ( ) ;
}
} else {
2019-05-14 14:08:05 +02:00
if ( cacheImage . filter ! = null ) {
float bitmapW = image . getWidth ( ) ;
float bitmapH = image . getHeight ( ) ;
if ( ! opts . inPurgeable & & w_filter ! = 0 & & bitmapW ! = w_filter & & bitmapW > w_filter + 20 ) {
float scaleFactor = bitmapW / w_filter ;
Bitmap scaledBitmap = Bitmaps . createScaledBitmap ( image , ( int ) w_filter , ( int ) ( bitmapH / scaleFactor ) , true ) ;
if ( image ! = scaledBitmap ) {
image . recycle ( ) ;
image = scaledBitmap ;
}
}
}
2019-01-23 18:03:33 +01:00
if ( checkInversion ) {
needInvert = Utilities . needInvert ( image , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ! = 0 ;
}
2016-01-11 18:19:48 +01:00
if ( blurType = = 1 ) {
if ( image . getConfig ( ) = = Bitmap . Config . ARGB_8888 ) {
Utilities . blurBitmap ( image , 3 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
}
} else if ( blurType = = 2 ) {
if ( image . getConfig ( ) = = Bitmap . Config . ARGB_8888 ) {
Utilities . blurBitmap ( image , 1 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
}
} else if ( blurType = = 3 ) {
if ( image . getConfig ( ) = = Bitmap . Config . ARGB_8888 ) {
Utilities . blurBitmap ( image , 7 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
Utilities . blurBitmap ( image , 7 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
Utilities . blurBitmap ( image , 7 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
}
} else if ( blurType = = 0 & & opts . inPurgeable ) {
Utilities . pinBitmap ( image ) ;
}
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-02-01 19:51:02 +01:00
}
2016-01-11 18:19:48 +01:00
} else {
try {
int delay = 20 ;
if ( mediaId ! = null ) {
delay = 0 ;
}
2021-01-28 15:15:51 +01:00
if ( delay ! = 0 & & lastCacheOutTime ! = 0 & & lastCacheOutTime > SystemClock . elapsedRealtime ( ) - delay & & Build . VERSION . SDK_INT < 21 ) {
2016-01-11 18:19:48 +01:00
Thread . sleep ( delay ) ;
}
2021-01-28 15:15:51 +01:00
lastCacheOutTime = SystemClock . elapsedRealtime ( ) ;
2016-01-11 18:19:48 +01:00
synchronized ( sync ) {
if ( isCancelled ) {
return ;
}
}
2019-05-14 14:08:05 +02:00
if ( force8888 | | cacheImage . filter = = null | | blurType ! = 0 | | cacheImage . imageLocation . path ! = null ) {
2016-01-11 18:19:48 +01:00
opts . inPreferredConfig = Bitmap . Config . ARGB_8888 ;
} else {
opts . inPreferredConfig = Bitmap . Config . RGB_565 ;
}
opts . inDither = false ;
2017-03-31 01:58:05 +02:00
if ( mediaId ! = null & & mediaThumbPath = = null ) {
2016-01-11 18:19:48 +01:00
if ( mediaIsVideo ) {
image = MediaStore . Video . Thumbnails . getThumbnail ( ApplicationLoader . applicationContext . getContentResolver ( ) , mediaId , MediaStore . Video . Thumbnails . MINI_KIND , opts ) ;
} else {
image = MediaStore . Images . Thumbnails . getThumbnail ( ApplicationLoader . applicationContext . getContentResolver ( ) , mediaId , MediaStore . Images . Thumbnails . MINI_KIND , opts ) ;
}
2014-08-22 16:24:33 +02:00
}
2016-01-11 18:19:48 +01:00
if ( image = = null ) {
2019-05-14 14:08:05 +02:00
if ( useNativeWebpLoader ) {
2016-01-11 18:19:48 +01:00
RandomAccessFile file = new RandomAccessFile ( cacheFileFinal , " r " ) ;
ByteBuffer buffer = file . getChannel ( ) . map ( FileChannel . MapMode . READ_ONLY , 0 , cacheFileFinal . length ( ) ) ;
BitmapFactory . Options bmOptions = new BitmapFactory . Options ( ) ;
bmOptions . inJustDecodeBounds = true ;
Utilities . loadWebpImage ( null , buffer , buffer . limit ( ) , bmOptions , true ) ;
image = Bitmaps . createBitmap ( bmOptions . outWidth , bmOptions . outHeight , Bitmap . Config . ARGB_8888 ) ;
Utilities . loadWebpImage ( image , buffer , buffer . limit ( ) , null , ! opts . inPurgeable ) ;
file . close ( ) ;
} else {
2018-07-30 04:07:02 +02:00
if ( opts . inPurgeable | | secureDocumentKey ! = null ) {
2016-01-11 18:19:48 +01:00
RandomAccessFile f = new RandomAccessFile ( cacheFileFinal , " r " ) ;
int len = ( int ) f . length ( ) ;
2018-07-30 04:07:02 +02:00
int offset = 0 ;
2019-03-03 21:40:48 +01:00
byte [ ] bytes = bytesLocal . get ( ) ;
2016-01-11 18:19:48 +01:00
byte [ ] data = bytes ! = null & & bytes . length > = len ? bytes : null ;
if ( data = = null ) {
bytes = data = new byte [ len ] ;
2019-03-03 21:40:48 +01:00
bytesLocal . set ( bytes ) ;
2016-01-11 18:19:48 +01:00
}
f . readFully ( data , 0 , len ) ;
2017-07-23 14:56:38 +02:00
f . close ( ) ;
2018-07-30 04:07:02 +02:00
boolean error = false ;
if ( secureDocumentKey ! = null ) {
EncryptedFileInputStream . decryptBytesWithKeyFile ( data , 0 , len , secureDocumentKey ) ;
byte [ ] hash = Utilities . computeSHA256 ( data , 0 , len ) ;
if ( secureDocumentHash = = null | | ! Arrays . equals ( hash , secureDocumentHash ) ) {
error = true ;
}
offset = ( data [ 0 ] & 0xff ) ;
len - = offset ;
} else if ( inEncryptedFile ) {
2017-07-23 14:56:38 +02:00
EncryptedFileInputStream . decryptBytesWithKeyFile ( data , 0 , len , cacheImage . encryptionKeyPath ) ;
}
2018-07-30 04:07:02 +02:00
if ( ! error ) {
image = BitmapFactory . decodeByteArray ( data , offset , len , opts ) ;
}
2016-01-11 18:19:48 +01:00
} else {
2017-07-23 14:56:38 +02:00
FileInputStream is ;
if ( inEncryptedFile ) {
is = new EncryptedFileInputStream ( cacheFileFinal , cacheImage . encryptionKeyPath ) ;
} else {
is = new FileInputStream ( cacheFileFinal ) ;
}
2019-05-14 14:08:05 +02:00
if ( cacheImage . imageLocation . document instanceof TLRPC . TL_document ) {
2019-01-23 18:03:33 +01:00
try {
ExifInterface exif = new ExifInterface ( is ) ;
int attribute = exif . getAttributeInt ( ExifInterface . TAG_ORIENTATION , 1 ) ;
switch ( attribute ) {
case ExifInterface . ORIENTATION_ROTATE_90 :
orientation = 90 ;
break ;
case ExifInterface . ORIENTATION_ROTATE_180 :
orientation = 180 ;
break ;
case ExifInterface . ORIENTATION_ROTATE_270 :
orientation = 270 ;
break ;
}
} catch ( Throwable ignore ) {
}
is . getChannel ( ) . position ( 0 ) ;
}
2016-01-11 18:19:48 +01:00
image = BitmapFactory . decodeStream ( is , null , opts ) ;
is . close ( ) ;
}
}
}
if ( image = = null ) {
if ( canDeleteFile & & ( cacheFileFinal . length ( ) = = 0 | | cacheImage . filter = = null ) ) {
cacheFileFinal . delete ( ) ;
}
} else {
boolean blured = false ;
if ( cacheImage . filter ! = null ) {
float bitmapW = image . getWidth ( ) ;
float bitmapH = image . getHeight ( ) ;
if ( ! opts . inPurgeable & & w_filter ! = 0 & & bitmapW ! = w_filter & & bitmapW > w_filter + 20 ) {
2019-06-04 12:14:50 +02:00
Bitmap scaledBitmap ;
if ( bitmapW > bitmapH & & w_filter > h_filter ) {
float scaleFactor = bitmapW / w_filter ;
2020-06-04 18:47:15 +02:00
if ( scaleFactor > 1 ) {
scaledBitmap = Bitmaps . createScaledBitmap ( image , ( int ) w_filter , ( int ) ( bitmapH / scaleFactor ) , true ) ;
} else {
scaledBitmap = image ;
}
2019-06-04 12:14:50 +02:00
} else {
float scaleFactor = bitmapH / h_filter ;
2020-06-04 18:47:15 +02:00
if ( scaleFactor > 1 ) {
scaledBitmap = Bitmaps . createScaledBitmap ( image , ( int ) ( bitmapW / scaleFactor ) , ( int ) h_filter , true ) ;
} else {
scaledBitmap = image ;
}
2019-06-04 12:14:50 +02:00
}
2016-01-11 18:19:48 +01:00
if ( image ! = scaledBitmap ) {
image . recycle ( ) ;
image = scaledBitmap ;
}
}
2019-01-23 18:03:33 +01:00
if ( image ! = null ) {
if ( checkInversion ) {
Bitmap b = image ;
int w = image . getWidth ( ) ;
int h = image . getHeight ( ) ;
if ( w * h > 150 * 150 ) {
b = Bitmaps . createScaledBitmap ( image , 100 , 100 , false ) ;
}
needInvert = Utilities . needInvert ( b , opts . inPurgeable ? 0 : 1 , b . getWidth ( ) , b . getHeight ( ) , b . getRowBytes ( ) ) ! = 0 ;
if ( b ! = image ) {
b . recycle ( ) ;
}
}
2021-06-25 02:43:10 +02:00
if ( blurType ! = 0 & & ( bitmapH > 100 | | bitmapW > 100 ) ) {
image = Bitmaps . createScaledBitmap ( image , 80 , 80 , false ) ;
bitmapH = 80 ;
bitmapW = 80 ;
}
2019-05-14 14:08:05 +02:00
if ( blurType ! = 0 & & bitmapH < 100 & & bitmapW < 100 ) {
2019-01-23 18:03:33 +01:00
if ( image . getConfig ( ) = = Bitmap . Config . ARGB_8888 ) {
Utilities . blurBitmap ( image , 3 , opts . inPurgeable ? 0 : 1 , image . getWidth ( ) , image . getHeight ( ) , image . getRowBytes ( ) ) ;
}
blured = true ;
2016-01-11 18:19:48 +01:00
}
}
}
if ( ! blured & & opts . inPurgeable ) {
Utilities . pinBitmap ( image ) ;
}
}
2017-07-23 14:56:38 +02:00
} catch ( Throwable ignore ) {
2014-08-22 16:24:33 +02:00
}
}
2016-01-11 18:19:48 +01:00
Thread . interrupted ( ) ;
2019-01-23 18:03:33 +01:00
if ( needInvert | | orientation ! = 0 ) {
onPostExecute ( image ! = null ? new ExtendedBitmapDrawable ( image , needInvert , orientation ) : null ) ;
} else {
onPostExecute ( image ! = null ? new BitmapDrawable ( image ) : null ) ;
}
2014-08-22 16:24:33 +02:00
}
}
2019-05-14 14:08:05 +02:00
private void onPostExecute ( final Drawable drawable ) {
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
2019-05-14 14:08:05 +02:00
Drawable toSet = null ;
String decrementKey = null ;
2019-07-18 15:01:39 +02:00
if ( drawable instanceof RLottieDrawable ) {
RLottieDrawable lottieDrawable = ( RLottieDrawable ) drawable ;
2019-06-04 12:14:50 +02:00
toSet = lottieMemCache . get ( cacheImage . key ) ;
if ( toSet = = null ) {
lottieMemCache . put ( cacheImage . key , lottieDrawable ) ;
toSet = lottieDrawable ;
2019-07-18 15:01:39 +02:00
} else {
lottieDrawable . recycle ( ) ;
}
if ( toSet ! = null ) {
incrementUseCount ( cacheImage . key ) ;
decrementKey = cacheImage . key ;
2019-06-04 12:14:50 +02:00
}
} else if ( drawable instanceof AnimatedFileDrawable ) {
2019-05-14 14:08:05 +02:00
toSet = drawable ;
} else if ( drawable instanceof BitmapDrawable ) {
BitmapDrawable bitmapDrawable = ( BitmapDrawable ) drawable ;
2021-09-20 07:54:41 +02:00
toSet = getFromMemCache ( cacheImage . key ) ;
boolean incrementUseCount = true ;
2018-08-27 10:33:11 +02:00
if ( toSet = = null ) {
2021-09-20 07:54:41 +02:00
if ( cacheImage . key . endsWith ( " _f " ) ) {
wallpaperMemCache . put ( cacheImage . key , bitmapDrawable ) ;
incrementUseCount = false ;
2021-11-05 11:06:49 +01:00
} else if ( ! cacheImage . key . endsWith ( " _isc " ) & & bitmapDrawable . getBitmap ( ) . getWidth ( ) < = 80 * AndroidUtilities . density & & bitmapDrawable . getBitmap ( ) . getHeight ( ) < = 80 * AndroidUtilities . density ) {
smallImagesMemCache . put ( cacheImage . key , bitmapDrawable ) ;
2021-09-20 07:54:41 +02:00
} else {
memCache . put ( cacheImage . key , bitmapDrawable ) ;
}
2016-01-11 18:19:48 +01:00
toSet = bitmapDrawable ;
2018-08-27 10:33:11 +02:00
} else {
Bitmap image = bitmapDrawable . getBitmap ( ) ;
image . recycle ( ) ;
2014-09-14 01:40:36 +02:00
}
2021-09-20 07:54:41 +02:00
if ( toSet ! = null & & incrementUseCount ) {
2019-05-14 14:08:05 +02:00
incrementUseCount ( cacheImage . key ) ;
decrementKey = cacheImage . key ;
}
2014-09-14 01:40:36 +02:00
}
2019-05-14 14:08:05 +02:00
final Drawable toSetFinal = toSet ;
final String decrementKetFinal = decrementKey ;
imageLoadQueue . postRunnable ( ( ) - > cacheImage . setImageAndClear ( toSetFinal , decrementKetFinal ) ) ;
2014-09-14 01:40:36 +02:00
} ) ;
2014-08-22 16:24:33 +02:00
}
2014-09-14 01:40:36 +02:00
public void cancel ( ) {
synchronized ( sync ) {
try {
isCancelled = true ;
if ( runningThread ! = null ) {
runningThread . interrupt ( ) ;
}
} catch ( Exception e ) {
//don't promt
}
}
2014-08-22 16:24:33 +02:00
}
}
2021-09-20 07:54:41 +02:00
private BitmapDrawable getFromMemCache ( String key ) {
BitmapDrawable drawable = memCache . get ( key ) ;
if ( drawable = = null ) {
2021-11-05 11:06:49 +01:00
drawable = smallImagesMemCache . get ( key ) ;
}
if ( drawable = = null ) {
drawable = wallpaperMemCache . get ( key ) ;
2021-09-20 07:54:41 +02:00
}
return drawable ;
}
2021-04-09 15:17:32 +02:00
public static Bitmap getStrippedPhotoBitmap ( byte [ ] photoBytes , String filter ) {
2019-12-31 14:08:08 +01:00
int len = photoBytes . length - 3 + Bitmaps . header . length + Bitmaps . footer . length ;
byte [ ] bytes = bytesLocal . get ( ) ;
byte [ ] data = bytes ! = null & & bytes . length > = len ? bytes : null ;
if ( data = = null ) {
bytes = data = new byte [ len ] ;
bytesLocal . set ( bytes ) ;
}
System . arraycopy ( Bitmaps . header , 0 , data , 0 , Bitmaps . header . length ) ;
System . arraycopy ( photoBytes , 3 , data , Bitmaps . header . length , photoBytes . length - 3 ) ;
System . arraycopy ( Bitmaps . footer , 0 , data , Bitmaps . header . length + photoBytes . length - 3 , Bitmaps . footer . length ) ;
data [ 164 ] = photoBytes [ 1 ] ;
data [ 166 ] = photoBytes [ 2 ] ;
Bitmap bitmap = BitmapFactory . decodeByteArray ( data , 0 , len ) ;
if ( bitmap ! = null & & ! TextUtils . isEmpty ( filter ) & & filter . contains ( " b " ) ) {
Utilities . blurBitmap ( bitmap , 3 , 1 , bitmap . getWidth ( ) , bitmap . getHeight ( ) , bitmap . getRowBytes ( ) ) ;
}
return bitmap ;
}
2014-08-22 16:24:33 +02:00
private class CacheImage {
2018-07-30 04:07:02 +02:00
2015-02-01 19:51:02 +01:00
protected String key ;
protected String url ;
protected String filter ;
2015-05-21 23:27:27 +02:00
protected String ext ;
2018-07-30 04:07:02 +02:00
protected SecureDocument secureDocument ;
2019-05-14 14:08:05 +02:00
protected ImageLocation imageLocation ;
2019-03-03 21:40:48 +01:00
protected Object parentObject ;
protected int size ;
protected int imageType ;
2019-12-31 14:08:08 +01:00
protected int type ;
2015-02-01 19:51:02 +01:00
2018-07-30 04:07:02 +02:00
protected int currentAccount ;
2015-02-01 19:51:02 +01:00
protected File finalFilePath ;
protected File tempFilePath ;
2017-07-23 14:56:38 +02:00
protected File encryptionKeyPath ;
2019-01-23 18:03:33 +01:00
protected ArtworkLoadTask artworkTask ;
2015-01-02 23:15:07 +01:00
protected HttpImageTask httpTask ;
2015-02-01 19:51:02 +01:00
protected CacheOutTask cacheTask ;
2014-08-22 16:24:33 +02:00
2015-02-01 19:51:02 +01:00
protected ArrayList < ImageReceiver > imageReceiverArray = new ArrayList < > ( ) ;
2019-07-18 15:01:39 +02:00
protected ArrayList < Integer > imageReceiverGuidsArray = new ArrayList < > ( ) ;
2016-10-11 13:57:01 +02:00
protected ArrayList < String > keys = new ArrayList < > ( ) ;
protected ArrayList < String > filters = new ArrayList < > ( ) ;
2019-12-31 14:08:08 +01:00
protected ArrayList < Integer > types = new ArrayList < > ( ) ;
2015-02-01 19:51:02 +01:00
2019-07-18 15:01:39 +02:00
public void addImageReceiver ( ImageReceiver imageReceiver , String key , String filter , int type , int guid ) {
2019-09-10 12:56:11 +02:00
int index = imageReceiverArray . indexOf ( imageReceiver ) ;
if ( index > = 0 ) {
imageReceiverGuidsArray . set ( index , guid ) ;
2016-10-11 13:57:01 +02:00
return ;
2014-08-22 16:24:33 +02:00
}
2016-10-11 13:57:01 +02:00
imageReceiverArray . add ( imageReceiver ) ;
2019-07-18 15:01:39 +02:00
imageReceiverGuidsArray . add ( guid ) ;
2016-10-11 13:57:01 +02:00
keys . add ( key ) ;
filters . add ( filter ) ;
2019-12-31 14:08:08 +01:00
types . add ( type ) ;
2019-03-03 21:40:48 +01:00
imageLoadingByTag . put ( imageReceiver . getTag ( type ) , this ) ;
2014-08-22 16:24:33 +02:00
}
2019-07-18 15:01:39 +02:00
public void replaceImageReceiver ( ImageReceiver imageReceiver , String key , String filter , int type , int guid ) {
2017-12-08 18:35:59 +01:00
int index = imageReceiverArray . indexOf ( imageReceiver ) ;
if ( index = = - 1 ) {
return ;
}
2019-12-31 14:08:08 +01:00
if ( types . get ( index ) ! = type ) {
2017-12-08 18:35:59 +01:00
index = imageReceiverArray . subList ( index + 1 , imageReceiverArray . size ( ) ) . indexOf ( imageReceiver ) ;
if ( index = = - 1 ) {
return ;
}
}
2019-07-18 15:01:39 +02:00
imageReceiverGuidsArray . set ( index , guid ) ;
2017-12-08 18:35:59 +01:00
keys . set ( index , key ) ;
filters . set ( index , filter ) ;
}
2019-12-31 14:08:08 +01:00
public void setImageReceiverGuid ( ImageReceiver imageReceiver , int guid ) {
int index = imageReceiverArray . indexOf ( imageReceiver ) ;
if ( index = = - 1 ) {
return ;
}
imageReceiverGuidsArray . set ( index , guid ) ;
}
2015-02-01 19:51:02 +01:00
public void removeImageReceiver ( ImageReceiver imageReceiver ) {
2019-12-31 14:08:08 +01:00
int currentMediaType = type ;
2015-02-01 19:51:02 +01:00
for ( int a = 0 ; a < imageReceiverArray . size ( ) ; a + + ) {
ImageReceiver obj = imageReceiverArray . get ( a ) ;
if ( obj = = null | | obj = = imageReceiver ) {
imageReceiverArray . remove ( a ) ;
2019-07-18 15:01:39 +02:00
imageReceiverGuidsArray . remove ( a ) ;
2016-10-11 13:57:01 +02:00
keys . remove ( a ) ;
filters . remove ( a ) ;
2019-12-31 14:08:08 +01:00
currentMediaType = types . remove ( a ) ;
2014-08-22 16:24:33 +02:00
if ( obj ! = null ) {
2019-12-31 14:08:08 +01:00
imageLoadingByTag . remove ( obj . getTag ( currentMediaType ) ) ;
2014-08-22 16:24:33 +02:00
}
a - - ;
}
}
2019-09-10 12:56:11 +02:00
if ( imageReceiverArray . isEmpty ( ) ) {
2019-05-14 14:08:05 +02:00
if ( imageLocation ! = null ) {
2017-12-08 18:35:59 +01:00
if ( ! forceLoadingImages . containsKey ( key ) ) {
2019-05-14 14:08:05 +02:00
if ( imageLocation . location ! = null ) {
FileLoader . getInstance ( currentAccount ) . cancelLoadFile ( imageLocation . location , ext ) ;
} else if ( imageLocation . document ! = null ) {
FileLoader . getInstance ( currentAccount ) . cancelLoadFile ( imageLocation . document ) ;
} else if ( imageLocation . secureDocument ! = null ) {
FileLoader . getInstance ( currentAccount ) . cancelLoadFile ( imageLocation . secureDocument ) ;
} else if ( imageLocation . webFile ! = null ) {
FileLoader . getInstance ( currentAccount ) . cancelLoadFile ( imageLocation . webFile ) ;
2017-12-08 18:35:59 +01:00
}
2015-02-01 19:51:02 +01:00
}
}
if ( cacheTask ! = null ) {
2019-12-31 14:08:08 +01:00
if ( currentMediaType = = ImageReceiver . TYPE_THUMB ) {
2015-02-01 19:51:02 +01:00
cacheThumbOutQueue . cancelRunnable ( cacheTask ) ;
} else {
cacheOutQueue . cancelRunnable ( cacheTask ) ;
}
cacheTask . cancel ( ) ;
cacheTask = null ;
}
if ( httpTask ! = null ) {
httpTasks . remove ( httpTask ) ;
httpTask . cancel ( true ) ;
httpTask = null ;
}
2019-01-23 18:03:33 +01:00
if ( artworkTask ! = null ) {
artworkTasks . remove ( artworkTask ) ;
artworkTask . cancel ( true ) ;
artworkTask = null ;
}
2015-02-01 19:51:02 +01:00
if ( url ! = null ) {
imageLoadingByUrl . remove ( url ) ;
}
if ( key ! = null ) {
imageLoadingByKeys . remove ( key ) ;
2015-01-02 23:15:07 +01:00
}
2014-08-22 16:24:33 +02:00
}
}
2019-05-14 14:08:05 +02:00
public void setImageAndClear ( final Drawable image , String decrementKey ) {
2015-02-01 19:51:02 +01:00
if ( image ! = null ) {
final ArrayList < ImageReceiver > finalImageReceiverArray = new ArrayList < > ( imageReceiverArray ) ;
2019-07-18 15:01:39 +02:00
final ArrayList < Integer > finalImageReceiverGuidsArray = new ArrayList < > ( imageReceiverGuidsArray ) ;
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
if ( image instanceof AnimatedFileDrawable ) {
boolean imageSet = false ;
AnimatedFileDrawable fileDrawable = ( AnimatedFileDrawable ) image ;
for ( int a = 0 ; a < finalImageReceiverArray . size ( ) ; a + + ) {
ImageReceiver imgView = finalImageReceiverArray . get ( a ) ;
2019-03-03 21:40:48 +01:00
AnimatedFileDrawable toSet = ( a = = 0 ? fileDrawable : fileDrawable . makeCopy ( ) ) ;
2019-12-31 14:08:08 +01:00
if ( imgView . setImageBitmapByKey ( toSet , key , type , false , finalImageReceiverGuidsArray . get ( a ) ) ) {
2019-03-03 21:40:48 +01:00
if ( toSet = = fileDrawable ) {
imageSet = true ;
}
} else {
if ( toSet ! = fileDrawable ) {
toSet . recycle ( ) ;
}
2016-01-11 18:19:48 +01:00
}
2015-02-01 19:51:02 +01:00
}
2018-08-27 10:33:11 +02:00
if ( ! imageSet ) {
2019-03-03 21:40:48 +01:00
fileDrawable . recycle ( ) ;
2018-08-27 10:33:11 +02:00
}
} else {
for ( int a = 0 ; a < finalImageReceiverArray . size ( ) ; a + + ) {
ImageReceiver imgView = finalImageReceiverArray . get ( a ) ;
2019-12-31 14:08:08 +01:00
imgView . setImageBitmapByKey ( image , key , types . get ( a ) , false , finalImageReceiverGuidsArray . get ( a ) ) ;
2018-08-27 10:33:11 +02:00
}
2015-02-01 19:51:02 +01:00
}
2019-05-14 14:08:05 +02:00
if ( decrementKey ! = null ) {
decrementUseCount ( decrementKey ) ;
}
2015-02-01 19:51:02 +01:00
} ) ;
}
2016-01-11 18:19:48 +01:00
for ( int a = 0 ; a < imageReceiverArray . size ( ) ; a + + ) {
ImageReceiver imageReceiver = imageReceiverArray . get ( a ) ;
2019-12-31 14:08:08 +01:00
imageLoadingByTag . remove ( imageReceiver . getTag ( type ) ) ;
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
imageReceiverArray . clear ( ) ;
2019-07-18 15:01:39 +02:00
imageReceiverGuidsArray . clear ( ) ;
2014-08-22 16:24:33 +02:00
if ( url ! = null ) {
imageLoadingByUrl . remove ( url ) ;
}
if ( key ! = null ) {
imageLoadingByKeys . remove ( key ) ;
}
}
}
private static volatile ImageLoader Instance = null ;
2015-05-03 13:48:36 +02:00
2014-08-22 16:24:33 +02:00
public static ImageLoader getInstance ( ) {
ImageLoader localInstance = Instance ;
if ( localInstance = = null ) {
synchronized ( ImageLoader . class ) {
localInstance = Instance ;
if ( localInstance = = null ) {
Instance = localInstance = new ImageLoader ( ) ;
}
}
}
return localInstance ;
}
public ImageLoader ( ) {
2015-10-29 18:10:07 +01:00
thumbGeneratingQueue . setPriority ( Thread . MIN_PRIORITY ) ;
2019-03-03 21:40:48 +01:00
int memoryClass = ( ( ActivityManager ) ApplicationLoader . applicationContext . getSystemService ( Context . ACTIVITY_SERVICE ) ) . getMemoryClass ( ) ;
int maxSize ;
2019-05-14 14:08:05 +02:00
if ( canForce8888 = memoryClass > = 192 ) {
2019-03-03 21:40:48 +01:00
maxSize = 30 ;
} else {
maxSize = 15 ;
}
int cacheSize = Math . min ( maxSize , memoryClass / 7 ) * 1024 * 1024 ;
2014-08-22 16:24:33 +02:00
2021-11-05 11:06:49 +01:00
int commonCacheSize = ( int ) ( cacheSize * 0 . 8f ) ;
int smallImagesCacheSize = ( int ) ( cacheSize * 0 . 2f ) ;
memCache = new LruCache < BitmapDrawable > ( commonCacheSize ) {
@Override
protected int sizeOf ( String key , BitmapDrawable value ) {
return value . getBitmap ( ) . getByteCount ( ) ;
}
@Override
protected void entryRemoved ( boolean evicted , String key , final BitmapDrawable oldValue , BitmapDrawable newValue ) {
if ( ignoreRemoval ! = null & & ignoreRemoval . equals ( key ) ) {
return ;
}
final Integer count = bitmapUseCounts . get ( key ) ;
if ( count = = null | | count = = 0 ) {
Bitmap b = oldValue . getBitmap ( ) ;
if ( ! b . isRecycled ( ) ) {
b . recycle ( ) ;
}
}
}
} ;
smallImagesMemCache = new LruCache < BitmapDrawable > ( smallImagesCacheSize ) {
2014-08-22 16:24:33 +02:00
@Override
2015-10-29 18:10:07 +01:00
protected int sizeOf ( String key , BitmapDrawable value ) {
2016-06-24 12:27:15 +02:00
return value . getBitmap ( ) . getByteCount ( ) ;
2014-08-22 16:24:33 +02:00
}
2015-05-03 13:48:36 +02:00
2014-08-22 16:24:33 +02:00
@Override
2015-10-29 18:10:07 +01:00
protected void entryRemoved ( boolean evicted , String key , final BitmapDrawable oldValue , BitmapDrawable newValue ) {
2019-01-23 18:03:33 +01:00
if ( ignoreRemoval ! = null & & ignoreRemoval . equals ( key ) ) {
2014-08-22 16:24:33 +02:00
return ;
}
2015-02-01 19:51:02 +01:00
final Integer count = bitmapUseCounts . get ( key ) ;
2014-08-22 16:24:33 +02:00
if ( count = = null | | count = = 0 ) {
2015-10-29 18:10:07 +01:00
Bitmap b = oldValue . getBitmap ( ) ;
2014-08-22 16:24:33 +02:00
if ( ! b . isRecycled ( ) ) {
b . recycle ( ) ;
}
}
}
} ;
2021-09-20 07:54:41 +02:00
wallpaperMemCache = new LruCache < BitmapDrawable > ( cacheSize / 4 ) {
@Override
protected int sizeOf ( String key , BitmapDrawable value ) {
return value . getBitmap ( ) . getByteCount ( ) ;
}
} ;
2014-08-22 16:24:33 +02:00
2019-07-18 15:01:39 +02:00
lottieMemCache = new LruCache < RLottieDrawable > ( 512 * 512 * 2 * 4 * 5 ) {
@Override
protected int sizeOf ( String key , RLottieDrawable value ) {
return value . getIntrinsicWidth ( ) * value . getIntrinsicHeight ( ) * 4 * 2 ;
}
2019-06-04 12:14:50 +02:00
@Override
2019-07-18 15:01:39 +02:00
protected void entryRemoved ( boolean evicted , String key , final RLottieDrawable oldValue , RLottieDrawable newValue ) {
final Integer count = bitmapUseCounts . get ( key ) ;
if ( count = = null | | count = = 0 ) {
oldValue . recycle ( ) ;
}
2019-06-04 12:14:50 +02:00
}
} ;
2018-07-30 04:07:02 +02:00
SparseArray < File > mediaDirs = new SparseArray < > ( ) ;
File cachePath = AndroidUtilities . getCacheDir ( ) ;
if ( ! cachePath . isDirectory ( ) ) {
try {
cachePath . mkdirs ( ) ;
} catch ( Exception e ) {
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
2018-07-30 04:07:02 +02:00
}
2020-03-30 14:00:09 +02:00
AndroidUtilities . createEmptyFile ( new File ( cachePath , " .nomedia " ) ) ;
2018-07-30 04:07:02 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_CACHE , cachePath ) ;
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
for ( int a = 0 ; a < UserConfig . MAX_ACCOUNT_COUNT ; a + + ) {
final int currentAccount = a ;
FileLoader . getInstance ( a ) . setDelegate ( new FileLoader . FileLoaderDelegate ( ) {
@Override
2021-01-28 15:15:51 +01:00
public void fileUploadProgressChanged ( FileUploadOperation operation , final String location , long uploadedSize , long totalSize , final boolean isEncrypted ) {
2020-01-23 07:15:40 +01:00
fileProgresses . put ( location , new long [ ] { uploadedSize , totalSize } ) ;
2021-01-28 15:15:51 +01:00
long currentTime = SystemClock . elapsedRealtime ( ) ;
if ( operation . lastProgressUpdateTime = = 0 | | operation . lastProgressUpdateTime < currentTime - 100 | | uploadedSize = = totalSize ) {
operation . lastProgressUpdateTime = currentTime ;
2014-08-22 16:24:33 +02:00
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileUploadProgressChanged , location , uploadedSize , totalSize , isEncrypted ) ) ;
2014-08-22 16:24:33 +02:00
}
2018-07-30 04:07:02 +02:00
}
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
@Override
public void fileDidUploaded ( final String location , final TLRPC . InputFile inputFile , final TLRPC . InputEncryptedFile inputEncryptedFile , final byte [ ] key , final byte [ ] iv , final long totalFileSize ) {
2018-08-27 10:33:11 +02:00
Utilities . stageQueue . postRunnable ( ( ) - > {
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileUploaded , location , inputFile , inputEncryptedFile , key , iv , totalFileSize ) ) ;
2018-08-27 10:33:11 +02:00
fileProgresses . remove ( location ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
@Override
public void fileDidFailedUpload ( final String location , final boolean isEncrypted ) {
2018-08-27 10:33:11 +02:00
Utilities . stageQueue . postRunnable ( ( ) - > {
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileUploadFailed , location , isEncrypted ) ) ;
2018-08-27 10:33:11 +02:00
fileProgresses . remove ( location ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
2014-08-22 16:24:33 +02:00
2018-07-30 04:07:02 +02:00
@Override
public void fileDidLoaded ( final String location , final File finalFile , final int type ) {
fileProgresses . remove ( location ) ;
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
if ( SharedConfig . saveToGallery & & telegramPath ! = null & & finalFile ! = null & & ( location . endsWith ( " .mp4 " ) | | location . endsWith ( " .jpg " ) ) ) {
if ( finalFile . toString ( ) . startsWith ( telegramPath . toString ( ) ) ) {
AndroidUtilities . addMediaToGallery ( finalFile . toString ( ) ) ;
2018-07-30 04:07:02 +02:00
}
2014-08-22 16:24:33 +02:00
}
2021-06-25 02:43:10 +02:00
NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileLoaded , location , finalFile ) ;
2018-08-27 10:33:11 +02:00
ImageLoader . this . fileDidLoaded ( location , finalFile , type ) ;
2014-08-22 16:24:33 +02:00
} ) ;
}
2018-07-30 04:07:02 +02:00
@Override
public void fileDidFailedLoad ( final String location , final int canceled ) {
fileProgresses . remove ( location ) ;
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
ImageLoader . this . fileDidFailedLoad ( location , canceled ) ;
2021-06-25 02:43:10 +02:00
NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileLoadFailed , location , canceled ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
@Override
2021-01-28 15:15:51 +01:00
public void fileLoadProgressChanged ( FileLoadOperation operation , final String location , long uploadedSize , long totalSize ) {
2020-01-23 07:15:40 +01:00
fileProgresses . put ( location , new long [ ] { uploadedSize , totalSize } ) ;
2021-01-28 15:15:51 +01:00
long currentTime = SystemClock . elapsedRealtime ( ) ;
if ( operation . lastProgressUpdateTime = = 0 | | operation . lastProgressUpdateTime < currentTime - 500 | | uploadedSize = = 0 ) {
operation . lastProgressUpdateTime = currentTime ;
2021-06-25 02:43:10 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > NotificationCenter . getInstance ( currentAccount ) . postNotificationName ( NotificationCenter . fileLoadProgressChanged , location , uploadedSize , totalSize ) ) ;
2018-07-30 04:07:02 +02:00
}
}
} ) ;
}
FileLoader . setMediaDirs ( mediaDirs ) ;
2014-08-22 16:24:33 +02:00
2014-10-01 21:55:24 +02:00
BroadcastReceiver receiver = new BroadcastReceiver ( ) {
@Override
public void onReceive ( Context arg0 , Intent intent ) {
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " file system changed " ) ;
}
2018-08-27 10:33:11 +02:00
Runnable r = ( ) - > checkMediaPaths ( ) ;
2014-10-01 21:55:24 +02:00
if ( Intent . ACTION_MEDIA_UNMOUNTED . equals ( intent . getAction ( ) ) ) {
2014-11-06 22:34:47 +01:00
AndroidUtilities . runOnUIThread ( r , 1000 ) ;
2014-10-01 21:55:24 +02:00
} else {
r . run ( ) ;
}
}
} ;
IntentFilter filter = new IntentFilter ( ) ;
filter . addAction ( Intent . ACTION_MEDIA_BAD_REMOVAL ) ;
filter . addAction ( Intent . ACTION_MEDIA_CHECKING ) ;
filter . addAction ( Intent . ACTION_MEDIA_EJECT ) ;
filter . addAction ( Intent . ACTION_MEDIA_MOUNTED ) ;
filter . addAction ( Intent . ACTION_MEDIA_NOFS ) ;
filter . addAction ( Intent . ACTION_MEDIA_REMOVED ) ;
filter . addAction ( Intent . ACTION_MEDIA_SHARED ) ;
filter . addAction ( Intent . ACTION_MEDIA_UNMOUNTABLE ) ;
filter . addAction ( Intent . ACTION_MEDIA_UNMOUNTED ) ;
filter . addDataScheme ( " file " ) ;
2015-11-26 22:04:02 +01:00
try {
2018-07-30 04:07:02 +02:00
ApplicationLoader . applicationContext . registerReceiver ( receiver , filter ) ;
} catch ( Throwable ignore ) {
2015-11-26 22:04:02 +01:00
}
2016-03-06 02:49:31 +01:00
checkMediaPaths ( ) ;
}
public void checkMediaPaths ( ) {
2018-08-27 10:33:11 +02:00
cacheOutQueue . postRunnable ( ( ) - > {
final SparseArray < File > paths = createMediaPaths ( ) ;
AndroidUtilities . runOnUIThread ( ( ) - > FileLoader . setMediaDirs ( paths ) ) ;
2015-11-26 22:04:02 +01:00
} ) ;
2014-09-25 05:54:35 +02:00
}
2018-07-30 04:07:02 +02:00
public void addTestWebFile ( String url , WebFile webFile ) {
if ( url = = null | | webFile = = null ) {
return ;
}
testWebFile . put ( url , webFile ) ;
}
public void removeTestWebFile ( String url ) {
if ( url = = null ) {
return ;
}
testWebFile . remove ( url ) ;
}
2021-06-25 02:43:10 +02:00
@TargetApi ( 26 )
private static void moveDirectory ( File source , File target ) {
2021-11-09 02:49:31 +01:00
if ( ! source . exists ( ) | | ( ! target . exists ( ) & & ! target . mkdir ( ) ) ) {
2021-06-25 02:43:10 +02:00
return ;
}
try ( Stream < Path > files = Files . list ( source . toPath ( ) ) ) {
files . forEach ( path - > {
File dest = new File ( target , path . getFileName ( ) . toString ( ) ) ;
if ( Files . isDirectory ( path ) ) {
moveDirectory ( path . toFile ( ) , dest ) ;
} else {
try {
Files . move ( path , dest . toPath ( ) ) ;
} catch ( Exception e ) {
FileLog . e ( e ) ;
}
}
} ) ;
} catch ( Exception e ) {
FileLog . e ( e ) ;
}
}
2018-07-30 04:07:02 +02:00
public SparseArray < File > createMediaPaths ( ) {
SparseArray < File > mediaDirs = new SparseArray < > ( ) ;
2014-09-25 16:57:17 +02:00
File cachePath = AndroidUtilities . getCacheDir ( ) ;
2014-09-28 15:37:26 +02:00
if ( ! cachePath . isDirectory ( ) ) {
try {
cachePath . mkdirs ( ) ;
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-09-28 15:37:26 +02:00
}
2014-09-25 16:57:17 +02:00
}
2020-03-30 14:00:09 +02:00
AndroidUtilities . createEmptyFile ( new File ( cachePath , " .nomedia " ) ) ;
2015-02-26 02:32:51 +01:00
2014-09-25 16:57:17 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_CACHE , cachePath ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " cache path = " + cachePath ) ;
}
2014-09-28 15:37:26 +02:00
2014-09-25 05:54:35 +02:00
try {
if ( Environment . MEDIA_MOUNTED . equals ( Environment . getExternalStorageState ( ) ) ) {
2020-12-23 08:48:30 +01:00
File path = Environment . getExternalStorageDirectory ( ) ;
if ( Build . VERSION . SDK_INT > = 19 & & ! TextUtils . isEmpty ( SharedConfig . storageCacheDir ) ) {
ArrayList < File > dirs = AndroidUtilities . getRootDirs ( ) ;
2021-09-20 07:54:41 +02:00
if ( dirs ! = null ) {
for ( int a = 0 , N = dirs . size ( ) ; a < N ; a + + ) {
File dir = dirs . get ( a ) ;
if ( dir . getAbsolutePath ( ) . startsWith ( SharedConfig . storageCacheDir ) ) {
path = dir ;
break ;
}
2020-12-23 08:48:30 +01:00
}
}
}
2021-06-25 02:43:10 +02:00
2021-11-09 02:49:31 +01:00
if ( Build . VERSION . SDK_INT > = 30 ) {
File newPath = ApplicationLoader . applicationContext . getExternalFilesDir ( null ) ;
telegramPath = new File ( newPath , " Telegram " ) ;
// File oldPath = new File(path, "Telegram");
// long moveStart = System.currentTimeMillis();
// moveDirectory(oldPath, telegramPath);
// long dt = System.currentTimeMillis() - moveStart;
// FileLog.d("move time = " + dt);
} else {
telegramPath = new File ( path , " Telegram " ) ;
2021-06-25 02:43:10 +02:00
}
2021-11-09 02:49:31 +01:00
telegramPath . mkdirs ( ) ;
2020-12-23 08:48:30 +01:00
if ( Build . VERSION . SDK_INT > = 19 & & ! telegramPath . isDirectory ( ) ) {
ArrayList < File > dirs = AndroidUtilities . getDataDirs ( ) ;
2021-09-20 07:54:41 +02:00
for ( int a = 0 , N = dirs . size ( ) ; a < N ; a + + ) {
File dir = dirs . get ( a ) ;
if ( dir . getAbsolutePath ( ) . startsWith ( SharedConfig . storageCacheDir ) ) {
path = dir ;
telegramPath = new File ( path , " Telegram " ) ;
telegramPath . mkdirs ( ) ;
break ;
2020-12-23 08:48:30 +01:00
}
}
}
2014-10-07 22:14:27 +02:00
2015-08-13 11:23:31 +02:00
if ( telegramPath . isDirectory ( ) ) {
try {
File imagePath = new File ( telegramPath , " Telegram Images " ) ;
imagePath . mkdir ( ) ;
2015-12-09 19:27:52 +01:00
if ( imagePath . isDirectory ( ) & & canMoveFiles ( cachePath , imagePath , FileLoader . MEDIA_DIR_IMAGE ) ) {
2015-08-13 11:23:31 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_IMAGE , imagePath ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " image path = " + imagePath ) ;
}
2014-09-28 15:37:26 +02:00
}
2015-08-13 11:23:31 +02:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-09-28 15:37:26 +02:00
}
2014-09-25 05:54:35 +02:00
2015-08-13 11:23:31 +02:00
try {
File videoPath = new File ( telegramPath , " Telegram Video " ) ;
videoPath . mkdir ( ) ;
2015-12-09 19:27:52 +01:00
if ( videoPath . isDirectory ( ) & & canMoveFiles ( cachePath , videoPath , FileLoader . MEDIA_DIR_VIDEO ) ) {
2015-08-13 11:23:31 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_VIDEO , videoPath ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " video path = " + videoPath ) ;
}
2014-09-28 15:37:26 +02:00
}
2015-08-13 11:23:31 +02:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-08-13 11:23:31 +02:00
}
2014-09-25 05:54:35 +02:00
2015-08-13 11:23:31 +02:00
try {
File audioPath = new File ( telegramPath , " Telegram Audio " ) ;
audioPath . mkdir ( ) ;
2015-12-09 19:27:52 +01:00
if ( audioPath . isDirectory ( ) & & canMoveFiles ( cachePath , audioPath , FileLoader . MEDIA_DIR_AUDIO ) ) {
2020-03-30 14:00:09 +02:00
AndroidUtilities . createEmptyFile ( new File ( audioPath , " .nomedia " ) ) ;
2015-08-13 11:23:31 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_AUDIO , audioPath ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " audio path = " + audioPath ) ;
}
2014-10-07 22:14:27 +02:00
}
2015-08-13 11:23:31 +02:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-08-13 11:23:31 +02:00
}
2014-10-07 22:14:27 +02:00
2015-08-13 11:23:31 +02:00
try {
File documentPath = new File ( telegramPath , " Telegram Documents " ) ;
documentPath . mkdir ( ) ;
2015-12-09 19:27:52 +01:00
if ( documentPath . isDirectory ( ) & & canMoveFiles ( cachePath , documentPath , FileLoader . MEDIA_DIR_DOCUMENT ) ) {
2020-03-30 14:00:09 +02:00
AndroidUtilities . createEmptyFile ( new File ( documentPath , " .nomedia " ) ) ;
2015-08-13 11:23:31 +02:00
mediaDirs . put ( FileLoader . MEDIA_DIR_DOCUMENT , documentPath ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " documents path = " + documentPath ) ;
}
2014-09-28 15:37:26 +02:00
}
2015-08-13 11:23:31 +02:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-09-28 15:37:26 +02:00
}
}
2015-08-13 11:23:31 +02:00
} else {
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " this Android can't rename files " ) ;
}
2014-08-22 16:24:33 +02:00
}
2018-07-30 04:07:02 +02:00
SharedConfig . checkSaveToGalleryFiles ( ) ;
2014-09-25 05:54:35 +02:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-09-25 05:54:35 +02:00
}
2014-09-28 15:37:26 +02:00
2014-09-25 05:54:35 +02:00
return mediaDirs ;
2014-08-22 16:24:33 +02:00
}
2015-12-09 19:27:52 +01:00
private boolean canMoveFiles ( File from , File to , int type ) {
2015-08-13 11:23:31 +02:00
RandomAccessFile file = null ;
try {
2015-12-09 19:27:52 +01:00
File srcFile = null ;
File dstFile = null ;
if ( type = = FileLoader . MEDIA_DIR_IMAGE ) {
2020-06-04 18:47:15 +02:00
srcFile = new File ( from , " 000000000_999999_temp.f " ) ;
dstFile = new File ( to , " 000000000_999999.f " ) ;
2015-12-09 19:27:52 +01:00
} else if ( type = = FileLoader . MEDIA_DIR_DOCUMENT ) {
2020-06-04 18:47:15 +02:00
srcFile = new File ( from , " 000000000_999999_temp.f " ) ;
dstFile = new File ( to , " 000000000_999999.f " ) ;
2015-12-09 19:27:52 +01:00
} else if ( type = = FileLoader . MEDIA_DIR_AUDIO ) {
2020-06-04 18:47:15 +02:00
srcFile = new File ( from , " 000000000_999999_temp.f " ) ;
dstFile = new File ( to , " 000000000_999999.f " ) ;
2015-12-09 19:27:52 +01:00
} else if ( type = = FileLoader . MEDIA_DIR_VIDEO ) {
2020-06-04 18:47:15 +02:00
srcFile = new File ( from , " 000000000_999999_temp.f " ) ;
dstFile = new File ( to , " 000000000_999999.f " ) ;
2015-12-09 19:27:52 +01:00
}
byte [ ] buffer = new byte [ 1024 ] ;
srcFile . createNewFile ( ) ;
file = new RandomAccessFile ( srcFile , " rws " ) ;
file . write ( buffer ) ;
file . close ( ) ;
file = null ;
boolean canRename = srcFile . renameTo ( dstFile ) ;
srcFile . delete ( ) ;
dstFile . delete ( ) ;
if ( canRename ) {
return true ;
2015-08-13 11:23:31 +02:00
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-08-13 11:23:31 +02:00
} finally {
try {
if ( file ! = null ) {
file . close ( ) ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-08-13 11:23:31 +02:00
}
}
return false ;
}
2015-01-02 23:15:07 +01:00
public Float getFileProgress ( String location ) {
2020-01-23 07:15:40 +01:00
if ( location = = null ) {
return null ;
}
long [ ] progress = fileProgresses . get ( location ) ;
if ( progress = = null ) {
return null ;
}
2020-04-24 11:21:58 +02:00
if ( progress [ 1 ] = = 0 ) {
return 0 . 0f ;
}
2020-01-23 07:15:40 +01:00
return Math . min ( 1f , progress [ 0 ] / ( float ) progress [ 1 ] ) ;
}
public long [ ] getFileProgressSizes ( String location ) {
2015-07-22 20:56:37 +02:00
if ( location = = null ) {
return null ;
}
2015-01-02 23:15:07 +01:00
return fileProgresses . get ( location ) ;
}
2018-07-30 04:07:02 +02:00
public String getReplacedKey ( String oldKey ) {
2019-01-23 18:03:33 +01:00
if ( oldKey = = null ) {
return null ;
}
2018-07-30 04:07:02 +02:00
return replacedBitmaps . get ( oldKey ) ;
}
2014-08-22 16:24:33 +02:00
private void performReplace ( String oldKey , String newKey ) {
2021-11-05 11:06:49 +01:00
LruCache < BitmapDrawable > currentCache = memCache ;
BitmapDrawable b = currentCache . get ( oldKey ) ;
if ( b = = null ) {
currentCache = smallImagesMemCache ;
b = currentCache . get ( oldKey ) ;
}
2018-07-30 04:07:02 +02:00
replacedBitmaps . put ( oldKey , newKey ) ;
2014-08-22 16:24:33 +02:00
if ( b ! = null ) {
2021-11-05 11:06:49 +01:00
BitmapDrawable oldBitmap = currentCache . get ( newKey ) ;
2017-03-31 01:58:05 +02:00
boolean dontChange = false ;
if ( oldBitmap ! = null & & oldBitmap . getBitmap ( ) ! = null & & b . getBitmap ( ) ! = null ) {
Bitmap oldBitmapObject = oldBitmap . getBitmap ( ) ;
Bitmap newBitmapObject = b . getBitmap ( ) ;
if ( oldBitmapObject . getWidth ( ) > newBitmapObject . getWidth ( ) | | oldBitmapObject . getHeight ( ) > newBitmapObject . getHeight ( ) ) {
dontChange = true ;
}
}
if ( ! dontChange ) {
ignoreRemoval = oldKey ;
2021-11-05 11:06:49 +01:00
currentCache . remove ( oldKey ) ;
currentCache . put ( newKey , b ) ;
2017-03-31 01:58:05 +02:00
ignoreRemoval = null ;
} else {
2021-11-05 11:06:49 +01:00
currentCache . remove ( oldKey ) ;
2017-03-31 01:58:05 +02:00
}
2014-08-22 16:24:33 +02:00
}
Integer val = bitmapUseCounts . get ( oldKey ) ;
if ( val ! = null ) {
bitmapUseCounts . put ( newKey , val ) ;
bitmapUseCounts . remove ( oldKey ) ;
}
}
public void incrementUseCount ( String key ) {
Integer count = bitmapUseCounts . get ( key ) ;
if ( count = = null ) {
bitmapUseCounts . put ( key , 1 ) ;
} else {
bitmapUseCounts . put ( key , count + 1 ) ;
}
}
public boolean decrementUseCount ( String key ) {
Integer count = bitmapUseCounts . get ( key ) ;
if ( count = = null ) {
return true ;
}
if ( count = = 1 ) {
bitmapUseCounts . remove ( key ) ;
return true ;
} else {
bitmapUseCounts . put ( key , count - 1 ) ;
}
return false ;
}
public void removeImage ( String key ) {
bitmapUseCounts . remove ( key ) ;
memCache . remove ( key ) ;
2021-11-05 11:06:49 +01:00
smallImagesMemCache . remove ( key ) ;
2014-08-22 16:24:33 +02:00
}
2019-07-18 15:01:39 +02:00
public boolean isInMemCache ( String key , boolean animated ) {
if ( animated ) {
return lottieMemCache . get ( key ) ! = null ;
} else {
2021-09-20 07:54:41 +02:00
return getFromMemCache ( key ) ! = null ;
2019-07-18 15:01:39 +02:00
}
2014-08-22 16:24:33 +02:00
}
public void clearMemory ( ) {
2021-11-05 11:06:49 +01:00
smallImagesMemCache . evictAll ( ) ;
2014-08-22 16:24:33 +02:00
memCache . evictAll ( ) ;
2019-06-04 12:14:50 +02:00
lottieMemCache . evictAll ( ) ;
2014-08-22 16:24:33 +02:00
}
2019-01-23 18:03:33 +01:00
private void removeFromWaitingForThumb ( int TAG , ImageReceiver imageReceiver ) {
2015-02-01 19:51:02 +01:00
String location = waitingForQualityThumbByTag . get ( TAG ) ;
if ( location ! = null ) {
ThumbGenerateInfo info = waitingForQualityThumb . get ( location ) ;
if ( info ! = null ) {
2019-07-18 15:01:39 +02:00
int index = info . imageReceiverArray . indexOf ( imageReceiver ) ;
if ( index > = 0 ) {
info . imageReceiverArray . remove ( index ) ;
info . imageReceiverGuidsArray . remove ( index ) ;
}
2019-01-23 18:03:33 +01:00
if ( info . imageReceiverArray . isEmpty ( ) ) {
2015-02-01 19:51:02 +01:00
waitingForQualityThumb . remove ( location ) ;
}
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
waitingForQualityThumbByTag . remove ( TAG ) ;
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
}
2019-03-03 21:40:48 +01:00
public void cancelLoadingForImageReceiver ( final ImageReceiver imageReceiver , final boolean cancelAll ) {
2015-02-01 19:51:02 +01:00
if ( imageReceiver = = null ) {
return ;
2014-08-22 16:24:33 +02:00
}
2021-11-05 11:06:49 +01:00
ArrayList < Runnable > runnables = imageReceiver . getLoadingOperations ( ) ;
if ( ! runnables . isEmpty ( ) ) {
for ( int i = 0 ; i < runnables . size ( ) ; i + + ) {
imageLoadQueue . cancelRunnable ( runnables . get ( i ) ) ;
}
runnables . clear ( ) ;
}
imageReceiver . addLoadingImageRunnable ( null ) ;
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > {
2019-03-03 21:40:48 +01:00
for ( int a = 0 ; a < 3 ; a + + ) {
2019-12-31 14:08:08 +01:00
int type ;
2019-03-03 21:40:48 +01:00
if ( a > 0 & & ! cancelAll ) {
return ;
}
2018-08-27 10:33:11 +02:00
if ( a = = 0 ) {
2019-12-31 14:08:08 +01:00
type = ImageReceiver . TYPE_THUMB ;
2019-03-03 21:40:48 +01:00
} else if ( a = = 1 ) {
2019-12-31 14:08:08 +01:00
type = ImageReceiver . TYPE_IMAGE ;
2019-03-03 21:40:48 +01:00
} else {
2019-12-31 14:08:08 +01:00
type = ImageReceiver . TYPE_MEDIA ;
2018-08-27 10:33:11 +02:00
}
2019-12-31 14:08:08 +01:00
int TAG = imageReceiver . getTag ( type ) ;
2018-08-27 10:33:11 +02:00
if ( TAG ! = 0 ) {
2019-03-03 21:40:48 +01:00
if ( a = = 0 ) {
removeFromWaitingForThumb ( TAG , imageReceiver ) ;
}
2018-08-27 10:33:11 +02:00
CacheImage ei = imageLoadingByTag . get ( TAG ) ;
if ( ei ! = null ) {
ei . removeImageReceiver ( imageReceiver ) ;
2015-02-01 19:51:02 +01:00
}
}
}
} ) ;
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
public BitmapDrawable getImageFromMemory ( TLObject fileLocation , String httpUrl , String filter ) {
2015-01-02 23:15:07 +01:00
if ( fileLocation = = null & & httpUrl = = null ) {
2014-08-22 16:24:33 +02:00
return null ;
}
2015-01-02 23:15:07 +01:00
String key = null ;
2014-08-22 16:24:33 +02:00
if ( httpUrl ! = null ) {
key = Utilities . MD5 ( httpUrl ) ;
} else {
2015-01-02 23:15:07 +01:00
if ( fileLocation instanceof TLRPC . FileLocation ) {
TLRPC . FileLocation location = ( TLRPC . FileLocation ) fileLocation ;
key = location . volume_id + " _ " + location . local_id ;
} else if ( fileLocation instanceof TLRPC . Document ) {
TLRPC . Document location = ( TLRPC . Document ) fileLocation ;
2019-01-23 18:03:33 +01:00
key = location . dc_id + " _ " + location . id ;
2018-07-30 04:07:02 +02:00
} else if ( fileLocation instanceof SecureDocument ) {
SecureDocument location = ( SecureDocument ) fileLocation ;
key = location . secureFile . dc_id + " _ " + location . secureFile . id ;
} else if ( fileLocation instanceof WebFile ) {
WebFile location = ( WebFile ) fileLocation ;
2017-03-31 01:58:05 +02:00
key = Utilities . MD5 ( location . url ) ;
2015-01-02 23:15:07 +01:00
}
2014-08-22 16:24:33 +02:00
}
if ( filter ! = null ) {
key + = " @ " + filter ;
}
2021-09-20 07:54:41 +02:00
return getFromMemCache ( key ) ;
2014-08-22 16:24:33 +02:00
}
2019-05-14 14:08:05 +02:00
private void replaceImageInCacheInternal ( final String oldKey , final String newKey , final ImageLocation newLocation ) {
2021-11-05 11:06:49 +01:00
for ( int i = 0 ; i < 2 ; i + + ) {
ArrayList < String > arr ;
if ( i = = 0 ) {
arr = memCache . getFilterKeys ( oldKey ) ;
} else {
arr = smallImagesMemCache . getFilterKeys ( oldKey ) ;
}
if ( arr ! = null ) {
for ( int a = 0 ; a < arr . size ( ) ; a + + ) {
String filter = arr . get ( a ) ;
String oldK = oldKey + " @ " + filter ;
String newK = newKey + " @ " + filter ;
performReplace ( oldK , newK ) ;
NotificationCenter . getGlobalInstance ( ) . postNotificationName ( NotificationCenter . didReplacedPhotoInMemCache , oldK , newK , newLocation ) ;
}
} else {
performReplace ( oldKey , newKey ) ;
NotificationCenter . getGlobalInstance ( ) . postNotificationName ( NotificationCenter . didReplacedPhotoInMemCache , oldKey , newKey , newLocation ) ;
2014-08-22 16:24:33 +02:00
}
2016-01-11 18:19:48 +01:00
}
}
2019-05-14 14:08:05 +02:00
public void replaceImageInCache ( final String oldKey , final String newKey , final ImageLocation newLocation , boolean post ) {
2016-01-11 18:19:48 +01:00
if ( post ) {
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > replaceImageInCacheInternal ( oldKey , newKey , newLocation ) ) ;
2016-01-11 18:19:48 +01:00
} else {
replaceImageInCacheInternal ( oldKey , newKey , newLocation ) ;
}
2014-08-22 16:24:33 +02:00
}
2021-11-05 11:06:49 +01:00
public void putImageToCache ( BitmapDrawable bitmap , String key , boolean smallImage ) {
if ( smallImage ) {
smallImagesMemCache . put ( key , bitmap ) ;
} else {
memCache . put ( key , bitmap ) ;
}
2014-10-10 19:16:39 +02:00
}
2019-01-23 18:03:33 +01:00
private void generateThumb ( int mediaType , File originalPath , ThumbGenerateInfo info ) {
if ( mediaType ! = FileLoader . MEDIA_DIR_IMAGE & & mediaType ! = FileLoader . MEDIA_DIR_VIDEO & & mediaType ! = FileLoader . MEDIA_DIR_DOCUMENT | | originalPath = = null | | info = = null ) {
2014-08-22 16:24:33 +02:00
return ;
}
2019-01-23 18:03:33 +01:00
String name = FileLoader . getAttachFileName ( info . parentDocument ) ;
2015-02-01 19:51:02 +01:00
ThumbGenerateTask task = thumbGenerateTasks . get ( name ) ;
if ( task = = null ) {
2019-01-23 18:03:33 +01:00
task = new ThumbGenerateTask ( mediaType , originalPath , info ) ;
2015-02-01 19:51:02 +01:00
thumbGeneratingQueue . postRunnable ( task ) ;
}
}
2014-08-22 16:24:33 +02:00
2017-12-08 18:35:59 +01:00
public void cancelForceLoadingForImageReceiver ( final ImageReceiver imageReceiver ) {
if ( imageReceiver = = null ) {
return ;
}
2019-03-03 21:40:48 +01:00
final String key = imageReceiver . getImageKey ( ) ;
2017-12-08 18:35:59 +01:00
if ( key = = null ) {
return ;
}
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > forceLoadingImages . remove ( key ) ) ;
2017-12-08 18:35:59 +01:00
}
2019-12-31 14:08:08 +01:00
private void createLoadOperationForImageReceiver ( final ImageReceiver imageReceiver , final String key , final String url , final String ext , final ImageLocation imageLocation , final String filter , final int size , final int cacheType , final int type , final int thumb , int guid ) {
2019-05-14 14:08:05 +02:00
if ( imageReceiver = = null | | url = = null | | key = = null | | imageLocation = = null ) {
2015-02-01 19:51:02 +01:00
return ;
}
2019-12-31 14:08:08 +01:00
int TAG = imageReceiver . getTag ( type ) ;
2018-07-30 04:07:02 +02:00
if ( TAG = = 0 ) {
2019-12-31 14:08:08 +01:00
imageReceiver . setTag ( TAG = lastImageNum , type ) ;
2015-02-01 19:51:02 +01:00
lastImageNum + + ;
if ( lastImageNum = = Integer . MAX_VALUE ) {
lastImageNum = 0 ;
}
}
2018-07-30 04:07:02 +02:00
final int finalTag = TAG ;
2015-02-01 19:51:02 +01:00
final boolean finalIsNeedsQualityThumb = imageReceiver . isNeedsQualityThumb ( ) ;
2019-01-23 18:03:33 +01:00
final Object parentObject = imageReceiver . getParentObject ( ) ;
2019-03-03 21:40:48 +01:00
final TLRPC . Document qualityDocument = imageReceiver . getQulityThumbDocument ( ) ;
2015-02-01 19:51:02 +01:00
final boolean shouldGenerateQualityThumb = imageReceiver . isShouldGenerateQualityThumb ( ) ;
2019-02-08 03:30:32 +01:00
final int currentAccount = imageReceiver . getCurrentAccount ( ) ;
2019-12-31 14:08:08 +01:00
final boolean currentKeyQuality = type = = ImageReceiver . TYPE_IMAGE & & imageReceiver . isCurrentKeyQuality ( ) ;
2021-11-05 11:06:49 +01:00
final Runnable loadOperationRunnable = ( ) - > {
2018-08-27 10:33:11 +02:00
boolean added = false ;
if ( thumb ! = 2 ) {
CacheImage alreadyLoadingUrl = imageLoadingByUrl . get ( url ) ;
CacheImage alreadyLoadingCache = imageLoadingByKeys . get ( key ) ;
CacheImage alreadyLoadingImage = imageLoadingByTag . get ( finalTag ) ;
if ( alreadyLoadingImage ! = null ) {
if ( alreadyLoadingImage = = alreadyLoadingCache ) {
2019-12-31 14:08:08 +01:00
alreadyLoadingImage . setImageReceiverGuid ( imageReceiver , guid ) ;
2015-02-01 19:51:02 +01:00
added = true ;
2018-08-27 10:33:11 +02:00
} else if ( alreadyLoadingImage = = alreadyLoadingUrl ) {
if ( alreadyLoadingCache = = null ) {
2019-12-31 14:08:08 +01:00
alreadyLoadingImage . replaceImageReceiver ( imageReceiver , key , filter , type , guid ) ;
2018-08-27 10:33:11 +02:00
}
2015-02-01 19:51:02 +01:00
added = true ;
2018-08-27 10:33:11 +02:00
} else {
alreadyLoadingImage . removeImageReceiver ( imageReceiver ) ;
2015-02-01 19:51:02 +01:00
}
2015-01-02 23:15:07 +01:00
}
2015-02-01 19:51:02 +01:00
2018-08-27 10:33:11 +02:00
if ( ! added & & alreadyLoadingCache ! = null ) {
2019-12-31 14:08:08 +01:00
alreadyLoadingCache . addImageReceiver ( imageReceiver , key , filter , type , guid ) ;
2018-08-27 10:33:11 +02:00
added = true ;
}
if ( ! added & & alreadyLoadingUrl ! = null ) {
2019-12-31 14:08:08 +01:00
alreadyLoadingUrl . addImageReceiver ( imageReceiver , key , filter , type , guid ) ;
2018-08-27 10:33:11 +02:00
added = true ;
}
}
2015-02-01 19:51:02 +01:00
2018-08-27 10:33:11 +02:00
if ( ! added ) {
boolean onlyCache = false ;
boolean isQuality = false ;
File cacheFile = null ;
boolean cacheFileExists = false ;
2019-05-14 14:08:05 +02:00
if ( imageLocation . path ! = null ) {
String location = imageLocation . path ;
2019-02-08 03:30:32 +01:00
if ( ! location . startsWith ( " http " ) & & ! location . startsWith ( " athumb " ) ) {
2018-08-27 10:33:11 +02:00
onlyCache = true ;
2019-02-08 03:30:32 +01:00
if ( location . startsWith ( " thumb:// " ) ) {
int idx = location . indexOf ( " : " , 8 ) ;
2018-08-27 10:33:11 +02:00
if ( idx > = 0 ) {
2019-02-08 03:30:32 +01:00
cacheFile = new File ( location . substring ( idx + 1 ) ) ;
2015-02-01 19:51:02 +01:00
}
2019-02-08 03:30:32 +01:00
} else if ( location . startsWith ( " vthumb:// " ) ) {
int idx = location . indexOf ( " : " , 9 ) ;
2018-08-27 10:33:11 +02:00
if ( idx > = 0 ) {
2019-02-08 03:30:32 +01:00
cacheFile = new File ( location . substring ( idx + 1 ) ) ;
2015-02-01 19:51:02 +01:00
}
2018-08-27 10:33:11 +02:00
} else {
2019-02-08 03:30:32 +01:00
cacheFile = new File ( location ) ;
2018-08-27 10:33:11 +02:00
}
}
2019-01-23 18:03:33 +01:00
} else if ( thumb = = 0 & & currentKeyQuality ) {
onlyCache = true ;
2019-03-03 21:40:48 +01:00
TLRPC . Document parentDocument ;
String localPath ;
File cachePath ;
boolean forceCache ;
String fileName ;
2019-12-31 14:08:08 +01:00
int mediaType ;
2019-03-03 21:40:48 +01:00
boolean bigThumb ;
if ( parentObject instanceof MessageObject ) {
MessageObject parentMessageObject = ( MessageObject ) parentObject ;
parentDocument = parentMessageObject . getDocument ( ) ;
localPath = parentMessageObject . messageOwner . attachPath ;
cachePath = FileLoader . getPathToMessage ( parentMessageObject . messageOwner ) ;
2019-12-31 14:08:08 +01:00
mediaType = parentMessageObject . getMediaType ( ) ;
2019-03-03 21:40:48 +01:00
bigThumb = false ;
} else if ( qualityDocument ! = null ) {
parentDocument = qualityDocument ;
cachePath = FileLoader . getPathToAttach ( parentDocument , true ) ;
if ( MessageObject . isVideoDocument ( parentDocument ) ) {
2019-12-31 14:08:08 +01:00
mediaType = FileLoader . MEDIA_DIR_VIDEO ;
2019-03-03 21:40:48 +01:00
} else {
2019-12-31 14:08:08 +01:00
mediaType = FileLoader . MEDIA_DIR_DOCUMENT ;
2019-03-03 21:40:48 +01:00
}
localPath = null ;
bigThumb = true ;
} else {
parentDocument = null ;
localPath = null ;
cachePath = null ;
2019-12-31 14:08:08 +01:00
mediaType = 0 ;
2019-03-03 21:40:48 +01:00
bigThumb = false ;
}
2019-01-23 18:03:33 +01:00
if ( parentDocument ! = null ) {
if ( finalIsNeedsQualityThumb ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , " q_ " + parentDocument . dc_id + " _ " + parentDocument . id + " .jpg " ) ;
if ( ! cacheFile . exists ( ) ) {
cacheFile = null ;
} else {
cacheFileExists = true ;
}
2015-02-01 19:51:02 +01:00
}
2018-08-27 10:33:11 +02:00
File attachPath = null ;
2019-03-03 21:40:48 +01:00
if ( ! TextUtils . isEmpty ( localPath ) ) {
attachPath = new File ( localPath ) ;
2018-08-27 10:33:11 +02:00
if ( ! attachPath . exists ( ) ) {
attachPath = null ;
2015-02-01 19:51:02 +01:00
}
2018-08-27 10:33:11 +02:00
}
if ( attachPath = = null ) {
2019-03-03 21:40:48 +01:00
attachPath = cachePath ;
2018-08-27 10:33:11 +02:00
}
2019-01-23 18:03:33 +01:00
if ( cacheFile = = null ) {
2019-03-03 21:40:48 +01:00
String location = FileLoader . getAttachFileName ( parentDocument ) ;
2018-08-27 10:33:11 +02:00
ThumbGenerateInfo info = waitingForQualityThumb . get ( location ) ;
if ( info = = null ) {
info = new ThumbGenerateInfo ( ) ;
2019-01-23 18:03:33 +01:00
info . parentDocument = parentDocument ;
2018-08-27 10:33:11 +02:00
info . filter = filter ;
2019-03-03 21:40:48 +01:00
info . big = bigThumb ;
2018-08-27 10:33:11 +02:00
waitingForQualityThumb . put ( location , info ) ;
2015-02-01 19:51:02 +01:00
}
2019-01-23 18:03:33 +01:00
if ( ! info . imageReceiverArray . contains ( imageReceiver ) ) {
info . imageReceiverArray . add ( imageReceiver ) ;
2019-07-18 15:01:39 +02:00
info . imageReceiverGuidsArray . add ( guid ) ;
2019-01-23 18:03:33 +01:00
}
2018-08-27 10:33:11 +02:00
waitingForQualityThumbByTag . put ( finalTag , location ) ;
2019-01-23 18:03:33 +01:00
if ( attachPath . exists ( ) & & shouldGenerateQualityThumb ) {
2019-12-31 14:08:08 +01:00
generateThumb ( mediaType , attachPath , info ) ;
2019-01-23 18:03:33 +01:00
}
return ;
2015-02-01 19:51:02 +01:00
}
}
2018-08-27 10:33:11 +02:00
}
2015-02-01 19:51:02 +01:00
2018-08-27 10:33:11 +02:00
if ( thumb ! = 2 ) {
2019-05-14 14:08:05 +02:00
boolean isEncrypted = imageLocation . isEncrypted ( ) ;
2018-08-27 10:33:11 +02:00
CacheImage img = new CacheImage ( ) ;
2019-05-14 14:08:05 +02:00
if ( ! currentKeyQuality ) {
2020-06-04 18:47:15 +02:00
if ( imageLocation . imageType = = FileLoader . IMAGE_TYPE_ANIMATION | | MessageObject . isGifDocument ( imageLocation . webFile ) | | MessageObject . isGifDocument ( imageLocation . document ) | | MessageObject . isRoundVideoDocument ( imageLocation . document ) ) {
2019-12-31 14:08:08 +01:00
img . imageType = FileLoader . IMAGE_TYPE_ANIMATION ;
2019-05-14 14:08:05 +02:00
} else if ( imageLocation . path ! = null ) {
String location = imageLocation . path ;
if ( ! location . startsWith ( " vthumb " ) & & ! location . startsWith ( " thumb " ) ) {
String trueExt = getHttpUrlExtension ( location , " jpg " ) ;
if ( trueExt . equals ( " mp4 " ) | | trueExt . equals ( " gif " ) ) {
2019-12-31 14:08:08 +01:00
img . imageType = FileLoader . IMAGE_TYPE_ANIMATION ;
2021-06-25 02:43:10 +02:00
} else if ( " tgs " . equals ( ext ) ) {
img . imageType = FileLoader . IMAGE_TYPE_LOTTIE ;
2019-05-14 14:08:05 +02:00
}
2019-02-08 03:30:32 +01:00
}
}
2018-08-27 10:33:11 +02:00
}
2016-01-11 18:19:48 +01:00
2018-08-27 10:33:11 +02:00
if ( cacheFile = = null ) {
2019-05-14 14:08:05 +02:00
int fileSize = 0 ;
2020-12-23 08:48:30 +01:00
if ( imageLocation . photoSize instanceof TLRPC . TL_photoStrippedSize | | imageLocation . photoSize instanceof TLRPC . TL_photoPathSize ) {
2019-01-23 18:03:33 +01:00
onlyCache = true ;
2019-05-14 14:08:05 +02:00
} else if ( imageLocation . secureDocument ! = null ) {
img . secureDocument = imageLocation . secureDocument ;
2018-08-27 10:33:11 +02:00
onlyCache = img . secureDocument . secureFile . dc_id = = Integer . MIN_VALUE ;
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url ) ;
2019-05-14 14:08:05 +02:00
} else if ( ! AUTOPLAY_FILTER . equals ( filter ) & & ( cacheType ! = 0 | | size < = 0 | | imageLocation . path ! = null | | isEncrypted ) ) {
2018-08-27 10:33:11 +02:00
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url ) ;
if ( cacheFile . exists ( ) ) {
cacheFileExists = true ;
} else if ( cacheType = = 2 ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url + " .enc " ) ;
}
2019-05-14 14:08:05 +02:00
if ( imageLocation . document ! = null ) {
2019-12-31 14:08:08 +01:00
if ( imageLocation . document instanceof DocumentObject . ThemeDocument ) {
DocumentObject . ThemeDocument themeDocument = ( DocumentObject . ThemeDocument ) imageLocation . document ;
if ( themeDocument . wallpaper = = null ) {
onlyCache = true ;
}
img . imageType = FileLoader . IMAGE_TYPE_THEME_PREVIEW ;
2020-03-30 14:00:09 +02:00
} else if ( " application/x-tgsdice " . equals ( imageLocation . document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_LOTTIE ;
onlyCache = true ;
2019-12-31 14:08:08 +01:00
} else if ( " application/x-tgsticker " . equals ( imageLocation . document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_LOTTIE ;
} else if ( " application/x-tgwallpattern " . equals ( imageLocation . document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_SVG ;
} else if ( BuildVars . DEBUG_PRIVATE_VERSION ) {
String name = FileLoader . getDocumentFileName ( imageLocation . document ) ;
if ( name . endsWith ( " .svg " ) ) {
2020-10-30 11:26:29 +01:00
img . imageType = FileLoader . IMAGE_TYPE_SVG ;
2019-12-31 14:08:08 +01:00
}
}
2019-05-14 14:08:05 +02:00
}
} else if ( imageLocation . document ! = null ) {
TLRPC . Document document = imageLocation . document ;
2019-03-03 21:40:48 +01:00
if ( document instanceof TLRPC . TL_documentEncrypted ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url ) ;
} else if ( MessageObject . isVideoDocument ( document ) ) {
2018-08-27 10:33:11 +02:00
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_VIDEO ) , url ) ;
2015-02-01 19:51:02 +01:00
} else {
2018-08-27 10:33:11 +02:00
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_DOCUMENT ) , url ) ;
2015-02-01 19:51:02 +01:00
}
2019-05-14 14:08:05 +02:00
if ( AUTOPLAY_FILTER . equals ( filter ) & & ! cacheFile . exists ( ) ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , document . dc_id + " _ " + document . id + " .temp " ) ;
}
2019-12-31 14:08:08 +01:00
if ( document instanceof DocumentObject . ThemeDocument ) {
DocumentObject . ThemeDocument themeDocument = ( DocumentObject . ThemeDocument ) document ;
if ( themeDocument . wallpaper = = null ) {
onlyCache = true ;
}
img . imageType = FileLoader . IMAGE_TYPE_THEME_PREVIEW ;
2020-03-30 14:00:09 +02:00
} else if ( " application/x-tgsdice " . equals ( imageLocation . document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_LOTTIE ;
onlyCache = true ;
2019-12-31 14:08:08 +01:00
} else if ( " application/x-tgsticker " . equals ( document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_LOTTIE ;
} else if ( " application/x-tgwallpattern " . equals ( document . mime_type ) ) {
img . imageType = FileLoader . IMAGE_TYPE_SVG ;
} else if ( BuildVars . DEBUG_PRIVATE_VERSION ) {
String name = FileLoader . getDocumentFileName ( imageLocation . document ) ;
if ( name . endsWith ( " .svg " ) ) {
2020-10-30 11:26:29 +01:00
img . imageType = FileLoader . IMAGE_TYPE_SVG ;
2019-12-31 14:08:08 +01:00
}
}
2019-05-14 14:08:05 +02:00
fileSize = document . size ;
} else if ( imageLocation . webFile ! = null ) {
2018-08-27 10:33:11 +02:00
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_DOCUMENT ) , url ) ;
} else {
2020-07-26 10:03:38 +02:00
if ( cacheType = = 1 ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url ) ;
} else {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_IMAGE ) , url ) ;
}
if ( AUTOPLAY_FILTER . equals ( filter ) & & imageLocation . location ! = null & & ! cacheFile . exists ( ) ) {
cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , imageLocation . location . volume_id + " _ " + imageLocation . location . local_id + " .temp " ) ;
}
2015-02-01 19:51:02 +01:00
}
2019-05-14 14:08:05 +02:00
if ( AUTOPLAY_FILTER . equals ( filter ) ) {
2019-12-31 14:08:08 +01:00
img . imageType = FileLoader . IMAGE_TYPE_ANIMATION ;
2019-05-14 14:08:05 +02:00
img . size = fileSize ;
onlyCache = true ;
}
2018-08-27 10:33:11 +02:00
}
2015-02-01 19:51:02 +01:00
2019-12-31 14:08:08 +01:00
img . type = type ;
2018-08-27 10:33:11 +02:00
img . key = key ;
img . filter = filter ;
2019-05-14 14:08:05 +02:00
img . imageLocation = imageLocation ;
2018-08-27 10:33:11 +02:00
img . ext = ext ;
img . currentAccount = currentAccount ;
2019-03-03 21:40:48 +01:00
img . parentObject = parentObject ;
2019-12-31 14:08:08 +01:00
if ( imageLocation . imageType ! = 0 ) {
img . imageType = imageLocation . imageType ;
2019-07-18 15:01:39 +02:00
}
2018-08-27 10:33:11 +02:00
if ( cacheType = = 2 ) {
img . encryptionKeyPath = new File ( FileLoader . getInternalCacheDir ( ) , url + " .enc.key " ) ;
}
2019-12-31 14:08:08 +01:00
img . addImageReceiver ( imageReceiver , key , filter , type , guid ) ;
2018-08-27 10:33:11 +02:00
if ( onlyCache | | cacheFileExists | | cacheFile . exists ( ) ) {
img . finalFilePath = cacheFile ;
2019-05-14 14:08:05 +02:00
img . imageLocation = imageLocation ;
2018-08-27 10:33:11 +02:00
img . cacheTask = new CacheOutTask ( img ) ;
imageLoadingByKeys . put ( key , img ) ;
if ( thumb ! = 0 ) {
cacheThumbOutQueue . postRunnable ( img . cacheTask ) ;
2015-02-01 19:51:02 +01:00
} else {
2018-08-27 10:33:11 +02:00
cacheOutQueue . postRunnable ( img . cacheTask ) ;
}
} else {
img . url = url ;
2019-02-08 03:30:32 +01:00
2018-08-27 10:33:11 +02:00
imageLoadingByUrl . put ( url , img ) ;
2019-05-14 14:08:05 +02:00
if ( imageLocation . path ! = null ) {
String file = Utilities . MD5 ( imageLocation . path ) ;
2019-02-08 03:30:32 +01:00
File cacheDir = FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) ;
img . tempFilePath = new File ( cacheDir , file + " _temp.jpg " ) ;
img . finalFilePath = cacheFile ;
2019-05-14 14:08:05 +02:00
if ( imageLocation . path . startsWith ( " athumb " ) ) {
2019-02-08 03:30:32 +01:00
img . artworkTask = new ArtworkLoadTask ( img ) ;
artworkTasks . add ( img . artworkTask ) ;
runArtworkTasks ( false ) ;
} else {
img . httpTask = new HttpImageTask ( img , size ) ;
httpTasks . add ( img . httpTask ) ;
runHttpTasks ( false ) ;
}
} else {
2019-05-14 14:08:05 +02:00
if ( imageLocation . location ! = null ) {
2018-08-27 10:33:11 +02:00
int localCacheType = cacheType ;
2019-05-14 14:08:05 +02:00
if ( localCacheType = = 0 & & ( size < = 0 | | imageLocation . key ! = null ) ) {
2018-08-27 10:33:11 +02:00
localCacheType = 1 ;
2017-12-08 18:35:59 +01:00
}
2019-05-14 14:08:05 +02:00
FileLoader . getInstance ( currentAccount ) . loadFile ( imageLocation , parentObject , ext , thumb ! = 0 ? 2 : 1 , localCacheType ) ;
} else if ( imageLocation . document ! = null ) {
FileLoader . getInstance ( currentAccount ) . loadFile ( imageLocation . document , parentObject , thumb ! = 0 ? 2 : 1 , cacheType ) ;
} else if ( imageLocation . secureDocument ! = null ) {
FileLoader . getInstance ( currentAccount ) . loadFile ( imageLocation . secureDocument , thumb ! = 0 ? 2 : 1 ) ;
} else if ( imageLocation . webFile ! = null ) {
FileLoader . getInstance ( currentAccount ) . loadFile ( imageLocation . webFile , thumb ! = 0 ? 2 : 1 , cacheType ) ;
2018-08-27 10:33:11 +02:00
}
if ( imageReceiver . isForceLoding ( ) ) {
forceLoadingImages . put ( img . key , 0 ) ;
2015-02-01 19:51:02 +01:00
}
}
}
2015-01-02 23:15:07 +01:00
}
2015-02-01 19:51:02 +01:00
}
2021-11-05 11:06:49 +01:00
} ;
imageLoadQueue . postRunnable ( loadOperationRunnable ) ;
imageReceiver . addLoadingImageRunnable ( loadOperationRunnable ) ;
2015-02-01 19:51:02 +01:00
}
2020-10-30 11:26:29 +01:00
public void preloadArtwork ( String athumbUrl ) {
imageLoadQueue . postRunnable ( ( ) - > {
String ext = getHttpUrlExtension ( athumbUrl , " jpg " ) ;
String url = Utilities . MD5 ( athumbUrl ) + " . " + ext ;
File cacheFile = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , url ) ;
if ( cacheFile . exists ( ) ) {
return ;
}
ImageLocation imageLocation = ImageLocation . getForPath ( athumbUrl ) ;
CacheImage img = new CacheImage ( ) ;
img . type = ImageReceiver . TYPE_THUMB ;
img . key = Utilities . MD5 ( athumbUrl ) ;
img . filter = null ;
img . imageLocation = imageLocation ;
img . ext = ext ;
img . parentObject = null ;
if ( imageLocation . imageType ! = 0 ) {
img . imageType = imageLocation . imageType ;
}
img . url = url ;
imageLoadingByUrl . put ( url , img ) ;
String file = Utilities . MD5 ( imageLocation . path ) ;
File cacheDir = FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) ;
img . tempFilePath = new File ( cacheDir , file + " _temp.jpg " ) ;
img . finalFilePath = cacheFile ;
img . artworkTask = new ArtworkLoadTask ( img ) ;
artworkTasks . add ( img . artworkTask ) ;
runArtworkTasks ( false ) ;
} ) ;
}
2015-02-01 19:51:02 +01:00
public void loadImageForImageReceiver ( ImageReceiver imageReceiver ) {
if ( imageReceiver = = null ) {
return ;
}
2017-07-23 14:56:38 +02:00
boolean imageSet = false ;
2019-03-03 21:40:48 +01:00
String mediaKey = imageReceiver . getMediaKey ( ) ;
2019-07-18 15:01:39 +02:00
int guid = imageReceiver . getNewGuid ( ) ;
2019-03-03 21:40:48 +01:00
if ( mediaKey ! = null ) {
2019-06-04 12:14:50 +02:00
ImageLocation mediaLocation = imageReceiver . getMediaLocation ( ) ;
Drawable drawable ;
2019-12-31 14:08:08 +01:00
if ( mediaLocation ! = null & & ( MessageObject . isAnimatedStickerDocument ( mediaLocation . document , true ) | | mediaLocation . imageType = = FileLoader . IMAGE_TYPE_LOTTIE ) ) {
2019-06-04 12:14:50 +02:00
drawable = lottieMemCache . get ( mediaKey ) ;
} else {
drawable = memCache . get ( mediaKey ) ;
2019-07-18 15:01:39 +02:00
if ( drawable ! = null ) {
memCache . moveToFront ( mediaKey ) ;
2021-11-05 11:06:49 +01:00
}
if ( drawable = = null ) {
drawable = smallImagesMemCache . get ( mediaKey ) ;
if ( drawable ! = null ) {
smallImagesMemCache . moveToFront ( mediaKey ) ;
}
}
if ( drawable = = null ) {
2021-09-20 07:54:41 +02:00
drawable = wallpaperMemCache . get ( mediaKey ) ;
if ( drawable ! = null ) {
wallpaperMemCache . moveToFront ( mediaKey ) ;
}
2019-07-18 15:01:39 +02:00
}
2019-06-04 12:14:50 +02:00
}
if ( drawable ! = null ) {
2019-03-03 21:40:48 +01:00
cancelLoadingForImageReceiver ( imageReceiver , true ) ;
2019-07-18 15:01:39 +02:00
imageReceiver . setImageBitmapByKey ( drawable , mediaKey , ImageReceiver . TYPE_MEDIA , true , guid ) ;
2017-07-23 14:56:38 +02:00
imageSet = true ;
2015-02-01 19:51:02 +01:00
if ( ! imageReceiver . isForcePreview ( ) ) {
2015-01-02 23:15:07 +01:00
return ;
}
}
2014-08-22 16:24:33 +02:00
}
2019-03-03 21:40:48 +01:00
String imageKey = imageReceiver . getImageKey ( ) ;
if ( ! imageSet & & imageKey ! = null ) {
2019-06-04 12:14:50 +02:00
ImageLocation imageLocation = imageReceiver . getImageLocation ( ) ;
Drawable drawable ;
2019-12-31 14:08:08 +01:00
if ( imageLocation ! = null & & ( MessageObject . isAnimatedStickerDocument ( imageLocation . document , true ) | | imageLocation . imageType = = FileLoader . IMAGE_TYPE_LOTTIE ) ) {
2019-06-04 12:14:50 +02:00
drawable = lottieMemCache . get ( imageKey ) ;
} else {
drawable = memCache . get ( imageKey ) ;
2019-07-18 15:01:39 +02:00
if ( drawable ! = null ) {
memCache . moveToFront ( imageKey ) ;
2021-11-05 11:06:49 +01:00
}
if ( drawable = = null ) {
drawable = smallImagesMemCache . get ( imageKey ) ;
if ( drawable ! = null ) {
smallImagesMemCache . moveToFront ( imageKey ) ;
}
}
if ( drawable = = null ) {
2021-09-20 07:54:41 +02:00
drawable = wallpaperMemCache . get ( imageKey ) ;
if ( drawable ! = null ) {
wallpaperMemCache . moveToFront ( imageKey ) ;
}
2019-07-18 15:01:39 +02:00
}
2019-06-04 12:14:50 +02:00
}
if ( drawable ! = null ) {
2019-03-03 21:40:48 +01:00
cancelLoadingForImageReceiver ( imageReceiver , true ) ;
2019-07-18 15:01:39 +02:00
imageReceiver . setImageBitmapByKey ( drawable , imageKey , ImageReceiver . TYPE_IMAGE , true , guid ) ;
2019-03-03 21:40:48 +01:00
imageSet = true ;
if ( ! imageReceiver . isForcePreview ( ) & & mediaKey = = null ) {
return ;
}
}
}
2015-02-01 19:51:02 +01:00
boolean thumbSet = false ;
String thumbKey = imageReceiver . getThumbKey ( ) ;
if ( thumbKey ! = null ) {
2019-07-18 15:01:39 +02:00
ImageLocation thumbLocation = imageReceiver . getThumbLocation ( ) ;
Drawable drawable ;
2019-12-31 14:08:08 +01:00
if ( thumbLocation ! = null & & ( MessageObject . isAnimatedStickerDocument ( thumbLocation . document , true ) | | thumbLocation . imageType = = FileLoader . IMAGE_TYPE_LOTTIE ) ) {
drawable = lottieMemCache . get ( thumbKey ) ;
2019-07-18 15:01:39 +02:00
} else {
drawable = memCache . get ( thumbKey ) ;
if ( drawable ! = null ) {
memCache . moveToFront ( thumbKey ) ;
2021-11-05 11:06:49 +01:00
}
if ( drawable = = null ) {
drawable = smallImagesMemCache . get ( thumbKey ) ;
if ( drawable ! = null ) {
smallImagesMemCache . moveToFront ( thumbKey ) ;
}
}
if ( drawable = = null ) {
2021-09-20 07:54:41 +02:00
drawable = wallpaperMemCache . get ( thumbKey ) ;
if ( drawable ! = null ) {
wallpaperMemCache . moveToFront ( thumbKey ) ;
}
2019-07-18 15:01:39 +02:00
}
}
if ( drawable ! = null ) {
imageReceiver . setImageBitmapByKey ( drawable , thumbKey , ImageReceiver . TYPE_THUMB , true , guid ) ;
2019-03-03 21:40:48 +01:00
cancelLoadingForImageReceiver ( imageReceiver , false ) ;
2017-07-23 14:56:38 +02:00
if ( imageSet & & imageReceiver . isForcePreview ( ) ) {
return ;
}
2015-02-01 19:51:02 +01:00
thumbSet = true ;
}
2014-08-22 16:24:33 +02:00
}
2019-01-23 18:03:33 +01:00
boolean qualityThumb = false ;
Object parentObject = imageReceiver . getParentObject ( ) ;
2019-03-03 21:40:48 +01:00
TLRPC . Document qualityDocument = imageReceiver . getQulityThumbDocument ( ) ;
2019-05-14 14:08:05 +02:00
ImageLocation thumbLocation = imageReceiver . getThumbLocation ( ) ;
String thumbFilter = imageReceiver . getThumbFilter ( ) ;
ImageLocation mediaLocation = imageReceiver . getMediaLocation ( ) ;
String mediaFilter = imageReceiver . getMediaFilter ( ) ;
2020-07-26 10:03:38 +02:00
ImageLocation originalImageLocation = imageReceiver . getImageLocation ( ) ;
2019-05-14 14:08:05 +02:00
String imageFilter = imageReceiver . getImageFilter ( ) ;
2020-07-26 10:03:38 +02:00
ImageLocation imageLocation = originalImageLocation ;
2019-03-03 21:40:48 +01:00
if ( imageLocation = = null & & imageReceiver . isNeedsQualityThumb ( ) & & imageReceiver . isCurrentKeyQuality ( ) ) {
if ( parentObject instanceof MessageObject ) {
2019-05-14 14:08:05 +02:00
MessageObject messageObject = ( MessageObject ) parentObject ;
imageLocation = ImageLocation . getForDocument ( messageObject . getDocument ( ) ) ;
2019-03-03 21:40:48 +01:00
qualityThumb = true ;
} else if ( qualityDocument ! = null ) {
2019-05-14 14:08:05 +02:00
imageLocation = ImageLocation . getForDocument ( qualityDocument ) ;
2019-03-03 21:40:48 +01:00
qualityThumb = true ;
}
2019-01-23 18:03:33 +01:00
}
2015-02-01 19:51:02 +01:00
boolean saveImageToCache = false ;
2019-03-03 21:40:48 +01:00
String imageUrl = null ;
2015-02-01 19:51:02 +01:00
String thumbUrl = null ;
2019-03-03 21:40:48 +01:00
String mediaUrl = null ;
imageKey = null ;
2015-02-01 19:51:02 +01:00
thumbKey = null ;
2019-03-03 21:40:48 +01:00
mediaKey = null ;
2020-06-04 18:47:15 +02:00
String imageExt ;
if ( imageLocation ! = null & & imageLocation . imageType = = FileLoader . IMAGE_TYPE_ANIMATION ) {
imageExt = " mp4 " ;
} else {
imageExt = null ;
}
String mediaExt ;
if ( mediaLocation ! = null & & mediaLocation . imageType = = FileLoader . IMAGE_TYPE_ANIMATION ) {
mediaExt = " mp4 " ;
} else {
mediaExt = null ;
}
String thumbExt = imageReceiver . getExt ( ) ;
if ( thumbExt = = null ) {
thumbExt = " jpg " ;
}
if ( imageExt = = null ) {
imageExt = thumbExt ;
}
if ( mediaExt = = null ) {
mediaExt = thumbExt ;
2015-05-21 23:27:27 +02:00
}
2019-03-03 21:40:48 +01:00
for ( int a = 0 ; a < 2 ; a + + ) {
2019-05-14 14:08:05 +02:00
ImageLocation object ;
2020-06-04 18:47:15 +02:00
String ext ;
2019-03-03 21:40:48 +01:00
if ( a = = 0 ) {
object = imageLocation ;
2020-06-04 18:47:15 +02:00
ext = imageExt ;
2019-03-03 21:40:48 +01:00
} else {
object = mediaLocation ;
2020-06-04 18:47:15 +02:00
ext = mediaExt ;
2019-03-03 21:40:48 +01:00
}
if ( object = = null ) {
continue ;
}
2019-12-31 14:08:08 +01:00
String key = object . getKey ( parentObject , mediaLocation ! = null ? mediaLocation : imageLocation , false ) ;
2019-05-14 14:08:05 +02:00
if ( key = = null ) {
continue ;
}
2019-12-31 14:08:08 +01:00
String url = object . getKey ( parentObject , mediaLocation ! = null ? mediaLocation : imageLocation , true ) ;
2019-05-14 14:08:05 +02:00
if ( object . path ! = null ) {
2019-12-31 14:08:08 +01:00
url = url + " . " + getHttpUrlExtension ( object . path , " jpg " ) ;
2020-12-23 08:48:30 +01:00
} else if ( object . photoSize instanceof TLRPC . TL_photoStrippedSize | | object . photoSize instanceof TLRPC . TL_photoPathSize ) {
2019-12-31 14:08:08 +01:00
url = url + " . " + ext ;
2019-05-14 14:08:05 +02:00
} else if ( object . location ! = null ) {
2019-12-31 14:08:08 +01:00
url = url + " . " + ext ;
2019-05-14 14:08:05 +02:00
if ( imageReceiver . getExt ( ) ! = null | | object . location . key ! = null | | object . location . volume_id = = Integer . MIN_VALUE & & object . location . local_id < 0 ) {
2019-01-23 18:03:33 +01:00
saveImageToCache = true ;
}
2019-05-14 14:08:05 +02:00
} else if ( object . webFile ! = null ) {
String defaultExt = FileLoader . getMimeTypePart ( object . webFile . mime_type ) ;
2019-12-31 14:08:08 +01:00
url = url + " . " + getHttpUrlExtension ( object . webFile . url , defaultExt ) ;
2019-05-14 14:08:05 +02:00
} else if ( object . secureDocument ! = null ) {
2019-12-31 14:08:08 +01:00
url = url + " . " + ext ;
2019-05-14 14:08:05 +02:00
} else if ( object . document ! = null ) {
if ( a = = 0 & & qualityThumb ) {
key = " q_ " + key ;
}
String docExt = FileLoader . getDocumentFileName ( object . document ) ;
int idx ;
2021-09-20 07:54:41 +02:00
if ( ( idx = docExt . lastIndexOf ( '.' ) ) = = - 1 ) {
2019-05-14 14:08:05 +02:00
docExt = " " ;
} else {
docExt = docExt . substring ( idx ) ;
}
if ( docExt . length ( ) < = 1 ) {
if ( " video/mp4 " . equals ( object . document . mime_type ) ) {
docExt = " .mp4 " ;
} else if ( " video/x-matroska " . equals ( object . document . mime_type ) ) {
docExt = " .mkv " ;
2016-03-06 02:49:31 +01:00
} else {
2015-05-21 23:27:27 +02:00
docExt = " " ;
2019-01-23 18:03:33 +01:00
}
2015-05-21 23:27:27 +02:00
}
2019-12-31 14:08:08 +01:00
url = url + docExt ;
2019-05-14 14:08:05 +02:00
saveImageToCache = ! MessageObject . isVideoDocument ( object . document ) & & ! MessageObject . isGifDocument ( object . document ) & & ! MessageObject . isRoundVideoDocument ( object . document ) & & ! MessageObject . canPreviewDocument ( object . document ) ;
2015-02-01 19:51:02 +01:00
}
2019-03-03 21:40:48 +01:00
if ( a = = 0 ) {
imageKey = key ;
imageUrl = url ;
} else {
mediaKey = key ;
mediaUrl = url ;
}
if ( object = = thumbLocation ) {
if ( a = = 0 ) {
imageLocation = null ;
imageKey = null ;
imageUrl = null ;
} else {
mediaLocation = null ;
mediaKey = null ;
mediaUrl = null ;
}
2014-08-22 16:24:33 +02:00
}
}
2019-05-14 14:08:05 +02:00
if ( thumbLocation ! = null ) {
2019-06-04 12:14:50 +02:00
ImageLocation strippedLoc = imageReceiver . getStrippedLocation ( ) ;
if ( strippedLoc = = null ) {
2020-07-26 10:03:38 +02:00
strippedLoc = mediaLocation ! = null ? mediaLocation : originalImageLocation ;
2019-06-04 12:14:50 +02:00
}
2019-12-31 14:08:08 +01:00
thumbKey = thumbLocation . getKey ( parentObject , strippedLoc , false ) ;
thumbUrl = thumbLocation . getKey ( parentObject , strippedLoc , true ) ;
2019-05-14 14:08:05 +02:00
if ( thumbLocation . path ! = null ) {
2019-12-31 14:08:08 +01:00
thumbUrl = thumbUrl + " . " + getHttpUrlExtension ( thumbLocation . path , " jpg " ) ;
2020-12-23 08:48:30 +01:00
} else if ( thumbLocation . photoSize instanceof TLRPC . TL_photoStrippedSize | | thumbLocation . photoSize instanceof TLRPC . TL_photoPathSize ) {
2020-06-04 18:47:15 +02:00
thumbUrl = thumbUrl + " . " + thumbExt ;
2019-05-14 14:08:05 +02:00
} else if ( thumbLocation . location ! = null ) {
2020-06-04 18:47:15 +02:00
thumbUrl = thumbUrl + " . " + thumbExt ;
2019-05-14 14:08:05 +02:00
}
2014-08-22 16:24:33 +02:00
}
2019-03-03 21:40:48 +01:00
if ( mediaKey ! = null & & mediaFilter ! = null ) {
mediaKey + = " @ " + mediaFilter ;
}
if ( imageKey ! = null & & imageFilter ! = null ) {
imageKey + = " @ " + imageFilter ;
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
if ( thumbKey ! = null & & thumbFilter ! = null ) {
thumbKey + = " @ " + thumbFilter ;
2014-08-22 16:24:33 +02:00
}
2021-09-20 07:54:41 +02:00
if ( imageReceiver . getUniqKeyPrefix ( ) ! = null ) {
imageKey = imageReceiver . getUniqKeyPrefix ( ) + imageKey ;
}
2019-05-14 14:08:05 +02:00
if ( imageLocation ! = null & & imageLocation . path ! = null ) {
2020-06-04 18:47:15 +02:00
createLoadOperationForImageReceiver ( imageReceiver , thumbKey , thumbUrl , thumbExt , thumbLocation , thumbFilter , 0 , 1 , ImageReceiver . TYPE_THUMB , thumbSet ? 2 : 1 , guid ) ;
createLoadOperationForImageReceiver ( imageReceiver , imageKey , imageUrl , imageExt , imageLocation , imageFilter , imageReceiver . getSize ( ) , 1 , ImageReceiver . TYPE_IMAGE , 0 , guid ) ;
2019-03-03 21:40:48 +01:00
} else if ( mediaLocation ! = null ) {
int mediaCacheType = imageReceiver . getCacheType ( ) ;
int imageCacheType = 1 ;
if ( mediaCacheType = = 0 & & saveImageToCache ) {
mediaCacheType = 1 ;
}
int thumbCacheType = mediaCacheType = = 0 ? 1 : mediaCacheType ;
if ( ! thumbSet ) {
2021-09-20 07:54:41 +02:00
createLoadOperationForImageReceiver ( imageReceiver , thumbKey , thumbUrl , thumbExt , thumbLocation , thumbFilter , 0 , thumbCacheType , ImageReceiver . TYPE_THUMB , 1 , guid ) ;
2019-03-03 21:40:48 +01:00
}
if ( ! imageSet ) {
2020-06-04 18:47:15 +02:00
createLoadOperationForImageReceiver ( imageReceiver , imageKey , imageUrl , imageExt , imageLocation , imageFilter , 0 , imageCacheType , ImageReceiver . TYPE_IMAGE , 0 , guid ) ;
2019-03-03 21:40:48 +01:00
}
2020-06-04 18:47:15 +02:00
createLoadOperationForImageReceiver ( imageReceiver , mediaKey , mediaUrl , mediaExt , mediaLocation , mediaFilter , imageReceiver . getSize ( ) , mediaCacheType , ImageReceiver . TYPE_MEDIA , 0 , guid ) ;
2015-02-01 19:51:02 +01:00
} else {
2019-03-03 21:40:48 +01:00
int imageCacheType = imageReceiver . getCacheType ( ) ;
if ( imageCacheType = = 0 & & saveImageToCache ) {
imageCacheType = 1 ;
2017-07-23 14:56:38 +02:00
}
2019-03-03 21:40:48 +01:00
int thumbCacheType = imageCacheType = = 0 ? 1 : imageCacheType ;
2020-06-04 18:47:15 +02:00
createLoadOperationForImageReceiver ( imageReceiver , thumbKey , thumbUrl , thumbExt , thumbLocation , thumbFilter , 0 , thumbCacheType , ImageReceiver . TYPE_THUMB , thumbSet ? 2 : 1 , guid ) ;
createLoadOperationForImageReceiver ( imageReceiver , imageKey , imageUrl , imageExt , imageLocation , imageFilter , imageReceiver . getSize ( ) , imageCacheType , ImageReceiver . TYPE_IMAGE , 0 , guid ) ;
2015-02-01 19:51:02 +01:00
}
}
private void httpFileLoadError ( final String location ) {
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > {
CacheImage img = imageLoadingByUrl . get ( location ) ;
if ( img = = null ) {
return ;
2014-08-22 16:24:33 +02:00
}
2018-08-27 10:33:11 +02:00
HttpImageTask oldTask = img . httpTask ;
2020-12-23 08:48:30 +01:00
if ( oldTask ! = null ) {
img . httpTask = new HttpImageTask ( oldTask . cacheImage , oldTask . imageSize ) ;
httpTasks . add ( img . httpTask ) ;
}
2018-08-27 10:33:11 +02:00
runHttpTasks ( false ) ;
2015-02-01 19:51:02 +01:00
} ) ;
}
2019-01-23 18:03:33 +01:00
private void artworkLoadError ( final String location ) {
imageLoadQueue . postRunnable ( ( ) - > {
CacheImage img = imageLoadingByUrl . get ( location ) ;
if ( img = = null ) {
return ;
}
ArtworkLoadTask oldTask = img . artworkTask ;
2020-12-23 08:48:30 +01:00
if ( oldTask ! = null ) {
img . artworkTask = new ArtworkLoadTask ( oldTask . cacheImage ) ;
artworkTasks . add ( img . artworkTask ) ;
}
2019-01-23 18:03:33 +01:00
runArtworkTasks ( false ) ;
} ) ;
}
2019-12-31 14:08:08 +01:00
private void fileDidLoaded ( final String location , final File finalFile , final int mediaType ) {
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > {
ThumbGenerateInfo info = waitingForQualityThumb . get ( location ) ;
2019-01-23 18:03:33 +01:00
if ( info ! = null & & info . parentDocument ! = null ) {
2019-12-31 14:08:08 +01:00
generateThumb ( mediaType , finalFile , info ) ;
2018-08-27 10:33:11 +02:00
waitingForQualityThumb . remove ( location ) ;
}
CacheImage img = imageLoadingByUrl . get ( location ) ;
if ( img = = null ) {
return ;
}
imageLoadingByUrl . remove ( location ) ;
ArrayList < CacheOutTask > tasks = new ArrayList < > ( ) ;
for ( int a = 0 ; a < img . imageReceiverArray . size ( ) ; a + + ) {
String key = img . keys . get ( a ) ;
String filter = img . filters . get ( a ) ;
2019-12-31 14:08:08 +01:00
int type = img . types . get ( a ) ;
2018-08-27 10:33:11 +02:00
ImageReceiver imageReceiver = img . imageReceiverArray . get ( a ) ;
2019-07-18 15:01:39 +02:00
int guid = img . imageReceiverGuidsArray . get ( a ) ;
2018-08-27 10:33:11 +02:00
CacheImage cacheImage = imageLoadingByKeys . get ( key ) ;
if ( cacheImage = = null ) {
cacheImage = new CacheImage ( ) ;
cacheImage . secureDocument = img . secureDocument ;
cacheImage . currentAccount = img . currentAccount ;
cacheImage . finalFilePath = finalFile ;
2020-04-24 11:21:58 +02:00
cacheImage . parentObject = img . parentObject ;
2018-08-27 10:33:11 +02:00
cacheImage . key = key ;
2019-05-14 14:08:05 +02:00
cacheImage . imageLocation = img . imageLocation ;
2019-12-31 14:08:08 +01:00
cacheImage . type = type ;
2018-08-27 10:33:11 +02:00
cacheImage . ext = img . ext ;
cacheImage . encryptionKeyPath = img . encryptionKeyPath ;
cacheImage . cacheTask = new CacheOutTask ( cacheImage ) ;
cacheImage . filter = filter ;
2019-12-31 14:08:08 +01:00
cacheImage . imageType = img . imageType ;
2018-08-27 10:33:11 +02:00
imageLoadingByKeys . put ( key , cacheImage ) ;
tasks . add ( cacheImage . cacheTask ) ;
}
2019-12-31 14:08:08 +01:00
cacheImage . addImageReceiver ( imageReceiver , key , filter , type , guid ) ;
2018-08-27 10:33:11 +02:00
}
for ( int a = 0 ; a < tasks . size ( ) ; a + + ) {
CacheOutTask task = tasks . get ( a ) ;
2019-12-31 14:08:08 +01:00
if ( task . cacheImage . type = = ImageReceiver . TYPE_THUMB ) {
2018-08-27 10:33:11 +02:00
cacheThumbOutQueue . postRunnable ( task ) ;
} else {
cacheOutQueue . postRunnable ( task ) ;
2014-08-22 16:24:33 +02:00
}
}
2015-02-01 19:51:02 +01:00
} ) ;
2015-01-02 23:15:07 +01:00
}
2015-02-01 19:51:02 +01:00
private void fileDidFailedLoad ( final String location , int canceled ) {
if ( canceled = = 1 ) {
2014-08-22 16:24:33 +02:00
return ;
}
2018-08-27 10:33:11 +02:00
imageLoadQueue . postRunnable ( ( ) - > {
CacheImage img = imageLoadingByUrl . get ( location ) ;
if ( img ! = null ) {
2019-05-14 14:08:05 +02:00
img . setImageAndClear ( null , null ) ;
2014-08-22 16:24:33 +02:00
}
2015-02-01 19:51:02 +01:00
} ) ;
2014-08-22 16:24:33 +02:00
}
private void runHttpTasks ( boolean complete ) {
if ( complete ) {
currentHttpTasksCount - - ;
}
2016-01-11 18:19:48 +01:00
while ( currentHttpTasksCount < 4 & & ! httpTasks . isEmpty ( ) ) {
2015-01-02 23:15:07 +01:00
HttpImageTask task = httpTasks . poll ( ) ;
2019-01-23 18:03:33 +01:00
if ( task ! = null ) {
task . executeOnExecutor ( AsyncTask . THREAD_POOL_EXECUTOR , null , null , null ) ;
currentHttpTasksCount + + ;
}
}
}
private void runArtworkTasks ( boolean complete ) {
if ( complete ) {
currentArtworkTasksCount - - ;
}
while ( currentArtworkTasksCount < 4 & & ! artworkTasks . isEmpty ( ) ) {
try {
ArtworkLoadTask task = artworkTasks . poll ( ) ;
task . executeOnExecutor ( AsyncTask . THREAD_POOL_EXECUTOR , null , null , null ) ;
currentArtworkTasksCount + + ;
} catch ( Throwable ignore ) {
runArtworkTasks ( false ) ;
}
2014-08-22 16:24:33 +02:00
}
}
2016-10-11 13:57:01 +02:00
public boolean isLoadingHttpFile ( String url ) {
return httpFileLoadTasksByKeys . containsKey ( url ) ;
}
2019-01-23 18:03:33 +01:00
public static String getHttpFileName ( String url ) {
return Utilities . MD5 ( url ) ;
}
public static File getHttpFilePath ( String url , String defaultExt ) {
String ext = getHttpUrlExtension ( url , defaultExt ) ;
return new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , Utilities . MD5 ( url ) + " . " + ext ) ;
}
2018-07-30 04:07:02 +02:00
public void loadHttpFile ( String url , String defaultExt , int currentAccount ) {
2015-01-02 23:15:07 +01:00
if ( url = = null | | url . length ( ) = = 0 | | httpFileLoadTasksByKeys . containsKey ( url ) ) {
return ;
}
2016-04-22 15:49:00 +02:00
String ext = getHttpUrlExtension ( url , defaultExt ) ;
2018-07-30 04:07:02 +02:00
File file = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , Utilities . MD5 ( url ) + " _temp. " + ext ) ;
2015-01-02 23:15:07 +01:00
file . delete ( ) ;
2018-07-30 04:07:02 +02:00
HttpFileTask task = new HttpFileTask ( url , file , ext , currentAccount ) ;
2015-01-02 23:15:07 +01:00
httpFileLoadTasks . add ( task ) ;
httpFileLoadTasksByKeys . put ( url , task ) ;
runHttpFileLoadTasks ( null , 0 ) ;
}
public void cancelLoadHttpFile ( String url ) {
HttpFileTask task = httpFileLoadTasksByKeys . get ( url ) ;
if ( task ! = null ) {
task . cancel ( true ) ;
httpFileLoadTasksByKeys . remove ( url ) ;
httpFileLoadTasks . remove ( task ) ;
}
Runnable runnable = retryHttpsTasks . get ( url ) ;
if ( runnable ! = null ) {
AndroidUtilities . cancelRunOnUIThread ( runnable ) ;
}
runHttpFileLoadTasks ( null , 0 ) ;
}
2015-02-26 02:32:51 +01:00
private void runHttpFileLoadTasks ( final HttpFileTask oldTask , final int reason ) {
2018-08-27 10:33:11 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > {
if ( oldTask ! = null ) {
currentHttpFileLoadTasksCount - - ;
}
if ( oldTask ! = null ) {
if ( reason = = 1 ) {
if ( oldTask . canRetry ) {
final HttpFileTask newTask = new HttpFileTask ( oldTask . url , oldTask . tempFile , oldTask . ext , oldTask . currentAccount ) ;
Runnable runnable = ( ) - > {
httpFileLoadTasks . add ( newTask ) ;
runHttpFileLoadTasks ( null , 0 ) ;
} ;
retryHttpsTasks . put ( oldTask . url , runnable ) ;
AndroidUtilities . runOnUIThread ( runnable , 1000 ) ;
} else {
2015-02-26 02:32:51 +01:00
httpFileLoadTasksByKeys . remove ( oldTask . url ) ;
2018-08-27 10:33:11 +02:00
NotificationCenter . getInstance ( oldTask . currentAccount ) . postNotificationName ( NotificationCenter . httpFileDidFailedLoad , oldTask . url , 0 ) ;
2015-02-26 02:32:51 +01:00
}
2018-08-27 10:33:11 +02:00
} else if ( reason = = 2 ) {
httpFileLoadTasksByKeys . remove ( oldTask . url ) ;
File file = new File ( FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) , Utilities . MD5 ( oldTask . url ) + " . " + oldTask . ext ) ;
String result = oldTask . tempFile . renameTo ( file ) ? file . toString ( ) : oldTask . tempFile . toString ( ) ;
2019-01-23 18:03:33 +01:00
NotificationCenter . getInstance ( oldTask . currentAccount ) . postNotificationName ( NotificationCenter . httpFileDidLoad , oldTask . url , result ) ;
2015-02-26 02:32:51 +01:00
}
2018-08-27 10:33:11 +02:00
}
while ( currentHttpFileLoadTasksCount < 2 & & ! httpFileLoadTasks . isEmpty ( ) ) {
HttpFileTask task = httpFileLoadTasks . poll ( ) ;
task . executeOnExecutor ( AsyncTask . THREAD_POOL_EXECUTOR , null , null , null ) ;
currentHttpFileLoadTasksCount + + ;
2015-01-02 23:15:07 +01:00
}
2015-02-26 02:32:51 +01:00
} ) ;
2015-01-02 23:15:07 +01:00
}
2019-01-23 18:03:33 +01:00
public static boolean shouldSendImageAsDocument ( String path , Uri uri ) {
BitmapFactory . Options bmOptions = new BitmapFactory . Options ( ) ;
bmOptions . inJustDecodeBounds = true ;
if ( path = = null & & uri ! = null & & uri . getScheme ( ) ! = null ) {
String imageFilePath = null ;
if ( uri . getScheme ( ) . contains ( " file " ) ) {
path = uri . getPath ( ) ;
} else {
try {
path = AndroidUtilities . getPath ( uri ) ;
} catch ( Throwable e ) {
FileLog . e ( e ) ;
}
}
}
if ( path ! = null ) {
BitmapFactory . decodeFile ( path , bmOptions ) ;
} else if ( uri ! = null ) {
boolean error = false ;
try {
InputStream inputStream = ApplicationLoader . applicationContext . getContentResolver ( ) . openInputStream ( uri ) ;
BitmapFactory . decodeStream ( inputStream , null , bmOptions ) ;
inputStream . close ( ) ;
} catch ( Throwable e ) {
FileLog . e ( e ) ;
return false ;
}
}
float photoW = bmOptions . outWidth ;
float photoH = bmOptions . outHeight ;
return photoW / photoH > 10 . 0f | | photoH / photoW > 10 . 0f ;
}
2015-02-01 19:51:02 +01:00
public static Bitmap loadBitmap ( String path , Uri uri , float maxWidth , float maxHeight , boolean useMaxScale ) {
2014-08-22 16:24:33 +02:00
BitmapFactory . Options bmOptions = new BitmapFactory . Options ( ) ;
bmOptions . inJustDecodeBounds = true ;
2016-03-16 13:26:32 +01:00
InputStream inputStream = null ;
2014-08-22 16:24:33 +02:00
if ( path = = null & & uri ! = null & & uri . getScheme ( ) ! = null ) {
String imageFilePath = null ;
if ( uri . getScheme ( ) . contains ( " file " ) ) {
path = uri . getPath ( ) ;
2021-03-19 11:25:58 +01:00
} else if ( Build . VERSION . SDK_INT < 30 | | ! " content " . equals ( uri . getScheme ( ) ) ) {
2014-08-22 16:24:33 +02:00
try {
2015-05-21 23:27:27 +02:00
path = AndroidUtilities . getPath ( uri ) ;
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
}
}
if ( path ! = null ) {
BitmapFactory . decodeFile ( path , bmOptions ) ;
} else if ( uri ! = null ) {
boolean error = false ;
try {
2016-03-16 13:26:32 +01:00
inputStream = ApplicationLoader . applicationContext . getContentResolver ( ) . openInputStream ( uri ) ;
BitmapFactory . decodeStream ( inputStream , null , bmOptions ) ;
inputStream . close ( ) ;
inputStream = ApplicationLoader . applicationContext . getContentResolver ( ) . openInputStream ( uri ) ;
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
return null ;
}
}
float photoW = bmOptions . outWidth ;
float photoH = bmOptions . outHeight ;
2015-02-01 19:51:02 +01:00
float scaleFactor = useMaxScale ? Math . max ( photoW / maxWidth , photoH / maxHeight ) : Math . min ( photoW / maxWidth , photoH / maxHeight ) ;
2014-08-22 16:24:33 +02:00
if ( scaleFactor < 1 ) {
scaleFactor = 1 ;
}
bmOptions . inJustDecodeBounds = false ;
2015-05-03 13:48:36 +02:00
bmOptions . inSampleSize = ( int ) scaleFactor ;
2017-07-08 18:32:04 +02:00
if ( bmOptions . inSampleSize % 2 ! = 0 ) {
int sample = 1 ;
while ( sample * 2 < bmOptions . inSampleSize ) {
sample * = 2 ;
}
bmOptions . inSampleSize = sample ;
}
2016-06-24 12:27:15 +02:00
bmOptions . inPurgeable = Build . VERSION . SDK_INT < 21 ;
2014-08-22 16:24:33 +02:00
Matrix matrix = null ;
2021-03-19 11:25:58 +01:00
try {
int orientation = 0 ;
if ( path ! = null ) {
ExifInterface exif = new ExifInterface ( path ) ;
orientation = exif . getAttributeInt ( ExifInterface . TAG_ORIENTATION , ExifInterface . ORIENTATION_NORMAL ) ;
} else if ( uri ! = null ) {
try ( InputStream stream = ApplicationLoader . applicationContext . getContentResolver ( ) . openInputStream ( uri ) ) {
ExifInterface exif = new ExifInterface ( stream ) ;
orientation = exif . getAttributeInt ( ExifInterface . TAG_ORIENTATION , ExifInterface . ORIENTATION_NORMAL ) ;
} catch ( Throwable ignore ) {
2014-08-22 16:24:33 +02:00
}
}
2021-03-19 11:25:58 +01:00
switch ( orientation ) {
case ExifInterface . ORIENTATION_ROTATE_90 :
matrix = new Matrix ( ) ;
matrix . postRotate ( 90 ) ;
break ;
case ExifInterface . ORIENTATION_ROTATE_180 :
matrix = new Matrix ( ) ;
matrix . postRotate ( 180 ) ;
break ;
case ExifInterface . ORIENTATION_ROTATE_270 :
matrix = new Matrix ( ) ;
matrix . postRotate ( 270 ) ;
break ;
}
} catch ( Throwable ignore ) {
2014-08-22 16:24:33 +02:00
}
2020-06-04 18:47:15 +02:00
scaleFactor / = bmOptions . inSampleSize ;
if ( scaleFactor > 1 ) {
if ( matrix = = null ) {
matrix = new Matrix ( ) ;
}
matrix . postScale ( 1 . 0f / scaleFactor , 1 . 0f / scaleFactor ) ;
}
2014-08-22 16:24:33 +02:00
Bitmap b = null ;
if ( path ! = null ) {
try {
b = BitmapFactory . decodeFile ( path , bmOptions ) ;
if ( b ! = null ) {
2015-10-29 18:10:07 +01:00
if ( bmOptions . inPurgeable ) {
Utilities . pinBitmap ( b ) ;
}
Bitmap newBitmap = Bitmaps . createBitmap ( b , 0 , 0 , b . getWidth ( ) , b . getHeight ( ) , matrix , true ) ;
if ( newBitmap ! = b ) {
b . recycle ( ) ;
b = newBitmap ;
}
2014-08-22 16:24:33 +02:00
}
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
ImageLoader . getInstance ( ) . clearMemory ( ) ;
2014-10-01 21:55:24 +02:00
try {
if ( b = = null ) {
b = BitmapFactory . decodeFile ( path , bmOptions ) ;
2015-10-29 18:10:07 +01:00
if ( b ! = null & & bmOptions . inPurgeable ) {
Utilities . pinBitmap ( b ) ;
}
2014-10-01 21:55:24 +02:00
}
if ( b ! = null ) {
2015-10-29 18:10:07 +01:00
Bitmap newBitmap = Bitmaps . createBitmap ( b , 0 , 0 , b . getWidth ( ) , b . getHeight ( ) , matrix , true ) ;
if ( newBitmap ! = b ) {
b . recycle ( ) ;
b = newBitmap ;
}
2014-10-01 21:55:24 +02:00
}
} catch ( Throwable e2 ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e2 ) ;
2014-08-22 16:24:33 +02:00
}
}
} else if ( uri ! = null ) {
try {
2016-03-16 13:26:32 +01:00
b = BitmapFactory . decodeStream ( inputStream , null , bmOptions ) ;
2014-08-22 16:24:33 +02:00
if ( b ! = null ) {
2015-10-29 18:10:07 +01:00
if ( bmOptions . inPurgeable ) {
Utilities . pinBitmap ( b ) ;
}
Bitmap newBitmap = Bitmaps . createBitmap ( b , 0 , 0 , b . getWidth ( ) , b . getHeight ( ) , matrix , true ) ;
if ( newBitmap ! = b ) {
b . recycle ( ) ;
b = newBitmap ;
}
2014-08-22 16:24:33 +02:00
}
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
} finally {
try {
2016-03-16 13:26:32 +01:00
inputStream . close ( ) ;
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-08-22 16:24:33 +02:00
}
}
}
return b ;
}
2015-05-21 23:27:27 +02:00
public static void fillPhotoSizeWithBytes ( TLRPC . PhotoSize photoSize ) {
2019-01-23 18:03:33 +01:00
if ( photoSize = = null | | photoSize . bytes ! = null & & photoSize . bytes . length ! = 0 ) {
2015-05-21 23:27:27 +02:00
return ;
}
File file = FileLoader . getPathToAttach ( photoSize , true ) ;
try {
RandomAccessFile f = new RandomAccessFile ( file , " r " ) ;
int len = ( int ) f . length ( ) ;
if ( len < 20000 ) {
photoSize . bytes = new byte [ ( int ) f . length ( ) ] ;
f . readFully ( photoSize . bytes , 0 , photoSize . bytes . length ) ;
}
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-05-21 23:27:27 +02:00
}
}
2020-09-30 15:48:47 +02:00
private static TLRPC . PhotoSize scaleAndSaveImageInternal ( TLRPC . PhotoSize photoSize , Bitmap bitmap , Bitmap . CompressFormat compressFormat , boolean progressive , int w , int h , float photoW , float photoH , float scaleFactor , int quality , boolean cache , boolean scaleAnyway , boolean forceCacheDir ) throws Exception {
2015-05-21 23:27:27 +02:00
Bitmap scaledBitmap ;
2014-11-17 23:04:31 +01:00
if ( scaleFactor > 1 | | scaleAnyway ) {
2015-10-29 18:10:07 +01:00
scaledBitmap = Bitmaps . createScaledBitmap ( bitmap , w , h , true ) ;
2014-10-01 21:55:24 +02:00
} else {
scaledBitmap = bitmap ;
}
2014-08-22 16:24:33 +02:00
2019-01-23 18:03:33 +01:00
boolean check = photoSize ! = null ;
2019-05-14 14:08:05 +02:00
TLRPC . TL_fileLocationToBeDeprecated location ;
if ( photoSize = = null | | ! ( photoSize . location instanceof TLRPC . TL_fileLocationToBeDeprecated ) ) {
location = new TLRPC . TL_fileLocationToBeDeprecated ( ) ;
2019-01-23 18:03:33 +01:00
location . volume_id = Integer . MIN_VALUE ;
location . dc_id = Integer . MIN_VALUE ;
location . local_id = SharedConfig . getLastLocalId ( ) ;
location . file_reference = new byte [ 0 ] ;
2021-06-25 02:43:10 +02:00
photoSize = new TLRPC . TL_photoSize_layer127 ( ) ;
2019-01-23 18:03:33 +01:00
photoSize . location = location ;
photoSize . w = scaledBitmap . getWidth ( ) ;
photoSize . h = scaledBitmap . getHeight ( ) ;
if ( photoSize . w < = 100 & & photoSize . h < = 100 ) {
photoSize . type = " s " ;
} else if ( photoSize . w < = 320 & & photoSize . h < = 320 ) {
photoSize . type = " m " ;
} else if ( photoSize . w < = 800 & & photoSize . h < = 800 ) {
photoSize . type = " x " ;
} else if ( photoSize . w < = 1280 & & photoSize . h < = 1280 ) {
photoSize . type = " y " ;
} else {
photoSize . type = " w " ;
}
2014-10-01 21:55:24 +02:00
} else {
2019-05-14 14:08:05 +02:00
location = ( TLRPC . TL_fileLocationToBeDeprecated ) photoSize . location ;
2014-10-01 21:55:24 +02:00
}
2014-09-30 00:48:11 +02:00
2015-02-01 19:51:02 +01:00
String fileName = location . volume_id + " _ " + location . local_id + " .jpg " ;
2019-12-31 14:08:08 +01:00
File fileDir ;
if ( forceCacheDir ) {
fileDir = FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) ;
} else {
fileDir = location . volume_id ! = Integer . MIN_VALUE ? FileLoader . getDirectory ( FileLoader . MEDIA_DIR_IMAGE ) : FileLoader . getDirectory ( FileLoader . MEDIA_DIR_CACHE ) ;
}
final File cacheFile = new File ( fileDir , fileName ) ;
2020-12-24 06:36:01 +01:00
if ( compressFormat = = Bitmap . CompressFormat . JPEG & & progressive & & BuildVars . DEBUG_VERSION ) {
2020-09-30 15:48:47 +02:00
photoSize . size = Utilities . saveProgressiveJpeg ( scaledBitmap , scaledBitmap . getWidth ( ) , scaledBitmap . getHeight ( ) , scaledBitmap . getRowBytes ( ) , quality , cacheFile . getAbsolutePath ( ) ) ;
} else {
FileOutputStream stream = new FileOutputStream ( cacheFile ) ;
scaledBitmap . compress ( compressFormat , quality , stream ) ;
if ( ! cache ) {
photoSize . size = ( int ) stream . getChannel ( ) . size ( ) ;
}
stream . close ( ) ;
}
2015-02-01 19:51:02 +01:00
if ( cache ) {
ByteArrayOutputStream stream2 = new ByteArrayOutputStream ( ) ;
2020-06-04 18:47:15 +02:00
scaledBitmap . compress ( compressFormat , quality , stream2 ) ;
2019-01-23 18:03:33 +01:00
photoSize . bytes = stream2 . toByteArray ( ) ;
photoSize . size = photoSize . bytes . length ;
2015-02-01 19:51:02 +01:00
stream2 . close ( ) ;
2014-09-30 00:48:11 +02:00
}
if ( scaledBitmap ! = bitmap ) {
scaledBitmap . recycle ( ) ;
}
2019-01-23 18:03:33 +01:00
return photoSize ;
2014-09-30 00:48:11 +02:00
}
public static TLRPC . PhotoSize scaleAndSaveImage ( Bitmap bitmap , float maxWidth , float maxHeight , int quality , boolean cache ) {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImage ( null , bitmap , Bitmap . CompressFormat . JPEG , false , maxWidth , maxHeight , quality , cache , 0 , 0 , false ) ;
2019-01-23 18:03:33 +01:00
}
2019-12-31 14:08:08 +01:00
public static TLRPC . PhotoSize scaleAndSaveImage ( TLRPC . PhotoSize photoSize , Bitmap bitmap , float maxWidth , float maxHeight , int quality , boolean cache , boolean forceCacheDir ) {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImage ( photoSize , bitmap , Bitmap . CompressFormat . JPEG , false , maxWidth , maxHeight , quality , cache , 0 , 0 , forceCacheDir ) ;
2014-11-17 23:04:31 +01:00
}
public static TLRPC . PhotoSize scaleAndSaveImage ( Bitmap bitmap , float maxWidth , float maxHeight , int quality , boolean cache , int minWidth , int minHeight ) {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImage ( null , bitmap , Bitmap . CompressFormat . JPEG , false , maxWidth , maxHeight , quality , cache , minWidth , minHeight , false ) ;
}
public static TLRPC . PhotoSize scaleAndSaveImage ( Bitmap bitmap , float maxWidth , float maxHeight , boolean progressive , int quality , boolean cache , int minWidth , int minHeight ) {
return scaleAndSaveImage ( null , bitmap , Bitmap . CompressFormat . JPEG , progressive , maxWidth , maxHeight , quality , cache , minWidth , minHeight , false ) ;
2020-06-04 18:47:15 +02:00
}
public static TLRPC . PhotoSize scaleAndSaveImage ( Bitmap bitmap , Bitmap . CompressFormat compressFormat , float maxWidth , float maxHeight , int quality , boolean cache , int minWidth , int minHeight ) {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImage ( null , bitmap , compressFormat , false , maxWidth , maxHeight , quality , cache , minWidth , minHeight , false ) ;
2019-01-23 18:03:33 +01:00
}
2020-09-30 15:48:47 +02:00
public static TLRPC . PhotoSize scaleAndSaveImage ( TLRPC . PhotoSize photoSize , Bitmap bitmap , Bitmap . CompressFormat compressFormat , boolean progressive , float maxWidth , float maxHeight , int quality , boolean cache , int minWidth , int minHeight , boolean forceCacheDir ) {
2014-09-30 00:48:11 +02:00
if ( bitmap = = null ) {
return null ;
}
float photoW = bitmap . getWidth ( ) ;
float photoH = bitmap . getHeight ( ) ;
if ( photoW = = 0 | | photoH = = 0 ) {
return null ;
}
2014-11-17 23:04:31 +01:00
boolean scaleAnyway = false ;
2014-09-30 00:48:11 +02:00
float scaleFactor = Math . max ( photoW / maxWidth , photoH / maxHeight ) ;
2015-01-02 23:15:07 +01:00
if ( minWidth ! = 0 & & minHeight ! = 0 & & ( photoW < minWidth | | photoH < minHeight ) ) {
2015-05-03 13:48:36 +02:00
if ( photoW < minWidth & & photoH > minHeight ) {
scaleFactor = photoW / minWidth ;
} else if ( photoW > minWidth & & photoH < minHeight ) {
scaleFactor = photoH / minHeight ;
} else {
scaleFactor = Math . max ( photoW / minWidth , photoH / minHeight ) ;
}
2014-11-17 23:04:31 +01:00
scaleAnyway = true ;
}
2015-05-03 13:48:36 +02:00
int w = ( int ) ( photoW / scaleFactor ) ;
int h = ( int ) ( photoH / scaleFactor ) ;
2014-09-30 00:48:11 +02:00
if ( h = = 0 | | w = = 0 ) {
return null ;
}
2014-08-22 16:24:33 +02:00
try {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImageInternal ( photoSize , bitmap , compressFormat , progressive , w , h , photoW , photoH , scaleFactor , quality , cache , scaleAnyway , forceCacheDir ) ;
2014-09-14 01:40:36 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-09-30 00:48:11 +02:00
ImageLoader . getInstance ( ) . clearMemory ( ) ;
System . gc ( ) ;
try {
2020-09-30 15:48:47 +02:00
return scaleAndSaveImageInternal ( photoSize , bitmap , compressFormat , progressive , w , h , photoW , photoH , scaleFactor , quality , cache , scaleAnyway , forceCacheDir ) ;
2014-09-30 00:48:11 +02:00
} catch ( Throwable e2 ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e2 ) ;
2014-09-30 00:48:11 +02:00
return null ;
}
2014-08-22 16:24:33 +02:00
}
}
2015-01-02 23:15:07 +01:00
2016-03-06 02:49:31 +01:00
public static String getHttpUrlExtension ( String url , String defaultExt ) {
2015-01-02 23:15:07 +01:00
String ext = null ;
2017-12-08 18:35:59 +01:00
String last = Uri . parse ( url ) . getLastPathSegment ( ) ;
if ( ! TextUtils . isEmpty ( last ) & & last . length ( ) > 1 ) {
url = last ;
}
2016-04-22 15:49:00 +02:00
int idx = url . lastIndexOf ( '.' ) ;
2015-01-02 23:15:07 +01:00
if ( idx ! = - 1 ) {
ext = url . substring ( idx + 1 ) ;
}
if ( ext = = null | | ext . length ( ) = = 0 | | ext . length ( ) > 4 ) {
2016-03-06 02:49:31 +01:00
ext = defaultExt ;
2015-01-02 23:15:07 +01:00
}
return ext ;
}
2015-02-01 19:51:02 +01:00
public static void saveMessageThumbs ( TLRPC . Message message ) {
2019-12-31 14:08:08 +01:00
if ( message . media = = null ) {
return ;
2015-02-01 19:51:02 +01:00
}
2019-12-31 14:08:08 +01:00
TLRPC . PhotoSize photoSize = findPhotoCachedSize ( message ) ;
2015-02-01 19:51:02 +01:00
if ( photoSize ! = null & & photoSize . bytes ! = null & & photoSize . bytes . length ! = 0 ) {
2019-01-23 18:03:33 +01:00
if ( photoSize . location = = null | | photoSize . location instanceof TLRPC . TL_fileLocationUnavailable ) {
2019-05-14 14:08:05 +02:00
photoSize . location = new TLRPC . TL_fileLocationToBeDeprecated ( ) ;
2015-02-01 19:51:02 +01:00
photoSize . location . volume_id = Integer . MIN_VALUE ;
2018-07-30 04:07:02 +02:00
photoSize . location . local_id = SharedConfig . getLastLocalId ( ) ;
2015-02-01 19:51:02 +01:00
}
File file = FileLoader . getPathToAttach ( photoSize , true ) ;
2017-07-23 14:56:38 +02:00
boolean isEncrypted = false ;
if ( MessageObject . shouldEncryptPhotoOrVideo ( message ) ) {
file = new File ( file . getAbsolutePath ( ) + " .enc " ) ;
isEncrypted = true ;
}
2015-02-01 19:51:02 +01:00
if ( ! file . exists ( ) ) {
try {
2017-07-23 14:56:38 +02:00
if ( isEncrypted ) {
File keyPath = new File ( FileLoader . getInternalCacheDir ( ) , file . getName ( ) + " .key " ) ;
RandomAccessFile keyFile = new RandomAccessFile ( keyPath , " rws " ) ;
long len = keyFile . length ( ) ;
byte [ ] encryptKey = new byte [ 32 ] ;
byte [ ] encryptIv = new byte [ 16 ] ;
if ( len > 0 & & len % 48 = = 0 ) {
keyFile . read ( encryptKey , 0 , 32 ) ;
keyFile . read ( encryptIv , 0 , 16 ) ;
} else {
Utilities . random . nextBytes ( encryptKey ) ;
Utilities . random . nextBytes ( encryptIv ) ;
keyFile . write ( encryptKey ) ;
keyFile . write ( encryptIv ) ;
}
keyFile . close ( ) ;
Utilities . aesCtrDecryptionByteArray ( photoSize . bytes , encryptKey , encryptIv , 0 , photoSize . bytes . length , 0 ) ;
}
2015-02-01 19:51:02 +01:00
RandomAccessFile writeFile = new RandomAccessFile ( file , " rws " ) ;
writeFile . write ( photoSize . bytes ) ;
writeFile . close ( ) ;
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-02-01 19:51:02 +01:00
}
}
2021-06-25 02:43:10 +02:00
TLRPC . TL_photoSize newPhotoSize = new TLRPC . TL_photoSize_layer127 ( ) ;
2015-02-01 19:51:02 +01:00
newPhotoSize . w = photoSize . w ;
newPhotoSize . h = photoSize . h ;
newPhotoSize . location = photoSize . location ;
newPhotoSize . size = photoSize . size ;
newPhotoSize . type = photoSize . type ;
if ( message . media instanceof TLRPC . TL_messageMediaPhoto ) {
2018-07-30 04:07:02 +02:00
for ( int a = 0 , count = message . media . photo . sizes . size ( ) ; a < count ; a + + ) {
2019-01-23 18:03:33 +01:00
TLRPC . PhotoSize size = message . media . photo . sizes . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
2015-02-01 19:51:02 +01:00
message . media . photo . sizes . set ( a , newPhotoSize ) ;
break ;
}
}
} else if ( message . media instanceof TLRPC . TL_messageMediaDocument ) {
2019-01-23 18:03:33 +01:00
for ( int a = 0 , count = message . media . document . thumbs . size ( ) ; a < count ; a + + ) {
TLRPC . PhotoSize size = message . media . document . thumbs . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
message . media . document . thumbs . set ( a , newPhotoSize ) ;
break ;
}
}
2015-04-09 20:00:14 +02:00
} else if ( message . media instanceof TLRPC . TL_messageMediaWebPage ) {
2018-07-30 04:07:02 +02:00
for ( int a = 0 , count = message . media . webpage . photo . sizes . size ( ) ; a < count ; a + + ) {
2019-01-23 18:03:33 +01:00
TLRPC . PhotoSize size = message . media . webpage . photo . sizes . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
2015-04-09 20:00:14 +02:00
message . media . webpage . photo . sizes . set ( a , newPhotoSize ) ;
break ;
}
}
2015-02-01 19:51:02 +01:00
}
}
}
2019-12-31 14:08:08 +01:00
private static TLRPC . PhotoSize findPhotoCachedSize ( TLRPC . Message message ) {
TLRPC . PhotoSize photoSize = null ;
if ( message . media instanceof TLRPC . TL_messageMediaPhoto ) {
for ( int a = 0 , count = message . media . photo . sizes . size ( ) ; a < count ; a + + ) {
TLRPC . PhotoSize size = message . media . photo . sizes . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
photoSize = size ;
break ;
}
}
} else if ( message . media instanceof TLRPC . TL_messageMediaDocument ) {
for ( int a = 0 , count = message . media . document . thumbs . size ( ) ; a < count ; a + + ) {
TLRPC . PhotoSize size = message . media . document . thumbs . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
photoSize = size ;
break ;
}
}
} else if ( message . media instanceof TLRPC . TL_messageMediaWebPage ) {
if ( message . media . webpage . photo ! = null ) {
for ( int a = 0 , count = message . media . webpage . photo . sizes . size ( ) ; a < count ; a + + ) {
TLRPC . PhotoSize size = message . media . webpage . photo . sizes . get ( a ) ;
if ( size instanceof TLRPC . TL_photoCachedSize ) {
photoSize = size ;
break ;
}
}
}
}
return photoSize ;
}
2015-02-01 19:51:02 +01:00
public static void saveMessagesThumbs ( ArrayList < TLRPC . Message > messages ) {
if ( messages = = null | | messages . isEmpty ( ) ) {
return ;
}
2016-03-06 02:49:31 +01:00
for ( int a = 0 ; a < messages . size ( ) ; a + + ) {
TLRPC . Message message = messages . get ( a ) ;
2015-02-01 19:51:02 +01:00
saveMessageThumbs ( message ) ;
}
}
2019-12-31 14:08:08 +01:00
public static MessageThumb generateMessageThumb ( TLRPC . Message message ) {
TLRPC . PhotoSize photoSize = findPhotoCachedSize ( message ) ;
if ( photoSize ! = null & & photoSize . bytes ! = null & & photoSize . bytes . length ! = 0 ) {
File file = FileLoader . getPathToAttach ( photoSize , true ) ;
2021-06-25 02:43:10 +02:00
TLRPC . TL_photoSize newPhotoSize = new TLRPC . TL_photoSize_layer127 ( ) ;
2019-12-31 14:08:08 +01:00
newPhotoSize . w = photoSize . w ;
newPhotoSize . h = photoSize . h ;
newPhotoSize . location = photoSize . location ;
newPhotoSize . size = photoSize . size ;
newPhotoSize . type = photoSize . type ;
if ( file . exists ( ) & & message . grouped_id = = 0 ) {
int h = photoSize . h ;
int w = photoSize . w ;
Point point = ChatMessageCell . getMessageSize ( w , h ) ;
String key = String . format ( Locale . US , " %d_%d@%d_%d_b " , photoSize . location . volume_id , photoSize . location . local_id , ( int ) ( point . x / AndroidUtilities . density ) , ( int ) ( point . y / AndroidUtilities . density ) ) ;
if ( ! getInstance ( ) . isInMemCache ( key , false ) ) {
Bitmap bitmap = ImageLoader . loadBitmap ( file . getPath ( ) , null , ( int ) ( point . x / AndroidUtilities . density ) , ( int ) ( point . y / AndroidUtilities . density ) , false ) ;
if ( bitmap ! = null ) {
Utilities . blurBitmap ( bitmap , 3 , 1 , bitmap . getWidth ( ) , bitmap . getHeight ( ) , bitmap . getRowBytes ( ) ) ;
Bitmap scaledBitmap = Bitmaps . createScaledBitmap ( bitmap , ( int ) ( point . x / AndroidUtilities . density ) , ( int ) ( point . y / AndroidUtilities . density ) , true ) ;
if ( scaledBitmap ! = bitmap ) {
bitmap . recycle ( ) ;
bitmap = scaledBitmap ;
}
return new MessageThumb ( key , new BitmapDrawable ( bitmap ) ) ;
}
}
}
} else if ( message . media instanceof TLRPC . TL_messageMediaDocument ) {
for ( int a = 0 , count = message . media . document . thumbs . size ( ) ; a < count ; a + + ) {
TLRPC . PhotoSize size = message . media . document . thumbs . get ( a ) ;
if ( size instanceof TLRPC . TL_photoStrippedSize ) {
TLRPC . PhotoSize thumbSize = FileLoader . getClosestPhotoSizeWithSize ( message . media . document . thumbs , 320 ) ;
int h = 0 ;
int w = 0 ;
if ( thumbSize ! = null ) {
h = thumbSize . h ;
w = thumbSize . w ;
} else {
for ( int k = 0 ; k < message . media . document . attributes . size ( ) ; k + + ) {
if ( message . media . document . attributes . get ( k ) instanceof TLRPC . TL_documentAttributeVideo ) {
TLRPC . TL_documentAttributeVideo videoAttribute = ( TLRPC . TL_documentAttributeVideo ) message . media . document . attributes . get ( k ) ;
h = videoAttribute . h ;
w = videoAttribute . w ;
break ;
}
}
}
Point point = ChatMessageCell . getMessageSize ( w , h ) ;
String key = String . format ( Locale . US , " %s_false@%d_%d_b " , ImageLocation . getStippedKey ( message , message , size ) , ( int ) ( point . x / AndroidUtilities . density ) , ( int ) ( point . y / AndroidUtilities . density ) ) ;
2021-11-05 11:06:49 +01:00
if ( ! getInstance ( ) . isInMemCache ( key , false ) ) {
2019-12-31 14:08:08 +01:00
Bitmap b = getStrippedPhotoBitmap ( size . bytes , null ) ;
if ( b ! = null ) {
Utilities . blurBitmap ( b , 3 , 1 , b . getWidth ( ) , b . getHeight ( ) , b . getRowBytes ( ) ) ;
Bitmap scaledBitmap = Bitmaps . createScaledBitmap ( b , ( int ) ( point . x / AndroidUtilities . density ) , ( int ) ( point . y / AndroidUtilities . density ) , true ) ;
if ( scaledBitmap ! = b ) {
b . recycle ( ) ;
b = scaledBitmap ;
}
return new MessageThumb ( key , new BitmapDrawable ( b ) ) ;
}
}
}
}
}
return null ;
}
public static class MessageThumb {
BitmapDrawable drawable ;
String key ;
public MessageThumb ( String key , BitmapDrawable bitmapDrawable ) {
this . key = key ;
this . drawable = bitmapDrawable ;
}
}
2014-08-22 16:24:33 +02:00
}