Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lp/inapp image preloading #501

Merged
merged 55 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
c89b9e4
Extracting gif cache
CTLalit Oct 24, 2023
7e245cb
fixup! Extracting gif cache
CTLalit Oct 24, 2023
1cbac83
Rename .java to .kt
CTLalit Oct 25, 2023
bb4d333
task(SDK-3362) Cache class
CTLalit Oct 25, 2023
ed4724c
task(SDK-3362) Fixed optimistic value
CTLalit Oct 25, 2023
aae6089
task(SDK-3362) CtCaches signature
CTLalit Oct 25, 2023
826e80f
task(SDK-3362) Optional logger
CTLalit Oct 25, 2023
8cd50f7
task(SDK-3362) Fixed cache methods signature
CTLalit Oct 25, 2023
8650abe
task(SDK-3362) File cache
CTLalit Oct 26, 2023
3c8ec31
task(SDK-3362) Renamed cache
CTLalit Oct 26, 2023
e14486f
task(SDK-3362) Exposed disk caches
CTLalit Oct 26, 2023
d752031
task(SDK-3362) instance() method
CTLalit Oct 26, 2023
b05d5b6
task(SDK-3362) logger instance passing
CTLalit Oct 26, 2023
8a7d170
task(SDK-3362) InAppImageProvider.kt
CTLalit Oct 27, 2023
bd4fb02
task(SDK-3362) Kotliny formatting
CTLalit Oct 27, 2023
9590b36
task(SDK-3362) formatting
CTLalit Oct 27, 2023
582cd51
task(SDK-3362) fixed inheritance
CTLalit Oct 27, 2023
bec8340
task(SDK-3362) data class signature
CTLalit Oct 27, 2023
1f33cd4
task(SDK-3362) save byte array
CTLalit Oct 27, 2023
6dd29f9
task(SDK-3362) formatting
CTLalit Oct 27, 2023
e92c856
task(SDK-3362) static usage
CTLalit Oct 27, 2023
d8318ed
task(SDK-3362) saved byte array along with bitmap
CTLalit Oct 27, 2023
842ae56
task(SDK-3362) Downloaded bitmap resp
CTLalit Oct 27, 2023
ce80675
task(SDK-3362) added method for cached image
CTLalit Oct 27, 2023
e3fd9d0
Merge branch 'develop' of github.com:CleverTap/clevertap-android-sdk …
CTLalit Oct 27, 2023
8126fd8
task(SDK-3362) compilation errors
CTLalit Oct 30, 2023
c7aa312
task(SDK-3362) image provider
CTLalit Oct 30, 2023
569d9af
task(SDK-3362) internal class
CTLalit Oct 30, 2023
d65c859
task(SDK-3362) gif functionality
CTLalit Oct 30, 2023
d0ca469
task(SDK-3362) Image fetch code extracted
CTLalit Oct 31, 2023
41bc238
task(SDK-3362) Cache image preloader class
CTLalit Oct 31, 2023
8c0533a
task(SDK-3362) Dispatchers to be injected
CTLalit Oct 31, 2023
47b561e
task(SDK-3362) Passed dispatcher deps
CTLalit Oct 31, 2023
65cb64a
task(SDK-3362) methods private
CTLalit Oct 31, 2023
be511b8
task(SDK-3362) Http url connection params
CTLalit Oct 31, 2023
c585b29
task(SDK-3362) Reused code for bitmap download
CTLalit Oct 31, 2023
fb0cc47
task(SDK-3362) Valid image
CTLalit Nov 1, 2023
c2499fb
task(SDK-3362) Delete methods
CTLalit Nov 1, 2023
7fc11ef
task(SDK-3362) Delete methods
CTLalit Nov 1, 2023
8fff9fb
task(SDK-3362) Used resource provider
CTLalit Nov 1, 2023
d581cf6
task(SDK-3362) Directory names fixed
CTLalit Nov 1, 2023
7a8d100
task(SDK-3362) resource provider
CTLalit Nov 2, 2023
1d3f745
task(SDK-3362) extract variable
CTLalit Nov 2, 2023
a2de070
task(SDK-3362) cache key safety
CTLalit Nov 2, 2023
1aa5a2d
task(SDK-3362) used image from media provider
CTLalit Nov 2, 2023
75e3efa
task(SDK-3362) Image preloader compile
CTLalit Nov 2, 2023
344d4dc
task(SDK-3362) Deleted legacy caches
CTLalit Nov 2, 2023
e0008c3
task(SDK-3362) Bitmap bytes
CTLalit Nov 2, 2023
ce6fc8a
task(SDK-3362) resource manager init
CTLalit Nov 2, 2023
9f5b31c
task(SDK-3362) hashing for file name
CTLalit Nov 3, 2023
27e114d
task(SDK-3362) Removed unused method
CTLalit Nov 6, 2023
19f230b
task(SDK-3362) Optimised method
CTLalit Nov 6, 2023
d367ab7
task(SDK-3362) Hashcode extraction
CTLalit Nov 6, 2023
20055e7
task(SDK-3362) File cache test
CTLalit Nov 6, 2023
997e250
Merge branch 'lp/in_app_caching' of github.com:CleverTap/clevertap-an…
CTLalit Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.clevertap.android.sdk;

