phone_status_processor.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/components/phonehub/phone_status_processor.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include "ash/components/phonehub/do_not_disturb_controller.h"
  8. #include "ash/components/phonehub/find_my_device_controller.h"
  9. #include "ash/components/phonehub/message_receiver.h"
  10. #include "ash/components/phonehub/multidevice_feature_access_manager.h"
  11. #include "ash/components/phonehub/mutable_phone_model.h"
  12. #include "ash/components/phonehub/notification_processor.h"
  13. #include "ash/components/phonehub/recent_apps_interaction_handler.h"
  14. #include "ash/components/phonehub/screen_lock_manager_impl.h"
  15. #include "ash/constants/ash_features.h"
  16. #include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
  17. #include "base/containers/flat_set.h"
  18. #include "base/strings/utf_string_conversions.h"
  19. namespace ash {
  20. namespace phonehub {
  21. namespace {
  22. using multidevice_setup::MultiDeviceSetupClient;
  23. PhoneStatusModel::MobileStatus GetMobileStatusFromProto(
  24. proto::MobileConnectionState mobile_status) {
  25. switch (mobile_status) {
  26. case proto::MobileConnectionState::NO_SIM:
  27. return PhoneStatusModel::MobileStatus::kNoSim;
  28. case proto::MobileConnectionState::SIM_BUT_NO_RECEPTION:
  29. return PhoneStatusModel::MobileStatus::kSimButNoReception;
  30. case proto::MobileConnectionState::SIM_WITH_RECEPTION:
  31. return PhoneStatusModel::MobileStatus::kSimWithReception;
  32. default:
  33. return PhoneStatusModel::MobileStatus::kNoSim;
  34. }
  35. }
  36. PhoneStatusModel::SignalStrength GetSignalStrengthFromProto(
  37. proto::SignalStrength signal_strength) {
  38. switch (signal_strength) {
  39. case proto::SignalStrength::ZERO_BARS:
  40. return PhoneStatusModel::SignalStrength::kZeroBars;
  41. case proto::SignalStrength::ONE_BAR:
  42. return PhoneStatusModel::SignalStrength::kOneBar;
  43. case proto::SignalStrength::TWO_BARS:
  44. return PhoneStatusModel::SignalStrength::kTwoBars;
  45. case proto::SignalStrength::THREE_BARS:
  46. return PhoneStatusModel::SignalStrength::kThreeBars;
  47. case proto::SignalStrength::FOUR_BARS:
  48. return PhoneStatusModel::SignalStrength::kFourBars;
  49. default:
  50. return PhoneStatusModel::SignalStrength::kZeroBars;
  51. }
  52. }
  53. PhoneStatusModel::ChargingState GetChargingStateFromProto(
  54. proto::ChargingState charging_state) {
  55. switch (charging_state) {
  56. case proto::ChargingState::NOT_CHARGING:
  57. return PhoneStatusModel::ChargingState::kNotCharging;
  58. case proto::ChargingState::CHARGING_AC:
  59. case proto::ChargingState::CHARGING_WIRELESS:
  60. return PhoneStatusModel::ChargingState::kChargingAc;
  61. case proto::ChargingState::CHARGING_USB:
  62. return PhoneStatusModel::ChargingState::kChargingUsb;
  63. default:
  64. return PhoneStatusModel::ChargingState::kNotCharging;
  65. }
  66. }
  67. PhoneStatusModel::BatterySaverState GetBatterySaverStateFromProto(
  68. proto::BatteryMode battery_mode) {
  69. switch (battery_mode) {
  70. case proto::BatteryMode::BATTERY_SAVER_OFF:
  71. return PhoneStatusModel::BatterySaverState::kOff;
  72. case proto::BatteryMode::BATTERY_SAVER_ON:
  73. return PhoneStatusModel::BatterySaverState::kOn;
  74. default:
  75. return PhoneStatusModel::BatterySaverState::kOff;
  76. }
  77. }
  78. MultideviceFeatureAccessManager::AccessStatus ComputeNotificationAccessState(
  79. const proto::PhoneProperties& phone_properties) {
  80. // If the user has a Work Profile active, notification access is not allowed
  81. // by Android. See https://crbug.com/1155151.
  82. if (phone_properties.profile_type() == proto::ProfileType::WORK_PROFILE)
  83. return MultideviceFeatureAccessManager::AccessStatus::kProhibited;
  84. if (phone_properties.notification_access_state() ==
  85. proto::NotificationAccessState::ACCESS_GRANTED) {
  86. return MultideviceFeatureAccessManager::AccessStatus::kAccessGranted;
  87. }
  88. return MultideviceFeatureAccessManager::AccessStatus::kAvailableButNotGranted;
  89. }
  90. // User has to consent and agree for phoneHub to have storage permission on the
  91. // phone
  92. MultideviceFeatureAccessManager::AccessStatus ComputeCameraRollAccessState(
  93. const proto::PhoneProperties& phone_properties) {
  94. if (phone_properties.camera_roll_access_state().feature_enabled()) {
  95. return MultideviceFeatureAccessManager::AccessStatus::kAccessGranted;
  96. } else {
  97. return MultideviceFeatureAccessManager::AccessStatus::
  98. kAvailableButNotGranted;
  99. }
  100. }
  101. MultideviceFeatureAccessManager::AccessProhibitedReason
  102. ComputeNotificationAccessProhibitedReason(
  103. const proto::PhoneProperties& phone_properties) {
  104. if (phone_properties.profile_disable_reason() ==
  105. proto::ProfileDisableReason::DISABLE_REASON_DISABLED_BY_POLICY) {
  106. return MultideviceFeatureAccessManager::AccessProhibitedReason::
  107. kDisabledByPhonePolicy;
  108. }
  109. if (phone_properties.profile_type() == proto::ProfileType::WORK_PROFILE) {
  110. return MultideviceFeatureAccessManager::AccessProhibitedReason::
  111. kWorkProfile;
  112. }
  113. return MultideviceFeatureAccessManager::AccessProhibitedReason::kUnknown;
  114. }
  115. ScreenLockManager::LockStatus ComputeScreenLockState(
  116. const proto::PhoneProperties& phone_properties) {
  117. switch (phone_properties.screen_lock_state()) {
  118. case proto::ScreenLockState::SCREEN_LOCK_UNKNOWN:
  119. return ScreenLockManager::LockStatus::kUnknown;
  120. case proto::ScreenLockState::SCREEN_LOCK_OFF:
  121. return ScreenLockManager::LockStatus::kLockedOff;
  122. case proto::ScreenLockState::SCREEN_LOCK_ON:
  123. return ScreenLockManager::LockStatus::kLockedOn;
  124. default:
  125. return ScreenLockManager::LockStatus::kUnknown;
  126. }
  127. }
  128. FindMyDeviceController::Status ComputeFindMyDeviceStatus(
  129. const proto::PhoneProperties& phone_properties) {
  130. if (phone_properties.find_my_device_capability() ==
  131. proto::FindMyDeviceCapability::NOT_ALLOWED) {
  132. return FindMyDeviceController::Status::kRingingNotAvailable;
  133. }
  134. bool is_ringing =
  135. phone_properties.ring_status() == proto::FindMyDeviceRingStatus::RINGING;
  136. return is_ringing ? FindMyDeviceController::Status::kRingingOn
  137. : FindMyDeviceController::Status::kRingingOff;
  138. }
  139. PhoneStatusModel CreatePhoneStatusModel(const proto::PhoneProperties& proto) {
  140. return PhoneStatusModel(
  141. GetMobileStatusFromProto(proto.connection_state()),
  142. PhoneStatusModel::MobileConnectionMetadata{
  143. GetSignalStrengthFromProto(proto.signal_strength()),
  144. base::UTF8ToUTF16(proto.mobile_provider())},
  145. GetChargingStateFromProto(proto.charging_state()),
  146. GetBatterySaverStateFromProto(proto.battery_mode()),
  147. proto.battery_percentage());
  148. }
  149. std::vector<RecentAppsInteractionHandler::UserState> GetUserStates(
  150. const RepeatedPtrField<proto::UserState>& user_states) {
  151. std::vector<RecentAppsInteractionHandler::UserState> states;
  152. for (const auto& user_state : user_states) {
  153. RecentAppsInteractionHandler::UserState state;
  154. state.user_id = user_state.user_id();
  155. state.is_enabled = !user_state.is_quiet_mode_enabled();
  156. states.emplace_back(state);
  157. }
  158. return states;
  159. }
  160. } // namespace
  161. PhoneStatusProcessor::PhoneStatusProcessor(
  162. DoNotDisturbController* do_not_disturb_controller,
  163. FeatureStatusProvider* feature_status_provider,
  164. MessageReceiver* message_receiver,
  165. FindMyDeviceController* find_my_device_controller,
  166. MultideviceFeatureAccessManager* multidevice_feature_access_manager,
  167. ScreenLockManager* screen_lock_manager,
  168. NotificationProcessor* notification_processor_,
  169. MultiDeviceSetupClient* multidevice_setup_client,
  170. MutablePhoneModel* phone_model,
  171. RecentAppsInteractionHandler* recent_apps_interaction_handler)
  172. : do_not_disturb_controller_(do_not_disturb_controller),
  173. feature_status_provider_(feature_status_provider),
  174. message_receiver_(message_receiver),
  175. find_my_device_controller_(find_my_device_controller),
  176. multidevice_feature_access_manager_(multidevice_feature_access_manager),
  177. screen_lock_manager_(screen_lock_manager),
  178. notification_processor_(notification_processor_),
  179. multidevice_setup_client_(multidevice_setup_client),
  180. phone_model_(phone_model),
  181. recent_apps_interaction_handler_(recent_apps_interaction_handler) {
  182. DCHECK(do_not_disturb_controller_);
  183. DCHECK(feature_status_provider_);
  184. DCHECK(message_receiver_);
  185. DCHECK(find_my_device_controller_);
  186. DCHECK(multidevice_feature_access_manager_);
  187. DCHECK(notification_processor_);
  188. DCHECK(multidevice_setup_client_);
  189. DCHECK(phone_model_);
  190. message_receiver_->AddObserver(this);
  191. feature_status_provider_->AddObserver(this);
  192. multidevice_setup_client_->AddObserver(this);
  193. MaybeSetPhoneModelName(multidevice_setup_client_->GetHostStatus().second);
  194. }
  195. PhoneStatusProcessor::~PhoneStatusProcessor() {
  196. message_receiver_->RemoveObserver(this);
  197. feature_status_provider_->RemoveObserver(this);
  198. multidevice_setup_client_->RemoveObserver(this);
  199. }
  200. void PhoneStatusProcessor::ProcessReceivedNotifications(
  201. const RepeatedPtrField<proto::Notification>& notification_protos) {
  202. multidevice_setup::mojom::FeatureState feature_state =
  203. multidevice_setup_client_->GetFeatureState(
  204. multidevice_setup::mojom::Feature::kPhoneHubNotifications);
  205. if (feature_state != multidevice_setup::mojom::FeatureState::kEnabledByUser) {
  206. // Do not process any notifications if notifications are not enabled in
  207. // settings.
  208. return;
  209. }
  210. std::vector<proto::Notification> inline_replyable_protos;
  211. for (const auto& proto : notification_protos) {
  212. if (!features::IsPhoneHubCallNotificationEnabled() &&
  213. (proto.category() == proto::Notification::Category::
  214. Notification_Category_INCOMING_CALL ||
  215. proto.category() == proto::Notification::Category::
  216. Notification_Category_ONGOING_CALL ||
  217. proto.category() == proto::Notification::Category::
  218. Notification_Category_SCREEN_CALL)) {
  219. continue;
  220. }
  221. inline_replyable_protos.emplace_back(proto);
  222. }
  223. notification_processor_->AddNotifications(inline_replyable_protos);
  224. }
  225. void PhoneStatusProcessor::SetReceivedPhoneStatusModelStates(
  226. const proto::PhoneProperties& phone_properties) {
  227. phone_model_->SetPhoneStatusModel(CreatePhoneStatusModel(phone_properties));
  228. do_not_disturb_controller_->SetDoNotDisturbStateInternal(
  229. phone_properties.notification_mode() ==
  230. proto::NotificationMode::DO_NOT_DISTURB_ON,
  231. phone_properties.profile_type() != proto::ProfileType::WORK_PROFILE);
  232. multidevice_feature_access_manager_->SetNotificationAccessStatusInternal(
  233. ComputeNotificationAccessState(phone_properties),
  234. ComputeNotificationAccessProhibitedReason(phone_properties));
  235. if (features::IsPhoneHubCameraRollEnabled()) {
  236. multidevice_feature_access_manager_->SetCameraRollAccessStatusInternal(
  237. ComputeCameraRollAccessState(phone_properties));
  238. }
  239. if (screen_lock_manager_) {
  240. screen_lock_manager_->SetLockStatusInternal(
  241. ComputeScreenLockState(phone_properties));
  242. }
  243. find_my_device_controller_->SetPhoneRingingStatusInternal(
  244. ComputeFindMyDeviceStatus(phone_properties));
  245. if (features::IsEcheSWAEnabled()) {
  246. recent_apps_interaction_handler_->set_user_states(
  247. GetUserStates(phone_properties.user_states()));
  248. }
  249. multidevice_feature_access_manager_->SetFeatureSetupRequestSupportedInternal(
  250. phone_properties.feature_setup_config()
  251. .feature_setup_request_supported());
  252. }
  253. void PhoneStatusProcessor::MaybeSetPhoneModelName(
  254. const absl::optional<multidevice::RemoteDeviceRef>& remote_device) {
  255. if (!remote_device.has_value()) {
  256. phone_model_->SetPhoneName(absl::nullopt);
  257. return;
  258. }
  259. phone_model_->SetPhoneName(base::UTF8ToUTF16(remote_device->name()));
  260. }
  261. void PhoneStatusProcessor::OnFeatureStatusChanged() {
  262. // Reset phone model instance when but still keep the phone's name.
  263. if (feature_status_provider_->GetStatus() !=
  264. FeatureStatus::kEnabledAndConnected) {
  265. phone_model_->SetPhoneStatusModel(absl::nullopt);
  266. notification_processor_->ClearNotificationsAndPendingUpdates();
  267. }
  268. }
  269. void PhoneStatusProcessor::OnPhoneStatusSnapshotReceived(
  270. proto::PhoneStatusSnapshot phone_status_snapshot) {
  271. PA_LOG(INFO) << "Received snapshot from phone with Android version "
  272. << phone_status_snapshot.properties().android_version()
  273. << " and GmsCore version "
  274. << phone_status_snapshot.properties().gmscore_version();
  275. ProcessReceivedNotifications(phone_status_snapshot.notifications());
  276. SetReceivedPhoneStatusModelStates(phone_status_snapshot.properties());
  277. if (features::IsEcheSWAEnabled()) {
  278. SetStreamableApps(phone_status_snapshot.streamable_apps());
  279. }
  280. }
  281. void PhoneStatusProcessor::OnPhoneStatusUpdateReceived(
  282. proto::PhoneStatusUpdate phone_status_update) {
  283. ProcessReceivedNotifications(phone_status_update.updated_notifications());
  284. SetReceivedPhoneStatusModelStates(phone_status_update.properties());
  285. if (!phone_status_update.removed_notification_ids().empty()) {
  286. base::flat_set<int64_t> removed_notification_ids;
  287. for (auto& id : phone_status_update.removed_notification_ids()) {
  288. removed_notification_ids.emplace(id);
  289. }
  290. notification_processor_->RemoveNotifications(removed_notification_ids);
  291. }
  292. }
  293. void PhoneStatusProcessor::OnHostStatusChanged(
  294. const MultiDeviceSetupClient::HostStatusWithDevice&
  295. host_device_with_status) {
  296. MaybeSetPhoneModelName(host_device_with_status.second);
  297. }
  298. void PhoneStatusProcessor::SetStreamableApps(
  299. const proto::StreamableApps& streamable_apps) {
  300. if (streamable_apps.apps_size() > 0 && recent_apps_interaction_handler_)
  301. recent_apps_interaction_handler_->SetStreamableApps(streamable_apps);
  302. }
  303. } // namespace phonehub
  304. } // namespace ash