Commit b582a513 authored by Shakti Sahu's avatar Shakti Sahu Committed by Commit Bot

Video Tutorials : Implemented share

This CL implements share functionality.
1 - Videos will be shared from share button click through a share
intent chooser.
2 - At startup, Chrome will save all the video share URLs in a
shared preference.
3 - At the receipient end, LaunchIntentDispatcher will check through
the saved shared pref to see if it is a video tutorial URL. If yes,
a video player will be launched.

Bug: 1117180
Change-Id: If169eab9053b2092532e4d48da8903bc06cf4813
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2437785
Commit-Queue: Shakti Sahu <shaktisahu@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827630}
parent 2f998ef9
......@@ -92,6 +92,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialListActivity.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialShareHelper.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowBridge.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java",
......
......@@ -28,6 +28,7 @@ import org.chromium.base.PackageManagerUtils;
import org.chromium.base.StrictModeContext;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.app.video_tutorials.VideoTutorialShareHelper;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider.CustomTabsUiType;
import org.chromium.chrome.browser.browserservices.SessionDataHolder;
import org.chromium.chrome.browser.browserservices.ui.splashscreen.trustedwebactivity.TwaSplashController;
......@@ -159,6 +160,11 @@ public class LaunchIntentDispatcher implements IntentHandler.IntentHandlerDelega
return Action.FINISH_ACTIVITY;
}
// Check if the URL is a video tutorial and needs to be handled in a video player.
if (VideoTutorialShareHelper.handleVideoTutorialURL(url)) {
return Action.FINISH_ACTIVITY;
}
// Check if a LIVE WebappActivity has to be brought back to the foreground. We can't
// check for a dead WebappActivity because we don't have that information without a global
// TabManager. If that ever lands, code to bring back any Tab could be consolidated
......
......@@ -124,7 +124,7 @@ public class NewTabPageVideoIPHManager {
@VisibleForTesting
protected void launchVideoPlayer(Tutorial tutorial) {
VideoPlayerActivity.playVideoTutorial(mContext, tutorial);
VideoPlayerActivity.playVideoTutorial(mContext, tutorial.featureType);
}
@VisibleForTesting
......
......@@ -81,10 +81,11 @@ public class VideoPlayerActivity extends SynchronousInitializationActivity {
}
/** Called to launch this activity to play a given video tutorial. */
static void playVideoTutorial(Context context, Tutorial tutorial) {
public static void playVideoTutorial(Context context, @FeatureType int featureType) {
Intent intent = new Intent();
intent.setClass(context, VideoPlayerActivity.class);
intent.putExtra(VideoPlayerActivity.EXTRA_VIDEO_TUTORIAL, tutorial.featureType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(VideoPlayerActivity.EXTRA_VIDEO_TUTORIAL, featureType);
context.startActivity(intent);
}
......
......@@ -42,6 +42,6 @@ public class VideoTutorialListActivity extends SynchronousInitializationActivity
}
private void onTutorialSelected(Tutorial tutorial) {
VideoPlayerActivity.playVideoTutorial(this, tutorial);
VideoPlayerActivity.playVideoTutorial(this, tutorial.featureType);
}
}
// 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.app.video_tutorials;
import android.text.TextUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.init.BrowserParts;
import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
import org.chromium.chrome.browser.init.EmptyBrowserParts;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.video_tutorials.FeatureType;
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.metrics.VideoTutorialMetrics;
import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction;
import java.util.HashSet;
import java.util.Set;
/**
* Helper class to handle share intents for video tutorials.
*/
public class VideoTutorialShareHelper {
/**
* Handles the URL, if it is a video tutorial share URL, otherwise returns false.
* @param url The URL being checked.
* @return True, if the URL was recognized as a video tutorial URL and handled, false otherwise.
*/
public static boolean handleVideoTutorialURL(String url) {
Set<String> videoTutorialUrls = SharedPreferencesManager.getInstance().readStringSet(
ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET, new HashSet<>());
if (!videoTutorialUrls.contains(url)) return false;
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.VIDEO_TUTORIALS)) return false;
launchVideoPlayer(url);
return true;
}
/**
* Writes the video tutorial share URLs to shared preferences. This is later used to identify
* whether a URL is a video tutorial.
*/
public static void saveUrlsToSharedPrefs() {
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.VIDEO_TUTORIALS)) {
SharedPreferencesManager.getInstance().removeKey(
ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET);
return;
}
VideoTutorialService videoTutorialService =
VideoTutorialServiceFactory.getForProfile(Profile.getLastUsedRegularProfile());
videoTutorialService.getTutorials(tutorials -> {
Set<String> shareUrlSet = new HashSet<>();
for (Tutorial tutorial : tutorials) {
if (TextUtils.isEmpty(tutorial.shareUrl)) continue;
shareUrlSet.add(tutorial.shareUrl);
}
SharedPreferencesManager.getInstance().writeStringSet(
ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET, shareUrlSet);
});
}
private static void launchVideoPlayer(String shareUrl) {
assert !TextUtils.isEmpty(shareUrl);
BrowserParts parts = new EmptyBrowserParts() {
@Override
public void finishNativeInitialization() {
VideoTutorialService videoTutorialService =
VideoTutorialServiceFactory.getForProfile(
Profile.getLastUsedRegularProfile());
videoTutorialService.getTutorials(tutorials -> {
for (Tutorial tutorial : tutorials) {
if (TextUtils.equals(tutorial.shareUrl, shareUrl)) {
VideoTutorialMetrics.recordUserAction(
tutorial.featureType, UserAction.OPEN_SHARED_VIDEO);
VideoPlayerActivity.playVideoTutorial(
ContextUtils.getApplicationContext(), tutorial.featureType);
return;
}
}
VideoTutorialMetrics.recordUserAction(
FeatureType.INVALID, UserAction.INVALID_SHARE_URL);
});
}
};
ChromeBrowserInitializer.getInstance().handlePreNativeStartup(parts);
ChromeBrowserInitializer.getInstance().handlePostNativeStartup(true, parts);
}
}
......@@ -36,6 +36,7 @@ import org.chromium.chrome.browser.ChromeBackupAgentImpl;
import org.chromium.chrome.browser.DefaultBrowserInfo;
import org.chromium.chrome.browser.DeferredStartupHandler;
import org.chromium.chrome.browser.DevToolsServer;
import org.chromium.chrome.browser.app.video_tutorials.VideoTutorialShareHelper;
import org.chromium.chrome.browser.banners.AppBannerManager;
import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider;
import org.chromium.chrome.browser.contacts_picker.ChromePickerAdapter;
......@@ -434,6 +435,8 @@ public class ProcessInitializationHandler {
() -> OfflineContentAvailabilityStatusProvider.getInstance());
deferredStartupHandler.addDeferredTask(
() -> EnterpriseInfo.getInstance().logDeviceEnterpriseInfo());
deferredStartupHandler.addDeferredTask(
() -> VideoTutorialShareHelper.saveUrlsToSharedPrefs());
}
private void initChannelsAsync() {
......
......@@ -725,6 +725,7 @@ public final class ChromePreferenceKeys {
public static final String VERIFIED_DIGITAL_ASSET_LINKS = "verified_digital_asset_links";
public static final String VIDEO_TUTORIALS_SHARE_URL_SET = "Chrome.VideoTutorials.ShareUrls";
public static final String VR_EXIT_TO_2D_COUNT = "VR_EXIT_TO_2D_COUNT";
public static final String VR_FEEDBACK_OPT_OUT = "VR_FEEDBACK_OPT_OUT";
......@@ -835,7 +836,8 @@ public final class ChromePreferenceKeys {
SETTINGS_SAFETY_CHECK_LAST_RUN_TIMESTAMP,
SETTINGS_SAFETY_CHECK_RUN_COUNTER,
SIGNIN_PROMO_IMPRESSIONS_COUNT_NTP,
TWA_DISCLOSURE_SEEN_PACKAGES
TWA_DISCLOSURE_SEEN_PACKAGES,
VIDEO_TUTORIALS_SHARE_URL_SET
);
// clang-format on
}
......
......@@ -68,6 +68,7 @@ if (is_android) {
"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/metrics/VideoTutorialMetrics.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java",
]
......
......@@ -33,7 +33,8 @@ public class VideoTutorialMetrics {
// Please treat this list as append only and keep it in sync with
// VideoTutorials.UserAction in enums.xml.
@IntDef({UserAction.CHANGE_LANGUAGE, UserAction.WATCH_NEXT_VIDEO, UserAction.TRY_NOW,
UserAction.SHARE, UserAction.CLOSE, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER})
UserAction.SHARE, UserAction.CLOSE, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER,
UserAction.OPEN_SHARED_VIDEO, UserAction.INVALID_SHARE_URL})
@Retention(RetentionPolicy.SOURCE)
public @interface UserAction {
int CHANGE_LANGUAGE = 0;
......@@ -42,7 +43,9 @@ public class VideoTutorialMetrics {
int SHARE = 3;
int CLOSE = 4;
int BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER = 5;
int NUM_ENTRIES = 6;
int OPEN_SHARED_VIDEO = 6;
int INVALID_SHARE_URL = 7;
int NUM_ENTRIES = 8;
}
/** Called to record various user actions on the video player. */
......
......@@ -76,7 +76,6 @@ if (is_android) {
"android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardViewBinder.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java",
......
......@@ -4,7 +4,12 @@
package org.chromium.chrome.browser.video_tutorials;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import org.chromium.base.Callback;
import org.chromium.base.Log;
import java.util.List;
import java.util.Locale;
......@@ -13,6 +18,31 @@ import java.util.Locale;
* Handles various feature utility functions associated with video tutorials UI.
*/
public class VideoTutorialUtils {
private static final String TAG = "VideoTutorialShare";
/**
* Creates and launches an Intent that allows sharing a video tutorial.
*/
public static void launchShareIntent(Context context, Tutorial tutorial) {
Intent intent = new Intent();
intent.setType("video/*");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, tutorial.shareUrl);
startShareIntent(context, intent);
}
private static void startShareIntent(Context context, Intent intent) {
try {
context.startActivity(Intent.createChooser(
intent, context.getString(R.string.share_link_chooser_title)));
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Cannot find activity for sharing");
} catch (Exception e) {
Log.e(TAG, "Cannot start activity for sharing, exception: " + e);
}
}
/**
* Converts a duration string in ms to a human-readable form.
* @param videoLengthSeconds The video length in seconds.
......
......@@ -177,6 +177,7 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
private void share() {
VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.SHARE);
VideoTutorialUtils.launchShareIntent(mContext, mTutorial);
}
private void close() {
......
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