public interface ILogger {
void debug(String message);

void debug(String suffix, String message);

void debug(String suffix, String message, Throwable t);

@SuppressWarnings("unused")
void debug(String message, Throwable t);

@SuppressWarnings("unused")
void info(String message);

void info(String suffix, String message);

@SuppressWarnings("unused")
void info(String suffix, String message, Throwable t);

@SuppressWarnings("unused")
void info(String message, Throwable t);

void verbose(String message);

void verbose(String suffix, String message);

void verbose(String suffix, String message, Throwable t);

void verbose(String message, Throwable t);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import android.util.Log;

public final class Logger {
public final class Logger implements ILogger {

private int debugLevel;

Expand Down Expand Up @@ -94,12 +94,14 @@ public static void v(String message, Throwable t) {
this.debugLevel = level;
}

@Override
public void debug(String message) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.INFO.intValue()) {
Log.d(Constants.CLEVERTAP_LOG_TAG, message);
}
}

@Override
public void debug(String suffix, String message) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.INFO.intValue()) {
if (message.length() > 4000) {
Expand All @@ -111,52 +113,60 @@ public void debug(String suffix, String message) {
}
}

@Override
public void debug(String suffix, String message, Throwable t) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.INFO.intValue()) {
Log.d(Constants.CLEVERTAP_LOG_TAG + ":" + suffix, message, t);
}
}

@Override
@SuppressWarnings("unused")
public void debug(String message, Throwable t) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.INFO.intValue()) {
Log.d(Constants.CLEVERTAP_LOG_TAG, message, t);
}
}

@Override
@SuppressWarnings("unused")
public void info(String message) {
if (getDebugLevel() >= CleverTapAPI.LogLevel.INFO.intValue()) {
Log.i(Constants.CLEVERTAP_LOG_TAG, message);
}
}

@Override
public void info(String suffix, String message) {
if (getDebugLevel() >= CleverTapAPI.LogLevel.INFO.intValue()) {
Log.i(Constants.CLEVERTAP_LOG_TAG + ":" + suffix, message);
}
}

@Override
@SuppressWarnings("unused")
public void info(String suffix, String message, Throwable t) {
if (getDebugLevel() >= CleverTapAPI.LogLevel.INFO.intValue()) {
Log.i(Constants.CLEVERTAP_LOG_TAG + ":" + suffix, message, t);
}
}

@Override
@SuppressWarnings("unused")
public void info(String message, Throwable t) {
if (getDebugLevel() >= CleverTapAPI.LogLevel.INFO.intValue()) {
Log.i(Constants.CLEVERTAP_LOG_TAG, message, t);
}
}

@Override
public void verbose(String message) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.DEBUG.intValue()) {
Log.v(Constants.CLEVERTAP_LOG_TAG, message);
}
}

@Override
public void verbose(String suffix, String message) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.DEBUG.intValue()) {
if (message.length() > 4000) {
Expand All @@ -168,12 +178,14 @@ public void verbose(String suffix, String message) {
}
}

@Override
public void verbose(String suffix, String message, Throwable t) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.DEBUG.intValue()) {
Log.v(Constants.CLEVERTAP_LOG_TAG + ":" + suffix, message, t);
}
}

