Skip to content

Commit 0ef68e4

Browse files
committed
[ads] RichNTT: Android
1 parent 5f96b0c commit 0ef68e4

30 files changed

+640
-8
lines changed

android/brave_java_sources.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ brave_java_sources = [
264264
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/ImageCredit.java",
265265
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/NTPImage.java",
266266
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/SponsoredLogo.java",
267+
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/SponsoredRichMedia.java",
267268
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/SponsoredTab.java",
268269
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/TopSite.java",
269270
"../../brave/android/java/org/chromium/chrome/browser/ntp_background_images/model/Wallpaper.java",

android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@
116116
import java.util.UUID;
117117
import java.util.concurrent.CopyOnWriteArrayList;
118118

119+
import android.net.Uri;
120+
import android.widget.FrameLayout;
121+
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
122+
import org.chromium.base.version_info.VersionInfo;
123+
import org.chromium.chrome.browser.content.WebContentsFactory;
124+
import org.chromium.chrome.browser.ntp_background_images.model.SponsoredRichMedia;
125+
import org.chromium.components.embedder_support.view.ContentView;
126+
import org.chromium.components.thinwebview.ThinWebView;
127+
import org.chromium.components.thinwebview.ThinWebViewConstraints;
128+
import org.chromium.components.thinwebview.ThinWebViewFactory;
129+
import org.chromium.content_public.browser.LoadUrlParams;
130+
import org.chromium.content_public.browser.WebContents;
131+
import org.chromium.net.NetId;
132+
import org.chromium.ui.base.IntentRequestTracker;
133+
import org.chromium.ui.base.ViewAndroidDelegate;
134+
119135
public class BraveNewTabPageLayout
120136
extends NewTabPageLayout implements ConnectionErrorHandler, OnBraveNtpListener {
121137
private static final String TAG = "BraveNewTabPage";
@@ -132,7 +148,14 @@ public class BraveNewTabPageLayout
132148
private Integer mInitialTileNum;
133149

134150
// Own members.
151+
private WindowAndroid mWindowAndroid;
152+
135153
private ImageView mBgImageView;
154+
private WebContents mSponsoredBackgroundWebContents;
155+
private ThinWebView mSponsoredBackgroundWebView;
156+
private FrameLayout mBackgroundSponsoredContentView;
157+
private SponsoredRichMedia mSponsoredRichMedia;
158+
136159
private Profile mProfile;
137160
private SponsoredTab mSponsoredTab;
138161
private boolean mIsTablet;
@@ -441,6 +464,31 @@ private void setNtpRecyclerView(LinearLayoutManager linearLayoutManager) {
441464
}
442465

443466
mPrevVisibleNewsCardPosition = firstNewsFeedPosition() - 1;
467+
468+
mRecyclerView.addOnItemTouchListener(
469+
new OnItemTouchListener() {
470+
@Override
471+
public boolean onInterceptTouchEvent(
472+
RecyclerView recyclerView, MotionEvent event) {
473+
final View childView =
474+
recyclerView.findChildViewUnder(event.getX(), event.getY());
475+
if (childView == null && mSponsoredBackgroundWebView != null) {
476+
mSponsoredBackgroundWebView.getView().dispatchTouchEvent(event);
477+
}
478+
return false;
479+
}
480+
481+
@Override
482+
public void onTouchEvent(RecyclerView recyclerView, MotionEvent event) {
483+
}
484+
485+
@Override
486+
public void onRequestDisallowInterceptTouchEvent(
487+
boolean disallowIntercept) {
488+
}
489+
}
490+
);
491+
444492
mRecyclerView.addOnScrollListener(
445493
new RecyclerView.OnScrollListener() {
446494
@Override
@@ -931,6 +979,11 @@ public void onConfigurationChanged(Configuration newConfig) {
931979
if (mWallpaper == null) {
932980
mSponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage());
933981
}
982+
} else if (ntpImage instanceof SponsoredRichMedia) {
983+
mSponsoredRichMedia = (SponsoredRichMedia) ntpImage;
984+
if (mSponsoredRichMedia == null) {
985+
mSponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage());
986+
}
934987
}
935988
super.onConfigurationChanged(newConfig);
936989
showNTPImage(ntpImage);
@@ -1181,6 +1234,8 @@ public void initialize(
11811234
tabStripHeightSupplier);
11821235

11831236
mIsTablet = isTablet;
1237+
mWindowAndroid = windowAndroid;
1238+
11841239

11851240
assert mMvTilesContainerLayout != null : "Something has changed in the upstream!";
11861241

@@ -1222,6 +1277,9 @@ private void showNTPImage(NTPImage ntpImage) {
12221277
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
12231278
setBackgroundImage(ntpImage);
12241279

1280+
} else if (ntpImage instanceof SponsoredRichMedia) {
1281+
final SponsoredRichMedia sponsoredRichMedia = (SponsoredRichMedia) ntpImage;
1282+
setupSponsoredBackgroundContent(sponsoredRichMedia);
12251283
} else if (UserPrefs.get(ProfileManager.getLastUsedRegularProfile())
12261284
.getBoolean(BravePref.NEW_TAB_PAGE_SHOW_BACKGROUND_IMAGE)
12271285
&& mSponsoredTab != null
@@ -1230,6 +1288,61 @@ private void showNTPImage(NTPImage ntpImage) {
12301288
}
12311289
}
12321290

1291+
private void createSponsoredBackgroundWebContentsIfNeeded() {
1292+
if (mSponsoredBackgroundWebContents != null) {
1293+
return;
1294+
}
1295+
1296+
mSponsoredBackgroundWebContents =
1297+
WebContentsFactory.createWebContentsWithWarmRenderer(
1298+
mProfile,
1299+
/* initiallyHidden= */ false,
1300+
/* targetNetwork= */ NetId.INVALID);
1301+
1302+
final ContentView webContentView =
1303+
ContentView.createContentView(mActivity, mSponsoredBackgroundWebContents);
1304+
final ViewAndroidDelegate delegate =
1305+
ViewAndroidDelegate.createBasicDelegate(webContentView);
1306+
mSponsoredBackgroundWebContents.setDelegates(
1307+
VersionInfo.getProductVersion(),
1308+
delegate,
1309+
webContentView,
1310+
mWindowAndroid,
1311+
WebContents.createDefaultInternalsHolder());
1312+
1313+
final IntentRequestTracker intentRequestTracker = mWindowAndroid.getIntentRequestTracker();
1314+
mSponsoredBackgroundWebView =
1315+
ThinWebViewFactory.create(
1316+
mActivity, new ThinWebViewConstraints(), intentRequestTracker);
1317+
mSponsoredBackgroundWebView
1318+
.getView()
1319+
.setLayoutParams(
1320+
new FrameLayout.LayoutParams(
1321+
ViewGroup.LayoutParams.MATCH_PARENT,
1322+
ViewGroup.LayoutParams.MATCH_PARENT));
1323+
mSponsoredBackgroundWebView.attachWebContents(mSponsoredBackgroundWebContents,
1324+
webContentView,
1325+
null);
1326+
1327+
mBackgroundSponsoredContentView = findViewById(R.id.bg_background_view);
1328+
mBackgroundSponsoredContentView.setVisibility(View.VISIBLE);
1329+
mBackgroundSponsoredContentView.addView(mSponsoredBackgroundWebView.getView());
1330+
}
1331+
1332+
private void setupSponsoredBackgroundContent(SponsoredRichMedia sponsoredRichMedia) {
1333+
createSponsoredBackgroundWebContentsIfNeeded();
1334+
1335+
Uri.Builder builder = Uri.parse("chrome://new-tab-takeover").buildUpon();
1336+
builder.appendQueryParameter("wallpaperUrl", sponsoredRichMedia.getWallpaperUrl());
1337+
builder.appendQueryParameter("creativeInstanceId", sponsoredRichMedia.getCreativeInstanceId());
1338+
builder.appendQueryParameter("placementId", sponsoredRichMedia.getPlacementId());
1339+
builder.appendQueryParameter("targetUrl", sponsoredRichMedia.getTargetUrl());
1340+
1341+
mSponsoredBackgroundWebContents
1342+
.getNavigationController()
1343+
.loadUrl(new LoadUrlParams(builder.build().toString()));
1344+
}
1345+
12331346
private void setBackgroundImage(NTPImage ntpImage) {
12341347
mBgImageView = (ImageView) findViewById(R.id.bg_image_view);
12351348
mBgImageView.setScaleType(ImageView.ScaleType.MATRIX);
@@ -1261,6 +1374,11 @@ private void checkAndShowNTPImage(boolean isReset) {
12611374
if (mWallpaper == null) {
12621375
mSponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage());
12631376
}
1377+
} else if (ntpImage instanceof SponsoredRichMedia) {
1378+
mSponsoredRichMedia = (SponsoredRichMedia) ntpImage;
1379+
if (mSponsoredRichMedia == null) {
1380+
mSponsoredTab.setNTPImage(SponsoredImageUtil.getBackgroundImage());
1381+
}
12641382
}
12651383
showNTPImage(ntpImage);
12661384
}

android/java/org/chromium/chrome/browser/ntp_background_images/NTPBackgroundImagesBridge.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.chromium.chrome.browser.ntp_background_images.model.ImageCredit;
1818
import org.chromium.chrome.browser.ntp_background_images.model.NTPImage;
1919
import org.chromium.chrome.browser.ntp_background_images.model.TopSite;
20+
import org.chromium.chrome.browser.ntp_background_images.model.SponsoredRichMedia;
2021
import org.chromium.chrome.browser.ntp_background_images.model.Wallpaper;
2122
import org.chromium.chrome.browser.ntp_background_images.util.NewTabPageListener;
2223
import org.chromium.chrome.browser.profiles.Profile;
@@ -155,6 +156,11 @@ public static Wallpaper createBrandedWallpaper(String imagePath, int focalPointX
155156
wallpaperId);
156157
}
157158

