chromium/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc

// 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/quick_pair/common/fast_pair/fast_pair_metrics.h"

#include "ash/quick_pair/common/device.h"
#include "ash/quick_pair/common/protocol.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
#include "components/cross_device/logging/logging.h"
#include "components/metrics/structured/structured_events.h"
#include "components/metrics/structured/structured_metrics_client.h"

namespace {

const char kDeviceTypeHeadphones[] = "HeadphonesDeviceType";
const char kDeviceTypeSpeaker[] = "SpeakerDeviceType";
const char kDeviceTypeTrueWirelessHeadphones[] =
    "TrueWirelessHeadphonesDeviceType";
const char kDeviceTypeMouse[] = "MouseDeviceType";
const char kDeviceTypeUnspecified[] = "UnspecifiedDeviceType";

const char kNotificationTypeFastPair[] = "FastPairNotificationType";
const char kNotificationTypeFastPairOne[] = "FastPairOneNotificationType";
const char kNotificationTypeUnspecified[] = "UnspecifiedNotificationType";

// If RSSI or TxPower are unknown, we emit -129, which is out of range of
// the real return values [-128, 127].
const int kUnknownRSSI = -129;
const int kUnknownTxPower = -129;

// Error strings should be kept in sync with the strings reflected in
// device/bluetooth/bluez/bluetooth_socket_bluez.cc.
const char kAcceptFailedString[] = "Failed to accept connection.";
const char kInvalidUUIDString[] = "Invalid UUID";
const char kSocketNotListeningString[] = "Socket is not listening.";

// Top Popular peripherals and first party devices. These device
// model names should be kept in sync with the FastPairTrackedModelID
// token in //tools/metrics/histograms/metadata/bluetooth/histograms.xml.
// Devices may have multiple Model IDs associated with the same device
// (for example, each Pixel Bud Pros have different Model IDs for each different
// color) so we append '_*' to the naming for subsequent Model IDs after the
// first one.
const char kPopularPeripheral_BoatRockerz255Pro_ModelId[] = "CFF121";
const char kPopularPeripheral_BoatRockerz255Pro_Name[] = "BoatRockerz255Pro";

const char kPopularPeripheral_BoseQuietComfort35II_ModelId[] = "0100F0";
const char kPopularPeripheral_BoseQuietComfort35II_Name[] =
    "BoseQuietComfort35II";
const char kPopularPeripheral_BoseQuietComfort35II_1_ModelId[] = "0000F0";
const char kPopularPeripheral_BoseQuietComfort35II_1_Name[] =
    "BoseQuietComfort35II_1";

const char kPopularPeripheral_JBLLIVEPROTWS_ModelId[] = "461BB8";
const char kPopularPeripheral_JBLLIVEPROTWS_Name[] = "JBLLIVEPROTWS";
const char kPopularPeripheral_JBLLIVEPROTWS_1_ModelId[] = "C6936A";
const char kPopularPeripheral_JBLLIVEPROTWS_1_Name[] = "JBLLIVEPROTWS_1";
const char kPopularPeripheral_JBLLIVEPROTWS_2_ModelId[] = "F52494";
const char kPopularPeripheral_JBLLIVEPROTWS_2_Name[] = "JBLLIVEPROTWS_2";
const char kPopularPeripheral_JBLLIVEPROTWS_3_ModelId[] = "15BA5F";
const char kPopularPeripheral_JBLLIVEPROTWS_3_Name[] = "JBLLIVEPROTWS_3";
const char kPopularPeripheral_JBLLIVEPROTWS_4_ModelId[] = "56DB24";
const char kPopularPeripheral_JBLLIVEPROTWS_4_Name[] = "JBLLIVEPROTWS_4";
const char kPopularPeripheral_JBLLIVEPROTWS_5_ModelId[] = "8CB05C";
const char kPopularPeripheral_JBLLIVEPROTWS_5_Name[] = "JBLLIVEPROTWS_5";
const char kPopularPeripheral_JBLLIVEPROTWS_6_ModelId[] = "F8013A";
const char kPopularPeripheral_JBLLIVEPROTWS_6_Name[] = "JBLLIVEPROTWS_6";

const char kPopularPeripheral_JBLLIVE300TWS_ModelId[] = "718FA4";
const char kPopularPeripheral_JBLLIVE300TWS_Name[] = "JBLLIVE300TWS";
const char kPopularPeripheral_JBLLIVE300TWS_1_ModelId[] = "7C1C37";
const char kPopularPeripheral_JBLLIVE300TWS_1_Name[] = "JBLLIVE300TWS_1";
const char kPopularPeripheral_JBLLIVE300TWS_2_ModelId[] = "2A35AD";
const char kPopularPeripheral_JBLLIVE300TWS_2_Name[] = "JBLLIVE300TWS_2";

const char kPopularPeripheral_JBLLIVE400BT_ModelId[] = "F00209";
const char kPopularPeripheral_JBLLIVE400BT_Name[] = "JBLLIVE400BT";
const char kPopularPeripheral_JBLLIVE400BT_1_ModelId[] = "F0020B";
const char kPopularPeripheral_JBLLIVE400BT_1_Name[] = "JBLLIVE400BT_1";
const char kPopularPeripheral_JBLLIVE400BT_2_ModelId[] = "F0020C";
const char kPopularPeripheral_JBLLIVE400BT_2_Name[] = "JBLLIVE400BT_2";
const char kPopularPeripheral_JBLLIVE400BT_3_ModelId[] = "F0020D";
const char kPopularPeripheral_JBLLIVE400BT_3_Name[] = "JBLLIVE400BT_3";
const char kPopularPeripheral_JBLLIVE400BT_4_ModelId[] = "F0020A";
const char kPopularPeripheral_JBLLIVE400BT_4_Name[] = "JBLLIVE400BT_4";

const char kPopularPeripheral_JBLTUNE125TWS_ModelId[] = "FF1B63";
const char kPopularPeripheral_JBLTUNE125TWS_Name[] = "JBLTUNE125TWS";
const char kPopularPeripheral_JBLTUNE125TWS_1_ModelId[] = "054B2D";
const char kPopularPeripheral_JBLTUNE125TWS_1_Name[] = "JBLTUNE125TWS_1";
const char kPopularPeripheral_JBLTUNE125TWS_2_ModelId[] = "D97EBA";
const char kPopularPeripheral_JBLTUNE125TWS_2_Name[] = "JBLTUNE125TWS_2";
const char kPopularPeripheral_JBLTUNE125TWS_3_ModelId[] = "565EAA";
const char kPopularPeripheral_JBLTUNE125TWS_3_Name[] = "JBLTUNE125TWS_3";
const char kPopularPeripheral_JBLTUNE125TWS_4_ModelId[] = "E1DD91";
const char kPopularPeripheral_JBLTUNE125TWS_4_Name[] = "JBLTUNE125TWS_4";
const char kPopularPeripheral_JBLTUNE125TWS_5_ModelId[] = "BD193B";
const char kPopularPeripheral_JBLTUNE125TWS_5_Name[] = "JBLTUNE125TWS_5";

const char kPopularPeripheral_JBLTUNE130NCTWS_ModelId[] = "BDB433";
const char kPopularPeripheral_JBLTUNE130NCTWS_Name[] = "JBLTUNE130NCTWS";
const char kPopularPeripheral_JBLTUNE130NCTWS_1_ModelId[] = "1115E7";
const char kPopularPeripheral_JBLTUNE130NCTWS_1_Name[] = "JBLTUNE130NCTWS_1";
const char kPopularPeripheral_JBLTUNE130NCTWS_2_ModelId[] = "436FD1";
const char kPopularPeripheral_JBLTUNE130NCTWS_2_Name[] = "JBLTUNE130NCTWS_2";
const char kPopularPeripheral_JBLTUNE130NCTWS_3_ModelId[] = "B73DBA";
const char kPopularPeripheral_JBLTUNE130NCTWS_3_Name[] = "JBLTUNE130NCTWS_3";

const char kPopularPeripheral_JBLTUNE225TWS_ModelId[] = "5C0C84";
const char kPopularPeripheral_JBLTUNE225TWS_Name[] = "JBLTUNE225TWS";
const char kPopularPeripheral_JBLTUNE225TWS_1_ModelId[] = "FAA6C3";
const char kPopularPeripheral_JBLTUNE225TWS_1_Name[] = "JBLTUNE225TWS_1";
const char kPopularPeripheral_JBLTUNE225TWS_2_ModelId[] = "9BC64D";
const char kPopularPeripheral_JBLTUNE225TWS_2_Name[] = "JBLTUNE225TWS_2";
const char kPopularPeripheral_JBLTUNE225TWS_3_ModelId[] = "B8393A";
const char kPopularPeripheral_JBLTUNE225TWS_3_Name[] = "JBLTUNE225TWS_3";
const char kPopularPeripheral_JBLTUNE225TWS_4_ModelId[] = "5BD6C9";
const char kPopularPeripheral_JBLTUNE225TWS_4_Name[] = "JBLTUNE225TWS_4";
const char kPopularPeripheral_JBLTUNE225TWS_5_ModelId[] = "9C98DB";
const char kPopularPeripheral_JBLTUNE225TWS_5_Name[] = "JBLTUNE225TWS_5";

const char kPopularPeripheral_JBLTUNE230NCTWS_ModelId[] = "96C12E";
const char kPopularPeripheral_JBLTUNE230NCTWS_Name[] = "JBLTUNE230NCTWS";
const char kPopularPeripheral_JBLTUNE230NCTWS_1_ModelId[] = "71F20A";
const char kPopularPeripheral_JBLTUNE230NCTWS_1_Name[] = "JBLTUNE230NCTWS_1";
const char kPopularPeripheral_JBLTUNE230NCTWS_2_ModelId[] = "EB01C0";
const char kPopularPeripheral_JBLTUNE230NCTWS_2_Name[] = "JBLTUNE230NCTWS_2";
const char kPopularPeripheral_JBLTUNE230NCTWS_3_ModelId[] = "A9394A";
const char kPopularPeripheral_JBLTUNE230NCTWS_3_Name[] = "JBLTUNE230NCTWS_3";

const char kPopularPeripheral_NothingEar1_ModelId[] = "31D53D";
const char kPopularPeripheral_NothingEar1_Name[] = "NOTHINGEAR1";
const char kPopularPeripheral_NothingEar1_1_ModelId[] = "624011";
const char kPopularPeripheral_NothingEar1_1_Name[] = "NOTHINGEAR1_1";

const char kPopularPeripheral_OnePlusBuds_ModelId[] = "5F5806";
const char kPopularPeripheral_OnePlusBuds_Name[] = "OnePlusBuds";
const char kPopularPeripheral_OnePlusBuds_1_ModelId[] = "81B915";
const char kPopularPeripheral_OnePlusBuds_1_Name[] = "OnePlusBuds_1";
const char kPopularPeripheral_OnePlusBuds_2_ModelId[] = "6C73F1";
const char kPopularPeripheral_OnePlusBuds_2_Name[] = "OnePlusBuds_2";

const char kPopularPeripheral_OnePlusBudsZ_ModelId[] = "A41C91";
const char kPopularPeripheral_OnePlusBudsZ_Name[] = "OnePlusBudsZ";
const char kPopularPeripheral_OnePlusBudsZ_1_ModelId[] = "1393DE";
const char kPopularPeripheral_OnePlusBudsZ_1_Name[] = "OnePlusBudsZ_1";
const char kPopularPeripheral_OnePlusBudsZ_2_ModelId[] = "E07634";
const char kPopularPeripheral_OnePlusBudsZ_2_Name[] = "OnePlusBudsZ_2";

const char kPopularPeripheral_PixelBuds_ModelId[] = "060000";
const char kPopularPeripheral_PixelBuds_Name[] = "PixelBuds";

const char kPopularPeripheral_PixelBudsASeries_ModelId[] = "718C17";
const char kPopularPeripheral_PixelBudsASeries_Name[] = "PixelBudsASeries";
const char kPopularPeripheral_PixelBudsASeries_1_ModelId[] = "8B66AB";
const char kPopularPeripheral_PixelBudsASeries_1_Name[] = "PixelBudsASeries_1";
const char kPopularPeripheral_PixelBudsASeries_2_ModelId[] = "3E7540";
const char kPopularPeripheral_PixelBudsASeries_2_Name[] = "PixelBudsASeries_2";

const char kPopularPeripheral_PixelBudsPro_ModelId[] = "F2020E";
const char kPopularPeripheral_PixelBudsPro_Name[] = "PixelBudsPro";
const char kPopularPeripheral_PixelBudsPro_1_ModelId[] = "6EDAF7";
const char kPopularPeripheral_PixelBudsPro_1_Name[] = "PixelBudsPro_1";
const char kPopularPeripheral_PixelBudsPro_2_ModelId[] = "5A36A5";
const char kPopularPeripheral_PixelBudsPro_2_Name[] = "PixelBudsPro_2";
const char kPopularPeripheral_PixelBudsPro_3_ModelId[] = "F58DE7";
const char kPopularPeripheral_PixelBudsPro_3_Name[] = "PixelBudsPro_3";
const char kPopularPeripheral_PixelBudsPro_4_ModelId[] = "9ADB11";
const char kPopularPeripheral_PixelBudsPro_4_Name[] = "PixelBudsPro_4";

const char kPopularPeripheral_RealMeBudsAirPro_ModelId[] = "8CD10F";
const char kPopularPeripheral_RealMeBudsAirPro_Name[] = "RealMeBudsAirPro";
const char kPopularPeripheral_RealMeBudsAirPro_1_ModelId[] = "A6E1A6";
const char kPopularPeripheral_RealMeBudsAirPro_1_Name[] = "RealMeBudsAirPro_1";
const char kPopularPeripheral_RealMeBudsAirPro_2_ModelId[] = "2F208E";
const char kPopularPeripheral_RealMeBudsAirPro_2_Name[] = "RealMeBudsAirPro_2";

const char kPopularPeripheral_RealMeBudsAir2_ModelId[] = "BA5D56";
const char kPopularPeripheral_RealMeBudsAir2_Name[] = "RealMeBudsAir2";

const char kPopularPeripheral_RealMeBudsAir2Neo_ModelId[] = "0B5374";
const char kPopularPeripheral_RealMeBudsAir2Neo_Name[] = "RealMeBudsAir2Neo";

const char kPopularPeripheral_RealMeBudsQ2TWS_ModelId[] = "72C415";
const char kPopularPeripheral_RealMeBudsQ2TWS_Name[] = "RealMeBudsQ2TWS";

const char kPopularPeripheral_RealMeTechLifeBudsT100_ModelId[] = "29C992";
const char kPopularPeripheral_RealMeTechLifeBudsT100_Name[] =
    "RealMeTechLifeBudsT100";
const char kPopularPeripheral_RealMeTechLifeBudsT100_1_ModelId[] = "D5C6CE";
const char kPopularPeripheral_RealMeTechLifeBudsT100_1_Name[] =
    "RealMeTechLifeBudsT100_1";
const char kPopularPeripheral_RealMeTechLifeBudsT100_2_ModelId[] = "62E69F";
const char kPopularPeripheral_RealMeTechLifeBudsT100_2_Name[] =
    "RealMeTechLifeBudsT100_2";

const char kPopularPeripheral_SonyWF1000XM3_ModelId[] = "38C95C";
const char kPopularPeripheral_SonyWF1000XM3_Name[] = "SonyWF1000XM3";
const char kPopularPeripheral_SonyWF1000XM3_1_ModelId[] = "9C98DB";
const char kPopularPeripheral_SonyWF1000XM3_1_Name[] = "SonyWF1000XM3_1";
const char kPopularPeripheral_SonyWF1000XM3_2_ModelId[] = "3BC95C";
const char kPopularPeripheral_SonyWF1000XM3_2_Name[] = "SonyWF1000XM3_2";
const char kPopularPeripheral_SonyWF1000XM3_3_ModelId[] = "3AC95C";
const char kPopularPeripheral_SonyWF1000XM3_3_Name[] = "SonyWF1000XM3_3";
const char kPopularPeripheral_SonyWF1000XM3_4_ModelId[] = "0AC95C";
const char kPopularPeripheral_SonyWF1000XM3_4_Name[] = "SonyWF1000XM3_4";
const char kPopularPeripheral_SonyWF1000XM3_5_ModelId[] = "0DC95C";
const char kPopularPeripheral_SonyWF1000XM3_5_Name[] = "SonyWF1000XM3_5";
const char kPopularPeripheral_SonyWF1000XM3_6_ModelId[] = "0BC95C";
const char kPopularPeripheral_SonyWF1000XM3_6_Name[] = "SonyWF1000XM3_6";
const char kPopularPeripheral_SonyWF1000XM3_7_ModelId[] = "0CC95C";
const char kPopularPeripheral_SonyWF1000XM3_7_Name[] = "SonyWF1000XM3_7";

const char kPopularPeripheral_SonyWH1000XM3_ModelId[] = "0BC95C";
const char kPopularPeripheral_SonyWH1000XM3_Name[] = "SonyWH1000XM3";
const char kPopularPeripheral_SonyWH1000XM3_1_ModelId[] = "AC95C";
const char kPopularPeripheral_SonyWH1000XM3_1_Name[] = "SonyWH1000XM3_1";

const char kPopularPeripheral_SRSXB13_ModelId[] = "741594";
const char kPopularPeripheral_SRSXB13_Name[] = "SRSXB13";
const char kPopularPeripheral_SRSXB13_1_ModelId[] = "DF4B02";
const char kPopularPeripheral_SRSXB13_1_Name[] = "SRSXB13_1";
const char kPopularPeripheral_SRSXB13_2_ModelId[] = "F5CEC7";
const char kPopularPeripheral_SRSXB13_2_Name[] = "SRSXB13_2";
const char kPopularPeripheral_SRSXB13_3_ModelId[] = "FFB35B";
const char kPopularPeripheral_SRSXB13_3_Name[] = "SRSXB13_3";
const char kPopularPeripheral_SRSXB13_4_ModelId[] = "36EFA5";
const char kPopularPeripheral_SRSXB13_4_Name[] = "SRSXB13_4";
const char kPopularPeripheral_SRSXB13_5_ModelId[] = "3E6B5B";
const char kPopularPeripheral_SRSXB13_5_Name[] = "SRSXB13_5";

const char kPopularPeripheral_SRSXB23_ModelId[] = "30D222";
const char kPopularPeripheral_SRSXB23_Name[] = "SRSXB23";
const char kPopularPeripheral_SRSXB23_1_ModelId[] = "438188";
const char kPopularPeripheral_SRSXB23_1_Name[] = "SRSXB23_1";
const char kPopularPeripheral_SRSXB23_2_ModelId[] = "4A9EF6";
const char kPopularPeripheral_SRSXB23_2_Name[] = "SRSXB23_2";
const char kPopularPeripheral_SRSXB23_3_ModelId[] = "6ABCC9";
const char kPopularPeripheral_SRSXB23_3_Name[] = "SRSXB23_3";
const char kPopularPeripheral_SRSXB23_4_ModelId[] = "3414EB";
const char kPopularPeripheral_SRSXB23_4_Name[] = "SRSXB23_4";

const char kPopularPeripheral_SRSXB33_ModelId[] = "20330C";
const char kPopularPeripheral_SRSXB33_Name[] = "SRSXB33";
const char kPopularPeripheral_SRSXB33_1_ModelId[] = "91DABC";
const char kPopularPeripheral_SRSXB33_1_Name[] = "SRSXB33_1";
const char kPopularPeripheral_SRSXB33_2_ModelId[] = "E5B91B";
const char kPopularPeripheral_SRSXB33_2_Name[] = "SRSXB33_2";
const char kPopularPeripheral_SRSXB33_3_ModelId[] = "5A0DDA";
const char kPopularPeripheral_SRSXB33_3_Name[] = "SRSXB33_3";

const char kPopularPeripheral_Other_Name[] = "Other";

const std::string GetFastPairTrackedModelId(const std::string& model_id) {
  if (model_id == kPopularPeripheral_BoatRockerz255Pro_ModelId) {
    return kPopularPeripheral_BoatRockerz255Pro_Name;
  }

  if (model_id == kPopularPeripheral_BoseQuietComfort35II_ModelId) {
    return kPopularPeripheral_BoseQuietComfort35II_Name;
  }
  if (model_id == kPopularPeripheral_BoseQuietComfort35II_1_ModelId) {
    return kPopularPeripheral_BoseQuietComfort35II_1_Name;
  }

  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_1_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_2_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_3_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_3_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_4_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_4_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_5_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_5_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVEPROTWS_6_ModelId) {
    return kPopularPeripheral_JBLLIVEPROTWS_6_Name;
  }