@Override
public void verbose(String message, Throwable t) {
if (getStaticDebugLevel() > CleverTapAPI.LogLevel.DEBUG.intValue()) {
Log.v(Constants.CLEVERTAP_LOG_TAG, message, t);
Expand Down
46 changes: 3 additions & 43 deletions clevertap-core/src/main/java/com/clevertap/android/sdk/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,11 @@
import com.clevertap.android.sdk.network.DownloadedBitmap;
import com.clevertap.android.sdk.network.DownloadedBitmapFactory;
import com.google.firebase.messaging.RemoteMessage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -164,37 +159,6 @@ public static long getNowInMillis() {
return System.currentTimeMillis();
}

public static byte[] getByteArrayFromImageURL(String srcUrl) {
srcUrl = srcUrl.replace("///", "/");
srcUrl = srcUrl.replace("//", "/");
srcUrl = srcUrl.replace("http:/", "http://");
srcUrl = srcUrl.replace("https:/", "https://");
HttpsURLConnection connection = null;
try {
URL url = new URL(srcUrl);
connection = (HttpsURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
byte[] buffer = new byte[8192];
int bytesRead;
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((bytesRead = is.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
} catch (IOException e) {
Logger.v("Error processing image bytes from url: " + srcUrl);
return null;
} finally {
try {
if (connection != null) {
connection.disconnect();
}
} catch (Throwable t) {
Logger.v("Couldn't close connection!", t);
}
}
}

@SuppressLint("MissingPermission")
public static String getCurrentNetworkType(final Context context) {
try {
Expand Down Expand Up @@ -329,11 +293,7 @@ public static boolean isActivityDead(Activity activity) {
if (activity == null) {
return true;
}
boolean isActivityDead = activity.isFinishing();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
isActivityDead = isActivityDead || activity.isDestroyed();
}
return isActivityDead;
return activity.isFinishing() || activity.isDestroyed();
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
Expand Down Expand Up @@ -497,14 +457,14 @@ private static boolean checkForExoPlayer() {
if (logo == null) {
throw new Exception("Logo is null");
}
return DownloadedBitmapFactory.INSTANCE.successBitmap(drawableToBitmap(logo), 0);
return DownloadedBitmapFactory.INSTANCE.successBitmap(drawableToBitmap(logo), 0, null);
} catch (Exception e) {
e.printStackTrace();
// Try to get the app icon now
// No error handling here - handle upstream
return DownloadedBitmapFactory.INSTANCE.successBitmap(
drawableToBitmap(context.getPackageManager().getApplicationIcon(context.getApplicationInfo())),
0);
0, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ class BitmapDownloader(
return DownloadedBitmapFactory.nullBitmapWithStatus(SIZE_LIMIT_EXCEEDED)
}

return bitmapInputStreamReader.readInputStream(inputStream, this, downloadStartTimeInMilliseconds)
?: DownloadedBitmapFactory.nullBitmapWithStatus(DOWNLOAD_FAILED)
return bitmapInputStreamReader.readInputStream(
inputStream = inputStream,
connection = this,
downloadStartTimeInMilliseconds = downloadStartTimeInMilliseconds
)
}
} catch (e: Throwable) {
Logger.v("Couldn't download the notification icon. URL was: $srcUrl")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,58 @@ import com.clevertap.android.sdk.Logger
import com.clevertap.android.sdk.Utils
import com.clevertap.android.sdk.network.DownloadedBitmap
import com.clevertap.android.sdk.network.DownloadedBitmapFactory
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.net.HttpURLConnection

class BitmapInputStreamDecoder(private val nextBitmapInputStreamReader: GzipBitmapInputStreamReader? = null) :
IBitmapInputStreamReader {
open class BitmapInputStreamDecoder(
val saveBytes: Boolean = false,
val logger: Logger? = null
) : IBitmapInputStreamReader {

override fun readInputStream(
inputStream: InputStream,
connection: HttpURLConnection,
downloadStartTimeInMilliseconds: Long
): DownloadedBitmap? {
Logger.v("reading bitmap input stream in BitmapInputStreamDecoder....")

return nextBitmapInputStreamReader?.readInputStream(inputStream,connection, downloadStartTimeInMilliseconds)
?: DownloadedBitmapFactory.successBitmap(
BitmapFactory.decodeStream(inputStream),
Utils.getNowInMillis() - downloadStartTimeInMilliseconds
)
): DownloadedBitmap {
logger?.verbose("reading bitmap input stream in BitmapInputStreamDecoder....")

val bufferForHttpInputStream = ByteArray(16384)
val finalDataFromHttpInputStream = ByteArrayOutputStream()

var totalBytesRead = 0
var bytesRead: Int

// Read data from input stream
while (inputStream.read(bufferForHttpInputStream).also { bytesRead = it } != -1) {
totalBytesRead += bytesRead
finalDataFromHttpInputStream.write(bufferForHttpInputStream, 0, bytesRead)
logger?.verbose("Downloaded $totalBytesRead bytes")
}
logger?.verbose("Total download size for bitmap = $totalBytesRead")

val dataReadFromStreamInByteArray = finalDataFromHttpInputStream.toByteArray()
// Decode the bitmap from decompressed data
val bitmap = BitmapFactory.decodeByteArray(
dataReadFromStreamInByteArray,
0,
dataReadFromStreamInByteArray.size
)

val fileLength = connection.contentLength
if (fileLength != -1 && fileLength != totalBytesRead) {
logger?.debug("File not loaded completely not going forward. URL was: ${connection.url}")
return DownloadedBitmapFactory.nullBitmapWithStatus(DownloadedBitmap.Status.DOWNLOAD_FAILED)
}

return DownloadedBitmapFactory.successBitmap(
bitmap = bitmap,
downloadTime = Utils.getNowInMillis() - downloadStartTimeInMilliseconds,
data = if (saveBytes) {
dataReadFromStreamInByteArray
} else {
null
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BitmapInputStreamReader(
inputStream: InputStream,
connection: HttpURLConnection,
downloadStartTimeInMilliseconds: Long
): DownloadedBitmap? {
): DownloadedBitmap {

Logger.v("reading bitmap input stream in BitmapInputStreamReader....")
val bufferForHttpInputStream = ByteArray(16384)
Expand All @@ -47,22 +47,31 @@ class BitmapInputStreamReader(
}

return nextBitmapInputStreamReader?.readInputStream(
ByteArrayInputStream(finalDataFromHttpInputStream.toByteArray()),
connection,
downloadStartTimeInMilliseconds
) ?: getDownloadedBitmapFromStream(finalDataFromHttpInputStream, downloadStartTimeInMilliseconds)
inputStream = ByteArrayInputStream(finalDataFromHttpInputStream.toByteArray()),
connection = connection,
downloadStartTimeInMilliseconds = downloadStartTimeInMilliseconds
) ?: getDownloadedBitmapFromStream(
dataReadFromStream = finalDataFromHttpInputStream,
downloadStartTimeInMilliseconds = downloadStartTimeInMilliseconds
)
}

private fun getDownloadedBitmapFromStream(
dataReadFromStream: ByteArrayOutputStream, downloadStartTimeInMilliseconds: Long
dataReadFromStream: ByteArrayOutputStream,
downloadStartTimeInMilliseconds: Long
): DownloadedBitmap {

val dataReadFromStreamInByteArray = dataReadFromStream.toByteArray()
// Decode the bitmap from decompressed data
val bitmap =
BitmapFactory.decodeByteArray(dataReadFromStreamInByteArray, 0, dataReadFromStreamInByteArray.size)
val bitmap = BitmapFactory.decodeByteArray(
dataReadFromStreamInByteArray,
0,
dataReadFromStreamInByteArray.size
)

return DownloadedBitmapFactory.successBitmap(
bitmap, Utils.getNowInMillis() - downloadStartTimeInMilliseconds
bitmap = bitmap,
downloadTime = Utils.getNowInMillis() - downloadStartTimeInMilliseconds
)
}
}
Loading