Skip to content

Commit 79b5978

Browse files
In-app messages on fullscreen now can gide the system bars for better click handling
1 parent 26f615f commit 79b5978

5 files changed

Lines changed: 114 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [Unreleased]
6+
### Added
7+
- Added `setShouldHideStatusBarOnFullScreenInApp` option to `IterableConfig.Builder`. When enabled, full screen in-app messages will hide the system status bar and navigation bar while the message is displayed, and automatically restore them when dismissed. Defaults to `false`.
8+
59
## [3.6.4]
610
### Fixed
711
- Updated `customPayload` of In-App Messages to be `@Nullable`

iterableapi/src/main/java/com/iterable/iterableapi/IterableConfig.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ public class IterableConfig {
148148
@Nullable
149149
final String webViewBaseUrl;
150150

151+
/**
152+
* When set to {@code true}, full screen in-app messages will hide the system status bar
153+
* and navigation bar while the message is displayed. The system bars are automatically
154+
* restored when the message is dismissed.
155+
* Defaults to {@code false}.
156+
*/
157+
final boolean shouldHideStatusBarOnFullScreenInApp;
158+
151159
/**
152160
* Get the configured WebView base URL
153161
* @return Base URL for WebView content, or null if not configured
@@ -183,6 +191,7 @@ private IterableConfig(Builder builder) {
183191
decryptionFailureHandler = builder.decryptionFailureHandler;
184192
mobileFrameworkInfo = builder.mobileFrameworkInfo;
185193
webViewBaseUrl = builder.webViewBaseUrl;
194+
shouldHideStatusBarOnFullScreenInApp = builder.shouldHideStatusBarOnFullScreenInApp;
186195
}
187196

188197
public static class Builder {
@@ -211,6 +220,7 @@ public static class Builder {
211220
private IterableIdentityResolution identityResolution = new IterableIdentityResolution();
212221
private IterableUnknownUserHandler iterableUnknownUserHandler;
213222
private String webViewBaseUrl;
223+
private boolean shouldHideStatusBarOnFullScreenInApp = false;
214224

215225
public Builder() {}
216226

@@ -465,6 +475,19 @@ public Builder setWebViewBaseUrl(@Nullable String webViewBaseUrl) {
465475
return this;
466476
}
467477

478+
/**
479+
* Set whether the SDK should hide the system status bar and navigation bar when
480+
* displaying full screen in-app messages. When enabled, the system bars are hidden
481+
* while the message is shown and automatically restored when it is dismissed.
482+
* Defaults to {@code false}.
483+
* @param shouldHide {@code true} to hide system bars for full screen in-app messages
484+
*/
485+
@NonNull
486+
public Builder setShouldHideStatusBarOnFullScreenInApp(boolean shouldHide) {
487+
this.shouldHideStatusBarOnFullScreenInApp = shouldHide;
488+
return this;
489+
}
490+
468491
@NonNull
469492
public IterableConfig build() {
470493
return new IterableConfig(this);

iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppFragmentHTMLNotification.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,14 @@ public void onStart() {
129129

130130
Dialog dialog = getDialog();
131131
if (dialog != null) {
132-
if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) {
132+
if (isFullScreenWithHiddenStatusBar()) {
133133
hideActivitySystemBars();
134134

135135
Window dialogWindow = dialog.getWindow();
136136
if (dialogWindow != null) {
137137
WindowCompat.setDecorFitsSystemWindows(dialogWindow, false);
138138
}
139-
} else {
139+
} else if (getInAppLayout(insetPadding) != InAppLayout.FULLSCREEN) {
140140
applyWindowGravity(dialog.getWindow(), "onStart");
141141
}
142142
}
@@ -300,12 +300,12 @@ public void run() {
300300
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
301301
super.onViewCreated(view, savedInstanceState);
302302

303-
if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) {
303+
if (isFullScreenWithHiddenStatusBar()) {
304304
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> {
305305
v.setPadding(0, 0, 0, 0);
306306
return WindowInsetsCompat.CONSUMED;
307307
});
308-
} else {
308+
} else if (getInAppLayout(insetPadding) != InAppLayout.FULLSCREEN) {
309309
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> {
310310
Insets sysBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
311311
v.setPadding(0, sysBars.top, 0, sysBars.bottom);
@@ -318,9 +318,6 @@ public void setLoaded(boolean loaded) {
318318
this.loaded = loaded;
319319
}
320320

321-
/**
322-
* Sets up the webView and the dialog layout
323-
*/
324321
@Override
325322
public void onSaveInstanceState(@NonNull Bundle outState) {
326323
super.onSaveInstanceState(outState);
@@ -330,7 +327,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) {
330327
@Override
331328
public void onResume() {
332329
super.onResume();
333-
if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) {
330+
if (isFullScreenWithHiddenStatusBar()) {
334331
hideActivitySystemBars();
335332
}
336333
}
@@ -342,7 +339,7 @@ public void onResume() {
342339
public void onStop() {
343340
orientationListener.disable();
344341

345-
if (getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN) {
342+
if (isFullScreenWithHiddenStatusBar()) {
346343
restoreActivitySystemBars();
347344
}
348345

@@ -767,6 +764,20 @@ InAppLayout getInAppLayout(Rect padding) {
767764
}
768765
}
769766

767+
private boolean isFullScreenWithHiddenStatusBar() {
768+
return getInAppLayout(insetPadding) == InAppLayout.FULLSCREEN && shouldHideStatusBar();
769+
}
770+
771+
private boolean shouldHideStatusBar() {
772+
try {
773+
return IterableApi.sharedInstance != null
774+
&& IterableApi.sharedInstance.config != null
775+
&& IterableApi.sharedInstance.config.shouldHideStatusBarOnFullScreenInApp;
776+
} catch (Exception e) {
777+
return false;
778+
}
779+
}
780+
770781
private void hideActivitySystemBars() {
771782
Activity activity = getActivity();
772783
if (activity == null || activity.getWindow() == null) {

iterableapi/src/test/java/com/iterable/iterableapi/IterableConfigTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,18 @@ class IterableConfigTest {
5151
val config: IterableConfig = configBuilder.build()
5252
assertFalse(config.keychainEncryption)
5353
}
54+
55+
@Test
56+
fun defaultShouldHideStatusBarOnFullScreenInApp() {
57+
val config = IterableConfig.Builder().build()
58+
assertFalse(config.shouldHideStatusBarOnFullScreenInApp)
59+
}
60+
61+
@Test
62+
fun setShouldHideStatusBarOnFullScreenInApp() {
63+
val config = IterableConfig.Builder()
64+
.setShouldHideStatusBarOnFullScreenInApp(true)
65+
.build()
66+
assertTrue(config.shouldHideStatusBarOnFullScreenInApp)
67+
}
5468
}

iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppHTMLNotificationTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,57 @@ public void testRoundToNearest90Degrees_EdgeCases() {
381381
assertEquals(360, IterableInAppFragmentHTMLNotification.roundToNearest90Degrees(315));
382382
assertEquals(360, IterableInAppFragmentHTMLNotification.roundToNearest90Degrees(359));
383383
}
384+
385+
// ===== Status Bar Hiding Config Tests =====
386+
387+
@Test
388+
public void testFullScreenInApp_StatusBarNotHiddenByDefault() {
389+
// With default config (shouldHideStatusBarOnFullScreenInApp = false),
390+
// full screen in-app messages should show without crashing and without hiding system bars
391+
Rect fullScreenPadding = new Rect(0, 0, 0, 0);
392+
IterableInAppDisplayer.showIterableFragmentNotificationHTML(activity, "<html><body>Test</body></html>", "", null, 0.0, fullScreenPadding, true, new IterableInAppMessage.InAppBgColor(null, 0.0f), false, IterableInAppLocation.IN_APP);
393+
shadowOf(getMainLooper()).idle();
394+
395+
IterableInAppFragmentHTMLNotification notification = IterableInAppFragmentHTMLNotification.getInstance();
396+
assertNotNull(notification);
397+
assertNotNull(notification.getDialog());
398+
assertTrue(notification.getDialog().isShowing());
399+
}
400+
401+
@Test
402+
public void testFullScreenInApp_StatusBarHiddenWhenConfigEnabled() {
403+
// Re-initialize with the config flag enabled
404+
IterableTestUtils.resetIterableApi();
405+
IterableTestUtils.createIterableApiNew(builder ->
406+
builder.setShouldHideStatusBarOnFullScreenInApp(true)
407+
);
408+
409+
Rect fullScreenPadding = new Rect(0, 0, 0, 0);
410+
IterableInAppDisplayer.showIterableFragmentNotificationHTML(activity, "<html><body>Test</body></html>", "", null, 0.0, fullScreenPadding, true, new IterableInAppMessage.InAppBgColor(null, 0.0f), false, IterableInAppLocation.IN_APP);
411+
shadowOf(getMainLooper()).idle();
412+
413+
IterableInAppFragmentHTMLNotification notification = IterableInAppFragmentHTMLNotification.getInstance();
414+
assertNotNull(notification);
415+
assertNotNull(notification.getDialog());
416+
assertTrue(notification.getDialog().isShowing());
417+
}
418+
419+
@Test
420+
public void testNonFullScreenInApp_UnaffectedByStatusBarConfig() {
421+
// Re-initialize with the config flag enabled
422+
IterableTestUtils.resetIterableApi();
423+
IterableTestUtils.createIterableApiNew(builder ->
424+
builder.setShouldHideStatusBarOnFullScreenInApp(true)
425+
);
426+
427+
// Use top padding (non-fullscreen) - should not be affected by the status bar config
428+
Rect topPadding = new Rect(0, 0, 0, -1);
429+
IterableInAppDisplayer.showIterableFragmentNotificationHTML(activity, "<html><body>Test</body></html>", "", null, 0.0, topPadding, true, new IterableInAppMessage.InAppBgColor(null, 0.0f), false, IterableInAppLocation.IN_APP);
430+
shadowOf(getMainLooper()).idle();
431+
432+
IterableInAppFragmentHTMLNotification notification = IterableInAppFragmentHTMLNotification.getInstance();
433+
assertNotNull(notification);
434+
assertNotNull(notification.getDialog());
435+
assertTrue(notification.getDialog().isShowing());
436+
}
384437
}

0 commit comments

Comments
 (0)