  if (model_id == kPopularPeripheral_JBLLIVE300TWS_ModelId) {
    return kPopularPeripheral_JBLLIVE300TWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE300TWS_1_ModelId) {
    return kPopularPeripheral_JBLLIVE300TWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE300TWS_2_ModelId) {
    return kPopularPeripheral_JBLLIVE300TWS_2_Name;
  }

  if (model_id == kPopularPeripheral_JBLLIVE400BT_ModelId) {
    return kPopularPeripheral_JBLLIVE400BT_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE400BT_1_ModelId) {
    return kPopularPeripheral_JBLLIVE400BT_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE400BT_2_ModelId) {
    return kPopularPeripheral_JBLLIVE400BT_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE400BT_3_ModelId) {
    return kPopularPeripheral_JBLLIVE400BT_3_Name;
  }
  if (model_id == kPopularPeripheral_JBLLIVE400BT_4_ModelId) {
    return kPopularPeripheral_JBLLIVE400BT_4_Name;
  }

  if (model_id == kPopularPeripheral_JBLTUNE125TWS_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE125TWS_1_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE125TWS_2_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE125TWS_3_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_3_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE125TWS_4_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_4_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE125TWS_5_ModelId) {
    return kPopularPeripheral_JBLTUNE125TWS_5_Name;
  }

