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 = [ ...@@ -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/NewTabPageVideoIPHManager.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.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/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/AutofillExpirationDateFixFlowBridge.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java", "java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java", "java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java",
......
...@@ -28,6 +28,7 @@ import org.chromium.base.PackageManagerUtils; ...@@ -28,6 +28,7 @@ import org.chromium.base.PackageManagerUtils;
import org.chromium.base.StrictModeContext; import org.chromium.base.StrictModeContext;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.app.ChromeActivity; 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.BrowserServicesIntentDataProvider.CustomTabsUiType;
import org.chromium.chrome.browser.browserservices.SessionDataHolder; import org.chromium.chrome.browser.browserservices.SessionDataHolder;
import org.chromium.chrome.browser.browserservices.ui.splashscreen.trustedwebactivity.TwaSplashController; import org.chromium.chrome.browser.browserservices.ui.splashscreen.trustedwebactivity.TwaSplashController;
...@@ -159,6 +160,11 @@ public class LaunchIntentDispatcher implements IntentHandler.IntentHandlerDelega ...@@ -159,6 +160,11 @@ public class LaunchIntentDispatcher implements IntentHandler.IntentHandlerDelega
return Action.FINISH_ACTIVITY; 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 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 // 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 // TabManager. If that ever lands, code to bring back any Tab could be consolidated
......
...@@ -124,7 +124,7 @@ public class NewTabPageVideoIPHManager { ...@@ -124,7 +124,7 @@ public class NewTabPageVideoIPHManager {
@VisibleForTesting @VisibleForTesting
protected void launchVideoPlayer(Tutorial tutorial) { protected void launchVideoPlayer(Tutorial tutorial) {
VideoPlayerActivity.playVideoTutorial(mContext, tutorial); VideoPlayerActivity.playVideoTutorial(mContext, tutorial.featureType);
} }
@VisibleForTesting @VisibleForTesting
......
...@@ -81,10 +81,11 @@ public class VideoPlayerActivity extends SynchronousInitializationActivity { ...@@ -81,10 +81,11 @@ public class VideoPlayerActivity extends SynchronousInitializationActivity {
} }
/** Called to launch this activity to play a given video tutorial. */ /** 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 intent = new Intent();
intent.setClass(context, VideoPlayerActivity.class); 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); context.startActivity(intent);
} }
......
...@@ -42,6 +42,6 @@ public class VideoTutorialListActivity extends SynchronousInitializationActivity ...@@ -42,6 +42,6 @@ public class VideoTutorialListActivity extends SynchronousInitializationActivity
} }
private void onTutorialSelected(Tutorial tutorial) { 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; ...@@ -36,6 +36,7 @@ import org.chromium.chrome.browser.ChromeBackupAgentImpl;
import org.chromium.chrome.browser.DefaultBrowserInfo; import org.chromium.chrome.browser.DefaultBrowserInfo;
import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.DeferredStartupHandler;
import org.chromium.chrome.browser.DevToolsServer; 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.banners.AppBannerManager;
import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider; import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider;
import org.chromium.chrome.browser.contacts_picker.ChromePickerAdapter; import org.chromium.chrome.browser.contacts_picker.ChromePickerAdapter;
...@@ -434,6 +435,8 @@ public class ProcessInitializationHandler { ...@@ -434,6 +435,8 @@ public class ProcessInitializationHandler {
() -> OfflineContentAvailabilityStatusProvider.getInstance()); () -> OfflineContentAvailabilityStatusProvider.getInstance());
deferredStartupHandler.addDeferredTask( deferredStartupHandler.addDeferredTask(
() -> EnterpriseInfo.getInstance().logDeviceEnterpriseInfo()); () -> EnterpriseInfo.getInstance().logDeviceEnterpriseInfo());
deferredStartupHandler.addDeferredTask(
() -> VideoTutorialShareHelper.saveUrlsToSharedPrefs());
} }
private void initChannelsAsync() { private void initChannelsAsync() {
......
...@@ -725,6 +725,7 @@ public final class ChromePreferenceKeys { ...@@ -725,6 +725,7 @@ public final class ChromePreferenceKeys {
public static final String VERIFIED_DIGITAL_ASSET_LINKS = "verified_digital_asset_links"; 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_EXIT_TO_2D_COUNT = "VR_EXIT_TO_2D_COUNT";
public static final String VR_FEEDBACK_OPT_OUT = "VR_FEEDBACK_OPT_OUT"; public static final String VR_FEEDBACK_OPT_OUT = "VR_FEEDBACK_OPT_OUT";
...@@ -835,7 +836,8 @@ public final class ChromePreferenceKeys { ...@@ -835,7 +836,8 @@ public final class ChromePreferenceKeys {
SETTINGS_SAFETY_CHECK_LAST_RUN_TIMESTAMP, SETTINGS_SAFETY_CHECK_LAST_RUN_TIMESTAMP,
SETTINGS_SAFETY_CHECK_RUN_COUNTER, SETTINGS_SAFETY_CHECK_RUN_COUNTER,
SIGNIN_PROMO_IMPRESSIONS_COUNT_NTP, SIGNIN_PROMO_IMPRESSIONS_COUNT_NTP,
TWA_DISCLOSURE_SEEN_PACKAGES TWA_DISCLOSURE_SEEN_PACKAGES,
VIDEO_TUTORIALS_SHARE_URL_SET
); );
// clang-format on // clang-format on
} }
......
...@@ -68,6 +68,7 @@ if (is_android) { ...@@ -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/VideoTutorialIPHUtils.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.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/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", "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java",
] ]
......
...@@ -33,7 +33,8 @@ public class VideoTutorialMetrics { ...@@ -33,7 +33,8 @@ public class VideoTutorialMetrics {
// Please treat this list as append only and keep it in sync with // Please treat this list as append only and keep it in sync with
// VideoTutorials.UserAction in enums.xml. // VideoTutorials.UserAction in enums.xml.
@IntDef({UserAction.CHANGE_LANGUAGE, UserAction.WATCH_NEXT_VIDEO, UserAction.TRY_NOW, @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) @Retention(RetentionPolicy.SOURCE)
public @interface UserAction { public @interface UserAction {
int CHANGE_LANGUAGE = 0; int CHANGE_LANGUAGE = 0;
...@@ -42,7 +43,9 @@ public class VideoTutorialMetrics { ...@@ -42,7 +43,9 @@ public class VideoTutorialMetrics {
int SHARE = 3; int SHARE = 3;
int CLOSE = 4; int CLOSE = 4;
int BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER = 5; 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. */ /** Called to record various user actions on the video player. */
......
...@@ -76,7 +76,6 @@ if (is_android) { ...@@ -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/TutorialCardViewBinder.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.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/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/VideoPlayerCoordinatorImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.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", "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java",
......
...@@ -4,7 +4,12 @@ ...@@ -4,7 +4,12 @@
package org.chromium.chrome.browser.video_tutorials; 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.Callback;
import org.chromium.base.Log;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
...@@ -13,6 +18,31 @@ import java.util.Locale; ...@@ -13,6 +18,31 @@ import java.util.Locale;
* Handles various feature utility functions associated with video tutorials UI. * Handles various feature utility functions associated with video tutorials UI.
*/ */
public class VideoTutorialUtils { 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. * Converts a duration string in ms to a human-readable form.
* @param videoLengthSeconds The video length in seconds. * @param videoLengthSeconds The video length in seconds.
......
...@@ -177,6 +177,7 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer { ...@@ -177,6 +177,7 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
private void share() { private void share() {
VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.SHARE); VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.SHARE);
VideoTutorialUtils.launchShareIntent(mContext, mTutorial);
} }
private void close() { 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