Skip to content

Commit

Permalink
[CrOS MultiDevice] Show notification when Messages pairing is lost.
Browse files Browse the repository at this point in the history
Once multi-device setup is completed, the "Messages" PWA is installed,
but further setup is required before the app can be used. Specifically,
the Chromebook needs to be paired with the user's phone via a QR code
displayed in the PWA.

However, this pairing is broken the PWA is migrated from
messages.android.com to messages.google.com (see
https://crbug.com/917855.

This CL alerts the user that the devices need to be re-paired when this
situation arises.

Bug: 918943
Change-Id: Ib662edf42ba01320cc12e6f3955b80c390d4493e
Reviewed-on: https://chromium-review.googlesource.com/c/1406159
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: Evan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#622126}
  • Loading branch information
Kyle Horimoto authored and Commit Bot committed Jan 11, 2019
1 parent f3fb24a commit e1a6276
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 5 deletions.
1 change: 1 addition & 0 deletions ash/public/cpp/vector_icons/BUILD.gn
Expand Up @@ -24,6 +24,7 @@ aggregate_vector_icons("ash_public_vector_icons") {
"notification_image.icon",
"notification_installed.icon",
"notification_linux.icon",
"notification_messages.icon",
"notification_mobile_data.icon",
"notification_mobile_data_off.icon",
"notification_multi_device_setup.icon",
Expand Down
30 changes: 30 additions & 0 deletions ash/public/cpp/vector_icons/notification_messages.icon
@@ -0,0 +1,30 @@
// 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.

CANVAS_DIMENSIONS, 36,
MOVE_TO, 31, 4,
H_LINE_TO, 5,
R_ARC_TO, 3, 3, 0, 0, 0, -2.98f, 3,
R_V_LINE_TO, 27,
LINE_TO, 10, 28,
R_H_LINE_TO, 21,
R_CUBIC_TO, 1.65f, 0, 3, -1.35f, 3, -3,
V_LINE_TO, 7,
R_CUBIC_TO, 0, -1.65f, -1.35f, -3, -3, -3,
CLOSE,
MOVE_TO, 9, 20,
R_H_LINE_TO, 12,
R_V_LINE_TO, 3,
H_LINE_TO, 9,
CLOSE,
R_MOVE_TO, 0, -6,
R_H_LINE_TO, 18,
R_V_LINE_TO, 3,
H_LINE_TO, 9,
CLOSE,
R_MOVE_TO, 0, -6,
R_H_LINE_TO, 18,
R_V_LINE_TO, 3,
H_LINE_TO, 9,
CLOSE
1 change: 1 addition & 0 deletions ash/system/message_center/message_center_controller.cc
Expand Up @@ -136,6 +136,7 @@ MessageCenterController::MessageCenterController() {
&kNotificationImageIcon,
&kNotificationInstalledIcon,
&kNotificationLinuxIcon,
&kNotificationMessagesIcon,
&kNotificationMultiDeviceSetupIcon,
&kNotificationMobileDataIcon,
&kNotificationMobileDataOffIcon,
Expand Down
8 changes: 8 additions & 0 deletions chrome/app/chromeos_strings.grdp
Expand Up @@ -181,6 +181,14 @@
Offer new features as they become available
</message>

<!-- Android Messages notification strings. -->
<message name="IDS_ANDROID_MESSAGES_PAIRING_LOST_NOTIFICATION_TITLE" desc="Title of the notification which alerts the user that they can set up their phones to sync text messages with their Chromebook.">
Pair your phone with Messages
</message>
<message name="IDS_ANDROID_MESSAGES_PAIRING_LOST_NOTIFICATION_MESSAGE" desc="Message for the body of the notification which alerts the user that they can set up their phones to sync text messages with their Chromebook.">
Send and receive text messages from your Chromebook
</message>

<!-- Update Screen Strings -->
<message name="IDS_CHECKING_FOR_UPDATES" desc="Notification for checking for update">
Checking for updates
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/chromeos/BUILD.gn
Expand Up @@ -329,6 +329,8 @@ source_set("chromeos") {
"android_sms/connection_establisher_impl.h",
"android_sms/connection_manager.cc",
"android_sms/connection_manager.h",
"android_sms/pairing_lost_notifier.cc",
"android_sms/pairing_lost_notifier.h",
"app_mode/app_launch_utils.cc",
"app_mode/app_launch_utils.h",
"app_mode/app_session.cc",
Expand Down Expand Up @@ -2111,6 +2113,7 @@ source_set("unit_tests") {
"android_sms/android_sms_app_helper_delegate_impl_unittest.cc",
"android_sms/connection_establisher_impl_unittest.cc",
"android_sms/connection_manager_unittest.cc",
"android_sms/pairing_lost_notifier_unittest.cc",
"app_mode/startup_app_launcher_unittest.cc",
"apps/apk_web_app_installer_unittest.cc",
"apps/intent_helper/apps_navigation_throttle_unittest.cc",
Expand Down
13 changes: 11 additions & 2 deletions chrome/browser/chromeos/android_sms/android_sms_service.cc
Expand Up @@ -8,6 +8,7 @@
#include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
#include "chrome/browser/chromeos/android_sms/connection_establisher_impl.h"
#include "chrome/browser/chromeos/android_sms/connection_manager.h"
#include "chrome/browser/chromeos/android_sms/pairing_lost_notifier.h"
#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/web_applications/web_app_provider.h"
Expand All @@ -32,16 +33,24 @@ AndroidSmsService::AndroidSmsService(
&web_app_provider->pending_app_manager(),
host_content_settings_map)),
android_sms_pairing_state_tracker_(
std::make_unique<AndroidSmsPairingStateTrackerImpl>(profile_)) {
std::make_unique<AndroidSmsPairingStateTrackerImpl>(profile_)),
pairing_lost_notifier_(std::make_unique<PairingLostNotifier>(
profile,
multidevice_setup_client,
profile_->GetPrefs(),
android_sms_app_helper_delegate_.get())) {
session_manager::SessionManager::Get()->AddObserver(this);
}

AndroidSmsService::~AndroidSmsService() = default;

void AndroidSmsService::Shutdown() {
connection_manager_.reset();
android_sms_app_helper_delegate_.reset();
// Note: |pairing_lost_notifier_| holds a reference to
// |android_sms_app_helper_delegate_|, so it should be deleted first.
pairing_lost_notifier_.reset();
android_sms_pairing_state_tracker_.reset();
android_sms_app_helper_delegate_.reset();
session_manager::SessionManager::Get()->RemoveObserver(this);
}

Expand Down
9 changes: 6 additions & 3 deletions chrome/browser/chromeos/android_sms/android_sms_service.h
Expand Up @@ -29,12 +29,14 @@ class MultiDeviceSetupClient;
namespace android_sms {

class ConnectionManager;
class PairingLostNotifier;

// KeyedService which manages Android Messages integration. This service
// has three main responsibilities:
// has four main responsibilities:
// (1) Maintaining a connection with the Messages ServiceWorker,
// (2) Managing installation/launching of the Messages PWA, and
// (3) Tracking the pairing state of the PWA.
// (2) Managing installation/launching of the Messages PWA,
// (3) Tracking the pairing state of the PWA, and
// (4) Notifying users when their phones need to be re-paired.
class AndroidSmsService : public KeyedService,
public session_manager::SessionManagerObserver {
public:
Expand Down Expand Up @@ -69,6 +71,7 @@ class AndroidSmsService : public KeyedService,
android_sms_app_helper_delegate_;
std::unique_ptr<AndroidSmsPairingStateTrackerImpl>
android_sms_pairing_state_tracker_;
std::unique_ptr<PairingLostNotifier> pairing_lost_notifier_;
std::unique_ptr<ConnectionManager> connection_manager_;

DISALLOW_COPY_AND_ASSIGN(AndroidSmsService);
Expand Down
10 changes: 10 additions & 0 deletions chrome/browser/chromeos/android_sms/android_sms_service_factory.cc
Expand Up @@ -3,14 +3,18 @@
// found in the LICENSE file.

#include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"

#include "chrome/browser/chromeos/android_sms/pairing_lost_notifier.h"
#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/web_applications/web_app_provider_factory.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"

namespace chromeos {

Expand Down Expand Up @@ -48,6 +52,7 @@ AndroidSmsServiceFactory::AndroidSmsServiceFactory()
DependsOn(chromeos::multidevice_setup::MultiDeviceSetupClientFactory::
GetInstance());
DependsOn(web_app::WebAppProviderFactory::GetInstance());
DependsOn(NotificationDisplayServiceFactory::GetInstance());
}

AndroidSmsServiceFactory::~AndroidSmsServiceFactory() = default;
Expand Down Expand Up @@ -79,6 +84,11 @@ bool AndroidSmsServiceFactory::ServiceIsNULLWhileTesting() const {
return true;
}

void AndroidSmsServiceFactory::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
PairingLostNotifier::RegisterProfilePrefs(registry);
}

} // namespace android_sms

} // namespace chromeos
Expand Up @@ -9,6 +9,10 @@
#include "chrome/browser/chromeos/android_sms/android_sms_service.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"

namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs

namespace chromeos {

namespace android_sms {
Expand All @@ -31,6 +35,8 @@ class AndroidSmsServiceFactory : public BrowserContextKeyedServiceFactory {
content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
bool ServiceIsNULLWhileTesting() const override;
void RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) override;

DISALLOW_COPY_AND_ASSIGN(AndroidSmsServiceFactory);
};
Expand Down
150 changes: 150 additions & 0 deletions chrome/browser/chromeos/android_sms/pairing_lost_notifier.cc
@@ -0,0 +1,150 @@
// 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.

#include "chrome/browser/chromeos/android_sms/pairing_lost_notifier.h"

#include "ash/public/cpp/notification_utils.h"
#include "ash/public/cpp/vector_icons/vector_icons.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/public/cpp/notification_types.h"

namespace chromeos {

namespace android_sms {

namespace {

const char kWasPreviouslySetUpPrefName[] = "android_sms.was_previously_set_up";

const char kAndroidSmsNotifierId[] = "ash.android_sms";
const char kPairingLostNotificationId[] = "android_sms.pairing_lost";

} // namespace

// static
void PairingLostNotifier::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kWasPreviouslySetUpPrefName, false);
}

PairingLostNotifier::PairingLostNotifier(
Profile* profile,
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
PrefService* pref_service,
multidevice_setup::AndroidSmsAppHelperDelegate*
android_sms_app_helper_delegate)
: profile_(profile),
multidevice_setup_client_(multidevice_setup_client),
pref_service_(pref_service),
android_sms_app_helper_delegate_(android_sms_app_helper_delegate),
weak_ptr_factory_(this) {
multidevice_setup_client_->AddObserver(this);
HandleMessagesFeatureState();
}

PairingLostNotifier::~PairingLostNotifier() {
multidevice_setup_client_->RemoveObserver(this);
}

void PairingLostNotifier::OnFeatureStatesChanged(
const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
feature_states_map) {
HandleMessagesFeatureState();
}

void PairingLostNotifier::HandleMessagesFeatureState() {
multidevice_setup::mojom::FeatureState state =
multidevice_setup_client_->GetFeatureStates()
.find(multidevice_setup::mojom::Feature::kMessages)
->second;

// If Messages is currently enabled or disabled, the user has completed the
// setup process.
if (state == multidevice_setup::mojom::FeatureState::kDisabledByUser ||
state == multidevice_setup::mojom::FeatureState::kEnabledByUser) {
HandleSetUpFeatureState();
return;
}

// If further setup is not required, there is no need to show a notification.
if (state != multidevice_setup::mojom::FeatureState::kFurtherSetupRequired)
return;

// The Messages was not previously set up, the notification should not be
// shown.
if (!pref_service_->GetBoolean(kWasPreviouslySetUpPrefName))
return;

// Set the preference to false to indicate that the app was not previously set
// up, then show the notification.
pref_service_->SetBoolean(kWasPreviouslySetUpPrefName, false);
ShowPairingLostNotification();
}

void PairingLostNotifier::HandleSetUpFeatureState() {
// Store a preference indicating that the feature has been set up. This
// preference will be checked in the future in the case that the phone has
// become unpaired.
pref_service_->SetBoolean(kWasPreviouslySetUpPrefName, true);

// If the "pairing lost" notification is currently visible, close it.
// Otherwise, the user could be confused that a notification is alerting the
// user to complete a task that has already been completed.
ClosePairingLostNotificationIfVisible();
}

void PairingLostNotifier::ShowPairingLostNotification() {
PA_LOG(INFO) << "PairingLostNotifier::ShowPairingLostNotification(): "
<< "Pairing has been lost; displaying notification.";

NotificationDisplayService::GetForProfile(profile_)->Display(
NotificationHandler::Type::TRANSIENT,
*ash::CreateSystemNotification(
message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
kPairingLostNotificationId,
l10n_util::GetStringUTF16(
IDS_ANDROID_MESSAGES_PAIRING_LOST_NOTIFICATION_TITLE),
l10n_util::GetStringUTF16(
IDS_ANDROID_MESSAGES_PAIRING_LOST_NOTIFICATION_MESSAGE),
base::string16() /* display_source */, GURL() /* origin_url */,
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kAndroidSmsNotifierId),
{} /* rich_notification_data */,
base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
base::BindRepeating(
&PairingLostNotifier::OnPairingLostNotificationClick,
weak_ptr_factory_.GetWeakPtr())),
ash::kNotificationMessagesIcon,
message_center::SystemNotificationWarningLevel::NORMAL));
}

void PairingLostNotifier::ClosePairingLostNotificationIfVisible() {
PA_LOG(INFO) << "PairingLostNotifier::"
<< "ClosePairingLostNotificationIfVisible(): "
<< "Closing pairing lost notification if visible.";

NotificationDisplayService::GetForProfile(profile_)->Close(
NotificationHandler::Type::TRANSIENT, kPairingLostNotificationId);
}

void PairingLostNotifier::OnPairingLostNotificationClick(
base::Optional<int> button_index) {
PA_LOG(INFO) << "PairingLostNotifier::OnPairingLostNotificationClick(): "
<< "Pairing notification clicked; opening PWA.";

ClosePairingLostNotificationIfVisible();
android_sms_app_helper_delegate_->SetUpAndLaunchAndroidSmsApp();
}

} // namespace android_sms

} // namespace chromeos

0 comments on commit e1a6276

Please sign in to comment.