  if (model_id == kPopularPeripheral_JBLTUNE130NCTWS_ModelId) {
    return kPopularPeripheral_JBLTUNE130NCTWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE130NCTWS_1_ModelId) {
    return kPopularPeripheral_JBLTUNE130NCTWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE130NCTWS_2_ModelId) {
    return kPopularPeripheral_JBLTUNE130NCTWS_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE130NCTWS_3_ModelId) {
    return kPopularPeripheral_JBLTUNE130NCTWS_3_Name;
  }

  if (model_id == kPopularPeripheral_JBLTUNE225TWS_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE225TWS_1_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE225TWS_2_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE225TWS_3_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_3_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE225TWS_4_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_4_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE225TWS_5_ModelId) {
    return kPopularPeripheral_JBLTUNE225TWS_5_Name;
  }

  if (model_id == kPopularPeripheral_JBLTUNE230NCTWS_ModelId) {
    return kPopularPeripheral_JBLTUNE230NCTWS_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE230NCTWS_1_ModelId) {
    return kPopularPeripheral_JBLTUNE230NCTWS_1_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE230NCTWS_2_ModelId) {
    return kPopularPeripheral_JBLTUNE230NCTWS_2_Name;
  }
  if (model_id == kPopularPeripheral_JBLTUNE230NCTWS_3_ModelId) {
    return kPopularPeripheral_JBLTUNE230NCTWS_3_Name;
  }

  if (model_id == kPopularPeripheral_NothingEar1_ModelId) {
    return kPopularPeripheral_NothingEar1_Name;
  }
  if (model_id == kPopularPeripheral_NothingEar1_1_ModelId) {
    return kPopularPeripheral_NothingEar1_1_Name;
  }

  if (model_id == kPopularPeripheral_OnePlusBuds_ModelId) {
    return kPopularPeripheral_OnePlusBuds_Name;
  }
  if (model_id == kPopularPeripheral_OnePlusBuds_1_ModelId) {
    return kPopularPeripheral_OnePlusBuds_1_Name;
  }
  if (model_id == kPopularPeripheral_OnePlusBuds_2_ModelId) {
    return kPopularPeripheral_OnePlusBuds_2_Name;
  }

  if (model_id == kPopularPeripheral_OnePlusBudsZ_ModelId) {
    return kPopularPeripheral_OnePlusBudsZ_Name;
  }
  if (model_id == kPopularPeripheral_OnePlusBudsZ_1_ModelId) {
    return kPopularPeripheral_OnePlusBudsZ_1_Name;
  }
  if (model_id == kPopularPeripheral_OnePlusBudsZ_2_ModelId) {
    return kPopularPeripheral_OnePlusBudsZ_2_Name;
  }

  if (model_id == kPopularPeripheral_PixelBuds_ModelId) {
    return kPopularPeripheral_PixelBuds_Name;
  }

  if (model_id == kPopularPeripheral_PixelBudsASeries_ModelId) {
    return kPopularPeripheral_PixelBudsASeries_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsASeries_1_ModelId) {
    return kPopularPeripheral_PixelBudsASeries_1_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsASeries_2_ModelId) {
    return kPopularPeripheral_PixelBudsASeries_2_Name;
  }

  if (model_id == kPopularPeripheral_PixelBudsPro_ModelId) {
    return kPopularPeripheral_PixelBudsPro_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsPro_1_ModelId) {
    return kPopularPeripheral_PixelBudsPro_1_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsPro_2_ModelId) {
    return kPopularPeripheral_PixelBudsPro_2_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsPro_3_ModelId) {
    return kPopularPeripheral_PixelBudsPro_3_Name;
  }
  if (model_id == kPopularPeripheral_PixelBudsPro_4_ModelId) {
    return kPopularPeripheral_PixelBudsPro_4_Name;
  }

  if (model_id == kPopularPeripheral_RealMeBudsAir2_ModelId) {
    return kPopularPeripheral_RealMeBudsAir2_Name;
  }

  if (model_id == kPopularPeripheral_RealMeBudsAir2Neo_ModelId) {
    return kPopularPeripheral_RealMeBudsAir2Neo_Name;
  }

  if (model_id == kPopularPeripheral_RealMeBudsAirPro_ModelId) {
    return kPopularPeripheral_RealMeBudsAirPro_Name;
  }
  if (model_id == kPopularPeripheral_RealMeBudsAirPro_1_ModelId) {
    return kPopularPeripheral_RealMeBudsAirPro_1_Name;
  }
  if (model_id == kPopularPeripheral_RealMeBudsAirPro_2_ModelId) {
    return kPopularPeripheral_RealMeBudsAirPro_2_Name;
  }

  if (model_id == kPopularPeripheral_RealMeBudsQ2TWS_ModelId) {
    return kPopularPeripheral_RealMeBudsQ2TWS_Name;
  }

  if (model_id == kPopularPeripheral_RealMeTechLifeBudsT100_ModelId) {
    return kPopularPeripheral_RealMeTechLifeBudsT100_Name;
  }
  if (model_id == kPopularPeripheral_RealMeTechLifeBudsT100_1_ModelId) {
    return kPopularPeripheral_RealMeTechLifeBudsT100_1_Name;
  }
  if (model_id == kPopularPeripheral_RealMeTechLifeBudsT100_2_ModelId) {
    return kPopularPeripheral_RealMeTechLifeBudsT100_2_Name;
  }

