Commit 514ffca0 authored by Yafei Duan's avatar Yafei Duan Committed by Commit Bot

[Offline Pages] Implement live page sharing.

Implement live page sharing:
- Adding a new temporary client namespace for the usage of live page
  sharing, which has a limit of one page per url and expiration period
  as one hour.
- Adding saveAndSharePage in OfflinePageUtils, implementing the workflow
  of save page, get page and share page.

Bug: 870895
Change-Id: Iab5f074dfa955ba30f8b125a70cedb87e8610246
Reviewed-on: https://chromium-review.googlesource.com/1162827Reviewed-by: default avatarPeter Williamson <petewil@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Commit-Queue: Yafei Duan <romax@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582418}
parent 51acd922
// Copyright 2018 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.offlinepages;
import android.app.Activity;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.share.ShareParams;
import org.chromium.chrome.browser.tab.Tab;
import java.util.List;
/**
* This callback will take the items in the Live Page Sharing namespace and check if there is a page
* matching the url of the given tab. If there is such page, share the page; otherwise save the page
* and share.
*/
public class GetPagesByNamespaceForLivePageSharingCallback
implements Callback<List<OfflinePageItem>> {
private Activity mActivity;
private Tab mTab;
private Callback<ShareParams> mShareCallback;
private OfflinePageBridge mBridge;
public GetPagesByNamespaceForLivePageSharingCallback(Activity activity, Tab tab,
final Callback<ShareParams> shareCallback, OfflinePageBridge bridge) {
mActivity = activity;
mTab = tab;
mShareCallback = shareCallback;
mBridge = bridge;
}
@Override
public void onResult(List<OfflinePageItem> items) {
// If there is already a page in the Live Page Sharing namespace and matches the url, share
// it directly.
for (OfflinePageItem item : items) {
if (item.getUrl().equals(mTab.getUrl())) {
OfflinePageUtils.sharePublishedPage(item, mActivity, mShareCallback);
return;
}
}
// Otherwise, save the page within Live Page Sharing namespace and share it using content
// URI.
mBridge.savePage(mTab.getWebContents(),
new ClientId(OfflinePageBridge.LIVE_PAGE_SHARING_NAMESPACE,
Integer.toString(mTab.getId())),
new SavePageAndShareCallback(mActivity, mShareCallback, mBridge));
}
}
\ No newline at end of file
......@@ -44,6 +44,7 @@ public class OfflinePageBridge {
public static final String NTP_SUGGESTIONS_NAMESPACE = "ntp_suggestions";
public static final String SUGGESTED_ARTICLES_NAMESPACE = "suggested_articles";
public static final String BROWSER_ACTIONS_NAMESPACE = "browser_actions";
public static final String LIVE_PAGE_SHARING_NAMESPACE = "live_page_sharing";
/**
* Retrieves the OfflinePageBridge for the given profile, creating it the first time
......
......@@ -21,6 +21,7 @@ import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.FileProviderHelper;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.profiles.Profile;
......@@ -373,6 +374,37 @@ public class OfflinePageUtils {
result, SavePageResult.RESULT_COUNT);
}
/**
* Save the page loaded in current tab and share the saved page.
*
* @param activity The activity used for sharing and file provider interaction.
* @param currentTab The current tab from which the page is being shared.
* @param shareCallback The callback to be used to send the ShareParams. This will only be
* called if this function call returns true.
* @return true if the sharing of the page is possible. The callback will be invoked if
* saving the page succeeds.
*/
public static boolean saveAndSharePage(
final Activity activity, Tab tab, final Callback<ShareParams> shareCallback) {
OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile());
if (offlinePageBridge == null) {
Log.e(TAG, "Unable to share current tab as an offline page.");
return false;
}
WebContents webContents = tab.getWebContents();
if (webContents == null) return false;
GetPagesByNamespaceForLivePageSharingCallback callback =
new GetPagesByNamespaceForLivePageSharingCallback(
activity, tab, shareCallback, offlinePageBridge);
offlinePageBridge.getPagesByNamespace(
OfflinePageBridge.LIVE_PAGE_SHARING_NAMESPACE, callback);
return true;
}
/**
* If possible, creates the ShareParams needed to share the current offline page loaded in the
* provided tab as a MHTML file.
......@@ -386,8 +418,23 @@ public class OfflinePageUtils {
*/
public static boolean maybeShareOfflinePage(
final Activity activity, Tab tab, final Callback<ShareParams> shareCallback) {
if (!OfflinePageBridge.isPageSharingEnabled()) return false;
if (tab == null) return false;
boolean isOfflinePage = OfflinePageUtils.isOfflinePage(tab);
RecordHistogram.recordBooleanHistogram("OfflinePages.SharedPageWasOffline", isOfflinePage);
// If the current tab is not showing an offline page, try to see if we should do live page
// sharing.
if (!isOfflinePage) {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.OFFLINE_PAGES_LIVE_PAGE_SHARING)) {
return saveAndSharePage(activity, tab, shareCallback);
} else {
return false;
}
}
OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile());
if (offlinePageBridge == null) {
......@@ -459,8 +506,8 @@ public class OfflinePageUtils {
*/
public static boolean isOfflinePageShareable(
OfflinePageBridge offlinePageBridge, OfflinePageItem offlinePage, Uri uri) {
// Return false if there is no offline page or sharing is not enabled.
if (offlinePage == null || !OfflinePageBridge.isPageSharingEnabled()) return false;
// Return false if there is no offline page.
if (offlinePage == null) return false;
String offlinePath = offlinePage.getFilePath();
......
// Copyright 2018 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.offlinepages;
import android.app.Activity;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.share.ShareParams;
import org.chromium.components.offlinepages.SavePageResult;
/**
* This callback will save get the saved page during live page sharing and share the page if saving
* process succeeds.
*/
public class SavePageAndShareCallback implements OfflinePageBridge.SavePageCallback {
private Activity mActivity;
private Callback<ShareParams> mShareCallback;
private OfflinePageBridge mBridge;
public SavePageAndShareCallback(Activity activity, final Callback<ShareParams> shareCallback,
OfflinePageBridge bridge) {
mActivity = activity;
mShareCallback = shareCallback;
mBridge = bridge;
}
@Override
public void onSavePageDone(int savePageResult, String url, long offlineId) {
if (savePageResult != SavePageResult.SUCCESS) {
// If the page is not saved, skip the sharing part.
return;
}
mBridge.getPageByOfflineId(offlineId, new Callback<OfflinePageItem>() {
@Override
public void onResult(OfflinePageItem page) {
OfflinePageUtils.sharePublishedPage(page, mActivity, mShareCallback);
}
});
}
}
\ No newline at end of file
......@@ -143,12 +143,8 @@ public class ShareMenuActionHandler {
private void triggerShare(final Activity activity, final Tab currentTab,
final boolean shareDirectly, boolean isIncognito) {
boolean isOfflinePage = OfflinePageUtils.isOfflinePage(currentTab);
RecordHistogram.recordBooleanHistogram("OfflinePages.SharedPageWasOffline", isOfflinePage);
if (isOfflinePage
&& OfflinePageUtils.maybeShareOfflinePage(
activity, currentTab, (ShareParams p) -> mDelegate.share(p))) {
if (OfflinePageUtils.maybeShareOfflinePage(
activity, currentTab, (ShareParams p) -> mDelegate.share(p))) {
return;
}
......
......@@ -926,6 +926,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/offlinepages/CctOfflinePageModelObserver.java",
"java/src/org/chromium/chrome/browser/offlinepages/ClientId.java",
"java/src/org/chromium/chrome/browser/offlinepages/DeletedPageInfo.java",
"java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java",
"java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java",
"java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java",
"java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java",
......@@ -934,6 +935,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java",
"java/src/org/chromium/chrome/browser/offlinepages/OfflinePagesDownloadManagerBridge.java",
"java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java",
"java/src/org/chromium/chrome/browser/offlinepages/SavePageAndShareCallback.java",
"java/src/org/chromium/chrome/browser/offlinepages/SavePageRequest.java",
"java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java",
"java/src/org/chromium/chrome/browser/offlinepages/TriggerConditions.java",
......
......@@ -16,6 +16,7 @@ const char kDownloadNamespace[] = "download";
const char kNTPSuggestionsNamespace[] = "ntp_suggestions";
const char kSuggestedArticlesNamespace[] = "suggested_articles";
const char kBrowserActionsNamespace[] = "browser_actions";
const char kLivePageSharingNamespace[] = "live_page_sharing";
const char kDefaultNamespace[] = "default";
......
......@@ -24,6 +24,7 @@ extern const char kDownloadNamespace[];
extern const char kNTPSuggestionsNamespace[];
extern const char kSuggestedArticlesNamespace[];
extern const char kBrowserActionsNamespace[];
extern const char kLivePageSharingNamespace[];
// Enum of namespaces used by metric collection.
// See OfflinePagesNamespaceEnumeration in enums.xml for histogram usages.
......@@ -39,6 +40,7 @@ enum class OfflinePagesNamespaceEnumeration {
NTP_SUGGESTION = 6,
SUGGESTED_ARTICLES = 7,
BROWSER_ACTIONS = 8,
LIVE_PAGE_SHARING = 9,
// NOTE: always keep this entry at the end. Add new result types only
// immediately above this line. Make sure to update the corresponding
// histogram enum accordingly.
......
......@@ -82,6 +82,15 @@ ClientPolicyController::ClientPolicyController() {
.SetIsUserRequestedDownload(true)
.SetShouldAllowDownload(true)
.Build()));
policies_.insert(
std::make_pair(kLivePageSharingNamespace,
OfflinePageClientPolicyBuilder(kLivePageSharingNamespace,
LifetimeType::TEMPORARY,
kUnlimitedPages, 1)
.SetIsRemovedOnCacheReset(true)
.SetExpirePeriod(base::TimeDelta::FromHours(1))
.SetIsOnlyShownInOriginalTab(true)
.Build()));
// Fallback policy.
policies_.insert(std::make_pair(
......
......@@ -244,6 +244,20 @@ TEST_F(ClientPolicyControllerTest, CheckSuggestedArticlesDefined) {
ExpectDisabledWhenPrefetchDisabled(kSuggestedArticlesNamespace, true);
}
TEST_F(ClientPolicyControllerTest, CheckLivePageSharingDefined) {
OfflinePageClientPolicy policy =
controller()->GetPolicy(kLivePageSharingNamespace);
EXPECT_EQ(policy.name_space, kLivePageSharingNamespace);
EXPECT_TRUE(isTemporary(policy));
EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kLivePageSharingNamespace));
ExpectRemovedOnCacheReset(kLivePageSharingNamespace, true);
ExpectDownloadSupport(kLivePageSharingNamespace, false);
ExpectUserRequestedDownloadSupport(kLivePageSharingNamespace, false);
ExpectRecentTab(kLivePageSharingNamespace, false);
ExpectOnlyOriginalTab(kLivePageSharingNamespace, true);
ExpectDisabledWhenPrefetchDisabled(kLivePageSharingNamespace, false);
}
TEST_F(ClientPolicyControllerTest, GetNamespacesRemovedOnCacheReset) {
std::vector<std::string> all_namespaces = controller()->GetAllNamespaces();
const std::vector<std::string>& cache_reset_namespaces_list =
......
......@@ -41,6 +41,8 @@ OfflinePagesNamespaceEnumeration ToNamespaceEnum(
return OfflinePagesNamespaceEnumeration::SUGGESTED_ARTICLES;
else if (name_space == kBrowserActionsNamespace)
return OfflinePagesNamespaceEnumeration::BROWSER_ACTIONS;
else if (name_space == kLivePageSharingNamespace)
return OfflinePagesNamespaceEnumeration::LIVE_PAGE_SHARING;
NOTREACHED();
return OfflinePagesNamespaceEnumeration::DEFAULT;
......
......@@ -35187,6 +35187,9 @@ Called by update_net_trust_anchors.py.-->
<int value="8" label="Browser_actions">
Namespace used when offline page is saved from browser actions.
</int>
<int value="9" label="Live_page_sharing">
Namespace used when offline page is saved for live page sharing.
</int>
</enum>
<enum name="OfflinePagesOfflineUsage">
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