@ -27,6 +27,7 @@ import de.c1710.filemojicompat.FileEmojiCompatConfig;
import okhttp3.OkHttpClient ;
import okhttp3.OkHttpClient ;
import okhttp3.Request ;
import okhttp3.Request ;
import okhttp3.Response ;
import okhttp3.Response ;
import okhttp3.ResponseBody ;
import okio.BufferedSink ;
import okio.BufferedSink ;
import okio.Okio ;
import okio.Okio ;
import okio.Source ;
import okio.Source ;
@ -81,7 +82,7 @@ public class EmojiCompatFont {
R . drawable . ic_notoemoji ,
R . drawable . ic_notoemoji ,
"https://tusky.app/hosted/emoji/NotoEmojiCompat.ttf" ,
"https://tusky.app/hosted/emoji/NotoEmojiCompat.ttf" ,
"11.0.0"
"11.0.0"
) ;
) ;
/ * *
/ * *
* This array stores all available EmojiCompat fonts .
* This array stores all available EmojiCompat fonts .
@ -109,14 +110,14 @@ public class EmojiCompatFont {
/ * *
/ * *
* Returns the Emoji font associated with this ID
* Returns the Emoji font associated with this ID
*
* @param id the ID of this font
* @param id the ID of this font
* @return the corresponding font . Will default to SYSTEM_DEFAULT if not in range .
* @return the corresponding font . Will default to SYSTEM_DEFAULT if not in range .
* /
* /
public static EmojiCompatFont byId ( int id ) {
public static EmojiCompatFont byId ( int id ) {
if ( id > = 0 & & id < FONTS . length ) {
if ( id > = 0 & & id < FONTS . length ) {
return FONTS [ id ] ;
return FONTS [ id ] ;
}
} else {
else {
return SYSTEM_DEFAULT ;
return SYSTEM_DEFAULT ;
}
}
}
}
@ -157,15 +158,15 @@ public class EmojiCompatFont {
/ * *
/ * *
* This method will return the actual font file ( regardless of its existence ) for
* This method will return the actual font file ( regardless of its existence ) for
* the current version ( not necessarily the latest ! ) .
* the current version ( not necessarily the latest ! ) .
*
* @return The font ( TTF ) file or null if called on SYSTEM_FONT
* @return The font ( TTF ) file or null if called on SYSTEM_FONT
* /
* /
@Nullable
@Nullable
private File getFont ( Context context ) {
private File getFont ( Context context ) {
if ( this ! = SYSTEM_DEFAULT ) {
if ( this ! = SYSTEM_DEFAULT ) {
File directory = new File ( context . getExternalFilesDir ( null ) , DIRECTORY ) ;
File directory = new File ( context . getExternalFilesDir ( null ) , DIRECTORY ) ;
return new File ( directory , this . getName ( ) + this . getVersion ( ) + ".ttf" ) ;
return new File ( directory , this . getName ( ) + this . getVersion ( ) + ".ttf" ) ;
}
} else {
else {
return null ;
return null ;
}
}
}
}
@ -185,6 +186,7 @@ public class EmojiCompatFont {
/ * *
/ * *
* Checks whether there is already a font version that satisfies the current version , i . e . it
* Checks whether there is already a font version that satisfies the current version , i . e . it
* has a higher or equal version code .
* has a higher or equal version code .
*
* @param context The Context
* @param context The Context
* @return Whether there is a font file with a higher or equal version code to the current
* @return Whether there is a font file with a higher or equal version code to the current
* /
* /
@ -199,10 +201,11 @@ public class EmojiCompatFont {
/ * *
/ * *
* Downloads the TTF file for this font
* Downloads the TTF file for this font
*
* @param listeners The listeners which will be notified when the download has been finished
* @param listeners The listeners which will be notified when the download has been finished
* /
* /
public void downloadFont ( Context context , Downloader . EmojiDownloadListener . . . listeners ) {
public void downloadFont ( Context context , Downloader . EmojiDownloadListener . . . listeners ) {
if ( this ! = SYSTEM_DEFAULT ) {
if ( this ! = SYSTEM_DEFAULT ) {
// Additionally run a cleanup process after the download has been successful.
// Additionally run a cleanup process after the download has been successful.
Downloader . EmojiDownloadListener cleanup = font - > deleteOldVersions ( context ) ;
Downloader . EmojiDownloadListener cleanup = font - > deleteOldVersions ( context ) ;
@ -216,9 +219,8 @@ public class EmojiCompatFont {
this ,
this ,
allListeners . toArray ( allListenersA ) )
allListeners . toArray ( allListenersA ) )
. execute ( getFont ( context ) ) ;
. execute ( getFont ( context ) ) ;
}
} else {
else {
for ( Downloader . EmojiDownloadListener listener : listeners ) {
for ( Downloader . EmojiDownloadListener listener : listeners ) {
// The system emoji font is always downloaded...
// The system emoji font is always downloaded...
listener . onDownloaded ( this ) ;
listener . onDownloaded ( this ) ;
}
}
@ -227,6 +229,7 @@ public class EmojiCompatFont {
/ * *
/ * *
* Deletes any older version of a font
* Deletes any older version of a font
*
* @param context The current Context
* @param context The current Context
* /
* /
private void deleteOldVersions ( Context context ) {
private void deleteOldVersions ( Context context ) {
@ -236,11 +239,11 @@ public class EmojiCompatFont {
Log . d ( TAG , String . format ( "deleteOldVersions: Found %d other font files" , existingFontFiles . size ( ) ) ) ;
Log . d ( TAG , String . format ( "deleteOldVersions: Found %d other font files" , existingFontFiles . size ( ) ) ) ;
for ( Pair < File , int [ ] > fileExists : existingFontFiles ) {
for ( Pair < File , int [ ] > fileExists : existingFontFiles ) {
if ( compareVersions ( fileExists . second , getVersionCode ( ) ) < 0 ) {
if ( compareVersions ( fileExists . second , getVersionCode ( ) ) < 0 ) {
File file = fileExists . first ;
File file = fileExists . first ;
// Uses side effects!
// Uses side effects!
Log . d ( TAG , String . format ( "Deleted %s successfully: %s" , file . getAbsolutePath ( ) ,
Log . d ( TAG , String . format ( "Deleted %s successfully: %s" , file . getAbsolutePath ( ) ,
file . delete ( ) ) ) ;
file . delete ( ) ) ) ;
}
}
}
}
}
}
@ -250,6 +253,7 @@ public class EmojiCompatFont {
/ * *
/ * *
* Loads all font files that are inside the files directory into an ArrayList with the information
* Loads all font files that are inside the files directory into an ArrayList with the information
* on whether they are older than the currently available version or not .
* on whether they are older than the currently available version or not .
*
* @param context The Context
* @param context The Context
* /
* /
private void loadExistingFontFiles ( Context context ) {
private void loadExistingFontFiles ( Context context ) {
@ -274,7 +278,7 @@ public class EmojiCompatFont {
this . existingFontFiles = new ArrayList < > ( existingFontFiles . length ) ;
this . existingFontFiles = new ArrayList < > ( existingFontFiles . length ) ;
for ( File file : existingFontFiles ) {
for ( File file : existingFontFiles ) {
Matcher matcher = fontRegex . matcher ( file . getName ( ) ) ;
Matcher matcher = fontRegex . matcher ( file . getName ( ) ) ;
if ( matcher . matches ( ) ) {
if ( matcher . matches ( ) ) {
String version = matcher . group ( 1 ) ;
String version = matcher . group ( 1 ) ;
@ -294,6 +298,7 @@ public class EmojiCompatFont {
/ * *
/ * *
* Returns the current or latest version of this font file ( if there is any )
* Returns the current or latest version of this font file ( if there is any )
*
* @param context The Context
* @param context The Context
* @return The file for this font with the current or ( if not existent ) highest version code or null if there is no file for this font .
* @return The file for this font with the current or ( if not existent ) highest version code or null if there is no file for this font .
* /
* /
@ -380,7 +385,7 @@ public class EmojiCompatFont {
* Stops downloading the font . If no one started a font download , nothing happens .
* Stops downloading the font . If no one started a font download , nothing happens .
* /
* /
public void cancelDownload ( ) {
public void cancelDownload ( ) {
if ( fontDownloader ! = null ) {
if ( fontDownloader ! = null ) {
fontDownloader . cancel ( false ) ;
fontDownloader . cancel ( false ) ;
fontDownloader = null ;
fontDownloader = null ;
}
}
@ -407,7 +412,7 @@ public class EmojiCompatFont {
}
}
@Override
@Override
protected File doInBackground ( File . . . files ) {
protected File doInBackground ( File . . . files ) {
// Only download to one file...
// Only download to one file...
File downloadFile = files [ 0 ] ;
File downloadFile = files [ 0 ] ;
try {
try {
@ -428,7 +433,7 @@ public class EmojiCompatFont {
// Download!
// Download!
if ( response . body ( ) ! = null
if ( response . body ( ) ! = null
& & response . isSuccessful ( )
& & response . isSuccessful ( )
& & ( size = response . body ( ) . contentLength ( ) ) > 0 ) {
& & ( size = networkResponseLength ( response ) ) > 0 ) {
float progress = 0 ;
float progress = 0 ;
source = response . body ( ) . source ( ) ;
source = response . body ( ) . source ( ) ;
try {
try {
@ -448,14 +453,13 @@ public class EmojiCompatFont {
Log . e ( TAG , "Status code: " + response . code ( ) ) ;
Log . e ( TAG , "Status code: " + response . code ( ) ) ;
failed = true ;
failed = true ;
}
}
}
} finally {
finally {
if ( source ! = null ) {
if ( source ! = null ) {
source . close ( ) ;
source . close ( ) ;
}
}
sink . close ( ) ;
sink . close ( ) ;
// This 'if' uses side effects to delete the File.
// This 'if' uses side effects to delete the File.
if ( isCancelled ( ) & & ! downloadFile . delete ( ) ) {
if ( isCancelled ( ) & & ! downloadFile . delete ( ) ) {
Log . e ( TAG , "Could not delete file " + downloadFile ) ;
Log . e ( TAG , "Could not delete file " + downloadFile ) ;
}
}
}
}
@ -468,28 +472,27 @@ public class EmojiCompatFont {
@Override
@Override
public void onProgressUpdate ( Float . . . progress ) {
public void onProgressUpdate ( Float . . . progress ) {
for ( EmojiDownloadListener listener : listeners ) {
for ( EmojiDownloadListener listener : listeners ) {
listener . onProgress ( progress [ 0 ] ) ;
listener . onProgress ( progress [ 0 ] ) ;
}
}
}
}
@Override
@Override
public void onPostExecute ( File downloadedFile ) {
public void onPostExecute ( File downloadedFile ) {
if ( ! failed & & downloadedFile . exists ( ) ) {
if ( ! failed & & downloadedFile . exists ( ) ) {
for ( EmojiDownloadListener listener : listeners ) {
for ( EmojiDownloadListener listener : listeners ) {
listener . onDownloaded ( font ) ;
listener . onDownloaded ( font ) ;
}
}
}
} else {
else {
fail ( downloadedFile ) ;
fail ( downloadedFile ) ;
}
}
}
}
private void fail ( File failedFile ) {
private void fail ( File failedFile ) {
if ( failedFile . exists ( ) & & ! failedFile . delete ( ) ) {
if ( failedFile . exists ( ) & & ! failedFile . delete ( ) ) {
Log . e ( TAG , "Could not delete file " + failedFile ) ;
Log . e ( TAG , "Could not delete file " + failedFile ) ;
}
}
for ( EmojiDownloadListener listener : listeners ) {
for ( EmojiDownloadListener listener : listeners ) {
listener . onFailed ( ) ;
listener . onFailed ( ) ;
}
}
}
}
@ -500,11 +503,13 @@ public class EmojiCompatFont {
public interface EmojiDownloadListener {
public interface EmojiDownloadListener {
/ * *
/ * *
* Called after successfully finishing a download .
* Called after successfully finishing a download .
*
* @param font The font related to this download . This will help identifying the download
* @param font The font related to this download . This will help identifying the download
* /
* /
void onDownloaded ( EmojiCompatFont font ) ;
void onDownloaded ( EmojiCompatFont font ) ;
// TODO: Add functionality
// TODO: Add functionality
/ * *
/ * *
* Called when something went wrong with the download .
* Called when something went wrong with the download .
* This one won ' t be called when the download has been cancelled though .
* This one won ' t be called when the download has been cancelled though .
@ -515,12 +520,39 @@ public class EmojiCompatFont {
/ * *
/ * *
* Called whenever the progress changed
* Called whenever the progress changed
*
* @param Progress A value between 0 and 1 representing the current progress
* @param Progress A value between 0 and 1 representing the current progress
* /
* /
default void onProgress ( float Progress ) {
default void onProgress ( float Progress ) {
// ARE WE THERE YET?
// ARE WE THERE YET?
}
}
}
}
/ * *
* This method is needed because when transparent compression is used OkHttp reports
* { @link ResponseBody # contentLength ( ) } as - 1 . We try to get the header which server sent
* us manually here .
*
* @see < a href = "https://github.com/square/okhttp/issues/259" > OkHttp issue 259 < / a >
* /
private long networkResponseLength ( Response response ) {
Response networkResponse = response . networkResponse ( ) ;
if ( networkResponse = = null ) {
// In case it's a fully cached response
ResponseBody body = response . body ( ) ;
return body = = null ? - 1 : body . contentLength ( ) ;
}
String header = networkResponse . header ( "Content-Length" ) ;
if ( header = = null ) {
return - 1 ;
}
try {
return Integer . parseInt ( header ) ;
} catch ( NumberFormatException e ) {
return - 1 ;
}
}
}
}
@Override
@Override