  if (model_id == kPopularPeripheral_SonyWF1000XM3_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_1_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_1_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_2_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_2_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_3_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_3_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_4_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_4_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_5_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_5_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_6_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_6_Name;
  }
  if (model_id == kPopularPeripheral_SonyWF1000XM3_7_ModelId) {
    return kPopularPeripheral_SonyWF1000XM3_7_Name;
  }

  if (model_id == kPopularPeripheral_SonyWH1000XM3_ModelId) {
    return kPopularPeripheral_SonyWH1000XM3_Name;
  }
  if (model_id == kPopularPeripheral_SonyWH1000XM3_1_ModelId) {
    return kPopularPeripheral_SonyWH1000XM3_1_Name;
  }

  if (model_id == kPopularPeripheral_SRSXB33_ModelId) {
    return kPopularPeripheral_SRSXB33_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB33_1_ModelId) {
    return kPopularPeripheral_SRSXB33_1_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB33_2_ModelId) {
    return kPopularPeripheral_SRSXB33_2_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB33_3_ModelId) {
    return kPopularPeripheral_SRSXB33_3_Name;
  }

  if (model_id == kPopularPeripheral_SRSXB23_ModelId) {
    return kPopularPeripheral_SRSXB23_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB23_1_ModelId) {
    return kPopularPeripheral_SRSXB23_1_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB23_2_ModelId) {
    return kPopularPeripheral_SRSXB23_2_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB23_3_ModelId) {
    return kPopularPeripheral_SRSXB23_3_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB23_4_ModelId) {
    return kPopularPeripheral_SRSXB23_4_Name;
  }

  if (model_id == kPopularPeripheral_SRSXB13_ModelId) {
    return kPopularPeripheral_SRSXB13_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB13_1_ModelId) {
    return kPopularPeripheral_SRSXB13_1_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB13_2_ModelId) {
    return kPopularPeripheral_SRSXB13_2_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB13_3_ModelId) {
    return kPopularPeripheral_SRSXB13_3_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB13_4_ModelId) {
    return kPopularPeripheral_SRSXB13_4_Name;
  }
  if (model_id == kPopularPeripheral_SRSXB13_5_ModelId) {
    return kPopularPeripheral_SRSXB13_5_Name;
  }

  return kPopularPeripheral_Other_Name;
}

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. This enum should be kept in sync
// with the BluetoothConnectToServiceError enum in
// //tools/metrics/histograms/metadata/bluetooth/enums.xml.
enum class ConnectToServiceError {
  kUnknownError = 0,
  kAcceptFailed = 1,
  kInvalidUUID = 2,
  kSocketNotListening = 3,
  kMaxValue = kSocketNotListening,
};

ConnectToServiceError GetConnectToServiceError(const std::string& error) {
  if (error == kAcceptFailedString) {
    return ConnectToServiceError::kAcceptFailed;
  }

  if (error == kInvalidUUIDString) {
    return ConnectToServiceError::kInvalidUUID;
  }

  if (error == kSocketNotListeningString) {
    return ConnectToServiceError::kSocketNotListening;
  }

  DCHECK(error != kSocketNotListeningString && error != kInvalidUUIDString &&
         error != kAcceptFailedString);
  return ConnectToServiceError::kUnknownError;
}

std::optional<std::string> GetFastPairDeviceType(
    const nearby::fastpair::Device& device_metadata) {
  // Needs to stay up to date with `DeviceType` enum in
  // ash/quick_pair/proto/enums.proto. We only expect these device
  // types because of filtering in the scanning component. Always expected to
  // be one of these values.
  if (device_metadata.device_type() ==
      nearby::fastpair::DeviceType::HEADPHONES) {
    return kDeviceTypeHeadphones;
  } else if (device_metadata.device_type() ==
             nearby::fastpair::DeviceType::SPEAKER) {
    return kDeviceTypeSpeaker;
  } else if (device_metadata.device_type() ==
             nearby::fastpair::DeviceType::TRUE_WIRELESS_HEADPHONES) {
    return kDeviceTypeTrueWirelessHeadphones;
  } else if (device_metadata.device_type() ==
             nearby::fastpair::DeviceType::MOUSE) {
    return kDeviceTypeMouse;
  } else if (device_metadata.device_type() ==
             nearby::fastpair::DeviceType::DEVICE_TYPE_UNSPECIFIED) {
    return kDeviceTypeUnspecified;
  }

  return std::nullopt;
}

std::optional<std::string> GetFastPairNotificationType(
    const nearby::fastpair::Device& device_metadata) {
  // Needs to stay up to date with `NotificationType` enum in
  // ash/quick_pair/proto/enums.proto. We only expect these notification
  // types because of filtering in the scanning component. Always expected to
  // be one of these values.
  DCHECK(device_metadata.notification_type() ==
             nearby::fastpair::NotificationType::FAST_PAIR ||
         device_metadata.notification_type() ==
             nearby::fastpair::NotificationType::FAST_PAIR_ONE ||
         device_metadata.notification_type() ==
             nearby::fastpair::NotificationType::NOTIFICATION_TYPE_UNSPECIFIED);
  if (device_metadata.notification_type() ==
      nearby::fastpair::NotificationType::FAST_PAIR) {
    return kNotificationTypeFastPair;
  } else if (device_metadata.notification_type() ==
             nearby::fastpair::NotificationType::FAST_PAIR_ONE) {
    return kNotificationTypeFastPairOne;
  } else if (device_metadata.notification_type() ==
             nearby::fastpair::NotificationType::
                 NOTIFICATION_TYPE_UNSPECIFIED) {
    return kNotificationTypeUnspecified;
  } else {
    return std::nullopt;
  }
}

const char kEngagementFlowInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.EngagementFunnel.Steps.InitialPairingProtocol";
const char kEngagementFlowSubsequentMetric[] =
    "Bluetooth.ChromeOS.FastPair.EngagementFunnel.Steps."
    "SubsequentPairingProtocol";
const char kTotalUxPairTimeInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.TotalUxPairTime.InitialPairingProtocol2";
const char kTotalUxPairTimeSubsequentMetric[] =
    "Bluetooth.ChromeOS.FastPair.TotalUxPairTime.SubsequentPairingProtocol2";
const char kRetroactiveEngagementFlowMetric[] =
    "Bluetooth.ChromeOS.FastPair.RetroactiveEngagementFunnel.Steps";
const char kPairingMethodMetric[] = "Bluetooth.ChromeOS.FastPair.PairingMethod";
const char kRetroactivePairingResultMetric[] =
    "Bluetooth.ChromeOS.FastPair.RetroactivePairing.Result";
const char kTotalGattConnectionTimeMetric[] =
    "Bluetooth.ChromeOS.FastPair.TotalGattConnectionTime";
const char kGattConnectionResult[] =
    "Bluetooth.ChromeOS.FastPair.GattConnection.Result";
const char kGattConnectionErrorMetric[] =
    "Bluetooth.ChromeOS.FastPair.GattConnection.ErrorReason";
const char kGattConnectionEffectiveSuccessRate[] =
    "Bluetooth.ChromeOS.FastPair.GattConnection.EffectiveSuccessRate";
const char kGattConnectionAttemptCount[] =
    "Bluetooth.ChromeOS.FastPair.GattConnection.AttemptCount";
const char kFastPairGattRetryFailureReason[] =
    "Bluetooth.ChromeOS.FastPair.GattConnection.RetryFailureReason";
const char kFastPairPairFailureInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.PairFailure.InitialPairingProtocol";
const char kFastPairPairFailureSubsequentMetric[] =
    "Bluetooth.ChromeOS.FastPair.PairFailure.SubsequentPairingProtocol";
const char kFastPairPairFailureRetroactiveMetric[] =
    "Bluetooth.ChromeOS.FastPair.PairFailure.RetroactivePairingProtocol";
const char kFastPairPairResultInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.Pairing.Result.InitialPairingProtocol";
const char kFastPairPairResultSubsequentMetric[] =
    "Bluetooth.ChromeOS.FastPair.Pairing.Result.SubsequentPairingProtocol";
const char kFastPairPairResultRetroactiveMetric[] =
    "Bluetooth.ChromeOS.FastPair.Pairing.Result.RetroactivePairingProtocol";
const char kFastPairAccountKeyWriteResultInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.Result."
    "InitialPairingProtocol";
const char kFastPairAccountKeyWriteResultSubsequentMetric[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.Result."
    "SubsequentPairingProtocol";
const char kFastPairAccountKeyWriteResultRetroactiveMetric[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.Result."
    "RetroactivePairingProtocol";
const char kFastPairAccountKeyWriteFailureInitialMetric[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Failure.InitialPairingProtocol";
const char kFastPairAccountKeyWriteFailureRetroactiveMetric[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Failure.RetroactivePairingProtocol";
const char kKeyGenerationResultMetric[] =
    "Bluetooth.ChromeOS.FastPair.KeyGenerationResult";
const char kDataEncryptorCreateResultMetric[] =
    "Bluetooth.ChromeOS.FastPair.FastPairDataEncryptor.CreateResult";
const char kWriteKeyBasedCharacteristicResult[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.Write.Result";
const char kWriteKeyBasedCharacteristicPairFailure[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.Write.PairFailure";
const char kWriteKeyBasedCharacteristicGattError[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.Write.GattErrorReason";
const char kNotifyKeyBasedCharacteristicTime[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.NotifyTime";
const char kKeyBasedCharacteristicDecryptTime[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.DecryptTime";
const char kKeyBasedCharacteristicDecryptResult[] =
    "Bluetooth.ChromeOS.FastPair.KeyBasedPairing.DecryptResult";
const char kWritePasskeyCharacteristicResult[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.Write.Result";
const char kWritePasskeyCharacteristicPairFailure[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.Write.PairFailure";
const char kWritePasskeyCharacteristicGattError[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.Write.GattErrorReason";
const char kNotifyPasskeyCharacteristicTime[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.NotifyTime";
const char kPasskeyCharacteristicDecryptTime[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.Decrypt.Time";
const char kPasskeyCharacteristicDecryptResult[] =
    "Bluetooth.ChromeOS.FastPair.Passkey.Decrypt.Result";
const char kWriteAccountKeyCharacteristicResult[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.Result";
const char kWriteAccountKeyCharacteristicGattError[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.GattErrorReason";
const char kWriteAccountKeyTime[] =
    "Bluetooth.ChromeOS.FastPair.AccountKey.Write.TotalTime";
const char kTotalDataEncryptorCreateTime[] =
    "Bluetooth.ChromeOS.FastPair.FastPairDataEncryptor.CreateTime";
const char kMessageStreamReceiveResult[] =
    "Bluetooth.ChromeOS.FastPair.MessageStream.Receive.Result";
const char kMessageStreamReceiveError[] =
    "Bluetooth.ChromeOS.FastPair.MessageStream.Receive.ErrorReason";
const char kMessageStreamConnectToServiceError[] =
    "Bluetooth.ChromeOS.FastPair.MessageStream.ConnectToService.ErrorReason";
const char kMessageStreamConnectToServiceResult[] =
    "Bluetooth.ChromeOS.FastPair.MessageStream.ConnectToService.Result";
const char kMessageStreamConnectToServiceTime[] =
    "Bluetooth.ChromeOS.FastPair.MessageStream.ConnectToService."
    "TotalConnectTime";
const char kDeviceMetadataFetchResult[] =
    "Bluetooth.ChromeOS.FastPair.DeviceMetadataFetcher.Result";
const char kDeviceMetadataFetchNetError[] =
    "Bluetooth.ChromeOS.FastPair.DeviceMetadataFetcher.Get.NetError";
const char kDeviceMetadataFetchHttpResponseError[] =
    "Bluetooth.ChromeOS.FastPair.DeviceMetadataFetcher.Get.HttpResponseError";
const char kFootprintsFetcherDeleteResult[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Delete.Result";
const char kFootprintsFetcherDeleteNetError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Delete.NetError";
const char kFootprintsFetcherDeleteHttpResponseError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Delete.HttpResponseError";
const char kFootprintsFetcherPostResult[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Post.Result";
const char kFootprintsFetcherPostNetError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Post.NetError";
const char kFootprintsFetcherPostHttpResponseError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Post.HttpResponseError";
const char kFootprintsFetcherGetResult[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Get.Result";
const char kFootprintsFetcherGetNetError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Get.NetError";
const char kFootprintsFetcherGetHttpResponseError[] =
    "Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Get.HttpResponseError";
const char kFastPairRepositoryCacheResult[] =
    "Bluetooth.ChromeOS.FastPair.FastPairRepository.Cache.Result";
const char kHandshakeResult[] = "Bluetooth.ChromeOS.FastPair.Handshake.Result";
const char kFastPairHandshakeStepInitial[] =
    "Bluetooth.ChromeOS.FastPair.Handshake.Steps.InitialPairingProtocol";
const char kFastPairHandshakeStepSubsequent[] =
    "Bluetooth.ChromeOS.FastPair.Handshake.Steps.SubsequentPairingProtocol";
const char kFastPairHandshakeStepRetroactive[] =
    "Bluetooth.ChromeOS.FastPair.Handshake.Steps.RetroactivePairingProtocol";
const char kHandshakeFailureReason[] =
    "Bluetooth.ChromeOS.FastPair.Handshake.FailureReason";
const char kBleScanSessionResult[] =
    "Bluetooth.ChromeOS.FastPair.Scanner.StartSession.Result";
const char kBleScanFilterResult[] =
    "Bluetooth.ChromeOS.FastPair.CreateScanFilter.Result";
const char kFastPairVersion[] =
    "Bluetooth.ChromeOS.FastPair.Discovered.Version";
const char kNavigateToSettings[] =
    "Bluetooth.ChromeOS.FastPair.NavigateToSettings.Result";
const char kConnectDeviceResult[] =
    "Bluetooth.ChromeOS.FastPair.ConnectDevice.Result";
const char kPairDeviceResult[] =
    "Bluetooth.ChromeOS.FastPair.PairDevice.Result";
const char kPairDeviceErrorReason[] =
    "Bluetooth.ChromeOS.FastPair.PairDevice.ErrorReason";
const char kConfirmPasskeyAskTime[] =
    "Bluetooth.ChromeOS.FastPair.RequestPasskey.Latency";
const char kConfirmPasskeyConfirmTime[] =
    "Bluetooth.ChromeOS.FastPair.ConfirmPasskey.Latency";
const char kFastPairRetryCount[] =
    "Bluetooth.ChromeOS.FastPair.PairRetry.Count";
const char kSavedDeviceRemoveResult[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.Remove.Result";
const char kSavedDeviceUpdateOptInStatusInitialResult[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.UpdateOptInStatus.Result."
    "InitialPairingProtocol";
const char kSavedDeviceUpdateOptInStatusRetroactiveResult[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.UpdateOptInStatus.Result."
    "RetroactivePairingProtocol";
const char kSavedDeviceUpdateOptInStatusSubsequentResult[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.UpdateOptInStatus.Result."
    "SubsequentPairingProtocol";
const char kSavedDeviceGetDevicesResult[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.GetSavedDevices.Result";
const char kSavedDevicesTotalUxLoadTime[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.TotalUxLoadTime";
const char kSavedDevicesCount[] =
    "Bluetooth.ChromeOS.FastPair.SavedDevices.DeviceCount";
constexpr char kFastPairGattConnectionStep[] = "FastPair.GattConnection";
constexpr char kProtocolPairingStepInitial[] =
    "FastPair.InitialPairing.Pairing";
constexpr char kProtocolPairingStepSubsequent[] =
    "FastPair.SubsequentPairing.Pairing";
constexpr char kInitialSuccessFunnelMetric[] = "FastPair.InitialPairing";
constexpr char kSubsequentSuccessFunnelMetric[] = "FastPair.SubsequentPairing";
constexpr char kRetroactiveSuccessFunnelMetric[] =
    "FastPair.RetroactivePairing";
constexpr char kInitializePairingProcessInitial[] =
    "FastPair.InitialPairing.Initialization";
constexpr char kInitializePairingProcessSubsequent[] =
    "FastPair.SubsequentPairing.Initialization";
constexpr char kInitializePairingProcessRetroactive[] =
    "FastPair.RetroactivePairing.Initialization";
constexpr char kInitializePairingProcessFailureReasonInitial[] =
    "FastPair.InitialPairing.Initialization.FailureReason";
constexpr char kInitializePairingProcessFailureReasonSubsequent[] =
    "FastPair.SubsequentPairing.Initialization.FailureReason";
constexpr char kInitializePairingProcessFailureReasonRetroactive[] =
    "FastPair.RetroactivePairing.Initialization.FailureReason";
constexpr char kInitializePairingProcessRetriesBeforeSuccessInitial[] =
    "FastPair.InitialPairing.Initialization.RetriesBeforeSuccess";
constexpr char kInitializePairingProcessRetriesBeforeSuccessSubsequent[] =
    "FastPair.SubsequentPairing.Initialization.RetriesBeforeSuccess";
constexpr char kInitializePairingProcessRetriesBeforeSuccessRetroactive[] =
    "FastPair.RetroactivePairing.Initialization.RetriesBeforeSuccess";
const char kHandshakeEffectiveSuccessRate[] =
    "FastPair.Handshake.EffectiveSuccessRate";
const char kHandshakeAttemptCount[] = "FastPair.Handshake.AttemptCount";
const char kGattServiceDiscoveryTime[] =
    "FastPair.GattServiceDiscovery.Latency";
const char kCreateBondTime[] = "FastPair.CreateBond.Latency";
const char kPasskeyNotify[] = "FastPair.PasskeyNotify.Latency";
const char kKeyBasedNotify[] = "FastPair.KeyBasedNotify.Latency";
const char kPasskeyWriteRequest[] = "FastPair.PasskeyWriteRequest.Latency";
const char kKeyBasedWriteRequest[] = "FastPair.KeyBasedWriteRequest.Latency";

const std::string GetEngagementFlowInitialModelIdMetric(
    const ash::quick_pair::Device& device) {
  return std::string(kEngagementFlowInitialMetric) + "." +
         GetFastPairTrackedModelId(device.metadata_id());
}

const std::string GetEngagementFlowSubsequentModelIdMetric(
    const ash::quick_pair::Device& device) {
  return std::string(kEngagementFlowSubsequentMetric) + "." +
         GetFastPairTrackedModelId(device.metadata_id());
}

const std::string GetRetroactiveEngagementFlowModelIdMetric(
    const ash::quick_pair::Device& device) {
  return std::string(kRetroactiveEngagementFlowMetric) + "." +
         GetFastPairTrackedModelId(device.metadata_id());
}

// The retroactive engagement flow doesn't record retroactive successes
// properly due to b/240581398, so we use the account key write metric
// to record metrics split by model ID.
const std::string GetAccountKeyWriteResultRetroactiveModelIdMetric(
    const ash::quick_pair::Device& device) {
  return std::string(kFastPairAccountKeyWriteResultRetroactiveMetric) + "." +
         GetFastPairTrackedModelId(device.metadata_id());
}

std::optional<std::string>
GetEngagementFunnelInitialDeviceTypeNotificationTypeMetric(
    const nearby::fastpair::Device& device_metadata) {
  std::optional<std::string> device_type =
      GetFastPairDeviceType(device_metadata);
  std::optional<std::string> notification_type =
      GetFastPairNotificationType(device_metadata);

  if (!device_type || !notification_type) {
    return std::nullopt;
  }

  return std::string(kEngagementFlowInitialMetric) + "." + device_type.value() +
         "." + notification_type.value();
}

std::optional<std::string>
GetEngagementFunnelSubsequentDeviceTypeNotificationTypeMetric(
    const nearby::fastpair::Device& device_metadata) {
  std::optional<std::string> device_type =
      GetFastPairDeviceType(device_metadata);
  std::optional<std::string> notification_type =
      GetFastPairNotificationType(device_metadata);

  if (!device_type || !notification_type) {
    return std::nullopt;
  }

  return std::string(kEngagementFlowSubsequentMetric) + "." +
         device_type.value() + "." + notification_type.value();
}

std::optional<std::string>
GetEngagementFunnelRetroactiveDeviceTypeNotificationTypeMetric(
    const nearby::fastpair::Device& device_metadata) {
  std::optional<std::string> device_type =
      GetFastPairDeviceType(device_metadata);
  std::optional<std::string> notification_type =
      GetFastPairNotificationType(device_metadata);

  if (!device_type || !notification_type) {
    return std::nullopt;
  }

  return std::string(kRetroactiveEngagementFlowMetric) + "." +
         device_type.value() + "." + notification_type.value();
}

}  // namespace

namespace ash {
namespace quick_pair {

void RecordFastPairDeviceAndNotificationSpecificEngagementFlow(
    const Device& device,
    const nearby::fastpair::Device& device_details,
    FastPairEngagementFlowEvent event) {
  std::optional<std::string> funnel_name;

  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      funnel_name = GetEngagementFunnelInitialDeviceTypeNotificationTypeMetric(
          device_details);

      if (!funnel_name) {
        break;
      }

      base::UmaHistogramSparse(funnel_name.value(), static_cast<int>(event));
      break;
    // The retroactive pairing flow is not included here because it does not
    // involve a discovery notification or have an error notification on
    // failures. It's flow is captured in `FastPairRetroactiveFlowEvent`.
    case Protocol::kFastPairRetroactive:
      break;
    case Protocol::kFastPairSubsequent:
      funnel_name =
          GetEngagementFunnelSubsequentDeviceTypeNotificationTypeMetric(
              device_details);
      if (!funnel_name) {
        break;
      }

      base::UmaHistogramSparse(funnel_name.value(), static_cast<int>(event));
      break;
  }
}

void RecordFastPairDeviceAndNotificationSpecificRetroactiveEngagementFlow(
    const Device& device,
    const nearby::fastpair::Device& device_details,
    FastPairRetroactiveEngagementFlowEvent event) {
  std::optional<std::string> funnel_name;

  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      break;
    // This is only implemented for the retroactive pairing scenario since it's
    // flow is unique compared to the initial and subsequent flow : it shows
    // an associate account notification to start the scenario, whereas initial
    // and subsequent show a discovery notification, and there is no error
    // notification if there is a failure.
    case Protocol::kFastPairRetroactive:
      funnel_name =
          GetEngagementFunnelRetroactiveDeviceTypeNotificationTypeMetric(
              device_details);

      if (!funnel_name) {
        break;
      }

      base::UmaHistogramSparse(funnel_name.value(), static_cast<int>(event));
      break;
    case Protocol::kFastPairSubsequent:
      break;
  }
}

void AttemptRecordingFastPairEngagementFlow(const Device& device,
                                            FastPairEngagementFlowEvent event) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramSparse(kEngagementFlowInitialMetric,
                               static_cast<int>(event));
      // Also record engagement flow metrics split per tracked model ID.
      base::UmaHistogramSparse(GetEngagementFlowInitialModelIdMetric(device),
                               static_cast<int>(event));
      break;
    case Protocol::kFastPairRetroactive:
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramSparse(kEngagementFlowSubsequentMetric,
                               static_cast<int>(event));
      // Also record engagement flow metrics split per tracked model ID.
      base::UmaHistogramSparse(GetEngagementFlowSubsequentModelIdMetric(device),
                               static_cast<int>(event));
      break;
  }
}

void RecordInitialSuccessFunnelFlow(FastPairInitialSuccessFunnelEvent event) {
  base::UmaHistogramEnumeration(kInitialSuccessFunnelMetric, event);
}

void RecordSubsequentSuccessFunnelFlow(
    FastPairSubsequentSuccessFunnelEvent event) {
  base::UmaHistogramEnumeration(kSubsequentSuccessFunnelMetric, event);
}

void RecordRetroactiveSuccessFunnelFlow(
    FastPairRetroactiveSuccessFunnelEvent event) {
  base::UmaHistogramEnumeration(kRetroactiveSuccessFunnelMetric, event);
}

void RecordFastPairInitializePairingProcessEvent(
    const Device& device,
    FastPairInitializePairingProcessEvent event) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(kInitializePairingProcessInitial, event);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramEnumeration(kInitializePairingProcessRetroactive,
                                    event);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramEnumeration(kInitializePairingProcessSubsequent, event);
      break;
  }
}

void RecordInitializationFailureReason(const Device& device,
                                       PairFailure failure_reason) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(
          kInitializePairingProcessFailureReasonInitial, failure_reason);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramEnumeration(
          kInitializePairingProcessFailureReasonRetroactive, failure_reason);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramEnumeration(
          kInitializePairingProcessFailureReasonSubsequent, failure_reason);
      break;
  }
}

void RecordInitializationRetriesBeforeSuccess(const Device& device,
                                              int num_retries_before_success) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramExactLinear(
          kInitializePairingProcessRetriesBeforeSuccessInitial,
          num_retries_before_success,
          /*exclusive_max=*/10);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramExactLinear(
          kInitializePairingProcessRetriesBeforeSuccessRetroactive,
          num_retries_before_success,
          /*exclusive_max=*/10);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramExactLinear(
          kInitializePairingProcessRetriesBeforeSuccessSubsequent,
          num_retries_before_success,
          /*exclusive_max=*/10);
      break;
  }
}

void AttemptRecordingTotalUxPairTime(const Device& device,
                                     base::TimeDelta total_pair_time) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramCustomTimes(kTotalUxPairTimeInitialMetric,
                                    total_pair_time, base::Milliseconds(1),
                                    base::Seconds(25), 50);
      break;
    case Protocol::kFastPairRetroactive:
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramCustomTimes(kTotalUxPairTimeSubsequentMetric,
                                    total_pair_time, base::Milliseconds(1),
                                    base::Seconds(25), 50);
      break;
  }
}

void AttemptRecordingFastPairRetroactiveEngagementFlow(
    const Device& device,
    FastPairRetroactiveEngagementFlowEvent event) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
    case Protocol::kFastPairSubsequent:
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramSparse(kRetroactiveEngagementFlowMetric,
                               static_cast<int>(event));
      // Also record engagement flow metrics split per tracked model ID.
      base::UmaHistogramSparse(
          GetRetroactiveEngagementFlowModelIdMetric(device),
          static_cast<int>(event));
      break;
  }
}

void RecordPairingMethod(PairingMethod method) {
  base::UmaHistogramEnumeration(kPairingMethodMetric, method);
}

void RecordRetroactivePairingResult(bool success) {
  base::UmaHistogramBoolean(kRetroactivePairingResultMetric, success);
}

void RecordTotalGattConnectionTime(base::TimeDelta total_gatt_connection_time) {
  base::UmaHistogramTimes(kTotalGattConnectionTimeMetric,
                          total_gatt_connection_time);
}

void RecordGattConnectionResult(bool success) {
  base::UmaHistogramBoolean(kGattConnectionResult, success);
}

void RecordGattConnectionErrorCode(
    device::BluetoothDevice::ConnectErrorCode error_code) {
  base::UmaHistogramEnumeration(
      kGattConnectionErrorMetric, error_code,
      device::BluetoothDevice::ConnectErrorCode::NUM_CONNECT_ERROR_CODES);
}

void RecordEffectiveGattConnectionSuccess(bool success) {
  base::UmaHistogramBoolean(kGattConnectionEffectiveSuccessRate, success);
}

void RecordGattConnectionAttemptCount(int num_attempts) {
  base::UmaHistogramExactLinear(kGattConnectionAttemptCount, num_attempts,
                                /*exclusive_max=*/10);
}

void RecordGattRetryFailureReason(PairFailure failure) {
  base::UmaHistogramEnumeration(kFastPairGattRetryFailureReason, failure);
}

void RecordPairingResult(const Device& device, bool success) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramBoolean(kFastPairPairResultInitialMetric, success);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramBoolean(kFastPairPairResultRetroactiveMetric, success);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramBoolean(kFastPairPairResultSubsequentMetric, success);
      break;
  }
}

void RecordPairingFailureReason(const Device& device, PairFailure failure) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(kFastPairPairFailureInitialMetric, failure);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramEnumeration(kFastPairPairFailureRetroactiveMetric,
                                    failure);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramEnumeration(kFastPairPairFailureSubsequentMetric,
                                    failure);
      break;
  }
}

void RecordAccountKeyFailureReason(const Device& device,
                                   AccountKeyFailure failure) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(
          kFastPairAccountKeyWriteFailureInitialMetric, failure);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramEnumeration(
          kFastPairAccountKeyWriteFailureRetroactiveMetric, failure);
      break;
    case Protocol::kFastPairSubsequent:
      break;
  }
}

void RecordAccountKeyResult(const Device& device, bool success) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramBoolean(kFastPairAccountKeyWriteResultInitialMetric,
                                success);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramBoolean(kFastPairAccountKeyWriteResultRetroactiveMetric,
                                success);
      // Also record engagement flow metrics split per tracked model ID.
      base::UmaHistogramBoolean(
          GetAccountKeyWriteResultRetroactiveModelIdMetric(device), success);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramBoolean(kFastPairAccountKeyWriteResultSubsequentMetric,
                                success);
      break;
  }
}

void RecordKeyPairGenerationResult(bool success) {
  base::UmaHistogramBoolean(kKeyGenerationResultMetric, success);
}

void RecordDataEncryptorCreateResult(bool success) {
  base::UmaHistogramBoolean(kDataEncryptorCreateResultMetric, success);
}

void RecordWriteKeyBasedCharacteristicResult(bool success) {
  base::UmaHistogramBoolean(kWriteKeyBasedCharacteristicResult, success);
}

void RecordWriteKeyBasedCharacteristicPairFailure(PairFailure failure) {
  base::UmaHistogramEnumeration(kWriteKeyBasedCharacteristicPairFailure,
                                failure);
}

void RecordWriteRequestGattError(
    device::BluetoothGattService::GattErrorCode error) {
  base::UmaHistogramEnumeration(kWriteKeyBasedCharacteristicGattError, error);
}

void RecordNotifyKeyBasedCharacteristicTime(base::TimeDelta total_notify_time) {
  base::UmaHistogramTimes(kNotifyKeyBasedCharacteristicTime, total_notify_time);
}

void RecordKeyBasedCharacteristicDecryptTime(base::TimeDelta decrypt_time) {
  base::UmaHistogramTimes(kKeyBasedCharacteristicDecryptTime, decrypt_time);
}

void RecordKeyBasedCharacteristicDecryptResult(bool success) {
  base::UmaHistogramBoolean(kKeyBasedCharacteristicDecryptResult, success);
}

void RecordWritePasskeyCharacteristicResult(bool success) {
  base::UmaHistogramBoolean(kWritePasskeyCharacteristicResult, success);
}

void RecordWritePasskeyCharacteristicPairFailure(PairFailure failure) {
  base::UmaHistogramEnumeration(kWritePasskeyCharacteristicPairFailure,
                                failure);
}

void RecordWritePasskeyGattError(
    device::BluetoothGattService::GattErrorCode error) {
  base::UmaHistogramEnumeration(kWritePasskeyCharacteristicGattError, error);
}

void RecordNotifyPasskeyCharacteristicTime(base::TimeDelta total_notify_time) {
  base::UmaHistogramTimes(kNotifyPasskeyCharacteristicTime, total_notify_time);
}

void RecordPasskeyCharacteristicDecryptTime(base::TimeDelta decrypt_time) {
  base::UmaHistogramTimes(kPasskeyCharacteristicDecryptTime, decrypt_time);
}

void RecordPasskeyCharacteristicDecryptResult(bool success) {
  base::UmaHistogramBoolean(kPasskeyCharacteristicDecryptResult, success);
}

void RecordWriteAccountKeyCharacteristicResult(bool success) {
  base::UmaHistogramBoolean(kWriteAccountKeyCharacteristicResult, success);
}

void RecordWriteAccountKeyGattError(
    device::BluetoothGattService::GattErrorCode error) {
  base::UmaHistogramEnumeration(kWriteAccountKeyCharacteristicGattError, error);
}

void RecordWriteAccountKeyTime(base::TimeDelta write_time) {
  base::UmaHistogramTimes(kWriteAccountKeyTime, write_time);
}

void RecordTotalDataEncryptorCreateTime(base::TimeDelta total_create_time) {
  base::UmaHistogramTimes(kTotalDataEncryptorCreateTime, total_create_time);
}

void RecordMessageStreamReceiveResult(bool success) {
  base::UmaHistogramBoolean(kMessageStreamReceiveResult, success);
}

void RecordMessageStreamReceiveError(
    device::BluetoothSocket::ErrorReason error) {
  base::UmaHistogramEnumeration(kMessageStreamReceiveError, error);
}

void RecordMessageStreamConnectToServiceResult(bool success) {
  base::UmaHistogramBoolean(kMessageStreamConnectToServiceResult, success);
}

void RecordMessageStreamConnectToServiceError(const std::string& error) {
  base::UmaHistogramEnumeration(kMessageStreamConnectToServiceError,
                                GetConnectToServiceError(error));
}

void RecordMessageStreamConnectToServiceTime(
    base::TimeDelta total_connect_time) {
  base::UmaHistogramTimes(kMessageStreamConnectToServiceTime,
                          total_connect_time);
}

void RecordDeviceMetadataFetchResult(const FastPairHttpResult& result) {
  base::UmaHistogramBoolean(kDeviceMetadataFetchResult, result.IsSuccess());

  if (result.net_error()) {
    base::UmaHistogramSparse(kDeviceMetadataFetchNetError,
                             -*result.net_error());
  }

  if (result.http_response_error()) {
    base::UmaHistogramSparse(kDeviceMetadataFetchHttpResponseError,
                             *result.http_response_error());
  }
}

void RecordFootprintsFetcherDeleteResult(const FastPairHttpResult& result) {
  base::UmaHistogramBoolean(kFootprintsFetcherDeleteResult, result.IsSuccess());

  if (result.net_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherDeleteNetError,
                             -*result.net_error());
  }

  if (result.http_response_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherDeleteHttpResponseError,
                             *result.http_response_error());
  }
}

void RecordFootprintsFetcherPostResult(const FastPairHttpResult& result) {
  base::UmaHistogramBoolean(kFootprintsFetcherPostResult, result.IsSuccess());

  if (result.net_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherPostNetError,
                             -*result.net_error());
  }

  if (result.http_response_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherPostHttpResponseError,
                             *result.http_response_error());
  }
}

