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 "shutdown_dialog.h"
17
18 #include <atomic>
19 #include <fstream>
20 #include <memory>
21 #include <set>
22 #include <string_ex.h>
23
24 #include <ability_manager_client.h>
25 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
26 #include <input_manager.h>
27 #include <key_event.h>
28 #include <key_option.h>
29 #endif
30 #include <message_parcel.h>
31
32 #include "config_policy_utils.h"
33 #include "json/reader.h"
34 #include "json/value.h"
35 #include "power_log.h"
36 #include "power_mgr_service.h"
37 #include "power_vibrator.h"
38
39 using namespace OHOS::MMI;
40 using namespace OHOS::AAFwk;
41
42 namespace OHOS {
43 namespace PowerMgr {
44 namespace {
45 static constexpr int32_t LONG_PRESS_DELAY_MS = 3000;
46 static constexpr int32_t INVALID_USERID = -1;
47 static constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
48 static constexpr int32_t INIT_LONG_PRESS_RETRY = 3;
49 static constexpr uint32_t RETRY_TIME = 1000;
50 std::atomic_bool g_isDialogShow = false;
51 std::atomic_bool g_longPressShow = false;
52 int32_t g_retryCount = 1;
53 sptr<IRemoteObject> g_remoteObject = nullptr;
54 const std::string DIALOG_CONFIG_PATH = "etc/systemui/poweroff_config.json";
55 } // namespace
56
57 std::string ShutdownDialog::bundleName_ = "com.ohos.powerdialog";
58 std::string ShutdownDialog::abilityName_ = "PowerUiExtensionAbility";
59 std::string ShutdownDialog::uiExtensionType_ = "sysDialog/power";
60 std::string ShutdownDialog::dialogBundleName_ = "com.ohos.systemui";
61 std::string ShutdownDialog::dialogAbilityName_ = "com.ohos.systemui.dialog";
62
ShutdownDialog()63 ShutdownDialog::ShutdownDialog() : dialogConnectionCallback_(new DialogAbilityConnection()) {}
64
~ShutdownDialog()65 ShutdownDialog::~ShutdownDialog()
66 {
67 dialogConnectionCallback_ = nullptr;
68 }
69
KeyMonitorInit()70 void ShutdownDialog::KeyMonitorInit()
71 {
72 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
73 POWER_HILOGD(FEATURE_SHUTDOWN, "Initialize the long press powerkey");
74 std::shared_ptr<KeyOption> keyOption = std::make_shared<KeyOption>();
75 std::set<int32_t> preKeys;
76
77 keyOption->SetPreKeys(preKeys);
78 keyOption->SetFinalKey(KeyEvent::KEYCODE_POWER);
79 keyOption->SetFinalKeyDown(true);
80 keyOption->SetFinalKeyDownDuration(LONG_PRESS_DELAY_MS);
81 longPressId_ =
82 InputManager::GetInstance()->SubscribeKeyEvent(keyOption, [this](std::shared_ptr<KeyEvent> keyEvent) {
83 POWER_HILOGI(FEATURE_SHUTDOWN, "Receive long press powerkey");
84 ConnectSystemUi();
85 StartVibrator();
86 });
87 if (longPressId_ < ERR_OK) {
88 if (g_retryCount <= INIT_LONG_PRESS_RETRY) {
89 POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press failed errcode = %{public}d, Try again in 1 second",
90 longPressId_);
91 FFRTTask task = [this] {
92 KeyMonitorInit();
93 };
94 FFRTUtils::SubmitDelayTask(task, RETRY_TIME, queue_);
95 g_retryCount++;
96 }
97 return;
98 }
99 POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press success");
100 #endif
101 }
102
KeyMonitorCancel()103 void ShutdownDialog::KeyMonitorCancel()
104 {
105 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
106 InputManager* inputManager = InputManager::GetInstance();
107 if (inputManager == nullptr) {
108 POWER_HILOGW(FEATURE_SHUTDOWN, "InputManager is null");
109 return;
110 }
111 if (longPressId_ >= ERR_OK) {
112 inputManager->UnsubscribeKeyEvent(longPressId_);
113 }
114 longPressId_ = 0;
115 #endif
116 }
117
ConnectSystemUi()118 bool ShutdownDialog::ConnectSystemUi()
119 {
120 if (g_isDialogShow) {
121 AppExecFwk::ElementName element;
122 dialogConnectionCallback_->OnAbilityConnectDone(element, g_remoteObject, INVALID_USERID);
123 POWER_HILOGW(FEATURE_SHUTDOWN, "power dialog has been show");
124 return true;
125 }
126 auto ams = AbilityManagerClient::GetInstance();
127 if (ams == nullptr) {
128 POWER_HILOGW(FEATURE_SHUTDOWN, "AbilityManagerClient is nullptr");
129 return false;
130 }
131
132 Want want;
133 want.SetElementName(dialogBundleName_, dialogAbilityName_);
134 ErrCode result = ams->ConnectAbility(want, dialogConnectionCallback_, INVALID_USERID);
135 if (result != ERR_OK) {
136 POWER_HILOGW(FEATURE_SHUTDOWN, "ConnectAbility systemui dialog failed, result = %{public}d", result);
137 return false;
138 }
139 POWER_HILOGI(FEATURE_SHUTDOWN, "ConnectAbility systemui dialog success.");
140 return true;
141 }
142
IsLongPress() const143 bool ShutdownDialog::IsLongPress() const
144 {
145 return g_longPressShow;
146 }
147
ResetLongPressFlag()148 void ShutdownDialog::ResetLongPressFlag()
149 {
150 g_longPressShow = false;
151 }
152
LoadDialogConfig()153 void ShutdownDialog::LoadDialogConfig()
154 {
155 char buf[MAX_PATH_LEN];
156 char* configPath = GetOneCfgFile(DIALOG_CONFIG_PATH.c_str(), buf, MAX_PATH_LEN);
157 if (configPath == nullptr || *configPath == '\0') {
158 POWER_HILOGI(COMP_UTILS, "do not find shutdown off json");
159 return;
160 }
161
162 std::ifstream inputStream(configPath, std::ios::in | std::ios::binary);
163 std::string contentStr(std::istreambuf_iterator<char> {inputStream}, std::istreambuf_iterator<char> {});
164 Json::Reader reader;
165 Json::Value root;
166 if (!reader.parse(contentStr.data(), contentStr.data() + contentStr.size(), root)) {
167 POWER_HILOGE(COMP_UTILS, "json parse error");
168 return;
169 }
170
171 if (root.isNull() || !root.isObject()) {
172 POWER_HILOGE(COMP_UTILS, "json root invalid[%{public}s]", contentStr.c_str());
173 return;
174 }
175
176 if (!root["bundleName"].isString() ||
177 !root["abilityName"].isString() || !root["uiExtensionType"].isString()) {
178 POWER_HILOGE(COMP_UTILS, "json varibale not support");
179 return;
180 }
181
182 bundleName_ = root["bundleName"].asString();
183 abilityName_ = root["abilityName"].asString();
184 uiExtensionType_ = root["uiExtensionType"].asString();
185 dialogBundleName_ = root["bundleName"].asString();
186 dialogAbilityName_ = "com.ohos.sceneboard.systemdialog";
187 POWER_HILOGI(COMP_UTILS, "PowerOff variables have changed");
188 }
189
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)190 void ShutdownDialog::DialogAbilityConnection::OnAbilityConnectDone(
191 const AppExecFwk::ElementName& element, const sptr<IRemoteObject>& remoteObject, int resultCode)
192 {
193 POWER_HILOGI(FEATURE_SHUTDOWN, "OnAbilityConnectDone");
194 std::lock_guard lock(mutex_);
195 if (remoteObject == nullptr) {
196 POWER_HILOGW(FEATURE_SHUTDOWN, "remoteObject is nullptr");
197 return;
198 }
199 if (g_remoteObject == nullptr) {
200 g_remoteObject = remoteObject;
201 }
202 FFRTUtils::SubmitTask([remoteObject] {
203 MessageParcel data;
204 MessageParcel reply;
205 MessageOption option;
206 data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
207 data.WriteString16(u"bundleName");
208 data.WriteString16(Str8ToStr16(ShutdownDialog::GetBundleName()));
209 data.WriteString16(u"abilityName");
210 data.WriteString16(Str8ToStr16(ShutdownDialog::GetAbilityName()));
211 data.WriteString16(u"parameters");
212 std::string midStr = "\"";
213 // sysDialogZOrder = 2 displayed on the lock screen
214 std::string paramStr = "{\"ability.want.params.uiExtensionType\":" + midStr +
215 ShutdownDialog::GetUiExtensionType() + midStr + ",\"sysDialogZOrder\":2}";
216 data.WriteString16(Str8ToStr16(paramStr));
217 POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is begin");
218 const uint32_t cmdCode = 1;
219 int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
220 if (ret != ERR_OK) {
221 POWER_HILOGW(FEATURE_SHUTDOWN, "show power dialog is failed: %{public}d", ret);
222 return;
223 }
224 g_isDialogShow = true;
225 g_longPressShow = true;
226 POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is success");
227 auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
228 if (pms == nullptr) {
229 return;
230 }
231 pms->RefreshActivityInner(
232 static_cast<int64_t>(time(nullptr)), UserActivityType::USER_ACTIVITY_TYPE_ATTENTION, false);
233 });
234 }
235
StartVibrator()236 void ShutdownDialog::StartVibrator()
237 {
238 std::shared_ptr<PowerVibrator> vibrator = PowerVibrator::GetInstance();
239 std::string scene = "shutdown_diag";
240 vibrator->StartVibrator(scene);
241 }
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)242 void ShutdownDialog::DialogAbilityConnection::OnAbilityDisconnectDone(
243 const AppExecFwk::ElementName& element, int resultCode)
244 {
245 POWER_HILOGD(FEATURE_SHUTDOWN, "OnAbilityDisconnectDone");
246 std::lock_guard lock(mutex_);
247 g_isDialogShow = false;
248 g_longPressShow = false;
249 g_remoteObject = nullptr;
250 }
251 } // namespace PowerMgr
252 } // namespace OHOS
253