123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- // 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.
- #include "ash/components/phonehub/multidevice_feature_access_manager_impl.h"
- #include "ash/components/multidevice/logging/logging.h"
- #include "ash/components/phonehub/connection_scheduler.h"
- #include "ash/components/phonehub/message_sender.h"
- #include "ash/components/phonehub/pref_names.h"
- #include "ash/components/phonehub/util/histogram_util.h"
- #include "ash/constants/ash_features.h"
- #include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
- #include "ash/webui/eche_app_ui/pref_names.h"
- #include "components/prefs/pref_change_registrar.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/pref_service.h"
- #include "pref_names.h"
- namespace ash {
- namespace phonehub {
- namespace {
- using multidevice_setup::mojom::Feature;
- using multidevice_setup::mojom::FeatureState;
- } // namespace
- // static
- void MultideviceFeatureAccessManagerImpl::RegisterPrefs(
- PrefRegistrySimple* registry) {
- registry->RegisterIntegerPref(
- prefs::kCameraRollAccessStatus,
- static_cast<int>(AccessStatus::kAvailableButNotGranted));
- registry->RegisterIntegerPref(
- prefs::kNotificationAccessStatus,
- static_cast<int>(AccessStatus::kAvailableButNotGranted));
- registry->RegisterIntegerPref(
- prefs::kNotificationAccessProhibitedReason,
- static_cast<int>(AccessProhibitedReason::kUnknown));
- registry->RegisterBooleanPref(prefs::kHasDismissedSetupRequiredUi, false);
- registry->RegisterBooleanPref(prefs::kNeedsOneTimeNotificationAccessUpdate,
- true);
- registry->RegisterBooleanPref(prefs::kFeatureSetupRequestSupported, false);
- }
- MultideviceFeatureAccessManagerImpl::MultideviceFeatureAccessManagerImpl(
- PrefService* pref_service,
- multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
- FeatureStatusProvider* feature_status_provider,
- MessageSender* message_sender,
- ConnectionScheduler* connection_scheduler)
- : pref_service_(pref_service),
- multidevice_setup_client_(multidevice_setup_client),
- feature_status_provider_(feature_status_provider),
- message_sender_(message_sender),
- connection_scheduler_(connection_scheduler) {
- DCHECK(feature_status_provider_);
- DCHECK(message_sender_);
- DCHECK(multidevice_setup_client_);
- current_feature_status_ = feature_status_provider_->GetStatus();
- PA_LOG(VERBOSE) << __func__
- << ": current feature status = " << current_feature_status_;
- feature_status_provider_->AddObserver(this);
- pref_change_registrar_.Init(pref_service_);
- pref_change_registrar_.Add(
- eche_app::prefs::kAppsAccessStatus,
- base::BindRepeating(
- &MultideviceFeatureAccessManagerImpl::NotifyAppsAccessChanged,
- base::Unretained(this)));
- }
- MultideviceFeatureAccessManagerImpl::~MultideviceFeatureAccessManagerImpl() {
- feature_status_provider_->RemoveObserver(this);
- pref_change_registrar_.RemoveAll();
- }
- bool MultideviceFeatureAccessManagerImpl::
- HasMultideviceFeatureSetupUiBeenDismissed() const {
- return pref_service_->GetBoolean(prefs::kHasDismissedSetupRequiredUi);
- }
- void MultideviceFeatureAccessManagerImpl::DismissSetupRequiredUi() {
- pref_service_->SetBoolean(prefs::kHasDismissedSetupRequiredUi, true);
- }
- bool MultideviceFeatureAccessManagerImpl::IsAccessRequestAllowed(
- Feature feature) {
- const FeatureState feature_state =
- multidevice_setup_client_->GetFeatureState(feature);
- bool result = feature_state == FeatureState::kDisabledByUser ||
- feature_state == FeatureState::kEnabledByUser;
- return result;
- }
- MultideviceFeatureAccessManagerImpl::AccessStatus
- MultideviceFeatureAccessManagerImpl::GetNotificationAccessStatus() const {
- int status = pref_service_->GetInteger(prefs::kNotificationAccessStatus);
- return static_cast<AccessStatus>(status);
- }
- MultideviceFeatureAccessManagerImpl::AccessStatus
- MultideviceFeatureAccessManagerImpl::GetCameraRollAccessStatus() const {
- int status = pref_service_->GetInteger(prefs::kCameraRollAccessStatus);
- return static_cast<AccessStatus>(status);
- }
- MultideviceFeatureAccessManager::AccessStatus
- MultideviceFeatureAccessManagerImpl::GetAppsAccessStatus() const {
- // TODO(samchiu): The AppsAccessStatus will be updated by eche_app_ui
- // component only. We should listen to pref change and update it to
- // MultiDeviceFeatureOptInView.
- int status = pref_service_->GetInteger(eche_app::prefs::kAppsAccessStatus);
- return static_cast<AccessStatus>(status);
- }
- bool MultideviceFeatureAccessManagerImpl::GetFeatureSetupRequestSupported()
- const {
- return pref_service_->GetBoolean(prefs::kFeatureSetupRequestSupported);
- }
- MultideviceFeatureAccessManagerImpl::AccessProhibitedReason
- MultideviceFeatureAccessManagerImpl::GetNotificationAccessProhibitedReason()
- const {
- int reason =
- pref_service_->GetInteger(prefs::kNotificationAccessProhibitedReason);
- return static_cast<AccessProhibitedReason>(reason);
- }
- void MultideviceFeatureAccessManagerImpl::SetNotificationAccessStatusInternal(
- AccessStatus access_status,
- AccessProhibitedReason reason) {
- // TODO(http://crbug.com/1215559): Deprecate when there are no more active
- // Phone Hub notification users on M89. Some users had notifications
- // automatically disabled when updating from M89 to M90+ because the
- // notification feature state went from enabled-by-default to
- // disabled-by-default. To re-enable those users, we once and only once notify
- // observers if access has been granted by the phone. Notably, the
- // MultideviceSetupStateUpdate will decide whether or not the notification
- // feature should be enabled. See MultideviceSetupStateUpdater's method
- // IsWaitingForAccessToInitiallyEnableNotifications() for more details.
- bool needs_one_time_notifications_access_update =
- pref_service_->GetBoolean(prefs::kNeedsOneTimeNotificationAccessUpdate) &&
- access_status == AccessStatus::kAccessGranted;
- if (!needs_one_time_notifications_access_update &&
- !HasAccessStatusChanged(access_status, reason)) {
- return;
- }
- pref_service_->SetBoolean(prefs::kNeedsOneTimeNotificationAccessUpdate,
- false);
- PA_LOG(INFO) << "Notification access: "
- << std::make_pair(GetNotificationAccessStatus(),
- GetNotificationAccessProhibitedReason())
- << " => " << std::make_pair(access_status, reason);
- pref_service_->SetInteger(prefs::kNotificationAccessStatus,
- static_cast<int>(access_status));
- pref_service_->SetInteger(prefs::kNotificationAccessProhibitedReason,
- static_cast<int>(reason));
- NotifyNotificationAccessChanged();
- if (IsNotificationSetupOperationInProgress()) {
- switch (access_status) {
- case AccessStatus::kProhibited:
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::
- kProhibitedFromProvidingAccess);
- break;
- case AccessStatus::kAccessGranted:
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::kCompletedSuccessfully);
- break;
- case AccessStatus::kAvailableButNotGranted:
- // Intentionally blank; the operation status should not change.
- break;
- }
- } else if (IsCombinedSetupOperationInProgress()) {
- switch (access_status) {
- case AccessStatus::kProhibited:
- SetCombinedSetupOperationStatus(CombinedAccessSetupOperation::Status::
- kProhibitedFromProvidingAccess);
- break;
- case AccessStatus::kAccessGranted:
- combined_setup_notifications_pending_ = false;
- break;
- case AccessStatus::kAvailableButNotGranted:
- // Intentionally blank; the operation status should not change.
- break;
- }
- if (!combined_setup_notifications_pending_ &&
- !combined_setup_camera_roll_pending_) {
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kCompletedSuccessfully);
- }
- }
- }
- void MultideviceFeatureAccessManagerImpl::SetCameraRollAccessStatusInternal(
- AccessStatus access_status) {
- PA_LOG(INFO) << "Camera Roll access: " << GetCameraRollAccessStatus()
- << " => " << access_status;
- pref_service_->SetInteger(prefs::kCameraRollAccessStatus,
- static_cast<int>(access_status));
- NotifyCameraRollAccessChanged();
- if (!IsCombinedSetupOperationInProgress()) {
- return;
- }
- switch (access_status) {
- case AccessStatus::kProhibited:
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kProhibitedFromProvidingAccess);
- break;
- case AccessStatus::kAccessGranted:
- combined_setup_camera_roll_pending_ = false;
- break;
- case AccessStatus::kAvailableButNotGranted:
- // Intentionally blank; the operation status should not change.
- break;
- }
- if (!combined_setup_notifications_pending_ &&
- !combined_setup_camera_roll_pending_) {
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kCompletedSuccessfully);
- }
- }
- void MultideviceFeatureAccessManagerImpl::
- SetFeatureSetupRequestSupportedInternal(bool supported) {
- pref_service_->SetBoolean(prefs::kFeatureSetupRequestSupported, supported);
- NotifyFeatureSetupRequestSupportedChanged();
- }
- void MultideviceFeatureAccessManagerImpl::OnNotificationSetupRequested() {
- PA_LOG(INFO) << "Notification access setup flow started.";
- switch (feature_status_provider_->GetStatus()) {
- // We're already connected, so request that the UI be shown on the phone.
- case FeatureStatus::kEnabledAndConnected:
- SendShowNotificationAccessSetupRequest();
- break;
- // We're already connecting, so wait until a connection succeeds before
- // trying to send a message
- case FeatureStatus::kEnabledAndConnecting:
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::kConnecting);
- break;
- // We are not connected, so schedule a connection; once the
- // connection succeeds, we'll send the message in OnFeatureStatusChanged().
- case FeatureStatus::kEnabledButDisconnected:
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::kConnecting);
- connection_scheduler_->ScheduleConnectionNow();
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- void MultideviceFeatureAccessManagerImpl::OnCombinedSetupRequested(
- bool camera_roll,
- bool notifications) {
- combined_setup_camera_roll_pending_ = camera_roll;
- combined_setup_notifications_pending_ = notifications;
- PA_LOG(INFO) << "Combined access setup flow started.";
- switch (feature_status_provider_->GetStatus()) {
- // We're already connected, so request that the UI be shown on the phone.
- case FeatureStatus::kEnabledAndConnected:
- SendShowCombinedAccessSetupRequest();
- break;
- // We're already connecting, so wait until a connection succeeds before
- // trying to send a message
- case FeatureStatus::kEnabledAndConnecting:
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kConnecting);
- break;
- // We are not connected, so schedule a connection; once the
- // connection succeeds, we'll send the message in OnFeatureStatusChanged().
- case FeatureStatus::kEnabledButDisconnected:
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kConnecting);
- connection_scheduler_->ScheduleConnectionNow();
- break;
- default:
- NOTREACHED();
- break;
- }
- }
- void MultideviceFeatureAccessManagerImpl::OnFeatureStatusChanged() {
- if (IsNotificationSetupOperationInProgress()) {
- FeatureStatusChangedNotificationAccessSetup();
- } else if (IsCombinedSetupOperationInProgress()) {
- FeatureStatusChangedCombinedAccessSetup();
- }
- }
- void MultideviceFeatureAccessManagerImpl::
- FeatureStatusChangedNotificationAccessSetup() {
- const FeatureStatus previous_feature_status = current_feature_status_;
- current_feature_status_ = feature_status_provider_->GetStatus();
- PA_LOG(VERBOSE) << __func__
- << ": previous feature status = " << previous_feature_status
- << ", current feature status = " << current_feature_status_;
- if (previous_feature_status == current_feature_status_)
- return;
- // If we were previously connecting and could not establish a connection,
- // send a timeout state.
- if (previous_feature_status == FeatureStatus::kEnabledAndConnecting &&
- current_feature_status_ != FeatureStatus::kEnabledAndConnected) {
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::kTimedOutConnecting);
- return;
- }
- // If we were previously connected and are now no longer connected, send a
- // connection disconnected state.
- if (previous_feature_status == FeatureStatus::kEnabledAndConnected &&
- current_feature_status_ != FeatureStatus::kEnabledAndConnected) {
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::kConnectionDisconnected);
- return;
- }
- if (current_feature_status_ == FeatureStatus::kEnabledAndConnected) {
- SendShowNotificationAccessSetupRequest();
- return;
- }
- }
- void MultideviceFeatureAccessManagerImpl::
- FeatureStatusChangedCombinedAccessSetup() {
- const FeatureStatus previous_feature_status = current_feature_status_;
- current_feature_status_ = feature_status_provider_->GetStatus();
- PA_LOG(VERBOSE) << __func__
- << ": previous feature status = " << previous_feature_status
- << ", current feature status = " << current_feature_status_;
- if (previous_feature_status == current_feature_status_)
- return;
- // If we were previously connecting and could not establish a connection,
- // send a timeout state.
- if (previous_feature_status == FeatureStatus::kEnabledAndConnecting &&
- current_feature_status_ != FeatureStatus::kEnabledAndConnected) {
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kTimedOutConnecting);
- return;
- }
- // If we were previously connected and are now no longer connected, send a
- // connection disconnected state.
- if (previous_feature_status == FeatureStatus::kEnabledAndConnected &&
- current_feature_status_ != FeatureStatus::kEnabledAndConnected) {
- SetCombinedSetupOperationStatus(
- CombinedAccessSetupOperation::Status::kConnectionDisconnected);
- return;
- }
- if (current_feature_status_ == FeatureStatus::kEnabledAndConnected) {
- SendShowCombinedAccessSetupRequest();
- return;
- }
- }
- void MultideviceFeatureAccessManagerImpl::
- SendShowNotificationAccessSetupRequest() {
- message_sender_->SendShowNotificationAccessSetupRequest();
- SetNotificationSetupOperationStatus(
- NotificationAccessSetupOperation::Status::
- kSentMessageToPhoneAndWaitingForResponse);
- }
- void MultideviceFeatureAccessManagerImpl::SendShowCombinedAccessSetupRequest() {
- message_sender_->SendFeatureSetupRequest(
- combined_setup_camera_roll_pending_,
- combined_setup_notifications_pending_);
- SetCombinedSetupOperationStatus(CombinedAccessSetupOperation::Status::
- kSentMessageToPhoneAndWaitingForResponse);
- }
- bool MultideviceFeatureAccessManagerImpl::HasAccessStatusChanged(
- AccessStatus access_status,
- AccessProhibitedReason reason) {
- if (access_status != GetNotificationAccessStatus())
- return true;
- if (access_status == AccessStatus::kProhibited &&
- reason != GetNotificationAccessProhibitedReason()) {
- return true;
- }
- return false;
- }
- } // namespace phonehub
- } // namespace ash
|