Commit cf250d93 authored by Regan Hsu's avatar Regan Hsu Committed by Chromium LUCI CQ

[CrOS PhoneHub] Show disabled "Enable Hotspot" button when no reception.

When there is no reception (including no sim), still show the "Enable
Hotspot" button, but disable it instead. Provide context to user via
tooltip and sublabel the button as "Not Available".

This was tested by disabling Google Fi on my dev phone.

Screenshot:
No service: http://go/tscreen/fdb1d2ad6dd867d78bbd82b81cfd20cf7da69ac6
No SIM: https://screenshot.googleplex.com/Acq4YtHx2tjWfWp

Bug: 1159847, 1106937
Change-Id: Ib5dfc852d79e1b3a6be8153e31eced2c20e5e263
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2606670
Commit-Queue: Regan Hsu <hsuregan@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#839789}
parent c563bf53
......@@ -1220,6 +1220,9 @@ This file contains the strings for ash.
<message name="IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP" desc="Tooltip message that indicates to the user that Phone Hub's 'Locate phone' feature is not available because the user disabled alarms that make sounds on their phone.">
Locate phone is not available when alarm sounds are disabled
</message>
<message name="IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP" desc="Tooltip message that indicates to the user that the Enable Hotspot feature is disabled because their phone does not have mobile data.">
Your phone must have mobile data to provide a hotspot
</message>
<message name="IDS_ASH_STYLUS_BATTERY_LOW_LABEL">
Low
......
fdb1d2ad6dd867d78bbd82b81cfd20cf7da69ac6
\ No newline at end of file
......@@ -65,6 +65,9 @@ void EnableHotspotQuickActionController::OnTetherStatusChanged() {
case Status::kConnected:
SetState(ActionState::kConnected);
break;
case Status::kNoReception:
SetState(ActionState::kNoReception);
break;
}
item_->SetVisible(true);
}
......@@ -73,12 +76,14 @@ void EnableHotspotQuickActionController::SetState(ActionState state) {
item_->SetEnabled(true);
bool icon_enabled;
bool button_enabled;
int state_text_id;
int sub_label_text;
SkColor sub_label_color;
switch (state) {
case ActionState::kOff:
icon_enabled = false;
button_enabled = true;
state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_DISABLED_STATE_TOOLTIP;
sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_OFF_STATE;
sub_label_color = AshColorProvider::Get()->GetContentLayerColor(
......@@ -86,6 +91,7 @@ void EnableHotspotQuickActionController::SetState(ActionState state) {
break;
case ActionState::kConnecting:
icon_enabled = true;
button_enabled = true;
state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE_TOOLTIP;
sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE;
sub_label_color = AshColorProvider::Get()->GetContentLayerColor(
......@@ -93,21 +99,37 @@ void EnableHotspotQuickActionController::SetState(ActionState state) {
break;
case ActionState::kConnected:
icon_enabled = true;
button_enabled = true;
state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTED_STATE_TOOLTIP;
sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTED_STATE;
sub_label_color = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPositive);
break;
case ActionState::kNoReception:
icon_enabled = false;
button_enabled = false;
state_text_id =
IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP;
sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_NOT_AVAILABLE_STATE;
sub_label_color = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorSecondary);
break;
}
item_->SetToggled(icon_enabled);
item_->SetEnabled(button_enabled);
item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text));
item_->SetSubLabelColor(sub_label_color);
base::string16 tooltip_state =
l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel());
item_->SetIconTooltip(
l10n_util::GetStringFUTF16(IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP,
item_->GetItemLabel(), tooltip_state));
if (state == ActionState::kNoReception) {
item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id));
} else {
base::string16 tooltip_state =
l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel());
item_->SetIconTooltip(l10n_util::GetStringFUTF16(
IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(),
tooltip_state));
}
}
} // namespace ash
......@@ -33,7 +33,7 @@ class EnableHotspotQuickActionController
private:
// All the possible states that the enable hotspot button can be viewed. Each
// state has a corresponding icon, labels and tooltip view.
enum class ActionState { kOff, kConnecting, kConnected };
enum class ActionState { kOff, kConnecting, kConnected, kNoReception };
// Set the item (including icon, label and tooltips) to a certain state.
void SetState(ActionState state);
......
......@@ -49,6 +49,7 @@ Polymer({
TetherStatus.CONNECTION_AVAILABLE,
TetherStatus.CONNECTING,
TetherStatus.CONNECTED,
TetherStatus.NO_RECEPTION,
];
},
readonly: true,
......
......@@ -212,6 +212,7 @@ export const TetherStatus = {
CONNECTION_AVAILABLE: 2,
CONNECTING: 3,
CONNECTED: 4,
NO_RECEPTION: 5,
};
/**
......@@ -224,6 +225,7 @@ export const tetherStatusToString = new Map([
[TetherStatus.CONNECTION_AVAILABLE, 'Connection available'],
[TetherStatus.CONNECTING, 'Connecting'],
[TetherStatus.CONNECTED, 'Connected'],
[TetherStatus.NO_RECEPTION, 'No reception'],
]);
/**
......
......@@ -47,6 +47,9 @@ std::ostream& operator<<(std::ostream& stream,
case TetherController::Status::kConnected:
stream << "[Connected]";
break;
case TetherController::Status::kNoReception:
stream << "[No Reception]";
break;
}
return stream;
}
......
......@@ -26,9 +26,10 @@ class TetherController {
// Instant Tethering is available for use, but currently a connection is
// unavailable. There are a variety of reasons why this may be the case:
// the feature could have been disabled in settings, the phone may not have
// cellular reception, or the phone may not have Google Play Services
// notifications enabled, which are required for the feature.
// the feature could have been disabled in settings, or the phone may not
// have Google Play Services notifications enabled, which are required
// for the feature. Note that the phone having no reception or no SIM card
// does not count in this case; instead, kNoReception is used.
kConnectionUnavailable = 1,
// It is possible to connect, but no connection is active or in progress.
......@@ -40,7 +41,10 @@ class TetherController {
kConnecting = 3,
// Connected via Instant Tethering.
kConnected = 4
kConnected = 4,
// The phone has no reception (including no SIM).
kNoReception = 5,
};
class Observer : public base::CheckedObserver {
......
......@@ -403,22 +403,27 @@ void TetherControllerImpl::UpdateStatus() {
}
TetherController::Status TetherControllerImpl::ComputeStatus() const {
bool does_sim_exist_with_reception =
phone_model_->phone_status_model().has_value() &&
phone_model_->phone_status_model()->mobile_status() ==
PhoneStatusModel::MobileStatus::kSimWithReception;
if (!does_sim_exist_with_reception)
return Status::kIneligibleForFeature;
FeatureState feature_state =
multidevice_setup_client_->GetFeatureState(Feature::kInstantTethering);
if (feature_state != FeatureState::kDisabledByUser &&
feature_state != FeatureState::kEnabledByUser) {
// Tethering may be for instance, prohibited by policy or not supported
// by the phone or Chromebook.
return Status::kIneligibleForFeature;
}
if (phone_model_->phone_status_model().has_value()) {
// If the phone status exists, and it indicates that the phone
// does not have reception, the status becomes no kNoReception.
bool does_sim_exist_with_reception =
phone_model_->phone_status_model()->mobile_status() ==
PhoneStatusModel::MobileStatus::kSimWithReception;
if (!does_sim_exist_with_reception)
return Status::kNoReception;
}
if (connect_disconnect_status_ ==
ConnectDisconnectStatus::kTurningOnInstantTethering ||
connect_disconnect_status_ ==
......
......@@ -365,19 +365,55 @@ TEST_F(TetherControllerImplTest, ExternalTetherChangesReflectToStatus) {
// Phone status changed to no reception.
phone_model()->SetPhoneStatusModel(CreateFakePhoneStatusModel(
PhoneStatusModel::MobileStatus::kSimButNoReception));
EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature);
EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception);
EXPECT_EQ(GetNumObserverStatusChanged(), 7U);
// Phone status changed to no SIM.
phone_model()->SetPhoneStatusModel(
CreateFakePhoneStatusModel(PhoneStatusModel::MobileStatus::kNoSim));
EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception);
EXPECT_EQ(GetNumObserverStatusChanged(), 7U);
// Tether feature becomes unsupported,
SetMultideviceSetupFeatureState(FeatureState::kNotSupportedByPhone);
EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature);
EXPECT_EQ(GetNumObserverStatusChanged(), 8U);
// Tether feature becomes supported, the status becomes kNoReception again.
SetMultideviceSetupFeatureState(FeatureState::kEnabledByUser);
EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception);
EXPECT_EQ(GetNumObserverStatusChanged(), 9U);
// Phone status changed to having reception. Connection is still unavailable.
phone_model()->SetPhoneStatusModel(CreateFakePhoneStatusModel(
PhoneStatusModel::MobileStatus::kSimWithReception));
EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionUnavailable);
EXPECT_EQ(GetNumObserverStatusChanged(), 8U);
EXPECT_EQ(GetNumObserverStatusChanged(), 10U);
// Phone Model is lost.
// Phone Model is lost, connection is still unavailable.
phone_model()->SetPhoneStatusModel(base::nullopt);
EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature);
EXPECT_EQ(GetNumObserverStatusChanged(), 9U);
EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionUnavailable);
EXPECT_EQ(GetNumObserverStatusChanged(), 10U);
// Even though there is no Phone Model, adding a visible tether network
// will cause the controller to indicate a connection is available.
AddVisibleTetherNetwork();
EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionAvailable);
EXPECT_EQ(GetNumObserverStatusChanged(), 11U);
// Even though there is no Phone Model, connecting to a visible tether network
// externally (e.g via OS Settings) will cause the controller to indicate a
// connecting tether state.
SetTetherNetworkStateConnecting();
EXPECT_EQ(GetStatus(), TetherController::Status::kConnecting);
EXPECT_EQ(GetNumObserverStatusChanged(), 12U);
// Even though there is no Phone Model, a connection to a visible tether
// network externally (e.g via OS Settings) will cause the controller to
// indicate a connected tether state.
SetTetherNetworkStateConnected();
EXPECT_EQ(GetStatus(), TetherController::Status::kConnected);
EXPECT_EQ(GetNumObserverStatusChanged(), 13U);
}
TEST_F(TetherControllerImplTest, AttemptConnectDisconnect) {
......
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