Initial support for camera assisted search with Google Lens in Omnibox and NTP
Design doc:go/lens-chrome-omnibox-ntp
Screenshot: https://screenshot.googleplex.com/5idKZZSfmGxs6ca
Change-Id: Ie799e6186e806d0a21d6f0f17bf83c66bfb242ea
Bug: 1175230,b/180518516
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2693505
Reviewed-by: Filip Gorski <[email protected]>
Reviewed-by: Yusuf Ozuysal <[email protected]>
Reviewed-by: Brandon Wylie <[email protected]>
Reviewed-by: Ben Goldberger <[email protected]>
Commit-Queue: Yu Su <[email protected]>
Cr-Commit-Position: refs/heads/master@{#857561}
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 07466c1..51f3783b 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -646,6 +646,7 @@
"java/res/drawable/infobar_downloading_fill_animation.xml",
"java/res/drawable/infobar_downloading_sweep_animation.xml",
"java/res/drawable/item_chooser_row_background.xml",
+ "java/res/drawable/lens_camera_icon.xml",
"java/res/drawable/lens_icon.xml",
"java/res/drawable/logo_partly_cloudy.xml",
"java/res/drawable/logo_translate_round.xml",
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index 7a19237..db9fe5aa 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -32,6 +32,7 @@
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.base.ViewUtils;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -50,6 +51,7 @@
private final @SurfaceMode int mSurfaceMode;
private final BottomSheetController mBottomSheetController;
private final Supplier<Tab> mParentTabSupplier;
+ private final WindowAndroid mWindowAndroid;
// Non-null in SurfaceMode.TASKS_ONLY, SurfaceMode.TWO_PANES and SurfaceMode.SINGLE_PANE modes.
@Nullable
@@ -142,12 +144,13 @@
public StartSurfaceCoordinator(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
BottomSheetController sheetController,
OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
- Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
+ Supplier<Tab> parentTabSupplier, boolean hadWarmStart, WindowAndroid windowAndroid) {
mActivity = activity;
mScrimCoordinator = scrimCoordinator;
mSurfaceMode = computeSurfaceMode();
mBottomSheetController = sheetController;
mParentTabSupplier = parentTabSupplier;
+ mWindowAndroid = windowAndroid;
boolean excludeMVTiles = StartSurfaceConfiguration.START_SURFACE_EXCLUDE_MV_TILES.getValue()
|| mSurfaceMode == SurfaceMode.OMNIBOX_ONLY
@@ -398,7 +401,7 @@
}
mTasksSurface = TabManagementModuleProvider.getDelegate().createTasksSurface(mActivity,
mScrimCoordinator, mPropertyModel, tabSwitcherType, mParentTabSupplier,
- !excludeMVTiles, hasTrendyTerms);
+ !excludeMVTiles, hasTrendyTerms, mWindowAndroid);
mTasksSurface.getView().setId(R.id.primary_tasks_surface_view);
mTasksSurface.addFakeSearchBoxShrinkAnimation();
mOffsetChangedListenerToGenerateScrollEvents = new AppBarLayout.OnOffsetChangedListener() {
@@ -438,7 +441,7 @@
mStartSurfaceMediator.setSecondaryTasksSurfacePropertyModel(propertyModel);
mSecondaryTasksSurface = TabManagementModuleProvider.getDelegate().createTasksSurface(
mActivity, mScrimCoordinator, propertyModel, TabSwitcherType.GRID,
- mParentTabSupplier, false, false);
+ mParentTabSupplier, false, false, mWindowAndroid);
if (mIsInitializedWithNative) {
mSecondaryTasksSurface.onFinishNativeInitialization(
mActivity, mActivity.getToolbarManager().getFakeboxDelegate());
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
index 3e15775..516863c 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
@@ -15,6 +15,7 @@
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
+import org.chromium.ui.base.WindowAndroid;
/** StartSurfaceDelegate. */
public class StartSurfaceDelegate {
@@ -26,8 +27,8 @@
public static StartSurface createStartSurface(ChromeActivity activity,
ScrimCoordinator scrimCoordinator, BottomSheetController sheetController,
OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
- Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
+ Supplier<Tab> parentTabSupplier, boolean hadWarmStart, WindowAndroid windowAndroid) {
return new StartSurfaceCoordinator(activity, scrimCoordinator, sheetController,
- startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart);
+ startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart, windowAndroid);
}
}
\ No newline at end of file
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 9817518..a4d1caa 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -8,6 +8,7 @@
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_INITIALIZED;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_LENS_BUTTON_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_SURFACE_BODY_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE;
@@ -48,6 +49,7 @@
import org.chromium.chrome.browser.feed.shared.stream.Stream;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
import org.chromium.chrome.browser.ntp.FakeboxDelegate;
import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -920,6 +922,8 @@
if (mFakeboxDelegate != null && mFakeboxDelegate.getVoiceRecognitionHandler() != null) {
mPropertyModel.set(IS_VOICE_RECOGNITION_BUTTON_VISIBLE,
mFakeboxDelegate.getVoiceRecognitionHandler().isVoiceSearchEnabled());
+ mPropertyModel.set(IS_LENS_BUTTON_VISIBLE,
+ mFakeboxDelegate.isLensEnabled(LensEntryPoint.TASKS_SURFACE));
}
});
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
index e9fd02c..e8140aa 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
@@ -27,6 +27,7 @@
import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
import org.chromium.chrome.tab_ui.R;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -47,9 +48,12 @@
public TasksSurfaceCoordinator(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
PropertyModel propertyModel, @TabSwitcherType int tabSwitcherType,
- Supplier<Tab> parentTabSupplier, boolean hasMVTiles, boolean hasTrendyTerms) {
+ Supplier<Tab> parentTabSupplier, boolean hasMVTiles, boolean hasTrendyTerms,
+ WindowAndroid windowAndroid) {
mView = (TasksView) LayoutInflater.from(activity).inflate(R.layout.tasks_view_layout, null);
- mView.initialize(activity.getLifecycleDispatcher());
+ mView.initialize(activity.getLifecycleDispatcher(),
+ parentTabSupplier.hasValue() ? parentTabSupplier.get().isIncognito() : false,
+ windowAndroid);
mPropertyModelChangeProcessor =
PropertyModelChangeProcessor.create(propertyModel, mView, TasksViewBinder::bind);
mPropertyModel = propertyModel;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceMediator.java
index 8708289..a76b20e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceMediator.java
@@ -14,9 +14,11 @@
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.INCOGNITO_COOKIE_CONTROLS_TOGGLE_ENFORCEMENT;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.INCOGNITO_LEARN_MORE_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_FAKE_SEARCH_BOX_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_LENS_BUTTON_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_SURFACE_BODY_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER;
import android.text.Editable;
@@ -26,6 +28,7 @@
import androidx.annotation.Nullable;
import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
import org.chromium.chrome.browser.ntp.FakeboxDelegate;
import org.chromium.chrome.browser.ntp.IncognitoCookieControlsManager;
import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
@@ -62,6 +65,7 @@
mModel.set(IS_SURFACE_BODY_VISIBLE, true);
mModel.set(IS_FAKE_SEARCH_BOX_VISIBLE, true);
mModel.set(IS_VOICE_RECOGNITION_BUTTON_VISIBLE, false);
+ mModel.set(IS_LENS_BUTTON_VISIBLE, false);
}
public void initWithNative(FakeboxDelegate fakeboxDelegate) {
@@ -103,6 +107,14 @@
}
});
+ mModel.set(LENS_BUTTON_CLICK_LISTENER, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO(b/181067692): Report user action for this click.
+ mFakeboxDelegate.startLens(LensEntryPoint.TASKS_SURFACE);
+ }
+ });
+
mIncognitoCookieControlsObserver = new IncognitoCookieControlsManager.Observer() {
@Override
public void onUpdate(boolean checked, @CookieControlsEnforcement int enforcement) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
index 5a034a9..b1ca0a9 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceProperties.java
@@ -27,6 +27,8 @@
new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_INCOGNITO_DESCRIPTION_VISIBLE =
new PropertyModel.WritableBooleanPropertyKey();
+ public static final PropertyModel.WritableBooleanPropertyKey IS_LENS_BUTTON_VISIBLE =
+ new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_SURFACE_BODY_VISIBLE =
new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_TAB_CAROUSEL_VISIBLE =
@@ -61,6 +63,9 @@
.WritableObjectPropertyKey<TextWatcher> FAKE_SEARCH_BOX_TEXT_WATCHER =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel
+ .WritableObjectPropertyKey<View.OnClickListener> LENS_BUTTON_CLICK_LISTENER =
+ new PropertyModel.WritableObjectPropertyKey<>();
+ public static final PropertyModel
.WritableObjectPropertyKey<View.OnClickListener> MORE_TABS_CLICK_LISTENER =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel.WritableBooleanPropertyKey MV_TILES_VISIBLE = IS_VISIBLE;
@@ -80,14 +85,14 @@
new PropertyModel.WritableObjectPropertyKey<>(true /* skipEquality */);
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_FAKE_SEARCH_BOX_VISIBLE,
IS_INCOGNITO, IS_INCOGNITO_DESCRIPTION_INITIALIZED, IS_INCOGNITO_DESCRIPTION_VISIBLE,
- IS_SURFACE_BODY_VISIBLE, IS_TAB_CAROUSEL_VISIBLE, IS_VOICE_RECOGNITION_BUTTON_VISIBLE,
- INCOGNITO_COOKIE_CONTROLS_CARD_VISIBILITY,
+ IS_LENS_BUTTON_VISIBLE, IS_SURFACE_BODY_VISIBLE, IS_TAB_CAROUSEL_VISIBLE,
+ IS_VOICE_RECOGNITION_BUTTON_VISIBLE, INCOGNITO_COOKIE_CONTROLS_CARD_VISIBILITY,
INCOGNITO_COOKIE_CONTROLS_ICON_CLICK_LISTENER, INCOGNITO_COOKIE_CONTROLS_TOGGLE_CHECKED,
INCOGNITO_COOKIE_CONTROLS_TOGGLE_CHECKED_LISTENER,
INCOGNITO_COOKIE_CONTROLS_TOGGLE_ENFORCEMENT, INCOGNITO_COOKIE_CONTROLS_MANAGER,
INCOGNITO_LEARN_MORE_CLICK_LISTENER, FAKE_SEARCH_BOX_CLICK_LISTENER,
- FAKE_SEARCH_BOX_TEXT_WATCHER, MORE_TABS_CLICK_LISTENER, MV_TILES_VISIBLE,
- VOICE_SEARCH_BUTTON_CLICK_LISTENER, TASKS_SURFACE_BODY_TOP_MARGIN,
+ FAKE_SEARCH_BOX_TEXT_WATCHER, LENS_BUTTON_CLICK_LISTENER, MORE_TABS_CLICK_LISTENER,
+ MV_TILES_VISIBLE, VOICE_SEARCH_BUTTON_CLICK_LISTENER, TASKS_SURFACE_BODY_TOP_MARGIN,
MV_TILES_CONTAINER_TOP_MARGIN, TAB_SWITCHER_TITLE_TOP_MARGIN, TRENDY_TERMS_VISIBLE,
RESET_TASK_SURFACE_HEADER_SCROLL_POSITION};
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
index 5f4a5ce..00677dd4 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
@@ -42,6 +42,7 @@
import org.chromium.components.browser_ui.widget.displaystyle.ViewResizer;
import org.chromium.components.content_settings.CookieControlsEnforcement;
import org.chromium.ui.base.ViewUtils;
+import org.chromium.ui.base.WindowAndroid;
// The view of the tasks surface.
class TasksView extends CoordinatorLayoutForPointer {
@@ -69,11 +70,12 @@
mContext = context;
}
- public void initialize(ActivityLifecycleDispatcher activityLifecycleDispatcher) {
+ public void initialize(ActivityLifecycleDispatcher activityLifecycleDispatcher,
+ boolean isIncognito, WindowAndroid windowAndroid) {
assert mSearchBoxCoordinator
!= null : "#onFinishInflate should be completed before the call to initialize.";
- mSearchBoxCoordinator.initialize(activityLifecycleDispatcher);
+ mSearchBoxCoordinator.initialize(activityLifecycleDispatcher, isIncognito, windowAndroid);
}
@Override
@@ -203,6 +205,7 @@
setBackgroundColor(backgroundColor);
mHeaderView.setBackgroundColor(backgroundColor);
+ mSearchBoxCoordinator.setIncognitoMode(isIncognito);
mSearchBoxCoordinator.setBackground(AppCompatResources.getDrawable(mContext,
isIncognito ? R.drawable.fake_search_box_bg_incognito : R.drawable.ntp_search_box));
int hintTextColor = isIncognito
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
index 971be0d..e526b59d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksViewBinder.java
@@ -17,9 +17,11 @@
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_INITIALIZED;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_LENS_BUTTON_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_SURFACE_BODY_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_VISIBLE;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE;
+import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MORE_TABS_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN;
import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE;
@@ -77,6 +79,9 @@
model.get(INCOGNITO_COOKIE_CONTROLS_MANAGER).updateIfNecessary();
}
view.setIncognitoDescriptionVisibility(isVisible);
+ } else if (propertyKey == IS_LENS_BUTTON_VISIBLE) {
+ view.getSearchBoxCoordinator().setLensButtonVisibility(
+ model.get(IS_LENS_BUTTON_VISIBLE));
} else if (propertyKey == IS_SURFACE_BODY_VISIBLE) {
view.setSurfaceBodyVisibility(model.get(IS_SURFACE_BODY_VISIBLE));
} else if (propertyKey == IS_TAB_CAROUSEL_VISIBLE) {
@@ -84,6 +89,9 @@
} else if (propertyKey == IS_VOICE_RECOGNITION_BUTTON_VISIBLE) {
view.getSearchBoxCoordinator().setVoiceSearchButtonVisibility(
model.get(IS_VOICE_RECOGNITION_BUTTON_VISIBLE));
+ } else if (propertyKey == LENS_BUTTON_CLICK_LISTENER) {
+ view.getSearchBoxCoordinator().addLensButtonClickListener(
+ model.get(LENS_BUTTON_CLICK_LISTENER));
} else if (propertyKey == MORE_TABS_CLICK_LISTENER) {
view.setMoreTabsOnClickListener(model.get(MORE_TABS_CLICK_LISTENER));
} else if (propertyKey == MV_TILES_VISIBLE) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
index 6a04f9f..05bab111 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
@@ -27,6 +27,7 @@
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
import org.chromium.components.module_installer.builder.ModuleInterface;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
import java.lang.annotation.Retention;
@@ -60,11 +61,13 @@
* TasksSurface.
* @param hasMVTiles whether has MV tiles on the surface.
* @param hasTrendyTerms whether has trendy terms on the surface.
+ * @param windowAndroid An instance of a {@link WindowAndroid}
* @return The {@link TasksSurface}.
*/
TasksSurface createTasksSurface(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
PropertyModel propertyModel, @TabSwitcherType int tabSwitcherType,
- Supplier<Tab> parentTabSupplier, boolean hasMVTiles, boolean hasTrendyTerms);
+ Supplier<Tab> parentTabSupplier, boolean hasMVTiles, boolean hasTrendyTerms,
+ WindowAndroid windowAndroid);
/**
* Create the {@link TabSwitcher} to display Tabs in grid.
@@ -118,12 +121,13 @@
* StartSurface.
* @param hadWarmStart Whether the activity had a warm start because the native library was
* already fully loaded and initialized
+ * @param windowAndroid An instance of a {@link WindowAndroid}
* @return the {@link StartSurface}
*/
StartSurface createStartSurface(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
BottomSheetController sheetController,
OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
- Supplier<Tab> parentTabSupplier, boolean hadWarmStart);
+ Supplier<Tab> parentTabSupplier, boolean hadWarmStart, WindowAndroid windowAndroid);
/**
* Create a {@link TabGroupModelFilter} for the given {@link TabModel}.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
index fb82f28..7995601 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
@@ -32,6 +32,7 @@
import org.chromium.chrome.features.start_surface.StartSurfaceDelegate;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
/**
@@ -43,9 +44,9 @@
public TasksSurface createTasksSurface(ChromeActivity activity,
ScrimCoordinator scrimCoordinator, PropertyModel propertyModel,
@TabSwitcherType int tabSwitcherType, Supplier<Tab> parentTabSupplier,
- boolean hasMVTiles, boolean hasTrendyTerms) {
+ boolean hasMVTiles, boolean hasTrendyTerms, WindowAndroid windowAndroid) {
return new TasksSurfaceCoordinator(activity, scrimCoordinator, propertyModel,
- tabSwitcherType, parentTabSupplier, hasMVTiles, hasTrendyTerms);
+ tabSwitcherType, parentTabSupplier, hasMVTiles, hasTrendyTerms, windowAndroid);
}
@Override
@@ -99,9 +100,9 @@
public StartSurface createStartSurface(ChromeActivity activity,
ScrimCoordinator scrimCoordinator, BottomSheetController sheetController,
OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
- Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
+ Supplier<Tab> parentTabSupplier, boolean hadWarmStart, WindowAndroid windowAndroid) {
return StartSurfaceDelegate.createStartSurface(activity, scrimCoordinator, sheetController,
- startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart);
+ startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart, windowAndroid);
}
@Override
diff --git a/chrome/android/java/res/drawable/lens_camera_icon.xml b/chrome/android/java/res/drawable/lens_camera_icon.xml
new file mode 100644
index 0000000..183b82d
--- /dev/null
+++ b/chrome/android/java/res/drawable/lens_camera_icon.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:fillColor="#4285F4"
+ android:pathData="M 12 9.52 C 13.9329966244 9.52 15.5 11.0870033756 15.5 13.02 C 15.5 14.9529966244 13.9329966244 16.52 12 16.52 C 10.0670033756 16.52 8.5 14.9529966244 8.5 13.02 C 8.5 11.0870033756 10.0670033756 9.52 12 9.52 Z" />
+ <path
+ android:fillColor="#EA4335"
+ android:pathData="M20,9v5.02V17c0,0.21-0.04,0.41-0.1,0.6v0v0c-0.2,0.62-0.68,1.1-1.29,1.29h0v0 C18.41,18.96,18.21,19,18,19H8.99l2,2h5.51H18c0.55,0,1.08-0.11,1.56-0.31c0.48-0.2,0.91-0.5,1.27-0.86 c0.18-0.18,0.34-0.38,0.49-0.59c0.29-0.43,0.5-0.91,0.6-1.43C21.97,17.55,22,17.28,22,17v-1.5v-3.48V10.5l-2.1-2.1 C19.96,8.59,20,8.79,20,9z" />
+ <path
+ android:fillColor="#4285F4"
+ android:pathData="M4,9c0-0.21,0.04-0.41,0.1-0.6C4.3,7.78,4.78,7.3,5.4,7.1C5.59,7.04,5.79,7,6,7h12 c0.21,0,0.41,0.04,0.6,0.1c0,0,0,0,0,0L16.5,5l-2-2h-1.68H12h-0.82H9.5l-2,2H6C3.79,5,2,6.79,2,9v1.5v1.51l2,2V9z" />
+ <path
+ android:fillColor="#34A853"
+ android:pathData="M18,5h-1.5l2.1,2.1c0.15,0.05,0.3,0.12,0.43,0.2c0.27,0.16,0.5,0.39,0.66,0.66 c0.08,0.13,0.15,0.28,0.2,0.43v0l2.1,2.1V9C22,6.79,20.21,5,18,5z" />
+ <path
+ android:fillColor="#FBBC04"
+ android:pathData="M6,21h4.99l-2-2H6c-1.1,0-2-0.9-2-2v-2.99l-2-2V17C2,19.21,3.79,21,6,21z" />
+</vector>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/fake_search_box_layout.xml b/chrome/android/java/res/layout/fake_search_box_layout.xml
index 6f113842..9be6648 100644
--- a/chrome/android/java/res/layout/fake_search_box_layout.xml
+++ b/chrome/android/java/res/layout/fake_search_box_layout.xml
@@ -63,4 +63,13 @@
android:src="@drawable/btn_mic"
android:scaleType="centerInside"
app:tint="@color/default_icon_color_tint_list" />
+ <org.chromium.ui.widget.ChromeImageView
+ android:id="@+id/lens_camera_button"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_btn_lens_camera"
+ android:src="@drawable/lens_camera_icon"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ app:tint="@color/default_icon_color_tint_list" />
</view>
diff --git a/chrome/android/java/res/layout/url_action_container.xml b/chrome/android/java/res/layout/url_action_container.xml
index 0c84cbf..dabc56b 100644
--- a/chrome/android/java/res/layout/url_action_container.xml
+++ b/chrome/android/java/res/layout/url_action_container.xml
@@ -28,6 +28,13 @@
android:contentDescription="@string/accessibility_toolbar_btn_mic" />
<org.chromium.ui.widget.ChromeImageButton
+ android:id="@+id/lens_camera_button"
+ style="@style/LocationBarActionButton"
+ android:src="@drawable/lens_camera_icon"
+ android:visibility="gone"
+ android:contentDescription="@string/accessibility_btn_lens_camera" />
+
+ <org.chromium.ui.widget.ChromeImageButton
android:id="@+id/bookmark_button"
style="@style/LocationBarActionButton"
android:visibility="gone"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 20ba0d5..8c479b5 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -286,7 +286,7 @@
<!-- The ntp_voice_search_button_width is 48dp and its icon is 24dp. Setting
8dp start padding will result in 8dp padding between the icon and the
end of the fakebox ((48 - 24 - 8) / 2). -->
- <dimen name="sei_ntp_voice_button_start_padding">8dp</dimen>
+ <dimen name="sei_ntp_fakebox_button_start_padding">8dp</dimen>
<dimen name="experimental_explore_sites_radius">8dp</dimen>
<dimen name="experimental_explore_sites_padding">8dp</dimen>
<dimen name="experimental_explore_sites_margin">16dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index fca81d2..1e47045e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -611,7 +611,7 @@
StartSurface startSurface = tabManagementDelegate.createStartSurface(this,
mRootUiCoordinator.getScrimCoordinator(),
mRootUiCoordinator.getBottomSheetController(), mStartSurfaceSupplier,
- mStartSurfaceParentTabSupplier, hadWarmStart());
+ mStartSurfaceParentTabSupplier, hadWarmStart(), getWindowAndroid());
}
}
// clang-format off
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/LensChipDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/LensChipDelegate.java
index 3d1ff0e0..0f00320 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/LensChipDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/LensChipDelegate.java
@@ -30,7 +30,7 @@
return;
}
mLensQueryParams =
- (new LensQueryParams.Builder(LensEntryPoint.CONTEXT_MENU_CHIP, isIncognito))
+ new LensQueryParams.Builder(LensEntryPoint.CONTEXT_MENU_CHIP, isIncognito)
.withPageUrl(pageUrl)
.withImageTitleOrAltText(titleOrAltText)
.withSrcUrl(srcUrl)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensController.java b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensController.java
index 42f33e97..12a4b526 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensController.java
@@ -142,7 +142,7 @@
/** Terminate any active Lens connections. */
public void terminateLensConnections() {}
- // TODO(yusuyoutube): revisit the wrapper object for this enablement check. LensQueryParams
+ // TODO(b/180960783): Revisit the wrapper object for this enablement check. LensQueryParams
// was designed to be only used in the Prime classification query.
/**
* Whether the Lens is enabled based on user signals.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensIntentParams.java b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensIntentParams.java
index 0700ffb..92c6dd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensIntentParams.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensIntentParams.java
@@ -35,8 +35,10 @@
public Builder() {}
- // TODO(yusuyoutube): remove the with* methods for the required params once
+ // TODO(b/180967190): remove the with* methods for the required params once
// downstream references are updated.
+ // lensEntryPoint and isIncognito are required params when creating the
+ // LensIntentParams.
public Builder(@LensEntryPoint int lensEntryPoint, boolean isIncognito) {
this();
this.mLensEntryPoint = lensEntryPoint;
@@ -149,37 +151,37 @@
}
}
- /** Retrieve the image URI for the intent. */
+ /** Returns the imageUri for this set of params. */
public Uri getImageUri() {
return mImageUri;
}
- /** Retrieve the page URL for the intent. */
+ /** Returns the pageUrl for this set of params. */
public String getPageUrl() {
return mPageUrl;
}
- /** Retrieve the image source URL for the intent. */
+ /** Returns the srcUrl for this set of params. */
public String getSrcUrl() {
return mSrcUrl;
}
- /** Retrieve the image title or alt text for the intent. */
+ /** Returns the imageTitleOrAltText for this set of params. */
public String getImageTitleOrAltText() {
return mImageTitleOrAltText;
}
- /** Retrieve whether the client is incognito for the intent. */
+ /** Returns the isIncognito for this set of params. */
public boolean getIsIncognito() {
return mIsIncognito;
}
- /** Retrieve whether the client requires account for the intent. */
+ /** Returns the requiresConfirmation for this set of params. */
public boolean getRequiresConfirmation() {
return mRequiresConfirmation;
}
- /** Retrieve the intent type. */
+ /** Returns the intentType for this set of params. */
public int getIntentType() {
return mIntentType;
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensQueryParams.java b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensQueryParams.java
index ed84102..b313fb54 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensQueryParams.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensQueryParams.java
@@ -6,6 +6,8 @@
import android.net.Uri;
+import androidx.annotation.NonNull;
+
import org.chromium.content_public.browser.WebContents;
/**
@@ -55,31 +57,61 @@
return this;
}
- public Builder withImageUri(Uri imageUri) {
+ /**
+ * Sets the image URI.
+ *
+ * @param imageUri The image URI to set as a parameter
+ */
+ public Builder withImageUri(@NonNull Uri imageUri) {
this.mImageUri = imageUri;
return this;
}
+ /**
+ * Sets the URL of the top level frame of the page.
+ *
+ * @param pageUrl The page URL string to set as a parameter
+ */
public Builder withPageUrl(String pageUrl) {
this.mPageUrl = pageUrl;
return this;
}
+ /**
+ * Sets the image title or alt text.
+ *
+ * @param imageTitleOrAltText The image title or alt text to set as a parameter
+ */
public Builder withImageTitleOrAltText(String imageTitleOrAltText) {
this.mImageTitleOrAltText = imageTitleOrAltText;
return this;
}
+ /**
+ * Sets the title of the top level frame of the page.
+ *
+ * @param pageTitle The page title string to set as a parameter
+ */
public Builder withPageTitle(String pageTitle) {
this.mPageTitle = pageTitle;
return this;
}
+ /**
+ * Sets the web contents.
+ *
+ * @param webContents The web contents to set as a parameter
+ */
public Builder withWebContents(WebContents webContents) {
this.mWebContents = webContents;
return this;
}
+ /**
+ * Sets the image source URL.
+ *
+ * @param srcUrl The image source URL string to set as a parameter
+ */
public Builder withSrcUrl(String srcUrl) {
this.mSrcUrl = srcUrl;
return this;
@@ -90,6 +122,9 @@
return this;
}
+ /**
+ * Build LensQueryParams object from parameters set.
+ */
public LensQueryParams build() {
LensQueryParams lensQueryParams = new LensQueryParams();
lensQueryParams.mLensEntryPoint = this.mLensEntryPoint;
@@ -104,34 +139,47 @@
}
}
- public void setImageUri(Uri imageUri) {
+ /**
+ * Sets the imageUri.
+ * With this setter method we can set the imageUri in a retrieve image callback.
+ * e.g., LensChipDelegate#getChipRenderParams.
+ * @param imageUri The image URI to set as a parameter
+ */
+ public void setImageUri(@NonNull Uri imageUri) {
mImageUri = imageUri;
}
+ /** Returns the image URI for this set of params. */
public Uri getImageUri() {
return mImageUri;
}
+ /** Returns the page url for this set of params. */
public String getPageUrl() {
return mPageUrl;
}
+ /** Returns the image title or alt text for this set of params. */
public String getImageTitleOrAltText() {
return mImageTitleOrAltText;
}
+ /** Returns the page title for this set of params. */
public String getPageTitle() {
return mPageTitle;
}
+ /** Returns the web contents for this set of params. */
public WebContents getWebContents() {
return mWebContents;
}
+ /** Returns the src url for this set of params. */
public String getSrcUrl() {
return mSrcUrl;
}
+ /** Returns the isIncognito for this set of params. */
public boolean getIsIncognito() {
return mIsIncognito;
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
index b11e4b6a..b13acb9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
@@ -6,6 +6,7 @@
import androidx.annotation.Nullable;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
@@ -59,4 +60,15 @@
* @param listener The listener to be removed.
*/
default void removeUrlFocusChangeListener(UrlFocusChangeListener listener) {}
+
+ /**
+ * Returns whether the Lens is currently enabled.
+ */
+ boolean isLensEnabled(@LensEntryPoint int lensEntryPoint);
+
+ /**
+ * Launches Lens from an entry point.
+ * @param lensEntryPoint the Lens entry point.
+ */
+ void startLens(@LensEntryPoint int lensEntryPoint);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 3f8f5e2..7fa5c2693 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -378,13 +378,14 @@
mContextMenuManager = new ContextMenuManager(mNewTabPageManager.getNavigationDelegate(),
mFeedSurfaceProvider.getTouchEnabledDelegate(), closeContextMenuCallback,
NewTabPage.CONTEXT_MENU_USER_ACTION_PREFIX);
- mTab.getWindowAndroid().addContextMenuCloseListener(mContextMenuManager);
+ windowAndroid.addContextMenuCloseListener(mContextMenuManager);
mNewTabPageLayout.initialize(mNewTabPageManager, activity, mTileGroupDelegate,
mSearchProviderHasLogo,
TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle(),
mFeedSurfaceProvider.getScrollDelegate(), mContextMenuManager,
- mFeedSurfaceProvider.getUiConfig(), activityTabProvider, lifecycleDispatcher, uma);
+ mFeedSurfaceProvider.getUiConfig(), activityTabProvider, lifecycleDispatcher, uma,
+ mTab.isIncognito(), windowAndroid);
TraceEvent.end(TAG);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index dbe079a..c4b4f8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -35,6 +35,7 @@
import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.native_page.ContextMenuManager;
import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
@@ -64,6 +65,7 @@
import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter;
import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.vr.VrModeObserver;
/**
@@ -129,6 +131,8 @@
/** Flag used to request some layout changes after the next layout pass is completed. */
private boolean mTileCountChanged;
private boolean mSnapshotTileGridChanged;
+ private boolean mIsIncognito;
+ private WindowAndroid mWindowAndroid;
/**
* Vertical inset to add to the top and bottom of the search box bounds. May be 0 if no inset
@@ -221,18 +225,23 @@
* @param tabProvider Provides the current active tab.
* @param lifecycleDispatcher Activity lifecycle dispatcher.
* @param uma {@link NewTabPageUma} object recording user metrics.
+ * @param isIncognito Whether the new tab page is in incognito mode.
+ * @param windowAndroid An instance of a {@link WindowAndroid}
*/
public void initialize(NewTabPageManager manager, Activity activity,
TileGroup.Delegate tileGroupDelegate, boolean searchProviderHasLogo,
boolean searchProviderIsGoogle, ScrollDelegate scrollDelegate,
ContextMenuManager contextMenuManager, UiConfig uiConfig, Supplier<Tab> tabProvider,
- ActivityLifecycleDispatcher lifecycleDispatcher, NewTabPageUma uma) {
+ ActivityLifecycleDispatcher lifecycleDispatcher, NewTabPageUma uma, boolean isIncognito,
+ WindowAndroid windowAndroid) {
TraceEvent.begin(TAG + ".initialize()");
mScrollDelegate = scrollDelegate;
mManager = manager;
mActivity = activity;
mUiConfig = uiConfig;
mNewTabPageUma = uma;
+ mIsIncognito = isIncognito;
+ mWindowAndroid = windowAndroid;
Profile profile = Profile.getLastUsedRegularProfile();
OfflinePageBridge offlinePageBridge =
@@ -263,7 +272,7 @@
mManager.getNavigationDelegate(), mSearchProviderLogoView, profile);
mSearchBoxCoordinator = new SearchBoxCoordinator(getContext(), this);
- mSearchBoxCoordinator.initialize(lifecycleDispatcher);
+ mSearchBoxCoordinator.initialize(lifecycleDispatcher, mIsIncognito, mWindowAndroid);
if (!DeviceFormFactor.isNonMultiDisplayContextOnTablet(activity)) {
mSearchBoxBoundsVerticalInset = getResources().getDimensionPixelSize(
R.dimen.ntp_search_box_bounds_vertical_inset_modern);
@@ -272,6 +281,7 @@
initializeSearchBoxTextView();
initializeVoiceSearchButton();
+ initializeLensButton();
initializeLayoutChangeListener();
setSearchProviderInfo(searchProviderHasLogo, searchProviderIsGoogle);
mSearchProviderLogoView.showSearchProviderInitialView();
@@ -333,7 +343,7 @@
// View is 48dp, image is 24dp. Increasing the padding from 4dp -> 8dp will split the
// remaining 16dp evenly between start/end resulting in a paddingEnd of 8dp.
int paddingStart = getResources().getDimensionPixelSize(
- R.dimen.sei_ntp_voice_button_start_padding);
+ R.dimen.sei_ntp_fakebox_button_start_padding);
ImageView voiceSearchButton = findViewById(R.id.voice_search_button);
voiceSearchButton.setPaddingRelative(paddingStart, voiceSearchButton.getPaddingTop(),
getPaddingEnd(), voiceSearchButton.getPaddingBottom());
@@ -342,6 +352,24 @@
TraceEvent.end(TAG + ".initializeVoiceSearchButton()");
}
+ private void initializeLensButton() {
+ TraceEvent.begin(TAG + ".initializeLensButton()");
+ // TODO(b/181067692): Report user action for this click.
+ mSearchBoxCoordinator.addLensButtonClickListener(
+ v -> mSearchBoxCoordinator.startLens(LensEntryPoint.NEW_TAB_PAGE));
+ if (SearchEngineLogoUtils.getInstance().isSearchEngineLogoEnabled()) {
+ // View is 48dp, image is 24dp. Increasing the padding from 4dp -> 8dp will split the
+ // remaining 16dp evenly between start/end resulting in a paddingEnd of 8dp.
+ int paddingStart = getResources().getDimensionPixelSize(
+ R.dimen.sei_ntp_fakebox_button_start_padding);
+ ImageView lensButton = findViewById(R.id.lens_camera_button);
+ lensButton.setPaddingRelative(paddingStart, lensButton.getPaddingTop(), getPaddingEnd(),
+ lensButton.getPaddingBottom());
+ }
+
+ TraceEvent.end(TAG + ".initializeLensButton()");
+ }
+
private void initializeLayoutChangeListener() {
TraceEvent.begin(TAG + ".initializeLayoutChangeListener()");
addOnLayoutChangeListener(
@@ -745,7 +773,29 @@
View searchBoxContainerView = mSearchBoxCoordinator.getView();
searchBoxContainerView.setPadding(searchBoxContainerView.getPaddingStart(),
searchBoxContainerView.getPaddingTop(),
- mManager.isVoiceSearchEnabled() ? 0 : mSearchBoxEndPadding,
+ mManager.isVoiceSearchEnabled()
+ || mSearchBoxCoordinator.isLensEnabled(LensEntryPoint.NEW_TAB_PAGE)
+ ? 0
+ : mSearchBoxEndPadding,
+ searchBoxContainerView.getPaddingBottom());
+ }
+
+ /**
+ * Update the visibility of the Lens button based on whether the feature is currently
+ * enabled.
+ */
+ void updateLensButtonVisibility() {
+ if (mSearchBoxEndPadding == UNSET_RESOURCE_FLAG) {
+ mSearchBoxEndPadding = SearchEngineLogoUtils.getInstance().isSearchEngineLogoEnabled()
+ ? getResources().getDimensionPixelSize(R.dimen.sei_search_box_lateral_padding)
+ : getResources().getDimensionPixelSize(R.dimen.location_bar_lateral_padding);
+ }
+ boolean isLensEnabled = mSearchBoxCoordinator.isLensEnabled(LensEntryPoint.NEW_TAB_PAGE);
+ mSearchBoxCoordinator.setLensButtonVisibility(isLensEnabled);
+ View searchBoxContainerView = mSearchBoxCoordinator.getView();
+ searchBoxContainerView.setPadding(searchBoxContainerView.getPaddingStart(),
+ searchBoxContainerView.getPaddingTop(),
+ isLensEnabled || mManager.isVoiceSearchEnabled() ? 0 : mSearchBoxEndPadding,
searchBoxContainerView.getPaddingBottom());
}
@@ -762,6 +812,7 @@
if (visibility == VISIBLE) {
updateVoiceSearchButtonVisibility();
+ updateLensButtonVisibility();
maybeShowVideoTutorialTryNowIPH();
}
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxCoordinator.java
index 2143c5e8..83233aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxCoordinator.java
@@ -13,7 +13,9 @@
import android.view.ViewGroup;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
/**
@@ -25,6 +27,8 @@
private final PropertyModel mModel;
private final ViewGroup mView;
private final SearchBoxMediator mMediator;
+ private boolean mIsIncognito;
+ private WindowAndroid mWindowAndroid;
/** Constructor. */
public SearchBoxCoordinator(Context context, ViewGroup parent) {
@@ -33,8 +37,11 @@
mMediator = new SearchBoxMediator(context, mModel, mView);
}
- public void initialize(ActivityLifecycleDispatcher activityLifecycleDispatcher) {
+ public void initialize(ActivityLifecycleDispatcher activityLifecycleDispatcher,
+ boolean isIncognito, WindowAndroid windowAndroid) {
mMediator.initialize(activityLifecycleDispatcher);
+ mIsIncognito = isIncognito;
+ mWindowAndroid = windowAndroid;
}
public View getView() {
@@ -85,6 +92,14 @@
mMediator.addVoiceSearchButtonClickListener(listener);
}
+ public void setLensButtonVisibility(boolean visible) {
+ mModel.set(SearchBoxProperties.LENS_VISIBILITY, visible);
+ }
+
+ public void addLensButtonClickListener(OnClickListener listener) {
+ mMediator.addLensButtonClickListener(listener);
+ }
+
public void setChipText(String chipText) {
mMediator.setChipText(chipText);
}
@@ -97,4 +112,16 @@
Pair<String, Boolean> searchText = mModel.get(SearchBoxProperties.SEARCH_TEXT);
return searchText == null ? false : searchText.second;
}
+
+ public boolean isLensEnabled(@LensEntryPoint int lensEntryPoint) {
+ return mMediator.isLensEnabled(lensEntryPoint, mIsIncognito);
+ }
+
+ public void startLens(@LensEntryPoint int lensEntryPoint) {
+ mMediator.startLens(lensEntryPoint, mWindowAndroid, mIsIncognito);
+ }
+
+ public void setIncognitoMode(boolean isIncognito) {
+ mIsIncognito = isIncognito;
+ }
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxMediator.java
index a63023d..1276dbf2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxMediator.java
@@ -17,6 +17,10 @@
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import org.chromium.chrome.browser.gsa.GSAState;
+import org.chromium.chrome.browser.lens.LensController;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
+import org.chromium.chrome.browser.lens.LensIntentParams;
+import org.chromium.chrome.browser.lens.LensQueryParams;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
@@ -26,6 +30,7 @@
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.externalauth.ExternalAuthUtils;
import org.chromium.ui.base.ViewUtils;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -38,6 +43,7 @@
private final PropertyModel mModel;
private final ViewGroup mView;
private final List<OnClickListener> mVoiceSearchClickListeners = new ArrayList<>();
+ private final List<OnClickListener> mLensClickListeners = new ArrayList<>();
private ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
private AssistantVoiceSearchService mAssistantVoiceSearchService;
private SearchBoxChipDelegate mChipDelegate;
@@ -129,6 +135,20 @@
}
/**
+ * Called to add a click listener for the voice search button.
+ */
+ void addLensButtonClickListener(OnClickListener listener) {
+ boolean hasExistingListeners = !mLensClickListeners.isEmpty();
+ mLensClickListeners.add(listener);
+ if (hasExistingListeners) return;
+ mModel.set(SearchBoxProperties.LENS_CLICK_CALLBACK, v -> {
+ for (OnClickListener clickListener : mLensClickListeners) {
+ clickListener.onClick(v);
+ }
+ });
+ }
+
+ /**
* Called to set or clear a chip on the search box.
* @param chipText The text to be shown on the chip.
*/
@@ -152,6 +172,29 @@
});
}
+ /**
+ * Launch the Lens app.
+ * @param lensEntryPoint A {@link LensEntryPoint}.
+ * @param windowAndroid A {@link WindowAndroid} instance.
+ * @param isIncognito Whether the request is from a Incognito tab.
+ */
+ void startLens(
+ @LensEntryPoint int lensEntryPoint, WindowAndroid windowAndroid, boolean isIncognito) {
+ LensController.getInstance().startLens(
+ windowAndroid, new LensIntentParams.Builder(lensEntryPoint, isIncognito).build());
+ }
+
+ /**
+ * Check whether the Lens is enabled for an entry point.
+ * @param lensEntryPoint A {@link LensEntryPoint}.
+ * @param isIncognito Whether the request is from a Incognito tab.
+ * @return Whether the Lens is currently enabled.
+ */
+ boolean isLensEnabled(@LensEntryPoint int lensEntryPoint, boolean isIncognito) {
+ return LensController.getInstance().isLensEnabled(
+ new LensQueryParams.Builder(lensEntryPoint, isIncognito).build());
+ }
+
private Drawable getRoundedDrawable(Bitmap bitmap) {
if (bitmap == null) return null;
RoundedBitmapDrawable roundedBitmapDrawable =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxProperties.java
index 087831e..f732779 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxProperties.java
@@ -29,6 +29,9 @@
new WritableObjectPropertyKey<>();
WritableObjectPropertyKey<OnClickListener> VOICE_SEARCH_CLICK_CALLBACK =
new WritableObjectPropertyKey<>();
+ WritableBooleanPropertyKey LENS_VISIBILITY = new WritableBooleanPropertyKey();
+ WritableObjectPropertyKey<OnClickListener> LENS_CLICK_CALLBACK =
+ new WritableObjectPropertyKey<>();
WritableObjectPropertyKey<Pair<String, Boolean>> SEARCH_TEXT =
new WritableObjectPropertyKey<>();
WritableBooleanPropertyKey SEARCH_HINT_VISIBILITY = new WritableBooleanPropertyKey();
@@ -47,7 +50,8 @@
PropertyKey[] ALL_KEYS = new PropertyKey[] {ALPHA, BACKGROUND, VISIBILITY,
VOICE_SEARCH_VISIBILITY, VOICE_SEARCH_DRAWABLE, VOICE_SEARCH_COLOR_STATE_LIST,
- VOICE_SEARCH_CLICK_CALLBACK, SEARCH_TEXT, SEARCH_HINT_VISIBILITY,
- SEARCH_BOX_CLICK_CALLBACK, SEARCH_BOX_TEXT_WATCHER, SEARCH_BOX_HINT_COLOR, CHIP_TEXT,
- CHIP_VISIBILITY, CHIP_DRAWABLE, CHIP_CLICK_CALLBACK, CHIP_CANCEL_CALLBACK};
+ VOICE_SEARCH_CLICK_CALLBACK, LENS_VISIBILITY, LENS_CLICK_CALLBACK, SEARCH_TEXT,
+ SEARCH_HINT_VISIBILITY, SEARCH_BOX_CLICK_CALLBACK, SEARCH_BOX_TEXT_WATCHER,
+ SEARCH_BOX_HINT_COLOR, CHIP_TEXT, CHIP_VISIBILITY, CHIP_DRAWABLE, CHIP_CLICK_CALLBACK,
+ CHIP_CANCEL_CALLBACK};
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxViewBinder.java
index 56221de3..ba352c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/search/SearchBoxViewBinder.java
@@ -25,6 +25,7 @@
public final void bind(PropertyModel model, View view, PropertyKey propertyKey) {
ImageView voiceSearchButton =
view.findViewById(org.chromium.chrome.R.id.voice_search_button);
+ ImageView lensButton = view.findViewById(org.chromium.chrome.R.id.lens_camera_button);
View searchBoxContainer = view;
final TextView searchBoxTextView = searchBoxContainer.findViewById(R.id.search_box_text);
final ChipView chipView = searchBoxContainer.findViewById(R.id.query_tiles_chip);
@@ -49,6 +50,11 @@
voiceSearchButton.setVisibility(model.get(SearchBoxProperties.VOICE_SEARCH_VISIBILITY)
? View.VISIBLE
: View.GONE);
+ } else if (SearchBoxProperties.LENS_VISIBILITY == propertyKey) {
+ lensButton.setVisibility(
+ model.get(SearchBoxProperties.LENS_VISIBILITY) ? View.VISIBLE : View.GONE);
+ } else if (SearchBoxProperties.LENS_CLICK_CALLBACK == propertyKey) {
+ lensButton.setOnClickListener(model.get(SearchBoxProperties.LENS_CLICK_CALLBACK));
} else if (SearchBoxProperties.SEARCH_BOX_CLICK_CALLBACK == propertyKey) {
searchBoxTextView.setOnClickListener(
model.get(SearchBoxProperties.SEARCH_BOX_CLICK_CALLBACK));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS
index 8747145c..1807816 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS
@@ -14,6 +14,10 @@
"+chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAState.java",
"+chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java",
"+chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java",
+ "+chrome/android/java/src/org/chromium/chrome/browser/lens/LensController.java",
+ "+chrome/android/java/src/org/chromium/chrome/browser/lens/LensEntryPoint.java",
+ "+chrome/android/java/src/org/chromium/chrome/browser/lens/LensIntentParams.java",
+ "+chrome/android/java/src/org/chromium/chrome/browser/lens/LensQueryParams.java",
"+chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java",
"+chrome/android/java/src/org/chromium/chrome/browser/night_mode/NightModeUtils.java",
"+chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
index 499c3f4..fd21c566 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -76,6 +76,7 @@
private View mUrlBar;
private View mDeleteButton;
private View mMicButton;
+ private View mLensButton;
private final OneshotSupplierImpl<TemplateUrlService> mTemplateUrlServiceSupplier =
new OneshotSupplierImpl<>();
private CallbackController mCallbackController = new CallbackController();
@@ -157,6 +158,9 @@
mMicButton = mLocationBarLayout.findViewById(R.id.mic_button);
mMicButton.setOnClickListener(mLocationBarMediator::micButtonClicked);
+ mLensButton = mLocationBarLayout.findViewById(R.id.lens_camera_button);
+ mLensButton.setOnClickListener(mLocationBarMediator::lensButtonClicked);
+
mUrlBar.setOnKeyListener(mLocationBarMediator);
mUrlCoordinator.addUrlTextChangeListener(mAutocompleteCoordinator);
// The LocationBar's direction is tied to the UrlBar's text direction. Icons inside the
@@ -201,6 +205,9 @@
mMicButton.setOnClickListener(null);
mMicButton = null;
+ mLensButton.setOnClickListener(null);
+ mLensButton = null;
+
mLocationBarMediator.removeUrlFocusChangeListener(mUrlCoordinator);
mUrlCoordinator.destroy();
mUrlCoordinator = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 81d8a156..29532d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -39,6 +39,7 @@
public class LocationBarLayout extends FrameLayout {
protected ImageButton mDeleteButton;
protected ImageButton mMicButton;
+ protected ImageButton mLensButton;
protected UrlBar mUrlBar;
protected UrlBarCoordinator mUrlCoordinator;
@@ -70,6 +71,7 @@
mDeleteButton = findViewById(R.id.delete_button);
mUrlBar = findViewById(R.id.url_bar);
mMicButton = findViewById(R.id.mic_button);
+ mLensButton = findViewById(R.id.lens_camera_button);
mUrlActionContainer = (LinearLayout) findViewById(R.id.url_action_container);
}
@@ -287,6 +289,11 @@
mMicButton.setVisibility(shouldShow ? VISIBLE : GONE);
}
+ /** Sets the visibility of the mic button. */
+ /* package */ void setLensButtonVisibility(boolean shouldShow) {
+ mLensButton.setVisibility(shouldShow ? VISIBLE : GONE);
+ }
+
protected void setUnfocusedWidth(int unfocusedWidth) {
mStatusCoordinator.setUnfocusedLocationBarWidth(unfocusedWidth);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
index 1bf7392..8808f804 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -34,6 +34,10 @@
import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.gsa.GSAState;
+import org.chromium.chrome.browser.lens.LensController;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
+import org.chromium.chrome.browser.lens.LensIntentParams;
+import org.chromium.chrome.browser.lens.LensQueryParams;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.ntp.FakeboxDelegate;
import org.chromium.chrome.browser.ntp.NewTabPageUma;
@@ -143,6 +147,7 @@
private boolean mUrlFocusedWithoutAnimations;
private boolean mIsUrlFocusChangeInProgress;
private final boolean mIsTablet;
+ private boolean mShouldShowLensButtonWhenUnfocused;
private boolean mShouldShowMicButtonWhenUnfocused;
// Whether the microphone and bookmark buttons should be shown in the tablet location bar. These
// buttons are hidden if the window size is < 600dp.
@@ -285,6 +290,7 @@
}
mDeferredNativeRunnables.clear();
updateMicButtonState();
+ updateLensButtonState();
}
/*package */ void setUrlFocusChangeFraction(float fraction) {
@@ -474,6 +480,7 @@
/* package */ void updateButtonVisibility() {
updateDeleteButtonVisibility();
updateMicButtonVisibility();
+ updateLensButtonVisibility();
if (mIsTablet) {
updateTabletButtonsVisibility();
}
@@ -527,6 +534,12 @@
VoiceRecognitionHandler.VoiceInteractionSource.OMNIBOX);
}
+ /** package */ void lensButtonClicked(View view) {
+ if (!mNativeInitialized || mLocationBarDataProvider == null) return;
+ RecordUserAction.record("MobileOmniboxLens");
+ startLens(LensEntryPoint.OMNIBOX);
+ }
+
/* package */ void setUrlFocusChangeInProgress(boolean inProgress) {
if (mUrlCoordinator == null) return;
mIsUrlFocusChangeInProgress = inProgress;
@@ -630,6 +643,11 @@
mShouldShowMicButtonWhenUnfocused = shouldShow;
}
+ /* package */ void setShouldShowLensButtonWhenUnfocusedForPhone(boolean shouldShow) {
+ assert !mIsTablet;
+ mShouldShowLensButtonWhenUnfocused = shouldShow;
+ }
+
/**
* @param shouldShow Whether buttons should be displayed in the URL bar when it's not
* focused.
@@ -907,6 +925,10 @@
updateButtonVisibility();
}
+ private void updateLensButtonState() {
+ updateButtonVisibility();
+ }
+
/**
* Updates the display of the mic button.
*/
@@ -914,6 +936,10 @@
mLocationBarLayout.setMicButtonVisibility(shouldShowMicButton());
}
+ private void updateLensButtonVisibility() {
+ mLocationBarLayout.setLensButtonVisibility(shouldShowLensButton());
+ }
+
private void updateDeleteButtonVisibility() {
mLocationBarLayout.setDeleteButtonVisibility(shouldShowDeleteButton());
}
@@ -955,6 +981,21 @@
}
}
+ private boolean shouldShowLensButton() {
+ if (mIsTablet) {
+ // TODO(b/180967835): add logic to enable Lens for tablets.
+ return false;
+ } else if (mShouldShowButtonsWhenUnfocused) {
+ return isLensEnabled(LensEntryPoint.OMNIBOX) && mNativeInitialized
+ && (mUrlHasFocus || mIsUrlFocusChangeInProgress);
+ } else {
+ boolean deleteButtonVisible = shouldShowDeleteButton();
+ return isLensEnabled(LensEntryPoint.OMNIBOX) && !deleteButtonVisible
+ && (mUrlHasFocus || mIsUrlFocusChangeInProgress || mUrlFocusChangeFraction > 0f
+ || mShouldShowMicButtonWhenUnfocused);
+ }
+ }
+
private boolean shouldShowSaveOfflineButton() {
assert mIsTablet;
if (!mNativeInitialized || mLocationBarDataProvider == null) return false;
@@ -1318,4 +1359,19 @@
updateSearchEngineStatusIcon();
mLocationBarLayout.updateStatusVisibility();
}
+
+ @Override
+ public boolean isLensEnabled(@LensEntryPoint int lensEntryPoint) {
+ return LensController.getInstance().isLensEnabled(
+ new LensQueryParams.Builder(lensEntryPoint, mLocationBarDataProvider.isIncognito())
+ .build());
+ }
+
+ @Override
+ public void startLens(@LensEntryPoint int lensEntryPoint) {
+ // TODO(b/181067692): Report user action for this click.
+ LensController.getInstance().startLens(mWindowAndroid,
+ new LensIntentParams.Builder(lensEntryPoint, mLocationBarDataProvider.isIncognito())
+ .build());
+ }
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
index 8e598a2..93005bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
@@ -95,6 +95,7 @@
ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE,
profile, GlobalDiscardableReferencePool.getReferencePool());
mSearchBoxCoordinator.addVoiceSearchButtonClickListener(v -> reloadTiles());
+ mSearchBoxCoordinator.addLensButtonClickListener(v -> reloadTiles());
reloadTiles();
}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a828e5d..998ca85 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6050,6 +6050,11 @@
flag_descriptions::kContextMenuTranslateWithGoogleLensDescription,
kOsAndroid,
FEATURE_VALUE_TYPE(chrome::android::kContextMenuTranslateWithGoogleLens)},
+
+ {"lens-camera-assisted-search",
+ flag_descriptions::kLensCameraAssistedSearchName,
+ flag_descriptions::kLensCameraAssistedSearchDescription, kOsAndroid,
+ FEATURE_VALUE_TYPE(chrome::android::kLensCameraAssistedSearch)},
#endif // defined(OS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4a1cc02f..6af3533 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3324,6 +3324,11 @@
"expiry_milestone": 92
},
{
+ "name": "lens-camera-assisted-search",
+ "owners": [ "yusuyoutube", "benwgold", "fgorski", "wylieb", "lens-chrome" ],
+ "expiry_milestone": 94
+ },
+ {
"name": "list-all-display-modes",
"owners": [ "//ui/display/OWNERS" ],
// This flag is used for debugging and development purposes to list all
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 485e9b88..34e1e03 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1417,6 +1417,12 @@
"Show security warnings for sites that use legacy TLS versions (TLS 1.0 "
"and TLS 1.1), which are deprecated and will be removed in the future.";
+const char kLensCameraAssistedSearchName[] =
+ "Google Lens in Omnibox and New Tab Page";
+const char kLensCameraAssistedSearchDescription[] =
+ "Enable an entry point to Google Lens to allow users to search what they "
+ "see using their mobile camera.";
+
const char kLiteVideoName[] = "Enable LiteVideos";
const char kLiteVideoDescription[] =
"Enable the LiteVideo optimization to throttle media requests to "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 9214f9a6..3cb81079 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -838,6 +838,9 @@
extern const char kLegacyTLSWarningsName[];
extern const char kLegacyTLSWarningsDescription[];
+extern const char kLensCameraAssistedSearchName[];
+extern const char kLensCameraAssistedSearchDescription[];
+
extern const char kLiteVideoName[];
extern const char kLiteVideoDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 39cd6b0..059c60d 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -196,6 +196,7 @@
&kInlineUpdateFlow,
&kInstantStart,
&kKitKatSupported,
+ &kLensCameraAssistedSearch,
&kNotificationSuspender,
&kOfflineIndicatorV2,
&kOfflineMeasurementsBackgroundTask,
@@ -460,6 +461,9 @@
const base::Feature kContextMenuTranslateWithGoogleLens{
"ContextMenuTranslateWithGoogleLens", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kLensCameraAssistedSearch{
+ "LensCameraAssistedSearch", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kContextualSearchDebug{"ContextualSearchDebug",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 98f60771..64d7531 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -91,6 +91,7 @@
extern const base::Feature kInstantStart;
extern const base::Feature kKitKatSupported;
extern const base::Feature kLanguagesPreference;
+extern const base::Feature kLensCameraAssistedSearch;
extern const base::Feature kNotificationSuspender;
extern const base::Feature kOfflineIndicatorV2;
extern const base::Feature kOfflineMeasurementsBackgroundTask;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 26b0a43..7999501f 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -274,6 +274,7 @@
"ContextMenuSearchAndShopWithGoogleLens";
public static final String CONTEXT_MENU_TRANSLATE_WITH_GOOGLE_LENS =
"ContextMenuTranslateWithGoogleLens";
+ public static final String LENS_CAMERA_ASSISTED_SEARCH = "LensCameraAssistedSearch";
public static final String CONTEXTUAL_SEARCH_DEBUG = "ContextualSearchDebug";
public static final String CONTEXTUAL_SEARCH_DEFINITIONS = "ContextualSearchDefinitions";
public static final String CONTEXTUAL_SEARCH_LEGACY_HTTP_POLICY =
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 39f057c..e8c25fd3 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3269,6 +3269,9 @@
<message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MIC" desc="Content description for the voice search button.">
Start voice search
</message>
+ <message name="IDS_ACCESSIBILITY_BTN_LENS_CAMERA" desc="Content description for the Lens button. When the user taps the button, they can perform a 'search with your camera or photos', which opens the Google Lens app.">
+ Search with your camera using Google Lens
+ </message>
<message name="IDS_ACCESSIBILITY_NEW_TAB_PAGE" desc="Accessibility text to read aloud when the user focuses the new tab view.">
New tab
</message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_BTN_LENS_CAMERA.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_BTN_LENS_CAMERA.png.sha1
new file mode 100644
index 0000000..7817a62
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_BTN_LENS_CAMERA.png.sha1
@@ -0,0 +1 @@
+b437a8116be72e934e4ec1b351e9c9cd3f339814
\ No newline at end of file
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 90d2722..fb04dfe 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -46372,6 +46372,7 @@
<int value="799680074" label="ContextualSearchTranslationModel:enabled"/>
<int value="802463708" label="WebViewSurfaceControl:enabled"/>
<int value="803282885" label="PreferHtmlOverPlugins:disabled"/>
+ <int value="804958673" label="LensCameraAssistedSearch:enabled"/>
<int value="805882800" label="SafetyCheckChromeCleanerChild:disabled"/>
<int value="806035639" label="EnableNeuralPalmDetectionFilter:disabled"/>
<int value="806334184" label="AndroidSpellChecker:enabled"/>
@@ -47074,6 +47075,7 @@
<int value="1454006695" label="BlinkHeapUnifiedGarbageCollection:disabled"/>
<int value="1454028829" label="EnhancedProtectionPromoCard:disabled"/>
<int value="1454143461" label="CaptureThumbnailOnNavigatingAway:disabled"/>
+ <int value="1454295160" label="LensCameraAssistedSearch:disabled"/>
<int value="1454363479" label="disable-storage-manager"/>
<int value="1454527518" label="ArcNativeBridgeExperiment:enabled"/>
<int value="1455881930" label="V8VmFuture:enabled"/>