195489c19Sopenharmony_ci/*
295489c19Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
395489c19Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
495489c19Sopenharmony_ci * you may not use this file except in compliance with the License.
595489c19Sopenharmony_ci * You may obtain a copy of the License at
695489c19Sopenharmony_ci *
795489c19Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
895489c19Sopenharmony_ci *
995489c19Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1095489c19Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1195489c19Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1295489c19Sopenharmony_ci * See the License for the specific language governing permissions and
1395489c19Sopenharmony_ci * limitations under the License.
1495489c19Sopenharmony_ci */
1595489c19Sopenharmony_ci
1695489c19Sopenharmony_ci#include "bluetooth_switch_module.h"
1795489c19Sopenharmony_ci
1895489c19Sopenharmony_ci#include <algorithm>
1995489c19Sopenharmony_ci#include "bluetooth_errorcode.h"
2095489c19Sopenharmony_ci#include "bluetooth_log.h"
2195489c19Sopenharmony_ci
2295489c19Sopenharmony_cinamespace OHOS {
2395489c19Sopenharmony_cinamespace Bluetooth {
2495489c19Sopenharmony_cistatic const char *ToString(BluetoothSwitchEvent event)
2595489c19Sopenharmony_ci{
2695489c19Sopenharmony_ci    switch (event) {
2795489c19Sopenharmony_ci        case BluetoothSwitchEvent::ENABLE_BLUETOOTH: return "ENABLE_BLUETOOTH";
2895489c19Sopenharmony_ci        case BluetoothSwitchEvent::DISABLE_BLUETOOTH: return "DISABLE_BLUETOOTH";
2995489c19Sopenharmony_ci        case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE: return "ENABLE_BLUETOOTH_TO_RESTRICE_MODE";
3095489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_ON: return "BLUETOOTH_ON";
3195489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_OFF: return "BLUETOOTH_OFF";
3295489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_HALF: return "BLUETOOTH_HALF";
3395489c19Sopenharmony_ci        default: break;
3495489c19Sopenharmony_ci    }
3595489c19Sopenharmony_ci    return "Unknown";
3695489c19Sopenharmony_ci}
3795489c19Sopenharmony_ci
3895489c19Sopenharmony_civoid BluetoothSwitchModule::LogBluetoothSwitchEvent(BluetoothSwitchEvent event)
3995489c19Sopenharmony_ci{
4095489c19Sopenharmony_ci    bool needLog = (event == BluetoothSwitchEvent::BLUETOOTH_ON ||
4195489c19Sopenharmony_ci        event == BluetoothSwitchEvent::BLUETOOTH_OFF ||
4295489c19Sopenharmony_ci        event == BluetoothSwitchEvent::BLUETOOTH_HALF) ? isBtSwitchProcessing_.load() : true;
4395489c19Sopenharmony_ci    if (needLog) {
4495489c19Sopenharmony_ci        HILOGI("Process Event: %{public}s", ToString(event));
4595489c19Sopenharmony_ci    }
4695489c19Sopenharmony_ci}
4795489c19Sopenharmony_ci
4895489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event)
4995489c19Sopenharmony_ci{
5095489c19Sopenharmony_ci    CHECK_AND_RETURN_LOG_RET(switchAction_, BT_ERR_INTERNAL_ERROR, "switchAction is nullptr");
5195489c19Sopenharmony_ci
5295489c19Sopenharmony_ci    std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
5395489c19Sopenharmony_ci    LogBluetoothSwitchEvent(event);
5495489c19Sopenharmony_ci    switch (event) {
5595489c19Sopenharmony_ci        case BluetoothSwitchEvent::ENABLE_BLUETOOTH:
5695489c19Sopenharmony_ci            return ProcessEnableBluetoothEvent();
5795489c19Sopenharmony_ci        case BluetoothSwitchEvent::DISABLE_BLUETOOTH:
5895489c19Sopenharmony_ci            return ProcessDisableBluetoothEvent();
5995489c19Sopenharmony_ci        case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE:
6095489c19Sopenharmony_ci            return ProcessEnableBluetoothToRestrictModeEvent();
6195489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_ON:
6295489c19Sopenharmony_ci            return ProcessBluetoothOnEvent();
6395489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_OFF:
6495489c19Sopenharmony_ci            return ProcessBluetoothOffEvent();
6595489c19Sopenharmony_ci        case BluetoothSwitchEvent::BLUETOOTH_HALF:
6695489c19Sopenharmony_ci            return ProcessBluetoothHalfEvent();
6795489c19Sopenharmony_ci        default: break;
6895489c19Sopenharmony_ci    }
6995489c19Sopenharmony_ci    HILOGI("Invalid event: %{public}s", ToString(event));
7095489c19Sopenharmony_ci    return BT_ERR_INTERNAL_ERROR;
7195489c19Sopenharmony_ci}
7295489c19Sopenharmony_ci
7395489c19Sopenharmony_civoid BluetoothSwitchModule::OnTaskTimeout(void)
7495489c19Sopenharmony_ci{
7595489c19Sopenharmony_ci    HILOGW("Bluetooth switch action timeout, clear resources");
7695489c19Sopenharmony_ci    std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
7795489c19Sopenharmony_ci    isBtSwitchProcessing_ = false;
7895489c19Sopenharmony_ci    cachedEventVec_.clear();
7995489c19Sopenharmony_ci}
8095489c19Sopenharmony_ci
8195489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothSwitchAction(
8295489c19Sopenharmony_ci    std::function<int(void)> action, BluetoothSwitchEvent cachedEvent)
8395489c19Sopenharmony_ci{
8495489c19Sopenharmony_ci    if (isBtSwitchProcessing_.load()) {
8595489c19Sopenharmony_ci        cachedEventVec_.push_back(cachedEvent);
8695489c19Sopenharmony_ci        HILOGW("BtSwich action is processing, cache the %{public}s event", ToString(cachedEvent));
8795489c19Sopenharmony_ci        return BT_NO_ERROR;
8895489c19Sopenharmony_ci    }
8995489c19Sopenharmony_ci
9095489c19Sopenharmony_ci    ffrt::task_attr taskAttr;
9195489c19Sopenharmony_ci    taskAttr.name("bt_switch").delay(taskTimeout_);
9295489c19Sopenharmony_ci    taskTimeoutHandle_ = ffrtQueue_.submit_h([switchWptr = weak_from_this()]() {
9395489c19Sopenharmony_ci        auto switchSptr = switchWptr.lock();
9495489c19Sopenharmony_ci        if (switchSptr == nullptr) {
9595489c19Sopenharmony_ci            HILOGE("switchSptr is nullptr");
9695489c19Sopenharmony_ci            return;
9795489c19Sopenharmony_ci        }
9895489c19Sopenharmony_ci        switchSptr->OnTaskTimeout();
9995489c19Sopenharmony_ci    }, taskAttr);
10095489c19Sopenharmony_ci
10195489c19Sopenharmony_ci    isBtSwitchProcessing_ = true;
10295489c19Sopenharmony_ci    int ret = action();
10395489c19Sopenharmony_ci    if (ret != BT_NO_ERROR) {
10495489c19Sopenharmony_ci        isBtSwitchProcessing_ = false;
10595489c19Sopenharmony_ci        ffrtQueue_.cancel(taskTimeoutHandle_);
10695489c19Sopenharmony_ci    }
10795489c19Sopenharmony_ci    return ret;
10895489c19Sopenharmony_ci}
10995489c19Sopenharmony_ci
11095489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessEnableBluetoothEvent(void)
11195489c19Sopenharmony_ci{
11295489c19Sopenharmony_ci    return ProcessBluetoothSwitchAction(
11395489c19Sopenharmony_ci        [this]() { return switchAction_->EnableBluetooth(); },
11495489c19Sopenharmony_ci        BluetoothSwitchEvent::ENABLE_BLUETOOTH);
11595489c19Sopenharmony_ci}
11695489c19Sopenharmony_ci
11795489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessDisableBluetoothEvent(void)
11895489c19Sopenharmony_ci{
11995489c19Sopenharmony_ci    return ProcessBluetoothSwitchAction(
12095489c19Sopenharmony_ci        [this]() { return switchAction_->DisableBluetooth(); },
12195489c19Sopenharmony_ci        BluetoothSwitchEvent::DISABLE_BLUETOOTH);
12295489c19Sopenharmony_ci}
12395489c19Sopenharmony_ci
12495489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessEnableBluetoothToRestrictModeEvent(void)
12595489c19Sopenharmony_ci{
12695489c19Sopenharmony_ci    return ProcessBluetoothSwitchAction(
12795489c19Sopenharmony_ci        [this]() { return switchAction_->EnableBluetoothToRestrictMode(); },
12895489c19Sopenharmony_ci        BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE);
12995489c19Sopenharmony_ci}
13095489c19Sopenharmony_ci
13195489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothOnEvent(void)
13295489c19Sopenharmony_ci{
13395489c19Sopenharmony_ci    return ProcessBluetoothSwitchActionEnd(
13495489c19Sopenharmony_ci        BluetoothSwitchEvent::ENABLE_BLUETOOTH,
13595489c19Sopenharmony_ci        {BluetoothSwitchEvent::DISABLE_BLUETOOTH});
13695489c19Sopenharmony_ci}
13795489c19Sopenharmony_ci
13895489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothOffEvent(void)
13995489c19Sopenharmony_ci{
14095489c19Sopenharmony_ci    return ProcessBluetoothSwitchActionEnd(
14195489c19Sopenharmony_ci        BluetoothSwitchEvent::DISABLE_BLUETOOTH,
14295489c19Sopenharmony_ci        {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE});
14395489c19Sopenharmony_ci}
14495489c19Sopenharmony_ci
14595489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothHalfEvent(void)
14695489c19Sopenharmony_ci{
14795489c19Sopenharmony_ci    return ProcessBluetoothSwitchActionEnd(
14895489c19Sopenharmony_ci        BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE,
14995489c19Sopenharmony_ci        {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::DISABLE_BLUETOOTH});
15095489c19Sopenharmony_ci}
15195489c19Sopenharmony_ci
15295489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothSwitchActionEnd(
15395489c19Sopenharmony_ci    BluetoothSwitchEvent curSwitchActionEvent, std::vector<BluetoothSwitchEvent> expectedEventVec)
15495489c19Sopenharmony_ci{
15595489c19Sopenharmony_ci    isBtSwitchProcessing_ = false;
15695489c19Sopenharmony_ci    ffrtQueue_.cancel(taskTimeoutHandle_);
15795489c19Sopenharmony_ci    DeduplicateCacheEvent(curSwitchActionEvent);
15895489c19Sopenharmony_ci
15995489c19Sopenharmony_ci    // Expect process the next event is in 'expectedProcessEventVec'
16095489c19Sopenharmony_ci    auto it = std::find_if(cachedEventVec_.begin(), cachedEventVec_.end(), [&expectedEventVec](auto event) {
16195489c19Sopenharmony_ci        return std::find(expectedEventVec.begin(), expectedEventVec.end(), event) != expectedEventVec.end();
16295489c19Sopenharmony_ci    });
16395489c19Sopenharmony_ci    if (it != cachedEventVec_.end()) {
16495489c19Sopenharmony_ci        if (it != cachedEventVec_.begin()) {
16595489c19Sopenharmony_ci            LogCacheEventIgnored(std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), it));
16695489c19Sopenharmony_ci        }
16795489c19Sopenharmony_ci        // Ignore the cached event before 'expectedEventVec'
16895489c19Sopenharmony_ci        BluetoothSwitchEvent event = *it;
16995489c19Sopenharmony_ci        cachedEventVec_.erase(cachedEventVec_.begin(), it + 1);
17095489c19Sopenharmony_ci        return ProcessBluetoothSwitchCachedEvent(event);
17195489c19Sopenharmony_ci    }
17295489c19Sopenharmony_ci
17395489c19Sopenharmony_ci    cachedEventVec_.clear();
17495489c19Sopenharmony_ci    return BT_NO_ERROR;
17595489c19Sopenharmony_ci}
17695489c19Sopenharmony_ci
17795489c19Sopenharmony_ciint BluetoothSwitchModule::ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)
17895489c19Sopenharmony_ci{
17995489c19Sopenharmony_ci    HILOGI("Auto process cached %{public}s event", ToString(event));
18095489c19Sopenharmony_ci    ffrtQueue_.submit([switchWptr = weak_from_this(), event]() {
18195489c19Sopenharmony_ci        auto switchSptr = switchWptr.lock();
18295489c19Sopenharmony_ci        if (switchSptr == nullptr) {
18395489c19Sopenharmony_ci            HILOGE("switchSptr is nullptr");
18495489c19Sopenharmony_ci            return;
18595489c19Sopenharmony_ci        }
18695489c19Sopenharmony_ci        switchSptr->ProcessBluetoothSwitchEvent(event);
18795489c19Sopenharmony_ci    });
18895489c19Sopenharmony_ci    return BT_NO_ERROR;
18995489c19Sopenharmony_ci}
19095489c19Sopenharmony_ci
19195489c19Sopenharmony_civoid BluetoothSwitchModule::DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)
19295489c19Sopenharmony_ci{
19395489c19Sopenharmony_ci    // 从缓存事件列表里,找到最后一个 curEvent,保留该事件之后的缓存事件
19495489c19Sopenharmony_ci    auto it = std::find(cachedEventVec_.rbegin(), cachedEventVec_.rend(), curEvent);
19595489c19Sopenharmony_ci    if (it != cachedEventVec_.rend()) {
19695489c19Sopenharmony_ci        // The it.base() is greater than cachedEventVec_.begin(), so std::distance > 0.
19795489c19Sopenharmony_ci        size_t pos = static_cast<size_t>(std::distance(cachedEventVec_.begin(), it.base())) - 1;
19895489c19Sopenharmony_ci
19995489c19Sopenharmony_ci        LogCacheEventIgnored(
20095489c19Sopenharmony_ci            std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1));
20195489c19Sopenharmony_ci        cachedEventVec_.erase(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1);
20295489c19Sopenharmony_ci    }
20395489c19Sopenharmony_ci}
20495489c19Sopenharmony_ci
20595489c19Sopenharmony_civoid BluetoothSwitchModule::LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)
20695489c19Sopenharmony_ci{
20795489c19Sopenharmony_ci    std::string log = "";
20895489c19Sopenharmony_ci    for (size_t i = 0; i < eventVec.size(); i++) {
20995489c19Sopenharmony_ci        // The last event current process event, not ignored
21095489c19Sopenharmony_ci        log += ToString(eventVec[i]);
21195489c19Sopenharmony_ci        log += " ";
21295489c19Sopenharmony_ci    }
21395489c19Sopenharmony_ci    if (!log.empty()) {
21495489c19Sopenharmony_ci        HILOGW("Ignore cache event: %{public}s", log.c_str());
21595489c19Sopenharmony_ci    }
21695489c19Sopenharmony_ci}
21795489c19Sopenharmony_ci}  // namespace Bluetooth
21895489c19Sopenharmony_ci}  // namespace OHOS
219