From 0fb31c15bad7a6156e8f92d78cafb81a76b5296e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAkshay?= <“ayyanchira.akshay@gmail.com”> Date: Wed, 10 Sep 2025 07:19:02 -0700 Subject: [PATCH 1/3] Cursor Iteration Needs reduction in code. Lot of repition. Heavy review and testing needed. Committing as inapps are looking stable and are sticking with the layout with back to back phone rotations when inapp performance would fail usually --- ...IterableInAppFragmentHTMLNotification.java | 241 ++++++++++++++++-- .../iterableapi/IterableWebChromeClient.java | 5 +- 2 files changed, 229 insertions(+), 17 deletions(-) diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java index 779c1c93c..df67a8248 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java @@ -26,6 +26,7 @@ import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.widget.FrameLayout; import android.widget.RelativeLayout; import androidx.annotation.NonNull; @@ -58,6 +59,12 @@ public class IterableInAppFragmentHTMLNotification extends DialogFragment implem private boolean callbackOnCancel = false; private String htmlString; private String messageId; + + // Resize debouncing fields + private Handler resizeHandler = new Handler(); + private Runnable pendingResizeRunnable; + private float lastContentHeight = -1; + private static final int RESIZE_DEBOUNCE_DELAY_MS = 200; private double backgroundAlpha; //TODO: remove in a future version private Rect insetPadding; @@ -105,6 +112,35 @@ public IterableInAppFragmentHTMLNotification() { insetPadding = new Rect(); this.setStyle(DialogFragment.STYLE_NO_FRAME, androidx.appcompat.R.style.Theme_AppCompat_NoActionBar); } + + @Override + public void onStart() { + super.onStart(); + + // Set dialog positioning after the dialog is created and shown + Dialog dialog = getDialog(); + if (dialog != null) { + Window window = dialog.getWindow(); + if (window != null) { + WindowManager.LayoutParams windowParams = window.getAttributes(); + int startGravity = getVerticalLocation(insetPadding); + + if (startGravity == Gravity.CENTER_VERTICAL) { + windowParams.gravity = Gravity.CENTER; + IterableLogger.d(TAG, "Set dialog gravity to CENTER in onStart"); + } else if (startGravity == Gravity.TOP) { + windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set dialog gravity to TOP in onStart"); + } else if (startGravity == Gravity.BOTTOM) { + windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set dialog gravity to BOTTOM in onStart"); + } + + window.setAttributes(windowParams); + IterableLogger.d(TAG, "Applied window gravity in onStart: " + windowParams.gravity); + } + } + } @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -144,6 +180,25 @@ public void onCancel(DialogInterface dialog) { } }); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + + // Set window gravity for the dialog + Window window = dialog.getWindow(); + WindowManager.LayoutParams windowParams = window.getAttributes(); + int dialogGravity = getVerticalLocation(insetPadding); + + if (dialogGravity == Gravity.CENTER_VERTICAL) { + windowParams.gravity = Gravity.CENTER; + IterableLogger.d(TAG, "Set dialog gravity to CENTER in onCreateDialog"); + } else if (dialogGravity == Gravity.TOP) { + windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set dialog gravity to TOP in onCreateDialog"); + } else if (dialogGravity == Gravity.BOTTOM) { + windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set dialog gravity to BOTTOM in onCreateDialog"); + } + + window.setAttributes(windowParams); + if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) { dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } else if (getInAppLayout(insetPadding) != InAppLayout.TOP) { @@ -162,23 +217,57 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) { getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } + + // Set initial window gravity based on inset padding + Window window = getDialog().getWindow(); + WindowManager.LayoutParams windowParams = window.getAttributes(); + int windowGravity = getVerticalLocation(insetPadding); + + if (windowGravity == Gravity.CENTER_VERTICAL) { + windowParams.gravity = Gravity.CENTER; + IterableLogger.d(TAG, "Set initial CENTER window gravity in onCreateView"); + } else if (windowGravity == Gravity.TOP) { + windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set initial TOP window gravity in onCreateView"); + } else if (windowGravity == Gravity.BOTTOM) { + windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Set initial BOTTOM window gravity in onCreateView"); + } + + window.setAttributes(windowParams); webView = new IterableWebView(getContext()); webView.setId(R.id.webView); + + // Debug the HTML content + IterableLogger.d(TAG, "HTML content preview: " + (htmlString.length() > 200 ? htmlString.substring(0, 200) + "..." : htmlString)); + webView.createWithHtml(this, htmlString); if (orientationListener == null) { orientationListener = new OrientationEventListener(getContext(), SensorManager.SENSOR_DELAY_NORMAL) { + private int lastOrientation = -1; + // Resize the webView on device rotation public void onOrientationChanged(int orientation) { - if (loaded) { - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - runResizeScript(); - } - }, 1000); + if (loaded && webView != null) { + // Only trigger on significant orientation changes (90 degree increments) + int currentOrientation = ((orientation + 45) / 90) * 90; + if (currentOrientation != lastOrientation && lastOrientation != -1) { + lastOrientation = currentOrientation; + + // Use longer delay for orientation changes to allow layout to stabilize + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + IterableLogger.d(TAG, "Orientation changed, triggering resize"); + runResizeScript(); + } + }, 1500); // Increased delay for better stability + } else if (lastOrientation == -1) { + lastOrientation = currentOrientation; + } } } }; @@ -186,17 +275,53 @@ public void run() { orientationListener.enable(); - RelativeLayout relativeLayout = new RelativeLayout(this.getContext()); - RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); - relativeLayout.setVerticalGravity(getVerticalLocation(insetPadding)); - relativeLayout.addView(webView, layoutParams); + // Create a FrameLayout as the main container for better positioning control + FrameLayout frameLayout = new FrameLayout(this.getContext()); + + // Create a RelativeLayout as a wrapper for the WebView + RelativeLayout webViewContainer = new RelativeLayout(this.getContext()); + + int gravity = getVerticalLocation(insetPadding); + IterableLogger.d(TAG, "Initial setup - gravity: " + gravity + " for inset padding: " + insetPadding); + + // Set FrameLayout gravity based on positioning + FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT + ); + + if (gravity == Gravity.CENTER_VERTICAL) { + containerParams.gravity = Gravity.CENTER; + IterableLogger.d(TAG, "Applied CENTER gravity to container"); + } else if (gravity == Gravity.TOP) { + containerParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Applied TOP gravity to container"); + } else if (gravity == Gravity.BOTTOM) { + containerParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + IterableLogger.d(TAG, "Applied BOTTOM gravity to container"); + } + + // Add WebView to the RelativeLayout container with WRAP_CONTENT for proper sizing + RelativeLayout.LayoutParams webViewParams = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT + ); + webViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); + webViewContainer.addView(webView, webViewParams); + + IterableLogger.d(TAG, "Added WebView with WRAP_CONTENT and CENTER_IN_PARENT rule"); + + // Add the container to the FrameLayout + frameLayout.addView(webViewContainer, containerParams); + + IterableLogger.d(TAG, "Created FrameLayout with positioned RelativeLayout container"); if (savedInstanceState == null || !savedInstanceState.getBoolean(IN_APP_OPEN_TRACKED, false)) { IterableApi.sharedInstance.trackInAppOpen(messageId, location); } prepareToShowWebView(); - return relativeLayout; + return frameLayout; } public void setLoaded(boolean loaded) { @@ -226,6 +351,12 @@ public void onStop() { public void onDestroy() { super.onDestroy(); + // Clean up pending resize operations + if (resizeHandler != null && pendingResizeRunnable != null) { + resizeHandler.removeCallbacks(pendingResizeRunnable); + pendingResizeRunnable = null; + } + if (this.getActivity() != null && this.getActivity().isChangingConfigurations()) { return; } @@ -414,7 +545,50 @@ private void processMessageRemoval() { @Override public void runResizeScript() { - resize(webView.getContentHeight()); + // Cancel any pending resize operation + if (pendingResizeRunnable != null) { + resizeHandler.removeCallbacks(pendingResizeRunnable); + } + + // Schedule a debounced resize operation + pendingResizeRunnable = new Runnable() { + @Override + public void run() { + performResizeWithValidation(); + } + }; + + resizeHandler.postDelayed(pendingResizeRunnable, RESIZE_DEBOUNCE_DELAY_MS); + } + + private void performResizeWithValidation() { + if (webView == null) { + IterableLogger.w(TAG, "WebView is null, skipping resize"); + return; + } + + float currentHeight = webView.getContentHeight(); + + // Validate content height + if (currentHeight <= 0) { + IterableLogger.w(TAG, "Invalid content height: " + currentHeight + "dp, skipping resize"); + return; + } + + // Check if height has stabilized (avoid unnecessary resizes for same height) + if (Math.abs(currentHeight - lastContentHeight) < 1.0f) { + IterableLogger.d(TAG, "Content height unchanged (" + currentHeight + "dp), skipping resize"); + return; + } + + lastContentHeight = currentHeight; + + IterableLogger.d( + TAG, + "💚 Resizing in-app to height: " + currentHeight + "dp" + ); + + resize(currentHeight); } /** @@ -462,9 +636,44 @@ public void run() { window.setLayout(webViewWidth, webViewHeight); getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } else { + // Resize the WebView directly with explicit size float relativeHeight = height * getResources().getDisplayMetrics().density; - RelativeLayout.LayoutParams webViewLayout = new RelativeLayout.LayoutParams(getResources().getDisplayMetrics().widthPixels, (int) relativeHeight); - webView.setLayoutParams(webViewLayout); + int newWebViewWidth = getResources().getDisplayMetrics().widthPixels; + int newWebViewHeight = (int) relativeHeight; + + // Set WebView to explicit size + RelativeLayout.LayoutParams webViewParams = new RelativeLayout.LayoutParams(newWebViewWidth, newWebViewHeight); + + // Apply positioning based on gravity + int resizeGravity = getVerticalLocation(insetPadding); + IterableLogger.d(TAG, "Resizing WebView directly - gravity: " + resizeGravity + " size: " + newWebViewWidth + "x" + newWebViewHeight + "px for inset padding: " + insetPadding); + + if (resizeGravity == Gravity.CENTER_VERTICAL) { + webViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); + IterableLogger.d(TAG, "Applied CENTER_IN_PARENT to WebView"); + } else if (resizeGravity == Gravity.TOP) { + webViewParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + webViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL); + IterableLogger.d(TAG, "Applied TOP alignment to WebView"); + } else if (resizeGravity == Gravity.BOTTOM) { + webViewParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + webViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL); + IterableLogger.d(TAG, "Applied BOTTOM alignment to WebView"); + } + + // Make dialog full screen to allow proper positioning + window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + + // Apply the new layout params to WebView + webView.setLayoutParams(webViewParams); + + // Force layout updates + webView.requestLayout(); + if (webView.getParent() instanceof ViewGroup) { + ((ViewGroup) webView.getParent()).requestLayout(); + } + + IterableLogger.d(TAG, "Applied explicit size and positioning to WebView: " + newWebViewWidth + "x" + newWebViewHeight); } } catch (IllegalArgumentException e) { IterableLogger.e(TAG, "Exception while trying to resize an in-app message", e); diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebChromeClient.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebChromeClient.java index 7631bbae0..8e630ca84 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebChromeClient.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableWebChromeClient.java @@ -12,6 +12,9 @@ public class IterableWebChromeClient extends WebChromeClient { @Override public void onProgressChanged(WebView view, int newProgress) { - inAppHTMLNotification.runResizeScript(); + // Only trigger resize when page is fully loaded (100%) to avoid multiple rapid calls + if (newProgress == 100) { + inAppHTMLNotification.runResizeScript(); + } } } From 8e15c0a3bb9586c897db1eeb3b86ebc8b20b6fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAkshay?= <“ayyanchira.akshay@gmail.com”> Date: Wed, 29 Oct 2025 14:05:34 -0700 Subject: [PATCH 2/3] Code refactor --- ...IterableInAppFragmentHTMLNotification.java | 172 ++++++++---------- 1 file changed, 78 insertions(+), 94 deletions(-) diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java index 69483b175..86fb3d813 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java @@ -52,9 +52,12 @@ public class IterableInAppFragmentHTMLNotification extends DialogFragment implem private static final int DELAY_THRESHOLD_MS = 500; - @Nullable static IterableInAppFragmentHTMLNotification notification; - @Nullable static IterableHelper.IterableUrlCallback clickCallback; - @Nullable static IterableInAppLocation location; + @Nullable + static IterableInAppFragmentHTMLNotification notification; + @Nullable + static IterableHelper.IterableUrlCallback clickCallback; + @Nullable + static IterableInAppLocation location; private IterableWebView webView; private boolean loaded; @@ -62,7 +65,7 @@ public class IterableInAppFragmentHTMLNotification extends DialogFragment implem private boolean callbackOnCancel = false; private String htmlString; private String messageId; - + // Resize debouncing fields private Handler resizeHandler = new Handler(); private Runnable pendingResizeRunnable; @@ -99,6 +102,7 @@ public static IterableInAppFragmentHTMLNotification createInstance(@NonNull Stri /** * Returns the notification instance currently being shown + * * @return notification instance */ public static IterableInAppFragmentHTMLNotification getInstance() { @@ -115,33 +119,15 @@ public IterableInAppFragmentHTMLNotification() { insetPadding = new Rect(); this.setStyle(DialogFragment.STYLE_NO_FRAME, androidx.appcompat.R.style.Theme_AppCompat_NoActionBar); } - + @Override public void onStart() { super.onStart(); - + // Set dialog positioning after the dialog is created and shown Dialog dialog = getDialog(); if (dialog != null) { - Window window = dialog.getWindow(); - if (window != null) { - WindowManager.LayoutParams windowParams = window.getAttributes(); - int startGravity = getVerticalLocation(insetPadding); - - if (startGravity == Gravity.CENTER_VERTICAL) { - windowParams.gravity = Gravity.CENTER; - IterableLogger.d(TAG, "Set dialog gravity to CENTER in onStart"); - } else if (startGravity == Gravity.TOP) { - windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set dialog gravity to TOP in onStart"); - } else if (startGravity == Gravity.BOTTOM) { - windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set dialog gravity to BOTTOM in onStart"); - } - - window.setAttributes(windowParams); - IterableLogger.d(TAG, "Applied window gravity in onStart: " + windowParams.gravity); - } + applyWindowGravity(dialog.getWindow(), "onStart"); } } @@ -183,25 +169,10 @@ public void onCancel(DialogInterface dialog) { } }); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - + // Set window gravity for the dialog - Window window = dialog.getWindow(); - WindowManager.LayoutParams windowParams = window.getAttributes(); - int dialogGravity = getVerticalLocation(insetPadding); - - if (dialogGravity == Gravity.CENTER_VERTICAL) { - windowParams.gravity = Gravity.CENTER; - IterableLogger.d(TAG, "Set dialog gravity to CENTER in onCreateDialog"); - } else if (dialogGravity == Gravity.TOP) { - windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set dialog gravity to TOP in onCreateDialog"); - } else if (dialogGravity == Gravity.BOTTOM) { - windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set dialog gravity to BOTTOM in onCreateDialog"); - } - - window.setAttributes(windowParams); - + applyWindowGravity(dialog.getWindow(), "onCreateDialog"); + if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) { dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } else if (getInAppLayout(insetPadding) != InAppLayout.TOP) { @@ -220,37 +191,22 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) { getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } - + // Set initial window gravity based on inset padding - Window window = getDialog().getWindow(); - WindowManager.LayoutParams windowParams = window.getAttributes(); - int windowGravity = getVerticalLocation(insetPadding); - - if (windowGravity == Gravity.CENTER_VERTICAL) { - windowParams.gravity = Gravity.CENTER; - IterableLogger.d(TAG, "Set initial CENTER window gravity in onCreateView"); - } else if (windowGravity == Gravity.TOP) { - windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set initial TOP window gravity in onCreateView"); - } else if (windowGravity == Gravity.BOTTOM) { - windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Set initial BOTTOM window gravity in onCreateView"); - } - - window.setAttributes(windowParams); + applyWindowGravity(getDialog().getWindow(), "onCreateView"); webView = new IterableWebView(getContext()); webView.setId(R.id.webView); - + // Debug the HTML content IterableLogger.d(TAG, "HTML content preview: " + (htmlString.length() > 200 ? htmlString.substring(0, 200) + "..." : htmlString)); - + webView.createWithHtml(this, htmlString); if (orientationListener == null) { orientationListener = new OrientationEventListener(getContext(), SensorManager.SENSOR_DELAY_NORMAL) { private int lastOrientation = -1; - + // Resize the webView on device rotation public void onOrientationChanged(int orientation) { if (loaded && webView != null) { @@ -258,7 +214,7 @@ public void onOrientationChanged(int orientation) { int currentOrientation = ((orientation + 45) / 90) * 90; if (currentOrientation != lastOrientation && lastOrientation != -1) { lastOrientation = currentOrientation; - + // Use longer delay for orientation changes to allow layout to stabilize final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @@ -280,19 +236,19 @@ public void run() { // Create a FrameLayout as the main container for better positioning control FrameLayout frameLayout = new FrameLayout(this.getContext()); - + // Create a RelativeLayout as a wrapper for the WebView RelativeLayout webViewContainer = new RelativeLayout(this.getContext()); - + int gravity = getVerticalLocation(insetPadding); IterableLogger.d(TAG, "Initial setup - gravity: " + gravity + " for inset padding: " + insetPadding); - + // Set FrameLayout gravity based on positioning FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT ); - + if (gravity == Gravity.CENTER_VERTICAL) { containerParams.gravity = Gravity.CENTER; IterableLogger.d(TAG, "Applied CENTER gravity to container"); @@ -303,20 +259,20 @@ public void run() { containerParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; IterableLogger.d(TAG, "Applied BOTTOM gravity to container"); } - + // Add WebView to the RelativeLayout container with WRAP_CONTENT for proper sizing RelativeLayout.LayoutParams webViewParams = new RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT ); webViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); webViewContainer.addView(webView, webViewParams); - + IterableLogger.d(TAG, "Added WebView with WRAP_CONTENT and CENTER_IN_PARENT rule"); - + // Add the container to the FrameLayout frameLayout.addView(webViewContainer, containerParams); - + IterableLogger.d(TAG, "Created FrameLayout with positioned RelativeLayout container"); if (savedInstanceState == null || !savedInstanceState.getBoolean(IN_APP_OPEN_TRACKED, false)) { @@ -519,7 +475,7 @@ private void hideWebView() { try { Animation anim = AnimationUtils.loadAnimation(getContext(), - animationResource); + animationResource); anim.setDuration(IterableConstants.ITERABLE_IN_APP_ANIMATION_DURATION); webView.startAnimation(anim); } catch (Exception e) { @@ -563,7 +519,7 @@ public void runResizeScript() { if (pendingResizeRunnable != null) { resizeHandler.removeCallbacks(pendingResizeRunnable); } - + // Schedule a debounced resize operation pendingResizeRunnable = new Runnable() { @Override @@ -571,42 +527,43 @@ public void run() { performResizeWithValidation(); } }; - + resizeHandler.postDelayed(pendingResizeRunnable, RESIZE_DEBOUNCE_DELAY_MS); } - + private void performResizeWithValidation() { if (webView == null) { IterableLogger.w(TAG, "WebView is null, skipping resize"); return; } - + float currentHeight = webView.getContentHeight(); - + // Validate content height if (currentHeight <= 0) { IterableLogger.w(TAG, "Invalid content height: " + currentHeight + "dp, skipping resize"); return; } - + // Check if height has stabilized (avoid unnecessary resizes for same height) if (Math.abs(currentHeight - lastContentHeight) < 1.0f) { IterableLogger.d(TAG, "Content height unchanged (" + currentHeight + "dp), skipping resize"); return; } - + lastContentHeight = currentHeight; - + IterableLogger.d( - TAG, - "💚 Resizing in-app to height: " + currentHeight + "dp" + TAG, + "💚 Resizing in-app to height: " + currentHeight + "dp" ); - + resize(currentHeight); } /** * Resizes the dialog window based upon the size of its webView HTML content + * * @param height */ public void resize(final float height) { @@ -621,7 +578,7 @@ public void run() { try { // Since this is run asynchronously, notification might've been dismissed already if (getContext() == null || notification == null || notification.getDialog() == null || - notification.getDialog().getWindow() == null || !notification.getDialog().isShowing()) { + notification.getDialog().getWindow() == null || !notification.getDialog().isShowing()) { return; } @@ -654,14 +611,14 @@ public void run() { float relativeHeight = height * getResources().getDisplayMetrics().density; int newWebViewWidth = getResources().getDisplayMetrics().widthPixels; int newWebViewHeight = (int) relativeHeight; - + // Set WebView to explicit size RelativeLayout.LayoutParams webViewParams = new RelativeLayout.LayoutParams(newWebViewWidth, newWebViewHeight); - + // Apply positioning based on gravity int resizeGravity = getVerticalLocation(insetPadding); IterableLogger.d(TAG, "Resizing WebView directly - gravity: " + resizeGravity + " size: " + newWebViewWidth + "x" + newWebViewHeight + "px for inset padding: " + insetPadding); - + if (resizeGravity == Gravity.CENTER_VERTICAL) { webViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); IterableLogger.d(TAG, "Applied CENTER_IN_PARENT to WebView"); @@ -674,19 +631,19 @@ public void run() { webViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL); IterableLogger.d(TAG, "Applied BOTTOM alignment to WebView"); } - + // Make dialog full screen to allow proper positioning window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); - + // Apply the new layout params to WebView webView.setLayoutParams(webViewParams); - + // Force layout updates webView.requestLayout(); if (webView.getParent() instanceof ViewGroup) { ((ViewGroup) webView.getParent()).requestLayout(); } - + IterableLogger.d(TAG, "Applied explicit size and positioning to WebView: " + newWebViewWidth + "x" + newWebViewHeight); } } catch (IllegalArgumentException e) { @@ -698,6 +655,7 @@ public void run() { /** * Returns the vertical position of the dialog for the given padding + * * @param padding * @return */ @@ -711,6 +669,32 @@ int getVerticalLocation(Rect padding) { return gravity; } + /** + * Sets the window gravity based on inset padding + * + * @param window The dialog window to configure + * @param context Debug context string for logging + */ + private void applyWindowGravity(Window window, String context) { + if (window == null) { + return; + } + + WindowManager.LayoutParams windowParams = window.getAttributes(); + int gravity = getVerticalLocation(insetPadding); + + if (gravity == Gravity.CENTER_VERTICAL) { + windowParams.gravity = Gravity.CENTER; + } else if (gravity == Gravity.TOP) { + windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + } else if (gravity == Gravity.BOTTOM) { + windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + } + + window.setAttributes(windowParams); + IterableLogger.d(TAG, "Set window gravity in " + context + ": " + windowParams.gravity); + } + InAppLayout getInAppLayout(Rect padding) { if (padding.top == 0 && padding.bottom == 0) { return InAppLayout.FULLSCREEN; From e85d78a51c2c6a9f19eda783b36287d55bfcfe72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAkshay?= <“ayyanchira.akshay@gmail.com”> Date: Thu, 30 Oct 2025 13:14:44 -0700 Subject: [PATCH 3/3] Possible flaky test fix? And removed unnecessary logging --- .../iterable/iterableapi/IterableApiResponseTest.java | 10 ++++++++-- .../IterableInAppFragmentHTMLNotification.java | 11 ----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableApiResponseTest.java b/iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableApiResponseTest.java index 021c70b1d..afab7676b 100644 --- a/iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableApiResponseTest.java +++ b/iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableApiResponseTest.java @@ -37,8 +37,14 @@ public class IterableApiResponseTest { private MockWebServer server; @Before - public void setUp() { + public void setUp() throws IOException { server = new MockWebServer(); + // Explicitly start the server to ensure it's ready + try { + server.start(); + } catch (IllegalStateException e) { + // Server may already be started by url() call below, which is fine + } IterableApi.overrideURLEndpointPath(server.url("").toString()); createIterableApi(); } @@ -138,7 +144,7 @@ public void onFailure(@NonNull String reason, @Nullable JSONObject data) { new IterableRequestTask().execute(request); server.takeRequest(5, TimeUnit.SECONDS); - assertTrue("onFailure is called", signal.await(1, TimeUnit.SECONDS)); + assertTrue("onFailure is called", signal.await(5, TimeUnit.SECONDS)); } diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java index 86fb3d813..468f1da23 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java @@ -198,9 +198,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c webView = new IterableWebView(getContext()); webView.setId(R.id.webView); - // Debug the HTML content - IterableLogger.d(TAG, "HTML content preview: " + (htmlString.length() > 200 ? htmlString.substring(0, 200) + "..." : htmlString)); - webView.createWithHtml(this, htmlString); if (orientationListener == null) { @@ -241,7 +238,6 @@ public void run() { RelativeLayout webViewContainer = new RelativeLayout(this.getContext()); int gravity = getVerticalLocation(insetPadding); - IterableLogger.d(TAG, "Initial setup - gravity: " + gravity + " for inset padding: " + insetPadding); // Set FrameLayout gravity based on positioning FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams( @@ -251,13 +247,10 @@ public void run() { if (gravity == Gravity.CENTER_VERTICAL) { containerParams.gravity = Gravity.CENTER; - IterableLogger.d(TAG, "Applied CENTER gravity to container"); } else if (gravity == Gravity.TOP) { containerParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Applied TOP gravity to container"); } else if (gravity == Gravity.BOTTOM) { containerParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - IterableLogger.d(TAG, "Applied BOTTOM gravity to container"); } // Add WebView to the RelativeLayout container with WRAP_CONTENT for proper sizing @@ -268,13 +261,9 @@ public void run() { webViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); webViewContainer.addView(webView, webViewParams); - IterableLogger.d(TAG, "Added WebView with WRAP_CONTENT and CENTER_IN_PARENT rule"); - // Add the container to the FrameLayout frameLayout.addView(webViewContainer, containerParams); - IterableLogger.d(TAG, "Created FrameLayout with positioned RelativeLayout container"); - if (savedInstanceState == null || !savedInstanceState.getBoolean(IN_APP_OPEN_TRACKED, false)) { IterableApi.sharedInstance.trackInAppOpen(messageId, location); }