1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/metrics/stylus_metrics_recorder.h"
#include "ash/shell.h"
#include "base/logging.h"
/* Emit metrics related to stylus utilization:
* StylusDetachedFromGarageSession
* StylusDetachedFromDockSession
* StylusDetachedFromGarageOrDockSession
* TODO(kenalba):
* + Usage of stylus (interacting with screen) while stylus is docked (only
* once a day).
* + Usage of stylus (interacting with screen) while stylus is attached (only
* once a day).
* + Usage of stylus (interacting with screen) while stylus is undocked (only
* once a day).
* + Usage of stylus (interacting with screen) while stylus is unattached
* (only once a day).
* + Usage of stylus (interacting with screen) while stylus is
* undocked/unattached (only once a day).
*
* Not currently possible with SFUL:
* Length of 'failed' vs. 'successful', aka a session
* where the pen was used vs. one where it was not.
* This is not possible as failed sessions don't have
* usetime, and the failure/success of a session
* needs to be known at the beginning of the session.
*
* Math between different metrics, hence several combinations
* need to be emitted in multiple metrics.
*/
namespace ash {
namespace {
bool IsStylusOnCharge(const PeripheralBatteryListener::BatteryInfo& battery) {
return (
battery.charge_status !=
PeripheralBatteryListener::BatteryInfo::ChargeStatus::kUnknown &&
battery.charge_status !=
PeripheralBatteryListener::BatteryInfo::ChargeStatus::kDischarging);
}
} // namespace
StylusSessionMetricsDelegate::StylusSessionMetricsDelegate(
const std::string& feature_name)
: metrics_(feature_name, this) {}
StylusSessionMetricsDelegate::~StylusSessionMetricsDelegate() = default;
bool StylusSessionMetricsDelegate::IsEligible() const {
return capable_;
}
bool StylusSessionMetricsDelegate::IsEnabled() const {
return capable_;
}
void StylusSessionMetricsDelegate::SetState(bool now_capable, bool in_session) {
if (active_ && (!in_session || !now_capable)) {
metrics_.StopSuccessfulUsage();
active_ = false;
}
capable_ = now_capable;
if (!active_ && in_session && now_capable) {
metrics_.RecordUsage(true);
metrics_.StartSuccessfulUsage();
active_ = true;
}
}
StylusMetricsRecorder::StylusMetricsRecorder() {
UpdateStylusState();
DCHECK(Shell::HasInstance());
DCHECK(Shell::Get()->peripheral_battery_listener());
Shell::Get()->peripheral_battery_listener()->AddObserver(this);
}
StylusMetricsRecorder::~StylusMetricsRecorder() {
Shell::Get()->peripheral_battery_listener()->RemoveObserver(this);
}
void StylusMetricsRecorder::OnAddingBattery(
const PeripheralBatteryListener::BatteryInfo& battery) {
if (battery.type == PeripheralBatteryListener::BatteryInfo::PeripheralType::
kStylusViaCharger) {
// Record the presence of the specific charger type; the API does
// not imply they are exclusive.
// TODO(kenalba): Avoid hard-coding this key
if (battery.key == "garaged-stylus-charger")
stylus_garage_present_ = true;
else
stylus_dock_present_ = true;
UpdateStylusState();
}
}
void StylusMetricsRecorder::OnRemovingBattery(
const PeripheralBatteryListener::BatteryInfo& battery) {
if (battery.type == PeripheralBatteryListener::BatteryInfo::PeripheralType::
kStylusViaCharger) {
// TODO(kenalba): Avoid hard-coding this key
if (battery.key == "garaged-stylus-charger")
stylus_garage_present_ = false;
else
stylus_dock_present_ = false;
stylus_on_charge_.reset();
UpdateStylusState();
}
}
void StylusMetricsRecorder::OnUpdatedBatteryLevel(
const PeripheralBatteryListener::BatteryInfo& battery) {
if (battery.type == PeripheralBatteryListener::BatteryInfo::PeripheralType::
kStylusViaCharger) {
stylus_on_charge_ = IsStylusOnCharge(battery);
UpdateStylusState();
}
}
void StylusMetricsRecorder::UpdateStylusState() {
/* Sessions are recorded when we know the device is capable of
* having a stylus garaged or docked, and the stylus is not on charge,
* and therefore not currently garaged or docked.
*/
const bool stylus_off_charge =
stylus_on_charge_.has_value() && *stylus_on_charge_ == false;
const bool stylus_detached_from_garage =
stylus_garage_present_ && stylus_off_charge;
const bool stylus_detached_from_dock =
stylus_dock_present_ && stylus_off_charge;
stylus_detached_from_garage_session_metrics_delegate_.SetState(
stylus_garage_present_, stylus_detached_from_garage);
stylus_detached_from_dock_session_metrics_delegate_.SetState(
stylus_dock_present_, stylus_detached_from_dock);
stylus_detached_from_garage_or_dock_session_metrics_delegate_.SetState(
stylus_garage_present_ || stylus_dock_present_,
stylus_detached_from_garage || stylus_detached_from_dock);
}
} // namespace ash
|