Commit 14293b89 authored by Shakti Sahu's avatar Shakti Sahu Committed by Commit Bot

Video Tutorials : Implemented try now button functionality

This CL adds :
1 - Try now button is shown on the video player for certain tutorials
for whom the steps are defined.
2 - The video player launches ChromeTabbedActivity and stores the
 tutorial info in a temporary tracker VideoTutorialTryNowTracker.
3 - NewTabPageLayout checks the tracker in onWindowVisibilityChanged()
 and shows IPH on search box for search or voice search.
4 - ToolbarButtonInProductHelpController checks the tracker on resume,
 and shows downloads tutorial IPH if any.
5 - IPHCommand and UserEducationHelper were modified to handle an
 "always show IPH", which is checked by checking if featureName is null.
 In that scenario, any call to feature engagement Tracker is skipped.
6- Some small fixs on layout XML file.

UX: https://docs.google.com/presentation/d/1jszfqrCLufu0mskWls6unqilpmG3PoHKdySsf4uF-eo/edit#slide=id.g8a320d9435_2_550

Bug: 1133637
Change-Id: I65262d0e2e85cb15f97971d039e47905983e90df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2439781
Commit-Queue: Shakti Sahu <shaktisahu@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815967}
parent 09b3d44e
......@@ -26,6 +26,7 @@ include_rules = [
"+chrome/browser/user_education",
"+chrome/browser/util/android/java",
"+chrome/browser/version",
"+chrome/browser/video_tutorials",
"+chrome/browser/webauthn/android",
"+components/browser_ui/android/bottomsheet",
"+components/browser_ui/banners/android",
......
......@@ -6,11 +6,13 @@ package org.chromium.chrome.browser.app.video_tutorials;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
import android.view.WindowManager;
import org.chromium.base.IntentUtils;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.SynchronousInitializationActivity;
import org.chromium.chrome.browser.WebContentsFactory;
import org.chromium.chrome.browser.profiles.Profile;
......@@ -18,6 +20,7 @@ import org.chromium.chrome.browser.video_tutorials.Tutorial;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialService;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory;
import org.chromium.chrome.browser.video_tutorials.player.VideoPlayerCoordinator;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.components.version_info.VersionConstants;
import org.chromium.content_public.browser.WebContents;
......@@ -44,7 +47,7 @@ public class VideoPlayerActivity extends SynchronousInitializationActivity {
VideoTutorialServiceFactory.getForProfile(Profile.getLastUsedRegularProfile());
mWindowAndroid = new ActivityWindowAndroid(this);
mCoordinator = VideoTutorialServiceFactory.createVideoPlayerCoordinator(
this, videoTutorialService, this::createWebContents, this::finish);
this, videoTutorialService, this::createWebContents, this::tryNow, this::finish);
setContentView(mCoordinator.getView());
int featureType = IntentUtils.safeGetIntExtra(getIntent(), EXTRA_VIDEO_TUTORIAL, 0);
......@@ -81,4 +84,13 @@ public class VideoPlayerActivity extends SynchronousInitializationActivity {
intent.putExtra(VideoPlayerActivity.EXTRA_VIDEO_TUTORIAL, tutorial.featureType);
context.startActivity(intent);
}
private void tryNow(Tutorial tutorial) {
VideoTutorialServiceFactory.getTryNowTracker().recordTryNowButtonClicked(
tutorial.featureType);
Intent intent = new Intent();
intent.setData(Uri.parse(UrlConstants.NTP_URL));
intent.setClass(this, ChromeTabbedActivity.class);
startActivity(intent);
}
}
......@@ -10,6 +10,7 @@ import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
......@@ -20,6 +21,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.CallbackController;
......@@ -32,6 +34,7 @@ import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareT
import org.chromium.chrome.browser.cryptids.ProbabilisticCryptidRenderer;
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.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.native_page.ContextMenuManager;
import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
......@@ -50,8 +53,14 @@ import org.chromium.chrome.browser.suggestions.tile.TileGridLayout;
import org.chromium.chrome.browser.suggestions.tile.TileGroup;
import org.chromium.chrome.browser.suggestions.tile.TileRenderer;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import org.chromium.chrome.browser.video_tutorials.FeatureType;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory;
import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker;
import org.chromium.chrome.browser.vr.VrModuleProvider;
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.vr.VrModeObserver;
......@@ -271,7 +280,6 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
if (VrModuleProvider.getDelegate().isInVr()) onEnterVr();
manager.addDestructionObserver(NewTabPageLayout.this::onDestroy);
mInitialized = true;
TraceEvent.end(TAG + ".initialize()");
......@@ -755,6 +763,7 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
if (visibility == VISIBLE) {
updateVoiceSearchButtonVisibility();
maybeShowVideoTutorialTryNowIPH();
}
}
......@@ -887,6 +896,49 @@ public class NewTabPageLayout extends LinearLayout implements TileGroup.Observer
mSearchBoxCoordinator.destroy();
}
private void maybeShowVideoTutorialTryNowIPH() {
VideoTutorialTryNowTracker tryNowTracker = VideoTutorialServiceFactory.getTryNowTracker();
UserEducationHelper userEducationHelper = new UserEducationHelper(
mActivity, new Handler(), TrackerFactory::getTrackerForProfile);
// TODO(shaktisahu): Pass correct y-inset.
// TODO(shaktisahu): Determine if there is conflict with another IPH.
if (tryNowTracker.didClickTryNowButton(FeatureType.SEARCH)) {
IPHCommandBuilder iphCommandBuilder = createIPHCommandBuilder(mActivity.getResources(),
R.string.video_tutorials_iph_tap_here_to_start,
R.string.video_tutorials_iph_tap_here_to_start, mSearchBoxCoordinator.getView(),
false);
userEducationHelper.requestShowIPH(iphCommandBuilder.build());
tryNowTracker.tryNowUIShown(FeatureType.SEARCH);
}
if (tryNowTracker.didClickTryNowButton(FeatureType.VOICE_SEARCH)) {
// TODO(shaktisahu): Pass voice search button.
IPHCommandBuilder iphCommandBuilder = createIPHCommandBuilder(mActivity.getResources(),
R.string.video_tutorials_iph_tap_voice_icon_to_start,
R.string.video_tutorials_iph_tap_voice_icon_to_start,
mSearchBoxCoordinator.getVoiceSearchButton(), true);
userEducationHelper.requestShowIPH(iphCommandBuilder.build());
tryNowTracker.tryNowUIShown(FeatureType.VOICE_SEARCH);
}
}
private static IPHCommandBuilder createIPHCommandBuilder(Resources resources,
@StringRes int stringId, @StringRes int accessibilityStringId, View anchorView,
boolean showHighlight) {
IPHCommandBuilder iphCommandBuilder =
new IPHCommandBuilder(resources, null, stringId, accessibilityStringId);
iphCommandBuilder.setAnchorView(anchorView).setCircleHighlight(showHighlight);
if (showHighlight) {
iphCommandBuilder.setOnShowCallback(
() -> ViewHighlighter.turnOnHighlight(anchorView, true /*circular*/));
iphCommandBuilder.setOnDismissCallback(() -> new Handler().postDelayed(() -> {
ViewHighlighter.turnOffHighlight(anchorView);
}, ViewHighlighter.IPH_MIN_DELAY_BETWEEN_TWO_HIGHLIGHTS));
}
return iphCommandBuilder;
}
/**
* Makes the Search Box and Logo as wide as Most Visited.
*/
......
......@@ -41,6 +41,10 @@ public class SearchBoxCoordinator {
return mView;
}
public View getVoiceSearchButton() {
return mView.findViewById(R.id.voice_search_button);
}
public void destroy() {
mMediator.destroy();
}
......
......@@ -33,6 +33,9 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import org.chromium.chrome.browser.video_tutorials.FeatureType;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory;
import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker;
import org.chromium.components.feature_engagement.EventConstants;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker;
......@@ -167,6 +170,7 @@ public class ToolbarButtonInProductHelpController
// (e.g. tab switch or in overview mode).
if (mActivity.isTablet()) return;
mScreenshotMonitor.startMonitoring();
mHandler.post(this::showVideoTutorialTryNowUIForDownload);
}
@Override
......@@ -317,6 +321,28 @@ public class ToolbarButtonInProductHelpController
.build());
}
/** Show the Try Now UI for video tutorial download feature. */
private void showVideoTutorialTryNowUIForDownload() {
VideoTutorialTryNowTracker tryNowTracker = VideoTutorialServiceFactory.getTryNowTracker();
if (!tryNowTracker.didClickTryNowButton(FeatureType.DOWNLOAD)) {
return;
}
Integer menuItemId = DownloadUtils.isAllowedToDownloadPage(mActivity.getActivityTab())
? R.id.offline_page_id
: R.id.downloads_menu_id;
mUserEducationHelper.requestShowIPH(
new IPHCommandBuilder(mActivity.getResources(), null,
R.string.video_tutorials_iph_tap_here_to_start,
R.string.video_tutorials_iph_tap_here_to_start)
.setAnchorView(mActivity.getToolbarManager().getMenuButtonView())
.setOnShowCallback(() -> turnOnHighlightForMenuItem(menuItemId, true))
.setOnDismissCallback(this::turnOffHighlightForMenuItem)
.build());
tryNowTracker.tryNowUIShown(FeatureType.DOWNLOAD);
}
private void turnOnHighlightForMenuItem(Integer highlightMenuItemId, boolean circleHighlight) {
if (mAppMenuHandler != null) {
mAppMenuHandler.setMenuHighlight(highlightMenuItemId, circleHighlight);
......
......@@ -15,6 +15,11 @@ import org.chromium.ui.widget.ViewRectProvider;
* Class encapsulating the data needed to show in-product help (IPH).
*/
public class IPHCommand {
/**
* Feature name associated with the IPH. If null, the IPH will be always shown and any calls to
* the {@link Tracker} will be avoided.
*/
@Nullable
public final String featureName;
public final String contentString;
public final String accessibilityText;
......@@ -30,7 +35,7 @@ public class IPHCommand {
public final long autoDismissTimeout;
public final ViewRectProvider viewRectProvider;
IPHCommand(String featureName, String contentString, String accessibilityText,
IPHCommand(@Nullable String featureName, String contentString, String accessibilityText,
boolean circleHighlight, boolean shouldHighlight, boolean dismissOnTouch,
View anchorView, Runnable onDismissCallback, Runnable onShowCallback, Rect insetRect,
long autoDismissTimeout, ViewRectProvider viewRectProvider) {
......@@ -47,4 +52,4 @@ public class IPHCommand {
this.autoDismissTimeout = autoDismissTimeout;
this.viewRectProvider = viewRectProvider;
}
}
\ No newline at end of file
}
......@@ -72,7 +72,7 @@ public class UserEducationHelper {
if (mActivity.isFinishing() || mActivity.isDestroyed()) return;
String featureName = iphCommand.featureName;
if (!tracker.shouldTriggerHelpUI(featureName)) return;
if (featureName != null && !tracker.shouldTriggerHelpUI(featureName)) return;
String contentString = iphCommand.contentString;
String accessibilityString = iphCommand.accessibilityText;
assert (!contentString.isEmpty());
......@@ -86,7 +86,7 @@ public class UserEducationHelper {
rectProvider, ChromeAccessibilityUtil.get().isAccessibilityEnabled());
textBubble.setDismissOnTouchInteraction(iphCommand.dismissOnTouch);
textBubble.addOnDismissListener(() -> mHandler.postDelayed(() -> {
tracker.dismissed(featureName);
if (featureName != null) tracker.dismissed(featureName);
iphCommand.onDismissCallback.run();
if (iphCommand.shouldHighlight) {
ViewHighlighter.turnOffHighlight(anchorView);
......
......@@ -65,6 +65,7 @@ if (is_android) {
"android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialIPHUtils.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java",
]
......
// Copyright 2020 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.
package org.chromium.chrome.browser.video_tutorials.iph;
import org.chromium.chrome.browser.video_tutorials.FeatureType;
/**
* This class acts as a temporary tracker of the user click on Try Now button on the video player
* during a chrome session. As soon as a
*/
public interface VideoTutorialTryNowTracker {
/**
* Called to record that the Try Now button has been clicked by the user, and we should show the
* appropriate UI.
* @param featureType The feature type associated with the tutorial.
*/
void recordTryNowButtonClicked(@FeatureType int featureType);
/**
* Called to determine whether or not the Try Now button was clicked by the user.
* @param featureType The feature type associated with the tutorial.
* @return Whether or not the Try Now button was clicked for a video tutorial.
*/
boolean didClickTryNowButton(@FeatureType int featureType);
/**
* Called when the try now UI was shown. Serves as a signal to reset the internal state of the
* tracker.
*/
void tryNowUIShown(@FeatureType int featureType);
}
\ No newline at end of file
......@@ -62,6 +62,7 @@ if (is_android) {
"android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialUtils.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHProperties.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHView.java",
......
......@@ -36,33 +36,35 @@
android:layout_height="0dp"
android:layout_centerInParent="true" />
<org.chromium.ui.widget.ButtonCompat
android:id="@+id/try_now"
android:layout_width="100dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/dummy_center"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:text="@string/video_tutorials_try_now"
style="@style/FilledButton.Flat" />
android:orientation="vertical">
<TextView
android:id="@+id/watch_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/try_now"
android:layout_marginTop="28dp"
android:textAppearance="@style/TextAppearance.TextMedium.Primary.Light"
android:text="@string/video_tutorials_watch_next_video" />
<org.chromium.ui.widget.ButtonCompat
android:id="@+id/try_now"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="@string/video_tutorials_try_now"
style="@style/FilledButton.Flat" />
<TextView
android:id="@+id/change_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/watch_next"
android:layout_marginTop="28dp"
android:textAppearance="@style/TextAppearance.TextMedium.Primary.Light" />
<TextView
android:id="@+id/watch_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:textAppearance="@style/TextAppearance.TextMedium.Primary.Light"
android:text="@string/video_tutorials_watch_next_video" />
<TextView
android:id="@+id/change_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:textAppearance="@style/TextAppearance.TextMedium.Primary.Light" />
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -15,8 +15,10 @@ import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.video_tutorials.iph.TryNowTrackerImpl;
import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinator;
import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinatorImpl;
import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker;
import org.chromium.chrome.browser.video_tutorials.list.TutorialListCoordinator;
import org.chromium.chrome.browser.video_tutorials.list.TutorialListCoordinatorImpl;
import org.chromium.chrome.browser.video_tutorials.player.VideoPlayerCoordinator;
......@@ -51,9 +53,10 @@ public class VideoTutorialServiceFactory {
/** See {@link VideoPlayerCoordinator}.*/
public static VideoPlayerCoordinator createVideoPlayerCoordinator(Context context,
VideoTutorialService videoTutorialService,
Supplier<Pair<WebContents, ContentView>> webContentsFactory, Runnable closeCallback) {
Supplier<Pair<WebContents, ContentView>> webContentsFactory,
Callback<Tutorial> tryNowCallback, Runnable closeCallback) {
return new VideoPlayerCoordinatorImpl(
context, videoTutorialService, webContentsFactory, closeCallback);
context, videoTutorialService, webContentsFactory, tryNowCallback, closeCallback);
}
/** See {@link TutorialListCoordinator}.*/
......@@ -64,12 +67,21 @@ public class VideoTutorialServiceFactory {
recyclerView, videoTutorialService, imageFetcher, clickCallback);
}
/** @return The tracker to track Try Now button clicks. */
public static VideoTutorialTryNowTracker getTryNowTracker() {
return LazyHolder.TRY_NOW_TRACKER;
}
public static void setVideoTutorialServiceForTesting(VideoTutorialService provider) {
sVideoTutorialServiceForTesting = provider;
}
private static final class LazyHolder {
private static final VideoTutorialTryNowTracker TRY_NOW_TRACKER = new TryNowTrackerImpl();
}
@NativeMethods
interface Natives {
VideoTutorialService getForProfile(Profile profile);
}
}
\ No newline at end of file
}
......@@ -41,6 +41,19 @@ public class VideoTutorialUtils {
});
}
/** @return Whether or not to show the Try Now button on the video player. */
public static boolean shouldShowTryNow(@FeatureType int featureType) {
switch (featureType) {
case FeatureType.DOWNLOAD:
case FeatureType.SEARCH:
case FeatureType.VOICE_SEARCH:
return true;
case FeatureType.CHROME_INTRO:
default:
return false;
}
}
private static Tutorial getNextTutorial(List<Tutorial> tutorials, Tutorial currentTutorial) {
int currentIndex = 0;
for (int i = 0; i < tutorials.size(); i++) {
......
// Copyright 2020 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.
package org.chromium.chrome.browser.video_tutorials.iph;
import org.chromium.chrome.browser.video_tutorials.FeatureType;
/**
* {@link VideoTutorialTryNowTracker} implementation.
*/
public class TryNowTrackerImpl implements VideoTutorialTryNowTracker {
private @FeatureType int mFeatureType = FeatureType.INVALID;
@Override
public void recordTryNowButtonClicked(@FeatureType int featureType) {
mFeatureType = featureType;
}
@Override
public boolean didClickTryNowButton(@FeatureType int featureType) {
return mFeatureType == featureType;
}
@Override
public void tryNowUIShown(@FeatureType int featureType) {
mFeatureType = FeatureType.INVALID;
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import android.content.Context;
import android.util.Pair;
import android.view.View;
import org.chromium.base.Callback;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver;
import org.chromium.chrome.browser.video_tutorials.R;
......@@ -42,10 +43,12 @@ public class VideoPlayerCoordinatorImpl implements VideoPlayerCoordinator {
* @param context The activity context.
* @param videoTutorialService The backend for serving video tutorials.
* @param webContentsFactory A supplier to supply WebContents and ContentView.
* @param tryNowCallback Callback to be invoked when try now button is clicked.
* @param closeCallback Callback to be invoked when this UI is closed.
*/
public VideoPlayerCoordinatorImpl(Context context, VideoTutorialService videoTutorialService,
Supplier<Pair<WebContents, ContentView>> webContentsFactory, Runnable closeCallback) {
Supplier<Pair<WebContents, ContentView>> webContentsFactory,
Callback<Tutorial> tryNowCallback, Runnable closeCallback) {
mContext = context;
mVideoTutorialService = videoTutorialService;
mModel = new PropertyModel(VideoPlayerProperties.ALL_KEYS);
......@@ -55,7 +58,7 @@ public class VideoPlayerCoordinatorImpl implements VideoPlayerCoordinator {
mLanguagePicker = new LanguagePickerCoordinator(
mView.getView().findViewById(R.id.language_picker), mVideoTutorialService);
mMediator = new VideoPlayerMediator(mContext, mModel, videoTutorialService, mLanguagePicker,
mWebContents, closeCallback);
mWebContents, tryNowCallback, closeCallback);
PropertyModelChangeProcessor.create(mModel, mView, new VideoPlayerViewBinder());
}
......
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.video_tutorials.player;
import android.content.Context;
import android.text.TextUtils;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.video_tutorials.Language;
import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver;
import org.chromium.chrome.browser.video_tutorials.R;
......@@ -32,18 +33,20 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
private final LanguagePickerCoordinator mLanguagePicker;
private final WebContents mWebContents;
private Tutorial mTutorial;
private final Callback<Tutorial> mTryNowCallback;
private final Runnable mCloseCallback;
private long mVideoStartTime;
/** Constructor. */
public VideoPlayerMediator(Context context, PropertyModel model,
VideoTutorialService videoTutorialService, LanguagePickerCoordinator languagePicker,
WebContents webContents, Runnable closeCallback) {
WebContents webContents, Callback<Tutorial> tryNowCallback, Runnable closeCallback) {
mContext = context;
mModel = model;
mVideoTutorialService = videoTutorialService;
mLanguagePicker = languagePicker;
mWebContents = webContents;
mTryNowCallback = tryNowCallback;
mCloseCallback = closeCallback;
mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, false);
......@@ -104,6 +107,8 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
mModel.set(VideoPlayerProperties.SHOW_MEDIA_CONTROLS, true);
mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, false);
mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, false);
mModel.set(VideoPlayerProperties.SHOW_TRY_NOW,
VideoTutorialUtils.shouldShowTryNow(mTutorial.featureType));
}
@Override
......@@ -112,11 +117,9 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
mModel.set(VideoPlayerProperties.SHOW_MEDIA_CONTROLS, true);
mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, true);
maybeShowWatchNextVideoButton();
mModel.set(VideoPlayerProperties.SHOW_TRY_NOW,
VideoTutorialUtils.shouldShowTryNow(mTutorial.featureType));
updateChangeLanguageButtonText();
VideoTutorialUtils.getNextTutorial(mVideoTutorialService, mTutorial, nextTutorial -> {
mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, nextTutorial != null);
});
}
private void changeLanguage() {
......@@ -144,6 +147,7 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
private void tryNow() {
VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.TRY_NOW);
mTryNowCallback.onResult(mTutorial);
}
private void share() {
......
......@@ -20,6 +20,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.chromium.base.Callback;
import org.chromium.base.metrics.test.ShadowRecordHistogram;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.video_tutorials.Tutorial;
......@@ -57,6 +58,8 @@ public class VideoPlayerMediatorUnitTest {
ArgumentCaptor<Runnable> mLanguagePickerCallback;
@Mock
PropertyObservable.PropertyObserver<PropertyKey> mPropertyObserver;
@Mock
Callback<Tutorial> mTryNowCallback;
@Before
public void setUp() {
......@@ -70,7 +73,7 @@ public class VideoPlayerMediatorUnitTest {
mTestVideoTutorialService = new TestVideoTutorialService();
mMediator = new VideoPlayerMediator(mContext, mModel, mTestVideoTutorialService,
mLanguagePicker, mWebContents, mCloseCallback);
mLanguagePicker, mWebContents, mTryNowCallback, mCloseCallback);
}
@Test
......
......@@ -17,6 +17,7 @@ interface VideoPlayerProperties {
WritableBooleanPropertyKey SHOW_LOADING_SCREEN = new WritableBooleanPropertyKey();
WritableBooleanPropertyKey SHOW_MEDIA_CONTROLS = new WritableBooleanPropertyKey();
WritableBooleanPropertyKey SHOW_LANGUAGE_PICKER = new WritableBooleanPropertyKey();
WritableBooleanPropertyKey SHOW_TRY_NOW = new WritableBooleanPropertyKey();
WritableBooleanPropertyKey SHOW_WATCH_NEXT = new WritableBooleanPropertyKey();
WritableBooleanPropertyKey SHOW_CHANGE_LANGUAGE = new WritableBooleanPropertyKey();
WritableObjectPropertyKey<String> CHANGE_LANGUAGE_BUTTON_TEXT =
......@@ -29,7 +30,7 @@ interface VideoPlayerProperties {
WritableObjectPropertyKey<Runnable> CALLBACK_CLOSE = new WritableObjectPropertyKey<>();
PropertyKey[] ALL_KEYS = new PropertyKey[] {SHOW_LOADING_SCREEN, SHOW_MEDIA_CONTROLS,
SHOW_LANGUAGE_PICKER, SHOW_WATCH_NEXT, SHOW_CHANGE_LANGUAGE,
SHOW_LANGUAGE_PICKER, SHOW_TRY_NOW, SHOW_WATCH_NEXT, SHOW_CHANGE_LANGUAGE,
CHANGE_LANGUAGE_BUTTON_TEXT, CALLBACK_WATCH_NEXT, CALLBACK_CHANGE_LANGUAGE,
CALLBACK_TRY_NOW, CALLBACK_SHARE, CALLBACK_CLOSE};
}
......@@ -24,6 +24,11 @@ class VideoPlayerViewBinder implements ViewBinder<PropertyModel, VideoPlayerView
view.showMediaControls(model.get(VideoPlayerProperties.SHOW_MEDIA_CONTROLS));
} else if (propertyKey == VideoPlayerProperties.SHOW_LANGUAGE_PICKER) {
view.showLanguagePicker(model.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER));
} else if (propertyKey == VideoPlayerProperties.SHOW_TRY_NOW) {
view.getView()
.findViewById(R.id.try_now)
.setVisibility(model.get(VideoPlayerProperties.SHOW_TRY_NOW) ? View.VISIBLE
: View.GONE);
} else if (propertyKey == VideoPlayerProperties.SHOW_WATCH_NEXT) {
view.getView()
.findViewById(R.id.watch_next)
......
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