Commit 0014aa02 authored by Regan Hsu's avatar Regan Hsu Committed by Commit Bot

[CrOS PhoneHub] Add Browser Tab Model to chrome://multidevice-internals

* Users can now set 2 tab model metadatas.
* If any fields are empty, the url metadata will be treated as nullopt.
* 3rd and 4th tabs will be added later.

Screenshots
https://screenshot.googleplex.com/AwV2evHm2c7QCMU
https://screenshot.googleplex.com/6q7tXZFAH3K8pSL
https://screenshot.googleplex.com/7rgRSDiU2EqKwXE
https://screenshot.googleplex.com/7mJtxtdg3GrDF6q

Bug: 1106937
Change-Id: I20872614efa1caa889267c1b01d4406255c60be1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2391647
Commit-Queue: Regan Hsu <hsuregan@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804145}
parent d3c720e6
...@@ -8,17 +8,30 @@ import("//tools/polymer/html_to_js.gni") ...@@ -8,17 +8,30 @@ import("//tools/polymer/html_to_js.gni")
js_type_check("closure_compile") { js_type_check("closure_compile") {
is_polymer3 = true is_polymer3 = true
deps = [ deps = [
":browser_tabs_metadata_form",
":log_object", ":log_object",
":logging_tab", ":logging_tab",
":multidevice_internals", ":multidevice_internals",
":multidevice_logs_browser_proxy", ":multidevice_logs_browser_proxy",
":multidevice_phonehub_browser_proxy", ":multidevice_phonehub_browser_proxy",
":multidevice_phonehub_browser_proxy",
":phone_status_model_form", ":phone_status_model_form",
":phonehub_tab", ":phonehub_tab",
":types", ":types",
] ]
} }
js_library("browser_tabs_model_form") {
deps = [
":multidevice_phonehub_browser_proxy",
":types",
]
}
js_library("browser_tabs_metadata_form") {
deps = [ ":types" ]
}
js_library("phone_status_model_form") { js_library("phone_status_model_form") {
deps = [ deps = [
":multidevice_phonehub_browser_proxy", ":multidevice_phonehub_browser_proxy",
...@@ -28,6 +41,7 @@ js_library("phone_status_model_form") { ...@@ -28,6 +41,7 @@ js_library("phone_status_model_form") {
js_library("phonehub_tab") { js_library("phonehub_tab") {
deps = [ deps = [
":browser_tabs_model_form",
":multidevice_phonehub_browser_proxy", ":multidevice_phonehub_browser_proxy",
":phone_status_model_form", ":phone_status_model_form",
":types", ":types",
...@@ -91,5 +105,7 @@ html_to_js("web_components") { ...@@ -91,5 +105,7 @@ html_to_js("web_components") {
"phonehub_tab.js", "phonehub_tab.js",
"phone_status_model_form.js", "phone_status_model_form.js",
"shared_style.js", "shared_style.js",
"browser_tabs_metadata_form.js",
"browser_tabs_model_form.js",
] ]
} }
<style include="cr-shared-style shared-style">
:host {
display: flex;
flex: 1 0 100%;
}
#faviconSelector {
align-items: normal;
}
</style>
<div class="column">
<div class="label">URL: </div>
<cr-input value="{{url_}}" id="urlInput" auto-validate required
error-message="This browser tab will be a nullopt if no url input">
</cr-input>
</div>
<div class="column">
<div class="label">Title: </div>
<cr-input value="{{title_}}" id="titleInput" auto-validate required
error-message="This browser tab will be a nullopt if no title input">
</cr-input>
</div>
<div class="column">
<div class="label">Last Accessed (ms): </div>
<cr-input value="{{lastAccessedTimeStamp_}}"
id="lastAccessedTimeStampInput" type="number" min="0"
on-change="onLastAccessTimeStampChanged_"
auto-validate error-message="Must be greater than 0" required>
</cr-input>
</div>
<div class="column" id="faviconSelector">
<div class="label">Favicon selector: </div>
<select id="faviconList" class="md-select"
on-change="onFaviconSelected_">
<template is="dom-repeat" items="[[faviconList_]]">
<option>[[getFaviconTypeName_(item)]]</option>
</template>
</select>
</div>
// 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.
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
import './shared_style.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {BrowserTabsMetadataModel, FaviconType} from './types.js';
/**
* Maps a FaviconType to its title label in the dropdown.
* @type {!Map<FaviconType, String>}
*/
const faviconTypeToStringMap = new Map([
[FaviconType.PINK, 'Pink'],
[FaviconType.RED, 'Red'],
[FaviconType.GREEN, 'Green'],
[FaviconType.BLUE, 'Blue'],
[FaviconType.YELLOW, 'Yellow'],
]);
Polymer({
is: 'browser-tabs-metadata-form',
_template: html`{__html_template__}`,
properties: {
/** @type{BrowserTabsMetadataModel} */
browserTabMetadata: {
type: Object,
notify: true,
computed: 'getMetadata_(url_, title_, lastAccessedTimeStamp_, favicon_)',
},
/** @private */
url_: {
type: String,
value: 'https://www.google.com/',
},
/** @private */
title_: {
type: String,
value: 'Google',
},
/** @private */
lastAccessedTimeStamp_: {
type: Number,
value: Date.now(),
},
/** @private{FaviconType} */
favicon_: {
type: Number,
value: FaviconType.PINK,
},
/** @private */
faviconList_: {
type: Array,
value: () => {
return [
FaviconType.PINK,
FaviconType.RED,
FaviconType.GREEN,
FaviconType.BLUE,
FaviconType.YELLOW,
];
},
readonly: true,
},
},
/**
* @param {FaviconType} faviconType
* @return {String}
* @private
*/
getFaviconTypeName_(faviconType) {
return faviconTypeToStringMap.get(faviconType);
},
/** @private */
onFaviconSelected_() {
const select = /** @type {!HTMLSelectElement} */
(this.$$('#faviconList'));
this.favicon_ = this.faviconList_[select.selectedIndex];
},
/**
* @return{BrowserTabsMetadataModel}
* @private
*/
getMetadata_() {
return {
url: this.url_,
title: this.title_,
lastAccessedTimeStamp: this.lastAccessedTimeStamp_,
favicon: this.favicon_,
};
},
/** @private */
onLastAccessTimeStampChanged_() {
const inputValue = this.$$('#lastAccessedTimeStampInput').value;
if (inputValue < 0) {
this.lastAccessedTimeStamp_ = 0;
return;
}
this.lastAccessedTimeStamp_ = Number(inputValue);
},
});
<style include="cr-shared-style shared-style">
:host {
display: flex;
height: 250px;
}
#fieldColumn {
flex: 2;
}
</style>
<div class="column">
<cr-button on-click="setFakeBrowserTabModel_" class="internals-button">
<span class="emphasize">Change Browser Tabs Status</span>
</cr-button>
<div class="label">
<span class="emphasize">Note:</span> Click the button above to propagate all
browser tab status values on the right hand side to the fake phonehub
manager. Note that if a field is empty, then that corresponding tab will
be nullopt.
</div>
</div>
<div class="column" id="fieldColumn">
<div class="cr-padded-text">
Toggle Tab Sync enabled
</div>
<cr-toggle checked="{{isTabSyncEnabled_}}">
</cr-toggle>
<template is="dom-if" if="[[isTabSyncEnabled_]]" restamp>
<div class="cr-row">
<div class="column">1: </div>
<browser-tabs-metadata-form
browser-tab-metadata="{{browserTabOneMetadata_}}">
</browser-tabs-metadata-form>
</div>
<div class="cr-row">
<div class="column">2: </div>
<browser-tabs-metadata-form
browser-tab-metadata="{{browserTabTwoMetadata_}}">
</browser-tabs-metadata-form>
</div>
</template>
</div>
// 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.
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
import './shared_style.js';
import './browser_tabs_metadata_form.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {MultidevicePhoneHubBrowserProxy} from './multidevice_phonehub_browser_proxy.js';
import {BrowserTabsMetadataModel, BrowserTabsModel} from './types.js';
Polymer({
is: 'browser-tabs-model-form',
_template: html`{__html_template__}`,
properties: {
/** @private */
isTabSyncEnabled_: {
type: Boolean,
value: false,
},
/** @private{BrowserTabsMetadataModel} */
browserTabOneMetadata_: {
type: Object,
},
/** @private{BrowserTabsMetadataModel} */
browserTabTwoMetadata_: {
type: Object,
},
},
/** @private{?MultidevicePhoneHubBrowserProxy}*/
browserProxy_: null,
/** @override */
created() {
this.browserProxy_ = MultidevicePhoneHubBrowserProxy.getInstance();
},
/** @private */
setFakeBrowserTabModel_() {
const browserTabsModel = {
isTabSyncEnabled: this.isTabSyncEnabled_,
browserTabOneMetadata:
this.isTabSyncEnabled_ ? this.browserTabOneMetadata_ : null,
browserTabTwoMetadata:
this.isTabSyncEnabled_ ? this.browserTabTwoMetadata_ : null,
};
this.browserProxy_.setBrowserTabs(browserTabsModel);
},
});
...@@ -12,6 +12,14 @@ ...@@ -12,6 +12,14 @@
</outputs> </outputs>
<release seq="1"> <release seq="1">
<includes> <includes>
<include name="IDR_MULTIDEVICE_INTERNALS_BROWSER_TABS_METADATA_FORM_JS"
file="${root_gen_dir}\chrome\browser\resources\chromeos\multidevice_internals\browser_tabs_metadata_form.js"
use_base_dir="false"
type="BINDATA"/>
<include name="IDR_MULTIDEVICE_INTERNALS_BROWSER_TABS_MODEL_FORM_JS"
file="${root_gen_dir}\chrome\browser\resources\chromeos\multidevice_internals\browser_tabs_model_form.js"
use_base_dir="false"
type="BINDATA"/>
<include name="IDR_MULTIDEVICE_INTERNALS_INDEX_HTML" <include name="IDR_MULTIDEVICE_INTERNALS_INDEX_HTML"
file="index.html" file="index.html"
type="BINDATA"/> type="BINDATA"/>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import {addSingletonGetter} from 'chrome://resources/js/cr.m.js'; import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
import {FeatureStatus, PhoneStatusModel} from './types.js'; import {BrowserTabsModel, FeatureStatus, PhoneStatusModel} from './types.js';
/** /**
* JavaScript hooks into the native WebUI handler for Phonehub tab. * JavaScript hooks into the native WebUI handler for Phonehub tab.
...@@ -33,6 +33,15 @@ export class MultidevicePhoneHubBrowserProxy { ...@@ -33,6 +33,15 @@ export class MultidevicePhoneHubBrowserProxy {
setFakePhoneStatus(phoneStatusModel) { setFakePhoneStatus(phoneStatusModel) {
chrome.send('setFakePhoneStatus', [phoneStatusModel]); chrome.send('setFakePhoneStatus', [phoneStatusModel]);
} }
/**
* Sets the browser tabs model.
* @param {!BrowserTabsModel} browserTabsModel The browser tab model with fake
* values.
*/
setBrowserTabs(browserTabsModel) {
chrome.send('setBrowserTabs', [browserTabsModel]);
}
} }
addSingletonGetter(MultidevicePhoneHubBrowserProxy); addSingletonGetter(MultidevicePhoneHubBrowserProxy);
...@@ -4,15 +4,6 @@ ...@@ -4,15 +4,6 @@
flex: 0 0 100%; flex: 0 0 100%;
} }
.column {
align-items: center;
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: center;
margin: 10px;
}
.phone-status-property { .phone-status-property {
flex-basis: 100%; flex-basis: 100%;
justify-content: center; justify-content: center;
...@@ -23,14 +14,6 @@ ...@@ -23,14 +14,6 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.label {
width: 100%;
}
cr-button {
width: 100%;
}
select { select {
margin-bottom: 10px; margin-bottom: 10px;
width: 100%; width: 100%;
......
...@@ -63,13 +63,13 @@ Polymer({ ...@@ -63,13 +63,13 @@ Polymer({
/** @private{MobileStatus} */ /** @private{MobileStatus} */
mobileStatus_: { mobileStatus_: {
type: Number, type: Number,
value: MobileStatus.SIM_WITH_RECEPTION, value: MobileStatus.NO_SIM,
}, },
/** @private{SignalStrength}*/ /** @private{SignalStrength}*/
signalStrength_: { signalStrength_: {
type: Number, type: Number,
value: SignalStrength.TWO_BARS, value: SignalStrength.ZERO_BARS,
}, },
/** @private */ /** @private */
...@@ -217,6 +217,7 @@ Polymer({ ...@@ -217,6 +217,7 @@ Polymer({
/** /**
* @param {MobileStatus} mobileStatus * @param {MobileStatus} mobileStatus
* @return {String}
* @private * @private
*/ */
getMobileStatusName_(mobileStatus) { getMobileStatusName_(mobileStatus) {
...@@ -225,6 +226,7 @@ Polymer({ ...@@ -225,6 +226,7 @@ Polymer({
/** /**
* @param {SignalStrength} signalStrength * @param {SignalStrength} signalStrength
* @return {String}
* @private * @private
*/ */
getSignalStrengthName_(signalStrength) { getSignalStrengthName_(signalStrength) {
...@@ -233,6 +235,7 @@ Polymer({ ...@@ -233,6 +235,7 @@ Polymer({
/** /**
* @param {ChargingState} chargingState * @param {ChargingState} chargingState
* @return {String}
* @private * @private
*/ */
getChargingStateName_(chargingState) { getChargingStateName_(chargingState) {
...@@ -241,6 +244,7 @@ Polymer({ ...@@ -241,6 +244,7 @@ Polymer({
/** /**
* @param {BatterySaverState} batterySaverState * @param {BatterySaverState} batterySaverState
* @return {String}
* @private * @private
*/ */
getBatterySaverStateName_(batterySaverState) { getBatterySaverStateName_(batterySaverState) {
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
display: flex; display: flex;
flex: 0 0 100%; flex: 0 0 100%;
} }
.cr-padded-text {
margin: 10px;
}
</style> </style>
<div class="cr-row"> <div class="cr-row">
...@@ -34,12 +30,15 @@ ...@@ -34,12 +30,15 @@
</select> </select>
<div class="cr-padded-text" hidden="[[isFeatureEnabledAndConnected_]]"> <div class="cr-padded-text" hidden="[[isFeatureEnabledAndConnected_]]">
More controls will appear if the feature status is set to More controls will appear if the feature status is set to
<div class="emphasize">ENABLED_AND_CONNECTED</div>. <span class="emphasize">ENABLED_AND_CONNECTED</span>.
</div> </div>
</div> </div>
<template is="dom-if" if="[[isFeatureEnabledAndConnected_]]" restamp> <template is="dom-if" if="[[isFeatureEnabledAndConnected_]]" restamp>
<div class="cr-row"> <div class="cr-row">
<phone-status-model-form></phone-status-model-form> <phone-status-model-form></phone-status-model-form>
</div> </div>
<div class="cr-row">
<browser-tabs-model-form></browser-tabs-model-form>
</div>
</template> </template>
</template> </template>
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js'; import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
import 'chrome://resources/cr_elements/md_select_css.m.js'; import 'chrome://resources/cr_elements/md_select_css.m.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js';
import './shared_style.js'; import './browser_tabs_model_form.js';
import './phone_status_model_form.js'; import './phone_status_model_form.js';
import './shared_style.js';
import {flush, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {flush, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {MultidevicePhoneHubBrowserProxy} from './multidevice_phonehub_browser_proxy.js'; import {MultidevicePhoneHubBrowserProxy} from './multidevice_phonehub_browser_proxy.js';
...@@ -77,7 +78,7 @@ Polymer({ ...@@ -77,7 +78,7 @@ Polymer({
isFeatureEnabledAndConnected_: { isFeatureEnabledAndConnected_: {
type: Boolean, type: Boolean,
computed: 'isFeatureEnabledAndConnectedComputed_(featureStatus_)', computed: 'isFeatureEnabledAndConnectedComputed_(featureStatus_)',
} },
}, },
/** @private {?MultidevicePhoneHubBrowserProxy}*/ /** @private {?MultidevicePhoneHubBrowserProxy}*/
......
...@@ -13,8 +13,29 @@ ...@@ -13,8 +13,29 @@
margin: 5px; margin: 5px;
} }
.label {
width: 100%;
}
.column {
align-items: center;
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: center;
margin: 10px;
}
.column cr-button {
width: 100%;
}
.emphasize { .emphasize {
font-weight: bold; font-weight: bold;
} }
.cr-padded-text {
margin: 10px;
}
</style> </style>
</template> </template>
...@@ -68,7 +68,7 @@ export const SignalStrength = { ...@@ -68,7 +68,7 @@ export const SignalStrength = {
/** /**
* Numerical values should not be changed because they must stay in sync with * Numerical values should not be changed because they must stay in sync with
* ChargingState inchromeos/components/phonehub/phone_status_model.h. * ChargingState in chromeos/components/phonehub/phone_status_model.h.
* @enum{number} * @enum{number}
*/ */
export const ChargingState = { export const ChargingState = {
...@@ -79,7 +79,7 @@ export const ChargingState = { ...@@ -79,7 +79,7 @@ export const ChargingState = {
/** /**
* Numerical values should not be changed because they must stay in sync with * Numerical values should not be changed because they must stay in sync with
* BatterySaverState inchromeos/components/phonehub/phone_status_model.h. * BatterySaverState in chromeos/components/phonehub/phone_status_model.h.
* @enum{number} * @enum{number}
*/ */
export const BatterySaverState = { export const BatterySaverState = {
...@@ -87,6 +87,19 @@ export const BatterySaverState = { ...@@ -87,6 +87,19 @@ export const BatterySaverState = {
ON: 1, ON: 1,
}; };
/**
* Numerical values should not be changed because they must stay in sync with
* FaviconType in chromeos/components/phonehub/phone_status_model.cc.
* @enum{number}
*/
export const FaviconType = {
PINK: 0,
RED: 1,
GREEN: 2,
BLUE: 3,
YELLOW: 4,
};
/** /**
* @typedef {{ * @typedef {{
* mobileStatus: !MobileStatus, * mobileStatus: !MobileStatus,
...@@ -98,3 +111,22 @@ export const BatterySaverState = { ...@@ -98,3 +111,22 @@ export const BatterySaverState = {
* }} * }}
*/ */
export let PhoneStatusModel; export let PhoneStatusModel;
/**
* @typedef {{
* url: string,
* title: string,
* lastAccessedTimeStamp: number,
* favicon: !FaviconType,
* }}
*/
export let BrowserTabsMetadataModel;
/**
* @typedef {{
* isTabSyncEnabled: boolean,
* browserTabOneMetadata: ?BrowserTabsMetadataModel,
* browserTabTwoMetadata: ?BrowserTabsMetadataModel,
* }}
*/
export let BrowserTabsModel;
...@@ -5,14 +5,89 @@ ...@@ -5,14 +5,89 @@
#include "chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h" #include "chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h"
#include "ash/public/cpp/system_tray.h" #include "ash/public/cpp/system_tray.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/phonehub/phone_hub_manager_factory.h" #include "chrome/browser/chromeos/phonehub/phone_hub_manager_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/components/phonehub/fake_phone_hub_manager.h" #include "chromeos/components/phonehub/fake_phone_hub_manager.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
namespace chromeos { namespace chromeos {
namespace multidevice { namespace multidevice {
namespace {
// Fake Favicon colors used for coloring the fake favicon bitmaps.
enum class FaviconType {
kPink = 0,
kRed = 1,
kGreen = 2,
kBlue = 3,
kYellow = 4,
};
const SkBitmap FaviconNumToBitmap(FaviconType favicon_num) {
SkBitmap bitmap;
bitmap.allocN32Pixels(16, 16);
switch (favicon_num) {
case FaviconType::kPink:
bitmap.eraseARGB(0, 255, 192, 203);
break;
case FaviconType::kRed:
bitmap.eraseARGB(0, 255, 0, 0);
break;
case FaviconType::kGreen:
bitmap.eraseARGB(0, 0, 255, 0);
break;
case FaviconType::kBlue:
bitmap.eraseARGB(0, 0, 0, 255);
break;
case FaviconType::kYellow:
bitmap.eraseARGB(0, 255, 255, 0);
break;
default:
break;
}
return bitmap;
}
base::Optional<phonehub::BrowserTabsModel::BrowserTabMetadata>
DictToBrowserTabMetadataModel(
const base::DictionaryValue* browser_tab_metadata) {
std::string url;
if (!browser_tab_metadata->GetString("url", &url) || url.empty()) {
return base::nullopt;
}
base::string16 title;
if (!browser_tab_metadata->GetString("title", &title) || title.empty()) {
return base::nullopt;
}
// JavaScript time stamps don't fit in int.
double last_accessed_timestamp;
if (!browser_tab_metadata->GetDouble("lastAccessedTimeStamp",
&last_accessed_timestamp)) {
return base::nullopt;
}
int favicon_type_as_int;
if (!browser_tab_metadata->GetInteger("favicon", &favicon_type_as_int)) {
return base::nullopt;
}
auto favicon_type = static_cast<FaviconType>(favicon_type_as_int);
gfx::Image favicon =
gfx::Image::CreateFrom1xBitmap(FaviconNumToBitmap(favicon_type));
return phonehub::BrowserTabsModel::BrowserTabMetadata(
GURL(url), title, base::Time::FromJsTime(last_accessed_timestamp),
favicon);
}
} // namespace
MultidevicePhoneHubHandler::MultidevicePhoneHubHandler() = default; MultidevicePhoneHubHandler::MultidevicePhoneHubHandler() = default;
MultidevicePhoneHubHandler::~MultidevicePhoneHubHandler() { MultidevicePhoneHubHandler::~MultidevicePhoneHubHandler() {
...@@ -36,6 +111,11 @@ void MultidevicePhoneHubHandler::RegisterMessages() { ...@@ -36,6 +111,11 @@ void MultidevicePhoneHubHandler::RegisterMessages() {
"setFakePhoneStatus", "setFakePhoneStatus",
base::BindRepeating(&MultidevicePhoneHubHandler::HandleSetFakePhoneStatus, base::BindRepeating(&MultidevicePhoneHubHandler::HandleSetFakePhoneStatus,
base::Unretained(this))); base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setBrowserTabs",
base::BindRepeating(&MultidevicePhoneHubHandler::HandleSetBrowserTabs,
base::Unretained(this)));
} }
void MultidevicePhoneHubHandler::SetSystemPhoneHubManagerEnabled() { void MultidevicePhoneHubHandler::SetSystemPhoneHubManagerEnabled() {
...@@ -130,5 +210,50 @@ void MultidevicePhoneHubHandler::HandleSetFakePhoneStatus( ...@@ -130,5 +210,50 @@ void MultidevicePhoneHubHandler::HandleSetFakePhoneStatus(
<< "\n battery percentage: " << battery_percentage; << "\n battery percentage: " << battery_percentage;
} }
void MultidevicePhoneHubHandler::HandleSetBrowserTabs(
const base::ListValue* args) {
const base::DictionaryValue* browser_tab_status_dict = nullptr;
CHECK(args->GetDictionary(0, &browser_tab_status_dict));
bool is_tab_sync_enabled;
CHECK(browser_tab_status_dict->GetBoolean("isTabSyncEnabled",
&is_tab_sync_enabled));
if (!is_tab_sync_enabled) {
fake_phone_hub_manager_->mutable_phone_model()->SetBrowserTabsModel(
phonehub::BrowserTabsModel(is_tab_sync_enabled));
PA_LOG(VERBOSE) << "Tab sync off; cleared browser tab metadata";
return;
}
base::Optional<phonehub::BrowserTabsModel::BrowserTabMetadata> metadata_one;
const base::DictionaryValue* browser_tab_one_metadata = nullptr;
if (browser_tab_status_dict->GetDictionary("browserTabOneMetadata",
&browser_tab_one_metadata)) {
metadata_one = DictToBrowserTabMetadataModel(browser_tab_one_metadata);
}
base::Optional<phonehub::BrowserTabsModel::BrowserTabMetadata> metadata_two;
const base::DictionaryValue* browser_tab_two_metadata = nullptr;
if (browser_tab_status_dict->GetDictionary("browserTabTwoMetadata",
&browser_tab_two_metadata)) {
metadata_two = DictToBrowserTabMetadataModel(browser_tab_two_metadata);
}
// TODO(hsuregan): Add metadata_three and metadata_four.
std::vector<base::Optional<phonehub::BrowserTabsModel::BrowserTabMetadata>>
metadatas{{metadata_one, metadata_two}};
std::sort(metadatas.begin(), metadatas.end());
fake_phone_hub_manager_->mutable_phone_model()->SetBrowserTabsModel(
phonehub::BrowserTabsModel(is_tab_sync_enabled, metadatas[1],
metadatas[0]));
if (metadatas[1].has_value())
PA_LOG(VERBOSE) << "Set most recent browser tab to" << *metadatas[1];
if (metadatas[0].has_value())
PA_LOG(VERBOSE) << "Set second most recent browser tab to" << *metadatas[0];
}
} // namespace multidevice } // namespace multidevice
} // namespace chromeos } // namespace chromeos
...@@ -35,6 +35,7 @@ class MultidevicePhoneHubHandler : public content::WebUIMessageHandler { ...@@ -35,6 +35,7 @@ class MultidevicePhoneHubHandler : public content::WebUIMessageHandler {
void HandleSetFakePhoneHubManagerEnabled(const base::ListValue* args); void HandleSetFakePhoneHubManagerEnabled(const base::ListValue* args);
void HandleSetFeatureStatus(const base::ListValue* args); void HandleSetFeatureStatus(const base::ListValue* args);
void HandleSetFakePhoneStatus(const base::ListValue* args); void HandleSetFakePhoneStatus(const base::ListValue* args);
void HandleSetBrowserTabs(const base::ListValue* args);
std::unique_ptr<phonehub::FakePhoneHubManager> fake_phone_hub_manager_; std::unique_ptr<phonehub::FakePhoneHubManager> fake_phone_hub_manager_;
}; };
......
...@@ -34,6 +34,12 @@ bool BrowserTabsModel::BrowserTabMetadata::operator!=( ...@@ -34,6 +34,12 @@ bool BrowserTabsModel::BrowserTabMetadata::operator!=(
return !(*this == other); return !(*this == other);
} }
bool BrowserTabsModel::BrowserTabMetadata::operator<(
const BrowserTabMetadata& other) const {
return std::tie(last_accessed_timestamp) <
std::tie(other.last_accessed_timestamp);
}
BrowserTabsModel::BrowserTabsModel( BrowserTabsModel::BrowserTabsModel(
bool is_tab_sync_enabled, bool is_tab_sync_enabled,
const base::Optional<BrowserTabMetadata>& most_recent_tab, const base::Optional<BrowserTabMetadata>& most_recent_tab,
......
...@@ -28,6 +28,7 @@ class BrowserTabsModel { ...@@ -28,6 +28,7 @@ class BrowserTabsModel {
bool operator==(const BrowserTabMetadata& other) const; bool operator==(const BrowserTabMetadata& other) const;
bool operator!=(const BrowserTabMetadata& other) const; bool operator!=(const BrowserTabMetadata& other) const;
bool operator<(const BrowserTabMetadata& other) const;
GURL url; GURL url;
base::string16 title; base::string16 title;
......
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