Commit ef008150 authored by Patrick Noland's avatar Patrick Noland Committed by Commit Bot

[ToolbarMVC] Move BottomToolbar listeners to toolbar/bottom

Bug: 865801
Change-Id: I4f718c8032bc6c86034a3aa867674d53837aaad2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2028259
Commit-Queue: Patrick Noland <pnoland@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737185}
parent 6776cd21
......@@ -4,7 +4,6 @@
package org.chromium.chrome.browser.toolbar;
import android.app.Activity;
import android.content.ComponentCallbacks;
import android.content.res.Configuration;
import android.content.res.Resources;
......@@ -28,7 +27,6 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Callback;
import org.chromium.base.MathUtils;
import org.chromium.base.metrics.CachedMetrics.ActionEvent;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.ObservableSupplier;
......@@ -129,7 +127,6 @@ import org.chromium.content_public.common.ContentUrlConstants;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.util.TokenHolder;
import org.chromium.ui.widget.Toast;
import java.util.List;
......@@ -151,9 +148,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
void updateReloadButtonState(boolean isLoading);
}
private static final ActionEvent ACCELERATOR_BUTTON_TAP_ACTION =
new ActionEvent("MobileToolbarOmniboxAcceleratorTap");
/**
* The number of ms to wait before reporting to UMA omnibox interaction metrics.
*/
......@@ -193,9 +187,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
private LayoutManager mLayoutManager;
private IdentityDiscController mIdentityDiscController;
private final ObservableSupplier<ShareDelegate> mShareDelegateSupplier;
private final Callback<ShareDelegate> mShareDelegateSupplierCallback;
private ObservableSupplierImpl<OnClickListener> mShareButtonListenerSupplier =
new ObservableSupplierImpl<>();
private ObservableSupplierImpl<View> mTabGroupPopUiParentSupplier;
private @Nullable TabGroupPopupUi mTabGroupPopupUi;
......@@ -265,8 +256,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
mActivity = activity;
mActionBarDelegate = new ViewShiftingActionBarDelegate(activity, controlContainer);
mShareDelegateSupplier = shareDelegateSupplier;
mShareDelegateSupplierCallback = this::onShareDelegateAvailable;
mShareDelegateSupplier.addObserver(mShareDelegateSupplierCallback);
mLocationBarModel = new LocationBarModel(activity);
mControlContainer = controlContainer;
......@@ -796,23 +785,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
* Enable the bottom toolbar.
*/
public void enableBottomToolbar() {
// TODO(crbug.com/1026020): Move creation of these listeners to bottom toolbar component.
final OnClickListener homeButtonListener = v -> {
recordBottomToolbarUseForIPH();
openHomepage();
};
final OnClickListener searchAcceleratorListener = v -> {
recordBottomToolbarUseForIPH();
ACCELERATOR_BUTTON_TAP_ACTION.record();
// Only switch to HomePage when overview is showing.
if (mOverviewModeBehavior.overviewVisible()) {
mShowStartSurfaceSupplier.get();
}
setUrlBarFocus(true, LocationBar.OmniboxFocusReason.ACCELERATOR_TAP);
};
if (FeatureUtilities.isDuetTabStripIntegrationAndroidEnabled()
&& FeatureUtilities.isBottomToolbarEnabled()) {
mTabGroupPopUiParentSupplier = new ObservableSupplierImpl<>();
......@@ -822,13 +794,13 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
mBottomControlsCoordinator = new BottomControlsCoordinator(mActivity.getFullscreenManager(),
mActivity.findViewById(R.id.bottom_controls_stub),
mActivity.getActivityTabProvider(), homeButtonListener, searchAcceleratorListener,
mShareButtonListenerSupplier,
mActivity.getActivityTabProvider(),
mTabGroupPopupUi != null
? mTabGroupPopupUi.getLongClickListenerForTriggering()
: BottomTabSwitcherActionMenuCoordinator.createOnLongClickListener(
id -> mActivity.onOptionsItemSelected(id, null)),
mAppThemeColorProvider);
mAppThemeColorProvider, mShareDelegateSupplier, mShowStartSurfaceSupplier,
this::openHomepage, (reason) -> setUrlBarFocus(true, reason));
mIsBottomToolbarVisible = FeatureUtilities.isBottomToolbarEnabled()
&& (!FeatureUtilities.isAdaptiveToolbarEnabled()
......@@ -836,32 +808,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
!= Configuration.ORIENTATION_LANDSCAPE);
mBottomControlsCoordinator.setBottomControlsVisible(mIsBottomToolbarVisible);
mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible);
Toast.setGlobalExtraYOffset(mActivity.getResources().getDimensionPixelSize(
FeatureUtilities.isLabeledBottomToolbarEnabled()
? R.dimen.labeled_bottom_toolbar_height
: R.dimen.bottom_toolbar_height));
}
// TODO(crbug.com/1026020): Move this logic to BottomToolbar class.
private void onShareDelegateAvailable(ShareDelegate shareDelegate) {
final OnClickListener shareButtonListener = v -> {
if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
recordBottomToolbarUseForIPH();
RecordUserAction.record("MobileBottomToolbarShareButton");
}
Tab tab = null;
Activity activity = null;
boolean isIncognito = false;
if (mTabModelSelector != null) {
tab = mTabModelSelector.getCurrentTab();
activity = ((TabImpl) tab).getActivity();
isIncognito = tab.isIncognito();
}
shareDelegate.share(tab, /*shareDirectly=*/false);
};
mShareButtonListenerSupplier.set(shareButtonListener);
}
/** Record that homepage button was used for IPH reasons */
......@@ -873,22 +819,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
}
}
/** Record that the bottom toolbar was used for IPH reasons. */
private void recordBottomToolbarUseForIPH() {
recordToolbarUseForIPH(EventConstants.CHROME_DUET_USED_BOTTOM_TOOLBAR);
}
/**
* Add bottom toolbar IPH tracking to an existing click listener.
* @param listener The listener to add bottom toolbar tracking to.
*/
private OnClickListener wrapBottomToolbarClickListenerForIPH(OnClickListener listener) {
return (v) -> {
recordBottomToolbarUseForIPH();
listener.onClick(v);
};
}
/**
* @return Whether the bottom toolbar is visible.
*/
......@@ -983,28 +913,16 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
}
if (mBottomControlsCoordinator != null) {
final OnClickListener closeTabsClickListener = v -> {
recordBottomToolbarUseForIPH();
final boolean isIncognito = mTabModelSelector.isIncognitoSelected();
if (isIncognito) {
RecordUserAction.record("MobileToolbarCloseAllIncognitoTabsButtonTap");
} else {
RecordUserAction.record("MobileToolbarCloseAllRegularTabsButtonTap");
}
mTabModelSelector.getModel(isIncognito).closeAllTabs();
Runnable closeAllTabsAction = () -> {
mTabModelSelector.getModel(mIncognitoStateProvider.isIncognitoSelected())
.closeAllTabs();
};
if (mAppMenuButtonHelper != null) {
mAppMenuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH());
}
mBottomControlsCoordinator.initializeWithNative(mActivity,
mActivity.getCompositorViewHolder().getResourceManager(),
mActivity.getCompositorViewHolder().getLayoutManager(),
wrapBottomToolbarClickListenerForIPH(tabSwitcherClickHandler),
wrapBottomToolbarClickListenerForIPH(newTabClickHandler),
closeTabsClickListener, mAppMenuButtonHelper, mOverviewModeBehavior,
mActivity.getCompositorViewHolder().getLayoutManager(), tabSwitcherClickHandler,
newTabClickHandler, mAppMenuButtonHelper, mOverviewModeBehavior,
mActivity.getWindowAndroid(), mTabCountProvider, mIncognitoStateProvider,
mActivity.findViewById(R.id.control_container));
mActivity.findViewById(R.id.control_container), closeAllTabsAction);
// Allow the bottom toolbar to be focused in accessibility after the top toolbar.
ApiCompatibilityUtils.setAccessibilityTraversalBefore(
......@@ -1281,8 +1199,6 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
if (mAppThemeColorProvider != null) mAppThemeColorProvider.destroy();
mActivity.unregisterComponentCallbacks(mComponentCallbacks);
mComponentCallbacks = null;
mShareDelegateSupplier.removeObserver(mShareDelegateSupplierCallback);
}
/**
......
......@@ -12,7 +12,9 @@ import android.view.ViewStub;
import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ChromeActivity;
......@@ -22,6 +24,7 @@ import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.ToolbarSwipeLayout;
import org.chromium.chrome.browser.flags.FeatureUtilities;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.share.ShareDelegate;
import org.chromium.chrome.browser.tasks.tab_management.TabGroupUi;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
......@@ -33,6 +36,7 @@ import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.chromium.ui.resources.ResourceManager;
import org.chromium.ui.widget.Toast;
/**
* The root coordinator for the bottom controls component. This component is intended for use with
......@@ -61,19 +65,23 @@ public class BottomControlsCoordinator {
* @param fullscreenManager A {@link ChromeFullscreenManager} to update the bottom controls
* height for the renderer.
* @param stub The bottom controls {@link ViewStub} to inflate.
* @param tabProvider The {@link ActivityTabProvider} used in the bottom toolbar.
* @param homeButtonListener The {@link OnClickListener} for the bottom toolbar's home button.
* @param searchAcceleratorListener The {@link OnClickListener} for the bottom toolbar's
* search accelerator.
* @param shareButtonListener The {@link OnClickListener} for the bottom toolbar's share button.
* @param tabProvider
* @param tabSwitcherLongclickListener
* @param themeColorProvider The {@link ThemeColorProvider} for the bottom toolbar.
* @param shareDelegateSupplier The supplier for the {@link ShareDelegate} the bottom controls
* should use to share content.
* @param showStartSurfaceCallable The action that opens the start surface, returning true if
* the start surface is shown.
* @param openHomepageAction The action that opens the homepage.
* @param setUrlBarFocusAction The function that sets Url bar focus. The first argument is
* whether the bar should be focused, and the second is the OmniboxFocusReason.
*/
public BottomControlsCoordinator(ChromeFullscreenManager fullscreenManager, ViewStub stub,
ActivityTabProvider tabProvider, OnClickListener homeButtonListener,
OnClickListener searchAcceleratorListener,
ObservableSupplier<OnClickListener> shareButtonListenerSupplier,
OnLongClickListener tabSwitcherLongclickListener,
ThemeColorProvider themeColorProvider) {
ActivityTabProvider tabProvider, OnLongClickListener tabSwitcherLongclickListener,
ThemeColorProvider themeColorProvider,
ObservableSupplier<ShareDelegate> shareDelegateSupplier,
Supplier<Boolean> showStartSurfaceCallable, Runnable openHomepageAction,
Callback<Integer> setUrlBarFocusAction) {
final ScrollingBottomViewResourceFrameLayout root =
(ScrollingBottomViewResourceFrameLayout) stub.inflate();
......@@ -108,10 +116,15 @@ public class BottomControlsCoordinator {
root.findViewById(R.id.bottom_container_slot), themeColorProvider);
} else {
mBottomToolbarCoordinator = new BottomToolbarCoordinator(
root.findViewById(R.id.bottom_toolbar_stub), tabProvider, homeButtonListener,
searchAcceleratorListener, shareButtonListenerSupplier,
tabSwitcherLongclickListener, themeColorProvider);
root.findViewById(R.id.bottom_toolbar_stub), tabProvider,
tabSwitcherLongclickListener, themeColorProvider, shareDelegateSupplier,
showStartSurfaceCallable, openHomepageAction, setUrlBarFocusAction);
}
Toast.setGlobalExtraYOffset(root.getResources().getDimensionPixelSize(
FeatureUtilities.isLabeledBottomToolbarEnabled()
? R.dimen.labeled_bottom_toolbar_height
: R.dimen.bottom_toolbar_height));
}
/**
......@@ -141,21 +154,22 @@ public class BottomControlsCoordinator {
* incognito toggle tab layout.
* @param incognitoStateProvider Notifies components when incognito mode is entered or exited.
* @param topToolbarRoot The root {@link ViewGroup} of the top toolbar.
* @param closeAllTabsAction The runnable that closes all tabs in the current tab model.
*/
public void initializeWithNative(ChromeActivity chromeActivity, ResourceManager resourceManager,
LayoutManager layoutManager, OnClickListener tabSwitcherListener,
OnClickListener newTabClickListener, OnClickListener closeTabsClickListener,
AppMenuButtonHelper menuButtonHelper, OverviewModeBehavior overviewModeBehavior,
WindowAndroid windowAndroid, TabCountProvider tabCountProvider,
IncognitoStateProvider incognitoStateProvider, ViewGroup topToolbarRoot) {
OnClickListener newTabClickListener, AppMenuButtonHelper menuButtonHelper,
OverviewModeBehavior overviewModeBehavior, WindowAndroid windowAndroid,
TabCountProvider tabCountProvider, IncognitoStateProvider incognitoStateProvider,
ViewGroup topToolbarRoot, Runnable closeAllTabsAction) {
mMediator.setLayoutManager(layoutManager);
mMediator.setResourceManager(resourceManager);
mMediator.setWindowAndroid(windowAndroid);
if (mBottomToolbarCoordinator != null) {
mBottomToolbarCoordinator.initializeWithNative(tabSwitcherListener, newTabClickListener,
closeTabsClickListener, menuButtonHelper, overviewModeBehavior,
tabCountProvider, incognitoStateProvider, topToolbarRoot);
menuButtonHelper, overviewModeBehavior, tabCountProvider,
incognitoStateProvider, topToolbarRoot, closeAllTabsAction);
mMediator.setToolbarSwipeHandler(
layoutManager.createToolbarSwipeHandler(/* supportSwipeDown = */ false));
}
......
......@@ -10,23 +10,38 @@ import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import org.chromium.base.Callback;
import org.chromium.base.metrics.CachedMetrics;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ThemeColorProvider;
import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.omnibox.LocationBar;
import org.chromium.chrome.browser.share.ShareDelegate;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
import org.chromium.chrome.browser.toolbar.TabCountProvider;
import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
import org.chromium.components.feature_engagement.EventConstants;
import org.chromium.components.feature_engagement.Tracker;
/**
* The root coordinator for the bottom toolbar. It has two sub-components: the browsing mode bottom
* toolbar and the tab switcher mode bottom toolbar.
*/
class BottomToolbarCoordinator {
private static final CachedMetrics.ActionEvent ACCELERATOR_BUTTON_TAP_ACTION =
new CachedMetrics.ActionEvent("MobileToolbarOmniboxAcceleratorTap");
/** The browsing mode bottom toolbar component */
private final BrowsingModeBottomToolbarCoordinator mBrowsingModeCoordinator;
......@@ -46,30 +61,60 @@ class BottomToolbarCoordinator {
/** The activity tab provider. */
private ActivityTabProvider mTabProvider;
private final ObservableSupplier<ShareDelegate> mShareDelegateSupplier;
private final Callback<ShareDelegate> mShareDelegateSupplierCallback;
private ObservableSupplierImpl<OnClickListener> mShareButtonListenerSupplier =
new ObservableSupplierImpl<>();
private final Supplier<Boolean> mShowStartSurfaceCallable;
/**
* Build the coordinator that manages the bottom toolbar.
* @param stub The bottom toolbar {@link ViewStub} to inflate.
* @param tabProvider The {@link ActivityTabProvider} used for making the IPH.
* @param homeButtonListener The {@link OnClickListener} for the home button.
* @param searchAcceleratorListener The {@link OnClickListener} for the search accelerator.
* @param shareButtonListener The {@link OnClickListener} for the share button.
* @param themeColorProvider The {@link ThemeColorProvider} for the bottom toolbar.
* @param shareDelegateSupplier The supplier for the {@link ShareDelegate} the bottom controls
* should use to share content.
* @param showStartSurfaceCallable The action that opens the start surface, returning true if
* the start surface is shown.
* @param openHomepageAction The action that opens the homepage.
* @param setUrlBarFocusAction The function that sets Url bar focus. The first argument is
*/
BottomToolbarCoordinator(ViewStub stub, ActivityTabProvider tabProvider,
OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
ObservableSupplier<OnClickListener> shareButtonListenerSupplier,
OnLongClickListener tabsSwitcherLongClickListner,
ThemeColorProvider themeColorProvider) {
OnLongClickListener tabsSwitcherLongClickListner, ThemeColorProvider themeColorProvider,
ObservableSupplier<ShareDelegate> shareDelegateSupplier,
Supplier<Boolean> showStartSurfaceCallable, Runnable openHomepageAction,
Callback<Integer> setUrlBarFocusAction) {
View root = stub.inflate();
mShowStartSurfaceCallable = showStartSurfaceCallable;
final OnClickListener homeButtonListener = v -> {
recordBottomToolbarUseForIPH();
openHomepageAction.run();
};
final OnClickListener searchAcceleratorListener = v -> {
recordBottomToolbarUseForIPH();
ACCELERATOR_BUTTON_TAP_ACTION.record();
// Only switch to HomePage when overview is showing.
if (mOverviewModeBehavior != null && mOverviewModeBehavior.overviewVisible()) {
mShowStartSurfaceCallable.get();
}
setUrlBarFocusAction.onResult(LocationBar.OmniboxFocusReason.ACCELERATOR_TAP);
};
mBrowsingModeCoordinator = new BrowsingModeBottomToolbarCoordinator(root, tabProvider,
homeButtonListener, searchAcceleratorListener, shareButtonListenerSupplier,
homeButtonListener, searchAcceleratorListener, mShareButtonListenerSupplier,
tabsSwitcherLongClickListner);
mTabSwitcherModeStub = root.findViewById(R.id.bottom_toolbar_tab_switcher_mode_stub);
mThemeColorProvider = themeColorProvider;
mTabProvider = tabProvider;
mShareDelegateSupplier = shareDelegateSupplier;
mShareDelegateSupplierCallback = this::onShareDelegateAvailable;
mShareDelegateSupplier.addObserver(mShareDelegateSupplierCallback);
}
/**
......@@ -88,12 +133,31 @@ class BottomToolbarCoordinator {
* incognito toggle tab layout.
* @param incognitoStateProvider Notifies components when incognito mode is entered or exited.
* @param topToolbarRoot The root {@link ViewGroup} of the top toolbar.
* @param closeAllTabsAction The runnable that closes all tabs in the current tab model.
*/
void initializeWithNative(OnClickListener tabSwitcherListener,
OnClickListener newTabClickListener, OnClickListener closeTabsClickListener,
AppMenuButtonHelper menuButtonHelper, OverviewModeBehavior overviewModeBehavior,
TabCountProvider tabCountProvider, IncognitoStateProvider incognitoStateProvider,
ViewGroup topToolbarRoot) {
OnClickListener newTabClickListener, AppMenuButtonHelper menuButtonHelper,
OverviewModeBehavior overviewModeBehavior, TabCountProvider tabCountProvider,
IncognitoStateProvider incognitoStateProvider, ViewGroup topToolbarRoot,
Runnable closeAllTabsAction) {
final OnClickListener closeTabsClickListener = v -> {
recordBottomToolbarUseForIPH();
final boolean isIncognito = incognitoStateProvider.isIncognitoSelected();
if (isIncognito) {
RecordUserAction.record("MobileToolbarCloseAllIncognitoTabsButtonTap");
} else {
RecordUserAction.record("MobileToolbarCloseAllRegularTabsButtonTap");
}
closeAllTabsAction.run();
};
if (menuButtonHelper != null) {
menuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH());
}
newTabClickListener = wrapBottomToolbarClickListenerForIPH(newTabClickListener);
tabSwitcherListener = wrapBottomToolbarClickListenerForIPH(tabSwitcherListener);
mBrowsingModeCoordinator.initializeWithNative(newTabClickListener, tabSwitcherListener,
menuButtonHelper, tabCountProvider, mThemeColorProvider, incognitoStateProvider,
overviewModeBehavior);
......@@ -163,5 +227,40 @@ class BottomToolbarCoordinator {
mOverviewModeObserver = null;
}
mThemeColorProvider.destroy();
mShareDelegateSupplier.removeObserver(mShareDelegateSupplierCallback);
}
private void onShareDelegateAvailable(ShareDelegate shareDelegate) {
final OnClickListener shareButtonListener = v -> {
if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
recordBottomToolbarUseForIPH();
RecordUserAction.record("MobileBottomToolbarShareButton");
}
Tab tab = mTabProvider.get();
shareDelegate.share(tab, /*shareDirectly=*/false);
};
mShareButtonListenerSupplier.set(shareButtonListener);
}
/** Record that the bottom toolbar was used for IPH reasons. */
private void recordBottomToolbarUseForIPH() {
Tab tab = mTabProvider.get();
if (tab == null) return;
Tracker tracker = TrackerFactory.getTrackerForProfile(((TabImpl) tab).getProfile());
tracker.notifyEvent(EventConstants.CHROME_DUET_USED_BOTTOM_TOOLBAR);
}
/**
* Add bottom toolbar IPH tracking to an existing click listener.
* @param listener The listener to add bottom toolbar tracking to.
*/
private OnClickListener wrapBottomToolbarClickListenerForIPH(OnClickListener listener) {
return (v) -> {
recordBottomToolbarUseForIPH();
listener.onClick(v);
};
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment