Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -31,6 +31,7 @@ public class CleverPushPreferences {
public static final String STORIES_UNREAD_COUNT_GROUP = "CleverPush_STORIES_UNREAD_COUNT_GROUP";
public static final String SUB_STORY_POSITION = "CleverPush_SUB_STORY_POSITION";
public static final String APP_BANNER_SHOWING = "CleverPush_APP_BANNER_SHOWING";
public static final String APP_BANNER_SHOWING_IN_PROGRESS = "CleverPush_APP_BANNER_SHOWING_IN_PROGRESS";
public static final String UNSUBSCRIBED = "CleverPush_UNSUBSCRIBED";
public static final String TOPIC_LAST_CHECKED = "CleverPush_TOPIC_LAST_CHECKED";
public static final String LAST_TIME_AUTO_SHOWED = "CleverPush_LAST_TIME_AUTO_SHOWED";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AppBannerCarouselAdapter extends RecyclerView.Adapter<AppBannerCarouselAdapter.ViewHolder> {

Expand Down Expand Up @@ -748,7 +750,10 @@ private void composeHtmlBanner(LinearLayout body, String htmlContent) {
"</script>\n";
String htmlWithJs;
if (lower.contains("</body>")) {
htmlWithJs = html.replaceAll("(?i)</body>", jsToInject + "</body>");
htmlWithJs = Pattern
.compile("(?i)</body>")
.matcher(html)
.replaceAll(Matcher.quoteReplacement(jsToInject + "</body>"));
} else if (lower.contains("<body")) {
htmlWithJs = html + jsToInject;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private AppBannerModule(String channel, boolean showDrafts, SharedPreferences sh
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
editor.putBoolean(CleverPushPreferences.APP_BANNER_SHOWING, false);
editor.putBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, false);
editor.apply();
}

Expand Down Expand Up @@ -1856,7 +1857,8 @@ void showBanner(AppBannerPopup bannerPopup, boolean force, AppBannerClosedListen
Banner banner = bannerPopup.getData();
setAppBannerClosedListener(appBannerClosedListener);
if (!force) {
if (sharedPreferences.getBoolean(CleverPushPreferences.APP_BANNER_SHOWING, false)) {
if (sharedPreferences.getBoolean(CleverPushPreferences.APP_BANNER_SHOWING, false)
|| sharedPreferences.getBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, false)) {
pendingFilteredBanners.add(bannerPopup);
Logger.d(TAG, "Skipping Banner " + banner.getId() + " because: A Banner is already on the screen");
return;
Expand Down Expand Up @@ -1905,6 +1907,8 @@ void showBanner(AppBannerPopup bannerPopup, boolean force, AppBannerClosedListen
bannerPopup.init();
bannerPopup.show();

sharedPreferences.edit().putBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, true).apply();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Race condition: flag set after show instead of before

The APP_BANNER_SHOWING_IN_PROGRESS flag is set at line 1910 after bannerPopup.show() is called, but it's checked at lines 1860-1861 to prevent concurrent banner display. Since show() starts an AsyncTask and the flag is set afterward, there's a window where multiple concurrent calls could pass the check before any of them sets the flag. This defeats the intended purpose of preventing overlapping banner displays. The flag needs to be set before calling show() to properly protect the critical section.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Flag stuck true when async banner display fails

The APP_BANNER_SHOWING_IN_PROGRESS flag is set to true at line 1910 but only reset in synchronous catch blocks and toggleShowing(false). If the tryShowSafe AsyncTask fails — either because the activity becomes invalid (finishing/destroyed) before the banner loads, or an exception occurs in displayBanner/animateBody — the popup never displays, the dismiss listener never fires, and the flag remains true. This blocks all future non-forced banners until app restart when the flag is reset in the constructor.

Additional Locations (1)

Fix in Cursor Fix in Web


getActivityLifecycleListener().setActivityInitializedListener(new ActivityInitializedListener() {
@Override
public void initialized() {
Expand Down Expand Up @@ -2006,6 +2010,7 @@ public void initialized() {
getCleverPushInstance().getAppBannerShownListener().shown(banner);
}
} catch (Exception ex) {
sharedPreferences.edit().putBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, false).apply();
Logger.e(TAG, "Error in showBanner. " + ex.getMessage(), ex);
}
}
Expand All @@ -2014,6 +2019,9 @@ void showBanner(AppBannerPopup bannerPopup) {
try {
showBanner(bannerPopup, false, null, null);
} catch (Exception ex) {
try {
sharedPreferences.edit().putBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, false).apply();
} catch (Exception ignore) { }
Logger.e(TAG, ex.getMessage(), ex);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ private void toggleShowing(boolean isShowing) {
SharedPreferences sharedPreferences = SharedPreferencesManager.getSharedPreferences(CleverPush.context);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(CleverPushPreferences.APP_BANNER_SHOWING, isShowing);
editor.putBoolean(CleverPushPreferences.APP_BANNER_SHOWING_IN_PROGRESS, isShowing);
editor.apply();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class InboxDetailBannerCarouselAdapter extends RecyclerView.Adapter<InboxDetailBannerCarouselAdapter.ViewHolder> {

Expand Down Expand Up @@ -475,7 +477,10 @@ private void composeHtmlBanner(LinearLayout body, String htmlContent) {
"</script>\n";
String htmlWithJs;
if (lower.contains("</body>")) {
htmlWithJs = html.replaceAll("(?i)</body>", jsToInject + "</body>");
htmlWithJs = Pattern
.compile("(?i)</body>")
.matcher(html)
.replaceAll(Matcher.quoteReplacement(jsToInject + "</body>"));
} else if (lower.contains("<body")) {
htmlWithJs = html + jsToInject;
} else {
Expand Down
1 change: 0 additions & 1 deletion cleverpush/src/main/res/layout/app_banner_html.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="wrap"
app:layout_constraintWidth_percent="1" />

</androidx.constraintlayout.widget.ConstraintLayout>
Expand Down
Loading