Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Expand Up @@ -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;
Expand Down Expand Up @@ -58,6 +59,12 @@
private boolean callbackOnCancel = false;
private String htmlString;
private String messageId;

// Resize debouncing fields
private Handler resizeHandler = new Handler();

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Handler.Handler
should be avoided because it has been deprecated.
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;
Expand Down Expand Up @@ -105,6 +112,35 @@
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) {
Expand Down Expand Up @@ -144,6 +180,25 @@
}
});
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) {
Expand All @@ -162,41 +217,111 @@
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be careful with the unit conversions since you are using an int and not a double.

Lets pull this calculation out to its own function so we can properly put tests around it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point actually especilly /90s can give easy values around 0 in decimals. Rounding up can be quite errorsome!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the logic to separate function and added tests for that method

if (currentOrientation != lastOrientation && lastOrientation != -1) {
lastOrientation = currentOrientation;

// Use longer delay for orientation changes to allow layout to stabilize
final Handler handler = new Handler();

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Handler.Handler
should be avoided because it has been deprecated.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated ✅

handler.postDelayed(new Runnable() {
@Override
public void run() {
IterableLogger.d(TAG, "Orientation changed, triggering resize");
runResizeScript();
}
}, 1500); // Increased delay for better stability
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number

} else if (lastOrientation == -1) {
lastOrientation = currentOrientation;
}
}
}
};
}

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) {
Expand Down Expand Up @@ -226,6 +351,12 @@
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;
}
Expand Down Expand Up @@ -414,7 +545,50 @@

@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);
}

/**
Expand Down Expand Up @@ -462,9 +636,44 @@
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
Loading