void RecordFootprintsFetcherGetResult(const FastPairHttpResult& result) {
  base::UmaHistogramBoolean(kFootprintsFetcherGetResult, result.IsSuccess());

  if (result.net_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherGetNetError,
                             -*result.net_error());
  }

  if (result.http_response_error()) {
    base::UmaHistogramSparse(kFootprintsFetcherGetHttpResponseError,
                             *result.http_response_error());
  }
}

void RecordFastPairRepositoryCacheResult(bool success) {
  base::UmaHistogramBoolean(kFastPairRepositoryCacheResult, success);
}

void RecordGattInitializationStep(
    FastPairGattConnectionSteps initialization_step) {
  base::UmaHistogramEnumeration(kFastPairGattConnectionStep,
                                initialization_step);
}

void RecordEffectiveHandshakeSuccess(bool success) {
  base::UmaHistogramBoolean(kHandshakeEffectiveSuccessRate, success);
}

void RecordHandshakeAttemptCount(int num_attempts) {
  base::UmaHistogramExactLinear(kHandshakeAttemptCount, num_attempts,
                                /*exclusive_max=*/10);
}

void RecordHandshakeResult(bool success) {
  base::UmaHistogramBoolean(kHandshakeResult, success);
}

void RecordHandshakeFailureReason(HandshakeFailureReason failure_reason) {
  base::UmaHistogramEnumeration(kHandshakeFailureReason, failure_reason);
}

