Commit 197d5cea authored by Tanya Gupta's avatar Tanya Gupta Committed by Commit Bot

[SendTabToSelf] Added icons and tap functionality to device picker.

This CL does a few things:
* Adds the icon for each device type.
* Adds ability to send a tab after the user selects a device.
* Enables the bottom controller when the feature is enabled.
* Adds the last active time to the device picker.
* Formatting of the device picker list.

Bug: 949223
Change-Id: Ic2d691a68f0fb7e55a375ee932b07633e5c644e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1633330Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Reviewed-by: default avatarsebsg <sebsg@chromium.org>
Commit-Queue: Tanya Gupta <tgupta@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664573}
parent a3897181
<?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. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="21"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="@color/default_icon_color"
android:pathData="M20 18c1.1 0 1.99-0.9 1.99-2L22 6c0-1.1-0.9-2-2-2H4c-1.1 0-2 0.9-2 2v10c0 1.1 0.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z" />
</vector>
\ No newline at end of file
<?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. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="21"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="@color/default_icon_color"
android:pathData="M4 6h18V4H4c-1.1 0-2 0.9-2 2v11H0v3h14v-3H4V6zm19 2h-6c-0.55 0-1 0.45-1 1v10c0 0.55 0.45 1 1 1h6c0.55 0 1-0.45 1-1V9c0-0.55-0.45-1-1-1zm-1 9h-4v-7h4v7z" />
</vector>
\ No newline at end of file
<?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. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="21"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="@color/default_icon_color"
android:pathData="M17 1.01L7 1c-1.1 0-2 0.9-2 2v18c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99zM17 19H7V5h10v14z" />
</vector>
\ No newline at end of file
...@@ -7,26 +7,43 @@ ...@@ -7,26 +7,43 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:minHeight="56dp" android:minHeight="70dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="10dp" android:paddingStart="10dp"
android:paddingEnd="10dp"> android:paddingEnd="10dp">
<org.chromium.ui.widget.ChromeImageView <org.chromium.ui.widget.ChromeImageView
android:id="@+id/device_icon" android:id="@+id/device_icon"
android:layout_width="30dp" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_weight="0.25"
android:layout_gravity="start" android:layout_gravity="start"
android:gravity="center_vertical"/> android:paddingTop="20dp"
<TextView android:gravity="center"
android:id="@+id/device_name" android:background="@android:color/transparent" />
android:layout_width="100dp" <LinearLayout
android:layout_height="0dp" android:layout_width="match_parent"
android:layout_weight="0.75" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="30dp" android:orientation="vertical"
android:paddingEnd="2dp" android:paddingStart="20dp"
android:maxLines="2" android:paddingEnd="10dp">
android:ellipsize="end"/> <TextView
android:id="@+id/device_name"
android:layout_width="match_parent"
android:layout_height="24dp"
android:gravity="center_vertical"
android:paddingEnd="2dp"
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.BlackTitle1" />
<TextView
android:id="@+id/last_active"
android:layout_width="match_parent"
android:layout_height="24dp"
android:gravity="center_vertical"
android:paddingEnd="2dp"
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.BlackBody" />
</LinearLayout>
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -7,14 +7,17 @@ ...@@ -7,14 +7,17 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:minHeight="56dp" android:minHeight="@dimen/min_touch_target_size"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="19dp" android:paddingStart="19dp"
android:paddingEnd="24dp"> android:paddingEnd="24dp">
<ListView <ListView
android:id="@+id/device_picker_list" android:id="@+id/device_picker_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1"
android:paddingTop="@dimen/min_touch_target_size"
android:divider="@null"
android:dividerHeight="0dp" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -13,11 +13,12 @@ ...@@ -13,11 +13,12 @@
<TextView <TextView
android:id="@+id/device_picker_toolbar" android:id="@+id/device_picker_toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="@dimen/min_touch_target_size"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="30dp" android:paddingStart="30dp"
android:paddingEnd="10dp" android:paddingEnd="30dp"
android:paddingTop="8dp" android:paddingTop="16dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"
android:ellipsize="end"/> android:ellipsize="end"
android:textAppearance="@style/TextAppearance.BlackHint1" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -112,6 +112,7 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceManager; ...@@ -112,6 +112,7 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.search_engines.SearchEngineChoiceNotification; import org.chromium.chrome.browser.search_engines.SearchEngineChoiceNotification;
import org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfAndroidBridge;
import org.chromium.chrome.browser.signin.SigninPromoUtil; import org.chromium.chrome.browser.signin.SigninPromoUtil;
import org.chromium.chrome.browser.snackbar.undo.UndoBarController; import org.chromium.chrome.browser.snackbar.undo.UndoBarController;
import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge; import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge;
...@@ -745,7 +746,7 @@ public class ChromeTabbedActivity ...@@ -745,7 +746,7 @@ public class ChromeTabbedActivity
}; };
OnClickListener bookmarkClickHandler = v -> addOrEditBookmark(getActivityTab()); OnClickListener bookmarkClickHandler = v -> addOrEditBookmark(getActivityTab());
if (shouldInitializeBottomSheet() && FeatureUtilities.isTabGroupsAndroidEnabled()) { if (shouldInitializeBottomSheet()) {
initializeBottomSheet(false); initializeBottomSheet(false);
} }
...@@ -2519,7 +2520,8 @@ public class ChromeTabbedActivity ...@@ -2519,7 +2520,8 @@ public class ChromeTabbedActivity
@Override @Override
protected boolean shouldInitializeBottomSheet() { protected boolean shouldInitializeBottomSheet() {
return FeatureUtilities.isTabGroupsAndroidEnabled(); return FeatureUtilities.isTabGroupsAndroidEnabled()
|| SendTabToSelfAndroidBridge.isSendingEnabled();
} }
@Override @Override
......
...@@ -5,35 +5,45 @@ ...@@ -5,35 +5,45 @@
package org.chromium.chrome.browser.send_tab_to_self; package org.chromium.chrome.browser.send_tab_to_self;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v7.content.res.AppCompatResources;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.TextView;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.ui.widget.ChromeImageView; import org.chromium.ui.widget.ChromeImageView;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
/** /**
* Adapter to populate the Target Device Picker sheet. * Adapter to populate the Target Device Picker sheet.
*/ */
public class DevicePickerBottomSheetAdapter extends BaseAdapter { public class DevicePickerBottomSheetAdapter extends BaseAdapter {
private final LayoutInflater mInflator; private final LayoutInflater mInflator;
private final Context mContext; private final Context mContext;
private final List<TargetDeviceInfo> mTargetDevices;
public DevicePickerBottomSheetAdapter() { public DevicePickerBottomSheetAdapter(Profile profile) {
mContext = ContextUtils.getApplicationContext(); mContext = ContextUtils.getApplicationContext();
mInflator = LayoutInflater.from(mContext); mInflator = LayoutInflater.from(mContext);
mTargetDevices = SendTabToSelfAndroidBridge.getAllTargetDeviceInfos(profile);
} }
@Override @Override
public int getCount() { public int getCount() {
return 0; return mTargetDevices.size();
} }
@Override @Override
public Object getItem(int position) { public TargetDeviceInfo getItem(int position) {
return null; return mTargetDevices.get(position);
} }
@Override @Override
...@@ -47,17 +57,48 @@ public class DevicePickerBottomSheetAdapter extends BaseAdapter { ...@@ -47,17 +57,48 @@ public class DevicePickerBottomSheetAdapter extends BaseAdapter {
convertView = convertView =
mInflator.inflate(R.layout.send_tab_to_self_device_picker_item, parent, false); mInflator.inflate(R.layout.send_tab_to_self_device_picker_item, parent, false);
TargetDeviceInfo deviceInfo = getItem(position);
ChromeImageView deviceIcon = convertView.findViewById(R.id.device_icon); ChromeImageView deviceIcon = convertView.findViewById(R.id.device_icon);
/// TODO(crbug.com/949223): Populate with the right icon here. deviceIcon.setImageDrawable(getDrawableForDeviceType(deviceInfo));
// deviceIcon.setImageDrawable(
// AppCompatResources.getDrawable(mContext, R.drawable.ic_check_googblue_24dp));
deviceIcon.setVisibility(View.VISIBLE); deviceIcon.setVisibility(View.VISIBLE);
// TODO(crbug.com/949223): Populate the device name here. TextView deviceName = convertView.findViewById(R.id.device_name);
// TextView deviceName = convertView.findViewById(R.id.device_name); deviceName.setText(deviceInfo.deviceName);
// deviceName.setText(getItem(position));
// TODO(crbug.com/949223): Add logic to handle click action TextView lastActive = convertView.findViewById(R.id.last_active);
long numDaysDeviceActive = TimeUnit.MILLISECONDS.toDays(
Calendar.getInstance().getTimeInMillis() - deviceInfo.lastUpdatedTimestamp);
lastActive.setText(getLastActiveMessage(numDaysDeviceActive));
} }
return convertView; return convertView;
} }
private String getLastActiveMessage(long numDays) {
if (numDays < 1) {
return mContext.getResources().getString(
R.string.send_tab_to_self_device_last_active_today);
} else if (numDays == 1) {
return mContext.getResources().getString(
R.string.send_tab_to_self_device_last_active_one_day_ago);
} else {
return mContext.getResources().getString(
R.string.send_tab_to_self_device_last_active_more_than_one_day, numDays);
}
}
private Drawable getDrawableForDeviceType(TargetDeviceInfo targetDevice) {
switch (targetDevice.deviceType) {
case TargetDeviceInfo.DeviceType.CHROMEOS:
case TargetDeviceInfo.DeviceType.LINUX:
case TargetDeviceInfo.DeviceType.MACOSX:
case TargetDeviceInfo.DeviceType.WIN: {
return AppCompatResources.getDrawable(mContext, R.drawable.computer_black_24dp);
}
case TargetDeviceInfo.DeviceType.PHONE: {
return AppCompatResources.getDrawable(mContext, R.drawable.smartphone_black_24dp);
}
}
return AppCompatResources.getDrawable(mContext, R.drawable.devices_black_24dp);
}
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.send_tab_to_self; package org.chromium.chrome.browser.send_tab_to_self;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
...@@ -15,8 +16,11 @@ import android.widget.TextView; ...@@ -15,8 +16,11 @@ import android.widget.TextView;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.ui.widget.Toast;
/** /**
* Bottom sheet content to display a list of devices a user can send a tab to after they have * Bottom sheet content to display a list of devices a user can send a tab to after they have
...@@ -28,13 +32,18 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte ...@@ -28,13 +32,18 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte
ViewGroup mToolbarView; ViewGroup mToolbarView;
ViewGroup mContentView; ViewGroup mContentView;
DevicePickerBottomSheetAdapter mAdapter; DevicePickerBottomSheetAdapter mAdapter;
NavigationEntry mEntry;
public DevicePickerBottomSheetContent(Context context, ChromeActivity activity) { public DevicePickerBottomSheetContent(
Context context, ChromeActivity activity, NavigationEntry entry) {
mContext = context; mContext = context;
mActivity = activity; mActivity = activity;
mAdapter = new DevicePickerBottomSheetAdapter(); mAdapter = new DevicePickerBottomSheetAdapter(
activity.getActivityTabProvider().get().getProfile());
mEntry = entry;
createToolbarView(); createToolbarView();
createContentView();
} }
private void createToolbarView() { private void createToolbarView() {
...@@ -49,10 +58,6 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte ...@@ -49,10 +58,6 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte
R.layout.send_tab_to_self_device_picker_list, null); R.layout.send_tab_to_self_device_picker_list, null);
ListView listView = mContentView.findViewById(R.id.device_picker_list); ListView listView = mContentView.findViewById(R.id.device_picker_list);
// Set the padding so that the toolbar is aligned with the list.
// TODO(tgupta): Figure out whether this can be incorporated directly in the definition of
// the list view rather than set programatically.
// listView.setPadding(0, convertDpToPx(80), 0, 0);
listView.setAdapter(mAdapter); listView.setAdapter(mAdapter);
listView.setOnItemClickListener(this); listView.setOnItemClickListener(this);
} }
...@@ -62,11 +67,6 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte ...@@ -62,11 +67,6 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte
return mContentView; return mContentView;
} }
private int convertDpToPx(int inDp) {
float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (inDp * scale + 0.5f);
}
@Override @Override
public View getToolbarView() { public View getToolbarView() {
return mToolbarView; return mToolbarView;
...@@ -85,6 +85,13 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte ...@@ -85,6 +85,13 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte
return BottomSheet.ContentPriority.HIGH; return BottomSheet.ContentPriority.HIGH;
} }
@Override
public boolean wrapContentEnabled() {
// Return true to have the bottom sheet only open as far as it needs to display the
// list of devices and nothing beyond that.
return true;
}
@Override @Override
public boolean swipeToDismissEnabled() { public boolean swipeToDismissEnabled() {
// This ensures that the bottom sheet reappears after the first time. Otherwise, the // This ensures that the bottom sheet reappears after the first time. Otherwise, the
...@@ -120,6 +127,17 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte ...@@ -120,6 +127,17 @@ public class DevicePickerBottomSheetContent implements BottomSheetContent, OnIte
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO(crbug.com/949223): Add logic to support tapping on a device. TargetDeviceInfo targetDeviceInfo = mAdapter.getItem(position);
Tab tab = mActivity.getActivityTabProvider().get();
SendTabToSelfAndroidBridge.addEntry(tab.getProfile(), mEntry.getUrl(), mEntry.getTitle(),
mEntry.getTimestamp(), targetDeviceInfo.cacheGuid);
Resources res = mContext.getResources();
String toastMessage =
res.getString(R.string.send_tab_to_self_toast, targetDeviceInfo.deviceName);
Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show();
mActivity.getBottomSheetController().hideContent(this, true);
} }
} }
...@@ -128,6 +128,16 @@ public class SendTabToSelfAndroidBridge { ...@@ -128,6 +128,16 @@ public class SendTabToSelfAndroidBridge {
return SendTabToSelfAndroidBridgeJni.get().isFeatureAvailable(webContents); return SendTabToSelfAndroidBridgeJni.get().isFeatureAvailable(webContents);
} }
/**
* Return whether the sending component of the feature is available. One of the uses of this
* function is to determine whether the bottom sheet should be initialized on startup.
*
* @return Whether the sending component is available.
*/
public static boolean isSendingEnabled() {
return SendTabToSelfAndroidBridgeJni.get().isSendingEnabled();
}
/** /**
* Shows an infobar for the webcontents passed in. * Shows an infobar for the webcontents passed in.
* *
...@@ -182,6 +192,8 @@ public class SendTabToSelfAndroidBridge { ...@@ -182,6 +192,8 @@ public class SendTabToSelfAndroidBridge {
boolean isFeatureAvailable(WebContents webContents); boolean isFeatureAvailable(WebContents webContents);
boolean isSendingEnabled();
void showInfoBar( void showInfoBar(
WebContents webContents, String guid, String url, String targetDeviceSyncCacheGuid); WebContents webContents, String guid, String url, String targetDeviceSyncCacheGuid);
......
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
package org.chromium.chrome.browser.send_tab_to_self; package org.chromium.chrome.browser.send_tab_to_self;
import org.chromium.chrome.R; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.share.ShareActivity; import org.chromium.chrome.browser.share.ShareActivity;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.ui.widget.Toast;
/** /**
* A simple activity that allows Chrome to expose send tab to self as an option in the share menu. * A simple activity that allows Chrome to expose send tab to self as an option in the share menu.
...@@ -21,15 +21,20 @@ public class SendTabToSelfShareActivity extends ShareActivity { ...@@ -21,15 +21,20 @@ public class SendTabToSelfShareActivity extends ShareActivity {
if (tab == null) return; if (tab == null) return;
NavigationEntry entry = tab.getWebContents().getNavigationController().getVisibleEntry(); NavigationEntry entry = tab.getWebContents().getNavigationController().getVisibleEntry();
if (entry == null) return; if (entry == null || triggeringActivity.getBottomSheetController() == null) {
return;
}
// TODO(crbug/946808) Add actual target device cache GUID. triggeringActivity.getBottomSheetController().requestShowContent(
String targetDeviceSyncCacheGuid = ""; createBottomSheetContent(triggeringActivity, entry), true);
SendTabToSelfAndroidBridge.addEntry(tab.getProfile(), entry.getUrl(), entry.getTitle(), // TODO(crbug.com/968246): Remove the need to call this explicitly and instead have it
entry.getTimestamp(), targetDeviceSyncCacheGuid); // automatically show since PeekStateEnabled is set to false.
triggeringActivity.getBottomSheetController().expandSheet();
}
Toast.makeText(triggeringActivity, R.string.send_tab_to_self_toast, Toast.LENGTH_SHORT) @VisibleForTesting
.show(); BottomSheetContent createBottomSheetContent(ChromeActivity activity, NavigationEntry entry) {
return new DevicePickerBottomSheetContent(getApplicationContext(), activity, entry);
} }
public static boolean featureIsAvailable(Tab currentTab) { public static boolean featureIsAvailable(Tab currentTab) {
......
...@@ -3942,8 +3942,8 @@ The site does NOT gain access to the camera. The camera images are only visible ...@@ -3942,8 +3942,8 @@ The site does NOT gain access to the camera. The camera images are only visible
</message> </message>
<!-- SendTabToSelf --> <!-- SendTabToSelf -->
<message name="IDS_SEND_TAB_TO_SELF_TOAST" desc="Text for a toast indicating that the tab was shared successfully on the user's other synced devices."> <message name="IDS_SEND_TAB_TO_SELF_TOAST" desc="Text for a toast indicating that the tab is being shared on the user's other synced devices.">
Tab sent to your devices Sending to <ph name="device_name">%1$s<ex>Tanya's Pixel 2</ex></ph>...
</message> </message>
<message name="IDS_SEND_TAB_TO_SELF_NOTIFICATION_CONTEXT_TEXT" desc="Text displayed as the second line of a notification indicating the domain and the device the tab is shared from."> <message name="IDS_SEND_TAB_TO_SELF_NOTIFICATION_CONTEXT_TEXT" desc="Text displayed as the second line of a notification indicating the domain and the device the tab is shared from.">
<ph name="DOMAIN">%1$s<ex>www.google.com</ex></ph> - Sent from <ph name="DEVICE_NAME">%2$s<ex>Tanya's Pixel 2XL</ex></ph> <ph name="DOMAIN">%1$s<ex>www.google.com</ex></ph> - Sent from <ph name="DEVICE_NAME">%2$s<ex>Tanya's Pixel 2XL</ex></ph>
...@@ -3969,6 +3969,15 @@ The site does NOT gain access to the camera. The camera images are only visible ...@@ -3969,6 +3969,15 @@ The site does NOT gain access to the camera. The camera images are only visible
<message name="IDS_SEND_TAB_TO_SELF_SHEET_TOOLBAR" desc="Header for device picker sheet where users can pick a device to send a tab to."> <message name="IDS_SEND_TAB_TO_SELF_SHEET_TOOLBAR" desc="Header for device picker sheet where users can pick a device to send a tab to.">
Send to Send to
</message> </message>
<message name="IDS_SEND_TAB_TO_SELF_DEVICE_LAST_ACTIVE_MORE_THAN_ONE_DAY" desc="String displayed in the device picker indicating the last time the device was synced to the user's account.">
Active <ph name="last_updated">%1$d<ex>5</ex></ph> days ago
</message>
<message name="IDS_SEND_TAB_TO_SELF_DEVICE_LAST_ACTIVE_ONE_DAY_AGO" desc="String displayed in the device picker indicating the last time the device was synced to the user's account one day ago.">
Active 1 day ago
</message>
<message name="IDS_SEND_TAB_TO_SELF_DEVICE_LAST_ACTIVE_TODAY" desc="String displayed in the device picker indicating the last time the device was synced to the user's account today.">
Active today
</message>
<!-- Chrome Duet --> <!-- Chrome Duet -->
<message name="IDS_IPH_DUET_TITLE" desc="This string appears in an overlay that explains a new UI to users. 'Search' refers to searching the web, and 'explore' refers to Chrome's suggested content."> <message name="IDS_IPH_DUET_TITLE" desc="This string appears in an overlay that explains a new UI to users. 'Search' refers to searching the web, and 'explore' refers to Chrome's suggested content.">
......
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
package org.chromium.chrome.browser.send_tab_to_self; package org.chromium.chrome.browser.send_tab_to_self;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import org.junit.Assert; import org.junit.Assert;
...@@ -27,11 +26,13 @@ import org.chromium.chrome.browser.ActivityTabProvider; ...@@ -27,11 +26,13 @@ import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** Tests for SendTabToSelfAndroidBridge */ /** Tests for SendTabToSelfShareActivityTest */
@RunWith(BaseRobolectricTestRunner.class) @RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
public class SendTabToSelfShareActivityTest { public class SendTabToSelfShareActivityTest {
...@@ -47,21 +48,25 @@ public class SendTabToSelfShareActivityTest { ...@@ -47,21 +48,25 @@ public class SendTabToSelfShareActivityTest {
@Mock @Mock
private ActivityTabProvider mActivityTabProvider; private ActivityTabProvider mActivityTabProvider;
@Mock @Mock
private Resources mResources;
@Mock
private WebContents mWebContents; private WebContents mWebContents;
@Mock @Mock
private NavigationController mNavigationController; private NavigationController mNavigationController;
@Mock @Mock
private NavigationEntry mNavigationEntry; private NavigationEntry mNavigationEntry;
@Mock
private BottomSheetContent mBottomSheetContent;
@Mock
private BottomSheetController mBottomSheetController;
private Profile mProfile; private Profile mProfile;
private static final String URL = "http://www.tanyastacos.com"; private class SendTabToSelfShareActivityForTest extends SendTabToSelfShareActivity {
private static final String TITLE = "Come try Tanya's famous tacos"; @Override
private static final long TIMESTAMP = 123456; BottomSheetContent createBottomSheetContent(
// TODO(crbug/946808) Add actual target device ID. ChromeActivity activity, NavigationEntry entry) {
private static final String TARGET_DEVICE_SYNC_CACHE_GUID = ""; return mBottomSheetContent;
}
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -92,18 +97,12 @@ public class SendTabToSelfShareActivityTest { ...@@ -92,18 +97,12 @@ public class SendTabToSelfShareActivityTest {
when(mTab.getWebContents()).thenReturn(mWebContents); when(mTab.getWebContents()).thenReturn(mWebContents);
when(mWebContents.getNavigationController()).thenReturn(mNavigationController); when(mWebContents.getNavigationController()).thenReturn(mNavigationController);
when(mNavigationController.getVisibleEntry()).thenReturn(mNavigationEntry); when(mNavigationController.getVisibleEntry()).thenReturn(mNavigationEntry);
when(mNavigationEntry.getUrl()).thenReturn(URL);
when(mNavigationEntry.getTitle()).thenReturn(TITLE);
when(mNavigationEntry.getTimestamp()).thenReturn(TIMESTAMP);
// Setup the mocked object chain to get the string needed by the Toast. // Setup the mocked object chain to get the bottom controller.
when(mChromeActivity.getResources()).thenReturn(mResources); when(mChromeActivity.getBottomSheetController()).thenReturn(mBottomSheetController);
when(mResources.getText(anyInt())).thenReturn("ToastText");
SendTabToSelfShareActivity shareActivity = new SendTabToSelfShareActivity(); SendTabToSelfShareActivityForTest shareActivity = new SendTabToSelfShareActivityForTest();
shareActivity.handleShareAction(mChromeActivity); shareActivity.handleShareAction(mChromeActivity);
verify(mNativeMock) verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true));
.addEntry(eq(mProfile), eq(URL), eq(TITLE), eq(TIMESTAMP),
eq(TARGET_DEVICE_SYNC_CACHE_GUID));
} }
} }
...@@ -209,6 +209,11 @@ static jboolean JNI_SendTabToSelfAndroidBridge_IsFeatureAvailable( ...@@ -209,6 +209,11 @@ static jboolean JNI_SendTabToSelfAndroidBridge_IsFeatureAvailable(
return ShouldOfferFeature(web_contents); return ShouldOfferFeature(web_contents);
} }
// Returns whether the sending component of the feature is enabled.
static jboolean JNI_SendTabToSelfAndroidBridge_IsSendingEnabled(JNIEnv* env) {
return IsSendingEnabled();
}
static void JNI_SendTabToSelfAndroidBridge_ShowInfoBar( static void JNI_SendTabToSelfAndroidBridge_ShowInfoBar(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& j_web_contents, const JavaParamRef<jobject>& j_web_contents,
......
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