Skip to content

Commit

Permalink
[Shopping Service] Add product info API
Browse files Browse the repository at this point in the history
This patch adds the infra to support basic querying of product
information given a URL on all platforms. A basic unit test suite
has also been added.

Change-Id: Iccbe4b5f2a75e4e2e18ccb8d7d0052df05548982
Bug: 1322095
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3593853
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Zhiyuan Cai <zhiyuancai@chromium.org>
Reviewed-by: David Maunder <davidjm@chromium.org>
Reviewed-by: Ayman Almadhoun <ayman@chromium.org>
Commit-Queue: Matthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1001062}
  • Loading branch information
iotitan authored and Chromium LUCI CQ committed May 9, 2022
1 parent 69b4a0d commit 5113aa5
Show file tree
Hide file tree
Showing 13 changed files with 525 additions and 11 deletions.
8 changes: 7 additions & 1 deletion chrome/browser/commerce/shopping_service_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
#include "chrome/browser/commerce/shopping_service_factory.h"

#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "components/commerce/core/shopping_service.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"

Expand Down Expand Up @@ -36,12 +39,15 @@ ShoppingServiceFactory::ShoppingServiceFactory()
"ShoppingService",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(BookmarkModelFactory::GetInstance());
DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance());
}

KeyedService* ShoppingServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new ShoppingService(
BookmarkModelFactory::GetInstance()->GetForBrowserContext(context));
BookmarkModelFactory::GetInstance()->GetForBrowserContext(context),
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(context)));
}

content::BrowserContext* ShoppingServiceFactory::GetBrowserContextToUse(
Expand Down
1 change: 1 addition & 0 deletions components/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ test("components_unittests") {
"//components/certificate_matching:unit_tests",
"//components/client_update_protocol:unit_tests",
"//components/cloud_devices/common:unit_tests",
"//components/commerce/core:shopping_service_unit_tests",
"//components/component_updater:unit_tests",
"//components/component_updater/installer_policies:unit_tests",
"//components/consent_auditor:unit_tests",
Expand Down
29 changes: 28 additions & 1 deletion components/commerce/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,15 @@ static_library("shopping_service") {
]

deps = [
":feature_list",
":proto",
"//base",
"//components/bookmarks/browser",
"//components/keyed_service/core",
"//components/optimization_guide/core",
"//components/optimization_guide/proto:optimization_guide_proto",
"//components/prefs:prefs",
"//url:url",
]

if (is_android) {
Expand All @@ -148,7 +153,10 @@ static_library("shopping_service") {
"android/shopping_service_android.h",
]

deps += [ ":shopping_service_jni_headers" ]
deps += [
":shopping_service_jni_headers",
"//url:gurl_android",
]
}
}

Expand All @@ -157,3 +165,22 @@ if (is_android) {
sources = [ "android/java/src/org/chromium/components/commerce/core/ShoppingService.java" ]
}
}