void RecordProtocolPairingStep(FastPairProtocolPairingSteps pairing_step,
                               const Device& device) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(kProtocolPairingStepInitial, pairing_step);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramEnumeration(kProtocolPairingStepSubsequent,
                                    pairing_step);
      break;
    case Protocol::kFastPairRetroactive:
      break;
  }
}

void RecordHandshakeStep(FastPairHandshakeSteps handshake_step,
                         const Device& device) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramEnumeration(kFastPairHandshakeStepInitial,
                                    handshake_step);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramEnumeration(kFastPairHandshakeStepRetroactive,
                                    handshake_step);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramEnumeration(kFastPairHandshakeStepSubsequent,
                                    handshake_step);
      break;
  }
}

void RecordBluetoothLowEnergyScannerStartSessionResult(bool success) {
  base::UmaHistogramBoolean(kBleScanSessionResult, success);
}

void RecordBluetoothLowEnergyScanFilterResult(bool success) {
  base::UmaHistogramBoolean(kBleScanFilterResult, success);
}

void RecordFastPairDiscoveredVersion(FastPairVersion version) {
  base::UmaHistogramEnumeration(kFastPairVersion, version);
}

void RecordNavigateToSettingsResult(bool success) {
  base::UmaHistogramBoolean(kNavigateToSettings, success);
}