159+
@CalledByNative
160+
public static SponsoredRichMedia createSponsoredRichMedia(String wallpaperUrl, String creativeInstanceId, String placementId, String targetUrl) {
161+
return new SponsoredRichMedia(wallpaperUrl, creativeInstanceId, placementId, targetUrl);
162+
}
163+
158164
@CalledByNative
159165
public void onUpdated() {
160166
for (NTPBackgroundImageServiceObserver observer : mObservers) {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at https://mozilla.org/MPL/2.0/. */
5+
6+
package org.chromium.chrome.browser.ntp_background_images.model;
7+
8+
public class SponsoredRichMedia extends NTPImage {
9+
private String mWallpaperUrl;
10+
private String mCreativeInstanceId;
11+
private String mPlacementId;
12+
private String mTargetUrl;
13+
14+
public SponsoredRichMedia(String wallpaperUrl, String creativeInstanceId, String placementId, String targetUrl) {
15+
mWallpaperUrl = wallpaperUrl;
16+
mCreativeInstanceId = creativeInstanceId;
17+
mPlacementId = placementId;
18+
mTargetUrl = targetUrl;
19+
}
20+
21+
public String getWallpaperUrl() {
22+
return mWallpaperUrl;
23+
}
24+
25+
public void setWallpaperUrl(String wallpaperUrl) {
26+
mWallpaperUrl = wallpaperUrl;
27+
}
28+
29+
public String getCreativeInstanceId() {
30+
return mCreativeInstanceId;
31+
}
32+
33+
public void setCreativeInstanceId(String creativeInstanceId) {
34+
mCreativeInstanceId = creativeInstanceId;
35+
}
36+
37+
public String getPlacementId() {
38+
return mPlacementId;
39+
}
40+
41+
public void setPlacementId(String placementId) {
42+
mPlacementId = placementId;
43+
}
44+
45+
public String getTargetUrl() {
46+
return mTargetUrl;
47+
}
48+
49+
public void setTargetUrl(String targetUrl) {
50+
mTargetUrl = targetUrl;
51+
}
52+
}

android/java/org/chromium/chrome/browser/util/TabUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
import org.chromium.content_public.browser.LoadUrlParams;
4747
import org.chromium.ui.util.ColorUtils;
4848

49+
import org.jni_zero.CalledByNative;
50+
4951
import java.lang.reflect.Field;
5052

5153
public class TabUtils {
@@ -236,6 +238,7 @@ public static void openUrlInNewTabInBackground(boolean isIncognito, String url)
236238
}
237239
}
238240

241+
@CalledByNative
239242
public static void openUrlInSameTab(String url) {
240243
try {
241244
BraveActivity braveActivity = BraveActivity.getBraveActivity();

android/java/res/layout/new_tab_page_layout.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
android:layout_height="match_parent"
2626
android:contentDescription="@null"/>
2727

28+
<FrameLayout
29+
android:id="@+id/bg_background_view"
30+
android:layout_width="match_parent"
31+
android:layout_height="match_parent">
32+
</FrameLayout>
33+
2834
<FrameLayout
2935
android:id="@+id/logo_holder"
3036
android:layout_width="match_parent"

browser/brave_content_browser_client.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ using extensions::ChromeContentBrowserClientExtensionsPart;
228228

229229
#if BUILDFLAG(IS_ANDROID)
230230
#include "brave/browser/ui/webui/brave_wallet/android/android_wallet_page_ui.h"
231+
#include "brave/browser/ui/webui/new_tab_takeover_page/android/new_tab_takeover_page_ui.h"
232+
#include "brave/components/brave_new_tab_ui/new_tab_takeover_page/mojom/new_tab_takeover_page.mojom.h"
231233
#endif // BUILDFLAG(IS_ANDROID)
232234

233235
#if !BUILDFLAG(IS_ANDROID)
@@ -681,7 +683,10 @@ void BraveContentBrowserClient::RegisterWebUIInterfaceBrokers(
681683
.Add<brave_news::mojom::BraveNewsController>()
682684
.Add<brave_news::mojom::BraveNewsInternals>();
683685
}
684-
#endif
686+
#else
687+
registry.ForWebUI<NewTabTakeoverPageUI>()
688+
.Add<new_tab_takeover_page::mojom::NewTabTakeoverPage>();
689+
#endif // !BUILDFLAG(IS_ANDROID)
685690
}
686691

687692
std::optional<base::UnguessableToken>

browser/ntp_background/android/ntp_background_images_bridge.cc

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,42 @@ NTPBackgroundImagesBridge::CreateBrandedWallpaper(
193193
ConvertUTF8ToJavaString(env, wallpaper_id ? *wallpaper_id : ""));
194194
}
195195

196+
base::android::ScopedJavaLocalRef<jobject>
197+
NTPBackgroundImagesBridge::CreateSponsoredRichMedia(
198+
const base::Value::Dict& data) {
199+
JNIEnv* env = AttachCurrentThread();
200+
201+
const std::string* wallpaper_url =
202+
data.FindString(ntp_background_images::kWallpaperURLKey);
203+
if (!wallpaper_url) {
204+
return base::android::ScopedJavaLocalRef<jobject>();
205+
}
206+
207+
const std::string* creative_instance_id =
208+
data.FindString(ntp_background_images::kCreativeInstanceIDKey);
209+
if (!creative_instance_id) {
210+
return base::android::ScopedJavaLocalRef<jobject>();
211+
}
212+
213+
const std::string* placement_id =
214+
data.FindString(ntp_background_images::kWallpaperIDKey);
215+
if (!placement_id) {
216+
return base::android::ScopedJavaLocalRef<jobject>();
217+
}
218+
219+
const std::string* target_url = data.FindStringByDottedPath(
220+
ntp_background_images::kLogoDestinationURLPath);
221+
if (!target_url) {
222+
return base::android::ScopedJavaLocalRef<jobject>();
223+
}
224+
225+
return Java_NTPBackgroundImagesBridge_createSponsoredRichMedia(
226+
env, ConvertUTF8ToJavaString(env, *wallpaper_url),
227+
ConvertUTF8ToJavaString(env, *creative_instance_id),
228+
ConvertUTF8ToJavaString(env, *placement_id),
229+
ConvertUTF8ToJavaString(env, *target_url));
230+
}
231+
196232
void NTPBackgroundImagesBridge::GetTopSites(JNIEnv* env,
197233
const JavaParamRef<jobject>& obj) {
198234
std::vector<ntp_background_images::TopSite> top_sites =
@@ -257,12 +293,18 @@ NTPBackgroundImagesBridge::GetCurrentWallpaper(
257293
if (!data)
258294
return base::android::ScopedJavaLocalRef<jobject>();
259295

260-
bool is_background =
296+
// TODO(aseren): Add SponsoredRichMedia support.
297+
const bool is_background =
261298
data->FindBool(ntp_background_images::kIsBackgroundKey).value_or(false);
262-
if (!is_background) {
263-
return CreateBrandedWallpaper(*data);
264-
} else {
299+
const std::string* sponsored_rich_media_type =
300+
data->FindString(ntp_background_images::kWallpaperTypeKey);
301+
if (is_background) {
265302
return CreateWallpaper(*data);
303+
} else if (sponsored_rich_media_type &&
304+
*sponsored_rich_media_type == "richMedia") {
305+
return CreateSponsoredRichMedia(*data);
306+
} else {
307+
return CreateBrandedWallpaper(*data);
266308
}
267309
}
268310

browser/ntp_background/android/ntp_background_images_bridge.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class NTPBackgroundImagesBridge : public NTPBackgroundImagesService::Observer,
7777
const base::Value::Dict& data);
7878
base::android::ScopedJavaLocalRef<jobject> CreateBrandedWallpaper(
7979
const base::Value::Dict& data);
80+
base::android::ScopedJavaLocalRef<jobject> CreateSponsoredRichMedia(
81+
const base::Value::Dict& data);
8082

8183
raw_ptr<Profile> profile_ = nullptr;
8284
raw_ptr<ViewCounterService> view_counter_service_ = nullptr;

browser/sources.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ if (is_android) {
412412
"//brave/browser/brave_ads/android",
413413
"//brave/browser/download/android:jni_headers",
414414
"//brave/browser/ntp_background/android",
415+
"//brave/browser/ui/webui/new_tab_takeover_page/android:new_tab_takeover_page",
415416
"//brave/build/android:jni_headers",
416417
"//brave/components/brave_sync:sync_service_impl_helper",
417418
"//chrome/android:jni_headers",

0 commit comments

Comments
 (0)