Commit e576f1de authored by Kyle Milka's avatar Kyle Milka Committed by Commit Bot

[SharingHub] Wire up QrCode to the sharing hub

Wire up QRCode sharing feature to the sharing hub.

Bug: 1009124
Change-Id: Ie3aa5723f90ec7ea54989e7ebe85dff1fc3dd42e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1888736
Commit-Queue: Kyle Milka <kmilka@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarGayane Petrosyan <gayane@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720739}
parent e333cbf6
......@@ -1462,7 +1462,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/share/ShareParams.java",
"java/src/org/chromium/chrome/browser/share/ShareSheetBottomSheetContent.java",
"java/src/org/chromium/chrome/browser/share/ShareSheetCoordinator.java",
"java/src/org/chromium/chrome/browser/share/ShareSheetMediator.java",
"java/src/org/chromium/chrome/browser/share/ShareSheetItemViewProperties.java",
"java/src/org/chromium/chrome/browser/sharing/SharingAdapter.java",
"java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java",
"java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java",
......
......@@ -428,8 +428,8 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/settings/website/WebsitePermissionsFetcherTest.java",
"javatests/src/org/chromium/chrome/browser/shape_detection/ShapeDetectionTest.java",
"javatests/src/org/chromium/chrome/browser/share/LensUtilsTest.java",
"javatests/src/org/chromium/chrome/browser/share/ShareSheetMediatorIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/share/ShareSheetMediatorTest.java",
"javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java",
"javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java",
"javatests/src/org/chromium/chrome/browser/signin/IdentityManagerIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java",
......
......@@ -14,11 +14,13 @@
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_touch_target_size"
android:orientation="horizontal"
android:id="@+id/share_sheet_chrome_apps" />
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_touch_target_size"
android:orientation="horizontal"
android:id="@+id/share_sheet_other_apps" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 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. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="vertical" >
<ImageView android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:padding="4dp"
android:scaleType="fitCenter"
tools:ignore="ContentDescription" />
<TextView android:id="@+id/text"
android:layout_width="88dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:maxLines="2"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
......@@ -145,7 +145,7 @@ def _CheckCompatibleAlertDialogBuilder(input_api, output_api):
BROWSER_ROOT + 'externalnav/ExternalNavigationDelegateImpl.java',
BROWSER_ROOT + 'payments/AndroidPaymentApp.java',
BROWSER_ROOT + 'permissions/AndroidPermissionRequester.java',
BROWSER_ROOT + 'share/ShareSheetMediator.java',
BROWSER_ROOT + 'share/ShareDelegateImpl.java',
BROWSER_ROOT + 'util/AccessibilityUtil.java',
BROWSER_ROOT + 'webapps/AddToHomescreenDialog.java',
BROWSER_ROOT + 'webapps/WebappOfflineDialog.java',
......
......@@ -434,7 +434,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
this, getStatusBarColorController().getStatusBarScrimDelegate(), coordinator);
initializeBottomSheetController();
mShareDelegate = new ShareDelegateImpl(mBottomSheetController);
mShareDelegate = new ShareDelegateImpl(
mBottomSheetController, new ShareDelegateImpl.ShareSheetDelegate());
mShareDelegateSupplier.set(mShareDelegate);
Intent intent = getIntent();
......
......@@ -4,50 +4,83 @@
package org.chromium.chrome.browser.share;
import android.app.Activity;
import android.content.Context;
import android.support.v7.content.res.AppCompatResources;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.share.qrcode.QrCodeCoordinator;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;
/**
* Coordinator for displaying the share sheet.
*/
public class ShareSheetCoordinator {
private ShareSheetMediator mMediator;
private static final int SHARE_SHEET_ITEM = 0;
private final BottomSheetController mBottomSheetController;
/**
* Constructs a new ShareSheetCoordinator.
*/
public ShareSheetCoordinator(BottomSheetController controller) {
mMediator = new ShareSheetMediator(new ShareSheetMediator.ShareSheetDelegate(), controller);
mBottomSheetController = controller;
}
/**
* Triggered when the share menu item is selected.
* This creates and shows a share intent picker dialog or starts a share intent directly.
* @param activity The activity that triggered this share action.
* @param tab The tab containing the content to be shared.
* @param shareDirectly Whether it should share directly with the activity that was most
* recently used to share.
* @param isIncognito Whether currentTab is incognito.
*/
public void onShareSelected(
Activity activity, Tab currentTab, boolean shareDirectly, boolean isIncognito) {
mMediator.onShareSelected(activity, currentTab, shareDirectly, isIncognito);
}
protected void showShareSheet(ShareParams params) {
Context context = params.getWindow().getContext().get();
ShareSheetBottomSheetContent bottomSheet = new ShareSheetBottomSheetContent(context);
// QR Codes
PropertyModel qrcodePropertyModel =
new PropertyModel.Builder(ShareSheetItemViewProperties.ALL_KEYS)
.with(ShareSheetItemViewProperties.ICON,
AppCompatResources.getDrawable(context, R.drawable.ic_launcher))
.with(ShareSheetItemViewProperties.LABEL,
context.getResources().getString(R.string.qr_code_share_icon_label))
.with(ShareSheetItemViewProperties.CLICK_LISTENER,
(currentContext) -> {
QrCodeCoordinator qrCodeCoordinator =
new QrCodeCoordinator(context);
qrCodeCoordinator.show();
})
.build();
ModelList modelList = new ModelList();
modelList.add(new ListItem(SHARE_SHEET_ITEM, qrcodePropertyModel));
SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(modelList);
RecyclerView rcView =
bottomSheet.getContentView().findViewById(R.id.share_sheet_chrome_apps);
adapter.registerType(SHARE_SHEET_ITEM, () -> {
return (ViewGroup) LayoutInflater.from(context).inflate(
R.layout.share_sheet_item, (ViewGroup) rcView, false);
}, ShareSheetCoordinator::bindShareItem);
LinearLayoutManager layoutManager =
new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
rcView.setLayoutManager(layoutManager);
rcView.setAdapter(adapter);
/**
* Triggers a share based on the provided {@link ShareParams}.
* @param params The container holding the share parameters.
*/
public void share(ShareParams params) {
mMediator.share(params);
mBottomSheetController.requestShowContent(bottomSheet, true);
}
@VisibleForTesting
public static void setScreenshotCaptureSkippedForTesting(boolean value) {
ShareSheetMediator.setScreenshotCaptureSkippedForTesting(value);
private static void bindShareItem(
PropertyModel model, ViewGroup parent, PropertyKey propertyKey) {
if (ShareSheetItemViewProperties.ICON.equals(propertyKey)) {
ImageView view = (ImageView) parent.findViewById(R.id.icon);
view.setImageDrawable(model.get(ShareSheetItemViewProperties.ICON));
} else if (ShareSheetItemViewProperties.LABEL.equals(propertyKey)) {
TextView view = (TextView) parent.findViewById(R.id.text);
view.setText(model.get(ShareSheetItemViewProperties.LABEL));
} else if (ShareSheetItemViewProperties.CLICK_LISTENER.equals(propertyKey)) {
parent.setOnClickListener(model.get(ShareSheetItemViewProperties.CLICK_LISTENER));
}
}
}
// Copyright 2019 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.share;
import android.graphics.drawable.Drawable;
import android.view.View.OnClickListener;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
/**
* The properties associated with rendering an item in the share sheet.
*/
final class ShareSheetItemViewProperties {
public static final WritableObjectPropertyKey<Drawable> ICON =
new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<String> LABEL = new WritableObjectPropertyKey();
public static final WritableObjectPropertyKey<OnClickListener> CLICK_LISTENER =
new WritableObjectPropertyKey<>();
public static final PropertyKey[] ALL_KEYS = {ICON, LABEL, CLICK_LISTENER};
}
......@@ -25,8 +25,8 @@ import org.chromium.base.task.TaskTraits;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.browser.share.ShareDelegate;
import org.chromium.chrome.browser.share.ShareDelegateImpl;
import org.chromium.chrome.browser.share.ShareHelper;
import org.chromium.chrome.browser.share.ShareSheetCoordinator;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.ui.RootUiCoordinator;
import org.chromium.chrome.browser.util.ChromeFileProvider;
......@@ -169,7 +169,7 @@ public class ShareIntentTest {
ShareHelper.setLastShareComponentName(
new ComponentName("test.package", "test.activity"), null);
// Skips the capture of screenshot and notifies with an empty file.
ShareSheetCoordinator.setScreenshotCaptureSkippedForTesting(true);
ShareDelegateImpl.setScreenshotCaptureSkippedForTesting(true);
WindowAndroid window = TestThreadUtils.runOnUiThreadBlocking(() -> {
return new WindowAndroid(mActivityTestRule.getActivity()) {
......@@ -199,6 +199,6 @@ public class ShareIntentTest {
@After
public void tearDown() {
ShareSheetCoordinator.setScreenshotCaptureSkippedForTesting(false);
ShareDelegateImpl.setScreenshotCaptureSkippedForTesting(false);
}
}
......@@ -18,7 +18,7 @@ import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.share.ShareSheetMediator.ShareSheetDelegate;
import org.chromium.chrome.browser.share.ShareDelegateImpl.ShareSheetDelegate;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
......@@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicReference;
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class ShareSheetMediatorIntegrationTest {
public class ShareDelegateImplIntegrationTest {
private static final String PAGE_WITH_HTTPS_CANONICAL_URL =
"/chrome/test/data/android/share/link_share_https_canonical.html";
private static final String PAGE_WITH_HTTP_CANONICAL_URL =
......@@ -100,7 +100,7 @@ public class ShareSheetMediatorIntegrationTest {
throws IllegalArgumentException, TimeoutException {
mActivityTestRule.loadUrl(pageUrl);
HistogramDelta urlResultDelta = new HistogramDelta(
ShareSheetMediator.CANONICAL_URL_RESULT_HISTOGRAM, expectedUrlResult);
ShareDelegateImpl.CANONICAL_URL_RESULT_HISTOGRAM, expectedUrlResult);
ShareParams params = triggerShare();
Assert.assertEquals(expectedShareUrl, params.getUrl());
Assert.assertEquals(1, urlResultDelta.getDelta());
......@@ -118,10 +118,9 @@ public class ShareSheetMediatorIntegrationTest {
}
};
new ShareSheetMediator(
delegate, mActivityTestRule.getActivity().getBottomSheetController())
.onShareSelected(mActivityTestRule.getActivity(),
mActivityTestRule.getActivity().getActivityTab(), false, false);
new ShareDelegateImpl(
mActivityTestRule.getActivity().getBottomSheetController(), delegate)
.share(mActivityTestRule.getActivity().getActivityTab(), false);
});
helper.waitForCallback(0);
return paramsRef.get();
......
......@@ -23,10 +23,10 @@ import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.concurrent.ExecutionException;
/**
* Tests (requiring native) of the ShareSheetMediator.
* Tests (requiring native) of the ShareDelegateImpl.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class ShareSheetMediatorTest {
public class ShareDelegateImplTest {
@Rule
public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
......@@ -43,37 +43,37 @@ public class ShareSheetMediatorTest {
mSadTabRule.setTab(mockTab);
// Null webContents:
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
// Null render frame:
mockTab.webContents = mockWebContents;
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
// Invalid/empty URL:
mockWebContents.renderFrameHost = mockRenderFrameHost;
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
// Disabled if showing error page.
mockTab.isShowingErrorPage = true;
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
mockTab.isShowingErrorPage = false;
// Disabled if showing interstitial page.
mockTab.isShowingInterstitialPage = true;
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
mockTab.isShowingInterstitialPage = false;
// Disabled if showing sad tab page.
mSadTabRule.show(true);
Assert.assertFalse(ShareSheetMediator.shouldFetchCanonicalUrl(mockTab));
Assert.assertFalse(ShareDelegateImpl.shouldFetchCanonicalUrl(mockTab));
mSadTabRule.show(false);
}
@Test
@SmallTest
public void testGetUrlToShare() {
Assert.assertNull(ShareSheetMediator.getUrlToShare(null, null));
Assert.assertEquals("", ShareSheetMediator.getUrlToShare("", null));
Assert.assertNull(ShareDelegateImpl.getUrlToShare(null, null));
Assert.assertEquals("", ShareDelegateImpl.getUrlToShare("", null));
final String httpUrl = "http://blah.com";
final String otherHttpUrl = "http://eek.com";
......@@ -83,21 +83,21 @@ public class ShareSheetMediatorTest {
final String contentUrl = "content://eek.com";
// HTTP Display URL, HTTP Canonical URL -> HTTP Display URL
Assert.assertEquals(httpUrl, ShareSheetMediator.getUrlToShare(httpUrl, otherHttpUrl));
Assert.assertEquals(httpUrl, ShareDelegateImpl.getUrlToShare(httpUrl, otherHttpUrl));
// HTTP Display URL, HTTPS Canonical URL -> HTTP Display URL
Assert.assertEquals(httpUrl, ShareSheetMediator.getUrlToShare(httpUrl, httpsUrl));
Assert.assertEquals(httpUrl, ShareDelegateImpl.getUrlToShare(httpUrl, httpsUrl));
// HTTPS Display URL, HTTP Canonical URL -> HTTP Canonical URL
Assert.assertEquals(httpUrl, ShareSheetMediator.getUrlToShare(httpsUrl, httpUrl));
Assert.assertEquals(httpUrl, ShareDelegateImpl.getUrlToShare(httpsUrl, httpUrl));
// HTTPS Display URL, HTTPS Canonical URL -> HTTPS Canonical URL
Assert.assertEquals(httpsUrl, ShareSheetMediator.getUrlToShare(httpsUrl, httpsUrl));
Assert.assertEquals(httpsUrl, ShareDelegateImpl.getUrlToShare(httpsUrl, httpsUrl));
Assert.assertEquals(
otherHttpsUrl, ShareSheetMediator.getUrlToShare(httpsUrl, otherHttpsUrl));
otherHttpsUrl, ShareDelegateImpl.getUrlToShare(httpsUrl, otherHttpsUrl));
// HTTPS Display URL, FTP URL -> HTTPS Display URL
Assert.assertEquals(httpsUrl, ShareSheetMediator.getUrlToShare(httpsUrl, ftpUrl));
Assert.assertEquals(httpsUrl, ShareDelegateImpl.getUrlToShare(httpsUrl, ftpUrl));
// HTTPS Display URL, Content URL -> HTTPS Display URL
Assert.assertEquals(httpsUrl, ShareSheetMediator.getUrlToShare(httpsUrl, contentUrl));
Assert.assertEquals(httpsUrl, ShareDelegateImpl.getUrlToShare(httpsUrl, contentUrl));
}
private static class MockUrlTab extends MockTab {
......
......@@ -15,7 +15,7 @@ import org.chromium.chrome.browser.share.qrcode.share_tab.QrCodeShareCoordinator
public class QrCodeCoordinator {
QrCodeDialog mDialog;
QrCodeCoordinator(Context context) {
public QrCodeCoordinator(Context context) {
QrCodeShareCoordinator shareCoordinator = new QrCodeShareCoordinator(context);
QrCodeScanCoordinator scanCoordinator = new QrCodeScanCoordinator(context);
......
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