void RecordConnectDeviceResult(bool success) {
  base::UmaHistogramBoolean(kConnectDeviceResult, success);
}

void RecordPairDeviceResult(bool success) {
  base::UmaHistogramBoolean(kPairDeviceResult, success);
}

void RecordPairDeviceErrorReason(
    device::BluetoothDevice::ConnectErrorCode error_code) {
  base::UmaHistogramEnumeration(
      kPairDeviceErrorReason, error_code,
      device::BluetoothDevice::NUM_CONNECT_ERROR_CODES);
}

void RecordConfirmPasskeyConfirmTime(base::TimeDelta total_confirm_time) {
  base::UmaHistogramTimes(kConfirmPasskeyConfirmTime, total_confirm_time);
}

void RecordConfirmPasskeyAskTime(base::TimeDelta total_ask_time) {
  base::UmaHistogramTimes(kConfirmPasskeyAskTime, total_ask_time);
}

void RecordGattServiceDiscoveryTime(
    base::TimeDelta total_gatt_service_discovery_time) {
  base::UmaHistogramTimes(kGattServiceDiscoveryTime,
                          total_gatt_service_discovery_time);
}

void RecordCreateBondTime(base::TimeDelta total_create_bond_time) {
  base::UmaHistogramTimes(kCreateBondTime, total_create_bond_time);
}

void RecordPasskeyNotifyTime(base::TimeDelta total_passkey_notify_time) {
  base::UmaHistogramTimes(kPasskeyNotify, total_passkey_notify_time);
}

void RecordKeyBasedNotifyTime(base::TimeDelta total_key_based_notify_time) {
  base::UmaHistogramTimes(kKeyBasedNotify, total_key_based_notify_time);
}

void RecordPasskeyWriteRequestTime(
    base::TimeDelta total_passkey_write_request_time) {
  base::UmaHistogramTimes(kPasskeyWriteRequest,
                          total_passkey_write_request_time);
}

void RecordKeyBasedWriteRequestTime(
    base::TimeDelta total_key_based_write_request_time) {
  base::UmaHistogramTimes(kKeyBasedWriteRequest,
                          total_key_based_write_request_time);
}

void RecordPairFailureRetry(int num_retries) {
  base::UmaHistogramExactLinear(kFastPairRetryCount, num_retries,
                                /*exclusive_max=*/10);
}

void RecordSavedDevicesRemoveResult(bool success) {
  base::UmaHistogramBoolean(kSavedDeviceRemoveResult, success);
}

void RecordSavedDevicesUpdatedOptInStatusResult(const Device& device,
                                                bool success) {
  switch (device.protocol()) {
    case Protocol::kFastPairInitial:
      base::UmaHistogramBoolean(kSavedDeviceUpdateOptInStatusInitialResult,
                                success);
      break;
    case Protocol::kFastPairRetroactive:
      base::UmaHistogramBoolean(kSavedDeviceUpdateOptInStatusRetroactiveResult,
                                success);
      break;
    case Protocol::kFastPairSubsequent:
      base::UmaHistogramBoolean(kSavedDeviceUpdateOptInStatusSubsequentResult,
                                success);
      break;
  }
}

void RecordGetSavedDevicesResult(bool success) {
  base::UmaHistogramBoolean(kSavedDeviceGetDevicesResult, success);
}

void RecordSavedDevicesTotalUxLoadTime(base::TimeDelta total_load_time) {
  base::UmaHistogramCustomTimes(kSavedDevicesTotalUxLoadTime, total_load_time,
                                base::Milliseconds(1), base::Seconds(25), 50);
}

void RecordSavedDevicesCount(int num_devices) {
  base::UmaHistogramCounts100(kSavedDevicesCount, num_devices);
}

int ConvertFastPairVersionToInt(std::optional<DeviceFastPairVersion> version) {
  if (!version) {
    return 0;
  }

  switch (version.value()) {
    case DeviceFastPairVersion::kV1:
      return 1;
    case DeviceFastPairVersion::kHigherThanV1:
      return 2;
  }
}

int GetRSSI(const device::BluetoothDevice* bt_device) {
  int rssi = kUnknownRSSI;
  if (bt_device) {
    if (bt_device->GetInquiryRSSI().has_value()) {
      rssi = bt_device->GetInquiryRSSI().value();
    }
  }
  return rssi;
}

int GetTxPower(const device::BluetoothDevice* bt_device) {
  int tx_power = kUnknownTxPower;
  if (bt_device) {
    if (bt_device->GetInquiryTxPower().has_value()) {
      tx_power = bt_device->GetInquiryTxPower().value();
    }
  }
  return tx_power;
}

// TODO(b/266739400): There is currently no way to properly unittest these
// changes. The metrics team plans on implementing a way to mock out the
// structured metrics client in the near future. We should follow up and
// implement proper tests for these functions once that is available.
void RecordStructuredDiscoveryNotificationShown(
    const Device& device,
    const device::BluetoothDevice* bt_device) {
  CD_LOG(INFO, Feature::FP) << __func__;
  int model_id;
  if (!base::HexStringToInt(device.metadata_id(), &model_id)) {
    return;
  }
  int version = ConvertFastPairVersionToInt(device.version());
  int rssi = GetRSSI(bt_device);
  int tx_power = GetTxPower(bt_device);
  CD_LOG(VERBOSE, Feature::FP)
      << __func__ << ": RSSI: " << rssi << ", TxPower: " << tx_power;
  metrics::structured::StructuredMetricsClient::Record(std::move(
      metrics::structured::events::v2::fast_pair::DiscoveryNotificationShown()
          .SetProtocol(static_cast<int>(device.protocol()))
          .SetModelId(model_id)
          .SetFastPairVersion(version)
          .SetRSSI(rssi)
          .SetTxPower(tx_power)));
}

void RecordStructuredPairingStarted(const Device& device,
                                    const device::BluetoothDevice* bt_device) {
  CD_LOG(INFO, Feature::FP) << __func__;
  int model_id;
  if (!base::HexStringToInt(device.metadata_id(), &model_id)) {
    return;
  }
  int version = ConvertFastPairVersionToInt(device.version());
  int rssi = GetRSSI(bt_device);
  int tx_power = GetTxPower(bt_device);
  CD_LOG(VERBOSE, Feature::FP)
      << __func__ << ": RSSI: " << rssi << ", TxPower: " << tx_power;
  metrics::structured::StructuredMetricsClient::Record(
      std::move(metrics::structured::events::v2::fast_pair::PairingStart()
                    .SetProtocol(static_cast<int>(device.protocol()))
                    .SetModelId(model_id)
                    .SetFastPairVersion(version)
                    .SetRSSI(rssi)
                    .SetTxPower(tx_power)));
}

void RecordStructuredPairingComplete(const Device& device,
                                     const device::BluetoothDevice* bt_device) {
  CD_LOG(INFO, Feature::FP) << __func__;
  int model_id;
  if (!base::HexStringToInt(device.metadata_id(), &model_id)) {
    return;
  }
  int version = ConvertFastPairVersionToInt(device.version());
  int rssi = GetRSSI(bt_device);
  int tx_power = GetTxPower(bt_device);
  CD_LOG(VERBOSE, Feature::FP)
      << __func__ << ": RSSI: " << rssi << ", TxPower: " << tx_power;
  metrics::structured::StructuredMetricsClient::Record(
      std::move(metrics::structured::events::v2::fast_pair::PairingComplete()
                    .SetProtocol(static_cast<int>(device.protocol()))
                    .SetModelId(model_id)
                    .SetFastPairVersion(version)
                    .SetRSSI(rssi)
                    .SetTxPower(tx_power)));
}

void RecordStructuredPairFailure(const Device& device, PairFailure failure) {
  CD_LOG(INFO, Feature::FP) << __func__;
  int model_id;
  if (!base::HexStringToInt(device.metadata_id(), &model_id)) {
    return;
  }
  int version = ConvertFastPairVersionToInt(device.version());
  metrics::structured::StructuredMetricsClient::Record(
      std::move(metrics::structured::events::v2::fast_pair::PairFailure()
                    .SetProtocol(static_cast<int>(device.protocol()))
                    .SetModelId(model_id)
                    .SetReason(static_cast<int>(failure))
                    .SetFastPairVersion(version)));
}

}  // namespace quick_pair
}  // namespace ash