1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "usb_function_switch_window.h"
17
18 #include <semaphore.h>
19 #include <sys/types.h>
20 #include <thread>
21 #include <unistd.h>
22
23 #include "cJSON.h"
24
25 #include "ability_manager_client.h"
26 #include "bundle_mgr_client.h"
27 #include "common_event_manager.h"
28 #include "common_event_support.h"
29 #include "usb_errors.h"
30
31 using namespace OHOS::AppExecFwk;
32 using namespace OHOS::EventFwk;
33
34 namespace OHOS {
35 namespace USB {
36 constexpr int32_t PARAM_BUF_LEN = 128;
37 constexpr int32_t INVALID_USERID = -1;
38 constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
39 constexpr int32_t MAX_RETRY_TIMES = 30;
40 constexpr int32_t RETRY_INTERVAL_SECONDS = 1;
41 constexpr uint32_t DELAY_CHECK_DIALOG = 1;
42
43 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::instance_;
44 std::mutex UsbFunctionSwitchWindow::insMutex_;
45
GetInstance()46 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::GetInstance()
47 {
48 std::lock_guard<std::mutex> guard(insMutex_);
49 if (instance_ == nullptr) {
50 USB_HILOGI(MODULE_USB_SERVICE, "reset to new instance");
51 instance_.reset(new UsbFunctionSwitchWindow());
52 }
53 return instance_;
54 }
55
UsbFunctionSwitchWindow()56 UsbFunctionSwitchWindow::UsbFunctionSwitchWindow() {}
57
~UsbFunctionSwitchWindow()58 UsbFunctionSwitchWindow::~UsbFunctionSwitchWindow()
59 {
60 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
61 (void)UnShowFunctionSwitchWindow();
62 }
63 }
64
Init()65 int32_t UsbFunctionSwitchWindow::Init()
66 {
67 USB_HILOGI(MODULE_USB_SERVICE, "init: window action=%{public}d,%{public}d", windowAction_, isDialogInstalled_);
68 if (isDialogInstalled_) {
69 return UEC_OK;
70 }
71
72 checkDialogTimer_.Unregister(checkDialogTimerId_);
73 checkDialogTimer_.Shutdown();
74 // async check dialog install status
75 auto task = [this]() {
76 CheckDialogInstallStatus();
77 checkDialogTimer_.Unregister(checkDialogTimerId_);
78 checkDialogTimer_.Shutdown();
79 };
80 auto ret = checkDialogTimer_.Setup();
81 if (ret != UEC_OK) {
82 USB_HILOGE(MODULE_USB_SERVICE, "set up timer failed %{public}u", ret);
83 // fall back to sync
84 CheckDialogInstallStatus();
85 return isDialogInstalled_ ? UEC_OK : ret;
86 }
87 checkDialogTimerId_ = checkDialogTimer_.Register(task, DELAY_CHECK_DIALOG, true);
88 return UEC_OK;
89 }
90
PopUpFunctionSwitchWindow()91 bool UsbFunctionSwitchWindow::PopUpFunctionSwitchWindow()
92 {
93 USB_HILOGI(MODULE_USB_SERVICE, "pop up function switch window");
94 char paramValue[PARAM_BUF_LEN] = { 0 };
95 const char defaultValue[PARAM_BUF_LEN] = { 0 };
96 std::lock_guard<std::mutex> guard(opMutex_);
97 int32_t ret = GetParameter("persist.usb.setting.gadget_conn_prompt", defaultValue, paramValue, sizeof(paramValue));
98 if (ret < 0) {
99 USB_HILOGE(MODULE_USB_SERVICE, "GetParameter fail");
100 return false;
101 }
102 ret = strcmp(paramValue, "true");
103 if (ret != 0) {
104 USB_HILOGE(MODULE_USB_SERVICE, "not allow open");
105 return false;
106 }
107 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
108 USB_HILOGI(MODULE_USB_SERVICE, "forbid: pop up function switch window");
109 return false;
110 }
111 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW;
112 return ShowFunctionSwitchWindow();
113 }
114
DismissFunctionSwitchWindow()115 bool UsbFunctionSwitchWindow::DismissFunctionSwitchWindow()
116 {
117 USB_HILOGI(MODULE_USB_SERVICE, "dismiss function switch window");
118 std::lock_guard<std::mutex> guard(opMutex_);
119 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
120 USB_HILOGI(MODULE_USB_SERVICE, "forbid: dismiss function switch window");
121 return false;
122 }
123 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_DISMISS;
124 return UnShowFunctionSwitchWindow();
125 }
126
OnAbilityConnectDone(const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int32_t resultCode)127 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
128 const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
129 {
130 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityConnectDone");
131 if (remoteObject == nullptr) {
132 USB_HILOGE(MODULE_USB_SERVICE, "remoteObject is nullptr");
133 return;
134 }
135
136 MessageParcel data;
137 MessageParcel reply;
138 MessageOption option;
139 data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
140 data.WriteString16(u"bundleName");
141 data.WriteString16(u"com.usb.right");
142 data.WriteString16(u"abilityName");
143 data.WriteString16(u"UsbFunctionSwitchExtAbility");
144 data.WriteString16(u"parameters");
145 cJSON* paramJson = cJSON_CreateObject();
146 std::string uiExtensionTypeStr = "sysDialog/common";
147 cJSON_AddStringToObject(paramJson, "ability.want.params.uiExtensionType", uiExtensionTypeStr.c_str());
148 char *pParamJson = cJSON_PrintUnformatted(paramJson);
149 cJSON_Delete(paramJson);
150 paramJson = nullptr;
151 if (!pParamJson) {
152 USB_HILOGE(MODULE_USB_SERVICE, "Print paramJson error");
153 return;
154 }
155 std::string paramStr(pParamJson);
156 data.WriteString16(Str8ToStr16(paramStr));
157 cJSON_free(pParamJson);
158 pParamJson = NULL;
159
160 const uint32_t cmdCode = 1;
161 int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
162 if (ret != ERR_OK) {
163 USB_HILOGI(MODULE_USB_SERVICE, "show dialog is failed: %{public}d", ret);
164 return;
165 }
166 remoteObject_ = remoteObject;
167 return;
168 }
169
OnAbilityDisconnectDone( const AppExecFwk::ElementName& element, int resultCode)170 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityDisconnectDone(
171 const AppExecFwk::ElementName& element, int resultCode)
172 {
173 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityDisconnectDone");
174 remoteObject_ = nullptr;
175 return;
176 }
177
CloseDialog()178 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::CloseDialog()
179 {
180 if (remoteObject_ == nullptr) {
181 USB_HILOGW(MODULE_USB_SERVICE, "CloseDialog: disconnected");
182 return;
183 }
184
185 MessageParcel data;
186 MessageParcel reply;
187 MessageOption option;
188 const uint32_t cmdCode = 3;
189 int32_t ret = remoteObject_->SendRequest(cmdCode, data, reply, option);
190 int32_t replyCode = -1;
191 bool success = false;
192 if (ret == ERR_OK) {
193 success = reply.ReadInt32(replyCode);
194 }
195 USB_HILOGI(MODULE_USB_SERVICE, "CloseDialog: ret=%{public}d, %{public}d, %{public}d", ret, success, replyCode);
196 }
197
ShowFunctionSwitchWindow()198 bool UsbFunctionSwitchWindow::ShowFunctionSwitchWindow()
199 {
200 USB_HILOGI(MODULE_USB_SERVICE, "show function switch window right now, installed: %{public}d", isDialogInstalled_);
201 if (!isDialogInstalled_) {
202 return false;
203 }
204
205 if (usbFuncAbilityConn == nullptr) {
206 usbFuncAbilityConn = sptr<UsbFuncAbilityConn>(new (std::nothrow) UsbFuncAbilityConn());
207 }
208
209 auto abilityManager = AAFwk::AbilityManagerClient::GetInstance();
210 if (abilityManager == nullptr) {
211 USB_HILOGE(MODULE_USB_SERVICE, "AbilityManagerClient is nullptr");
212 return false;
213 }
214
215 AAFwk::Want want;
216 want.SetElementName("com.ohos.sceneboard", "com.ohos.sceneboard.systemdialog");
217 auto ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
218 if (ret != ERR_OK) {
219 want.SetElementName("com.ohos.systemui", "com.ohos.systemui.dialog");
220 ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
221 if (ret != ERR_OK) {
222 USB_HILOGE(MODULE_USB_SERVICE, "ConnectServiceExtensionAbility systemui failed, ret: %{public}d", ret);
223 usbFuncAbilityConn = nullptr;
224 return false;
225 }
226 }
227 USB_HILOGI(MODULE_SERVICE, "StartAbility success, ret: %{public}d", ret);
228 return true;
229 }
230
UnShowFunctionSwitchWindow()231 bool UsbFunctionSwitchWindow::UnShowFunctionSwitchWindow()
232 {
233 if (usbFuncAbilityConn == nullptr) {
234 return true;
235 }
236
237 auto abmc = AAFwk::AbilityManagerClient::GetInstance();
238 if (abmc == nullptr) {
239 USB_HILOGE(MODULE_USB_SERVICE, "GetInstance failed");
240 return false;
241 }
242 USB_HILOGI(MODULE_USB_SERVICE, "unshow function switch window");
243 usbFuncAbilityConn->CloseDialog();
244
245 auto ret = abmc->DisconnectAbility(usbFuncAbilityConn);
246 if (ret != UEC_OK) {
247 USB_HILOGE(MODULE_SERVICE, "DisconnectAbility failed %{public}d", ret);
248 return false;
249 }
250 USB_HILOGD(MODULE_USB_SERVICE, "unshow function switch window success");
251 return true;
252 }
253
CheckDialogInstallStatus()254 bool UsbFunctionSwitchWindow::CheckDialogInstallStatus()
255 {
256 AppExecFwk::BundleInfo info;
257 AppExecFwk::BundleMgrClient bmc;
258 int32_t retryTimes = 0;
259 while (retryTimes < MAX_RETRY_TIMES) {
260 isDialogInstalled_ = bmc.GetBundleInfo(functionSwitchBundleName_,
261 AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, info, AppExecFwk::Constants::ALL_USERID);
262 USB_HILOGI(MODULE_USB_SERVICE, "check dialog, times=%{public}d,res=%{public}d", retryTimes, isDialogInstalled_);
263 if (!isDialogInstalled_) {
264 retryTimes++;
265 sleep(RETRY_INTERVAL_SECONDS);
266 continue;
267 }
268
269 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
270 ShowFunctionSwitchWindow();
271 }
272 return true;
273 }
274 USB_HILOGE(MODULE_USB_SERVICE, "dialog is not installed");
275 return false;
276 }
277 } // namespace USB
278 } // namespace OHOS
279