source_set("shopping_service_unit_tests") {
testonly = true

sources = [ "shopping_service_unittest.cc" ]

deps = [
":feature_list",
":shopping_service",
"//base/test:test_support",
"//components/bookmarks/browser",
"//components/bookmarks/test",
"//components/commerce/core:proto",
"//components/optimization_guide/core",
"//components/optimization_guide/proto:optimization_guide_proto",
"//testing/gtest",
"//url:url",
]
}
1 change: 1 addition & 0 deletions components/commerce/core/DEPS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include_rules = [
"+components/bookmarks/browser",
"+components/bookmarks/test",
"+components/flags_ui",
"+components/keyed_service",
"+components/optimization_guide",
Expand Down
1 change: 1 addition & 0 deletions components/commerce/core/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ android_library("core_java") {
deps = [
"//base:jni_java",
"//build/android:build_java",
"//url:gurl_java",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,90 @@
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.url.GURL;

/** A central hub for accessing shopping and product infomration. */
@JNINamespace("commerce")
public class ShoppingService {
/** A data container for product info provided by the shopping service. */
public static final class ProductInfo {
public final String title;
public final GURL imageUrl;
public final long productClusterId;
public final long offerId;
public final String currencyCode;
public final long amountMicros;
public final String countryCode;

ProductInfo(String title, GURL imageUrl, long productClusterId, long offerId,
String currencyCode, long amountMicros, String countryCode) {
this.title = title;
this.imageUrl = imageUrl;
this.productClusterId = productClusterId;
this.offerId = offerId;
this.currencyCode = currencyCode;
this.amountMicros = amountMicros;
this.countryCode = countryCode;
}
}

/** A callback for acquiring product information about a page. */
public interface ProductInfoCallback {
/**
* A notification that fetching product information for the URL has completed.
* @param url The URL the product info was fetched for.
* @param info The product info for the URL or {@code null} if none is available.
*/
void onResult(GURL url, ProductInfo info);
}

/** A pointer to the native side of the object. */
private long mNativeShoppingService;
private long mNativeShoppingServiceAndroid;

/** Private constructor to ensure construction only happens by native. */
private ShoppingService(long nativePtr) {
mNativeShoppingService = nativePtr;
mNativeShoppingServiceAndroid = nativePtr;
}

/**
* Fetch information about a product for a URL.
* @param url The URL to fetch product info for.
* @param callback The callback that will run after the fetch is completed. The product info
* object will be null if there is none available.
*/
public void getProductInfoForUrl(GURL url, ProductInfoCallback callback) {
if (mNativeShoppingServiceAndroid == 0) return;

ShoppingServiceJni.get().getProductInfoForUrl(
mNativeShoppingServiceAndroid, this, url, callback);
}

@CalledByNative
private void destroy() {
mNativeShoppingService = 0;
mNativeShoppingServiceAndroid = 0;
}

@CalledByNative
private static ShoppingService create(long nativePtr) {
return new ShoppingService(nativePtr);
}

@CalledByNative
private static ProductInfo createProductInfo(String title, GURL imageUrl, long productClusterId,
long offerId, String currencyCode, long amountMicros, String countryCode) {
return new ProductInfo(title, imageUrl, productClusterId, offerId, currencyCode,
amountMicros, countryCode);
}

@CalledByNative
private static void runProductInfoCallback(
ProductInfoCallback callback, GURL url, ProductInfo info) {
callback.onResult(url, info);
}

@NativeMethods
interface Natives {}
interface Natives {
void getProductInfoForUrl(long nativeShoppingServiceAndroid, ShoppingService caller,
GURL url, ProductInfoCallback callback);
}
}
45 changes: 43 additions & 2 deletions components/commerce/core/android/shopping_service_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@

#include "components/commerce/core/android/shopping_service_android.h"

#include "components/commerce/core/shopping_service.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "components/commerce/core/shopping_service_jni_headers/ShoppingService_jni.h"
#include "url/android/gurl_android.h"
#include "url/gurl.h"

using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;

namespace commerce {

ShoppingServiceAndroid::ShoppingServiceAndroid(ShoppingService* service)
: shopping_service_(service) {
: shopping_service_(service), weak_ptr_factory_(this) {
java_ref_.Reset(Java_ShoppingService_create(
base::android::AttachCurrentThread(), reinterpret_cast<jlong>(this)));
}
Expand All @@ -19,4 +25,39 @@ ShoppingServiceAndroid::~ShoppingServiceAndroid() {
Java_ShoppingService_destroy(base::android::AttachCurrentThread(), java_ref_);
}

void ShoppingServiceAndroid::GetProductInfoForUrl(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_gurl,
const JavaParamRef<jobject>& j_callback) {
CHECK(shopping_service_);

GURL url = *url::GURLAndroid::ToNativeGURL(env, j_gurl);

shopping_service_->GetProductInfoForUrl(
url, base::BindOnce(&ShoppingServiceAndroid::HandleProductInfoCallback,
weak_ptr_factory_.GetWeakPtr(), env,
ScopedJavaGlobalRef<jobject>(j_callback)));
}

void ShoppingServiceAndroid::HandleProductInfoCallback(
JNIEnv* env,
const ScopedJavaGlobalRef<jobject>& callback,
const GURL& url,
const absl::optional<ProductInfo>& info) {
ScopedJavaLocalRef<jobject> info_java_object(nullptr);
if (info.has_value()) {
info_java_object = Java_ShoppingService_createProductInfo(
env, ConvertUTF8ToJavaString(env, info->title),
url::GURLAndroid::FromNativeGURL(env, GURL(info->image_url)),
info->product_cluster_id, info->offer_id,
ConvertUTF8ToJavaString(env, info->currency_code), info->amount_micros,
ConvertUTF8ToJavaString(env, info->country_code));
}

Java_ShoppingService_runProductInfoCallback(
env, callback, url::GURLAndroid::FromNativeGURL(env, url),
info_java_object);
}

} // namespace commerce
17 changes: 17 additions & 0 deletions components/commerce/core/android/shopping_service_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "components/commerce/core/shopping_service.h"

using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;

class GURL;

namespace commerce {

class ShoppingService;
Expand All @@ -24,16 +29,28 @@ class ShoppingServiceAndroid : public base::SupportsUserData::Data {
ShoppingServiceAndroid(ShoppingService* service);
~ShoppingServiceAndroid() override;

void GetProductInfoForUrl(JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_gurl,
const JavaParamRef<jobject>& j_callback);

ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }

private:
void HandleProductInfoCallback(JNIEnv* env,
const ScopedJavaGlobalRef<jobject>& callback,
const GURL& url,
const absl::optional<ProductInfo>& info);

// A handle to the backing shopping service. This is held as a raw pointer
// since this object's lifecycle is tied to the service itself. This object
// will always be destroyed before the service is.
raw_ptr<ShoppingService> shopping_service_;

// A handle to the java side of this object.
ScopedJavaGlobalRef<jobject> java_ref_;

base::WeakPtrFactory<ShoppingServiceAndroid> weak_ptr_factory_;
};

} // namespace commerce
Expand Down

0 comments on commit 5113aa5

Please sign in to comment.