1 /*
2 * Copyright (c) 2024 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 "camera_picker_impl.h"
17 #include "bool_wrapper.h"
18 #include "cj_lambda.h"
19 #include "int_wrapper.h"
20 #include "string_wrapper.h"
21
22 using namespace std;
23
24 namespace OHOS::CameraStandard {
25 constexpr char CAMERA_PICKER_ABILITY_ACTION_PHOTO[] = "ohos.want.action.imageCapture";
26 constexpr char CAMERA_PICKER_ABILITY_ACTION_VIDEO[] = "ohos.want.action.videoCapture";
27
28 thread_local uint32_t cameraPickerTaskId = 0x08000000;
29
30 std::function<void(int32_t, std::string, std::string)> onResultCallBack = nullptr;
31
32 struct AsyncContext {
33 bool status;
34 int32_t taskId;
35 int32_t errorCode;
36 std::string errorMsg;
37 std::string funcName;
38 bool isInvalidArgument;
39 };
40
41 struct CameraPickerAsyncContext : public AsyncContext {
42 std::string resultUri;
43 std::string errorMsg;
44 PickerProfile pickerProfile;
45 AAFwk::Want want;
46 std::shared_ptr<PickerContextProxy> contextProxy;
47 std::shared_ptr<UIExtensionCallback> uiExtCallback;
48 int32_t resultCode;
49 bool bRetBool;
50 };
51
PickerMediaTypeToString(int32_t type)52 static string PickerMediaTypeToString(int32_t type)
53 {
54 if (type == 0) {
55 return "photo";
56 }
57 return "video";
58 }
59
StringToPickerMediaType(std::string type)60 static int32_t StringToPickerMediaType(std::string type)
61 {
62 if (type == "photo") {
63 return 0;
64 }
65 return 1;
66 }
67
CArrI32ToVector(const CArrI32 & cArr)68 static vector<string> CArrI32ToVector(const CArrI32 &cArr)
69 {
70 vector<string> ret;
71 for (int64_t i = 0; i < cArr.size; i++) {
72 ret.emplace_back(PickerMediaTypeToString(cArr.head[i]));
73 }
74 return ret;
75 }
76
MallocCString(const std::string & origin)77 char *MallocCString(const std::string &origin)
78 {
79 auto len = origin.length() + 1;
80 char *res = static_cast<char *>(malloc(sizeof(char) * len));
81 if (res == nullptr) {
82 return nullptr;
83 }
84 return std::char_traits<char>::copy(res, origin.c_str(), len);
85 }
86
UIExtensionCallback(std::shared_ptr<PickerContextProxy> contextProxy)87 UIExtensionCallback::UIExtensionCallback(std::shared_ptr<PickerContextProxy> contextProxy) : contextProxy_(contextProxy)
88 {
89 }
90
FinishPicker(int32_t code)91 bool UIExtensionCallback::FinishPicker(int32_t code)
92 {
93 {
94 std::unique_lock<std::mutex> lock(cbMutex_);
95 if (isCallbackReturned_) {
96 MEDIA_ERR_LOG("alreadyCallback");
97 return false;
98 }
99 isCallbackReturned_ = true;
100 }
101 resultCode_ = code;
102 CloseWindow();
103 NotifyResultLock();
104 return true;
105 }
106
OnRelease(int32_t releaseCode)107 void UIExtensionCallback::OnRelease(int32_t releaseCode)
108 {
109 MEDIA_INFO_LOG("UIExtensionComponent OnRelease(), releaseCode = %{public}d", releaseCode);
110 FinishPicker(releaseCode);
111 }
112
OnResult(int32_t resultCode,const OHOS::AAFwk::Want & result)113 void UIExtensionCallback::OnResult(int32_t resultCode, const OHOS::AAFwk::Want &result)
114 {
115 const AAFwk::WantParams &wantParams = result.GetParams();
116 std::string uri = wantParams.GetStringParam("resourceUri");
117 std::string resourceMode = wantParams.GetStringParam("mode");
118 MEDIA_INFO_LOG("OnResult is called,resultCode = %{public}d, uri = %{public}s ,CaptureMode:%{public}s", resultCode,
119 uri.c_str(), resourceMode.c_str());
120 resultUri_ = uri;
121 resultMode_ = resourceMode;
122 FinishPicker(resultCode);
123 if (onResultCallBack != nullptr) {
124 onResultCallBack(resultCode, uri, resourceMode);
125 }
126 }
127
OnReceive(const OHOS::AAFwk::WantParams & request)128 void UIExtensionCallback::OnReceive(const OHOS::AAFwk::WantParams &request)
129 {
130 MEDIA_INFO_LOG("UIExtensionComponent OnReceive()");
131 }
132
OnError(int32_t errorCode,const std::string & name,const std::string & message)133 void UIExtensionCallback::OnError(int32_t errorCode, const std::string &name, const std::string &message)
134 {
135 MEDIA_INFO_LOG("UIExtensionComponent OnError(), errorCode = %{public}d, name = %{public}s, message = %{public}s",
136 errorCode, name.c_str(), message.c_str());
137 FinishPicker(errorCode);
138 }
139
OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy> & uiProxy)140 void UIExtensionCallback::OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy> &uiProxy)
141 {
142 MEDIA_INFO_LOG("UIExtensionComponent OnRemoteReady()");
143 }
144
OnDestroy()145 void UIExtensionCallback::OnDestroy()
146 {
147 MEDIA_INFO_LOG("UIExtensionComponent OnDestroy()");
148 FinishPicker(0);
149 }
150
CloseWindow()151 void UIExtensionCallback::CloseWindow()
152 {
153 MEDIA_INFO_LOG("start CloseWindow");
154 if (contextProxy_ == nullptr) {
155 MEDIA_ERR_LOG("contextProxy_ is nullptr");
156 return;
157 }
158 auto uiContent = contextProxy_->GetUIContent();
159 if (uiContent != nullptr && sessionId_ != 0) {
160 MEDIA_INFO_LOG("CloseModalUIExtension");
161 uiContent->CloseModalUIExtension(sessionId_);
162 }
163 }
164
SetPickerWantParams(AAFwk::Want & want,std::shared_ptr<PickerContextProxy> & pickerContextProxy,const vector<string> & mediaTypes,PickerProfile & pickerProfile)165 static void SetPickerWantParams(AAFwk::Want &want, std::shared_ptr<PickerContextProxy> &pickerContextProxy,
166 const vector<string> &mediaTypes, PickerProfile &pickerProfile)
167 {
168 MEDIA_DEBUG_LOG("SetPickerWantParams enter");
169 AAFwk::WantParams wantParam;
170 bool isPhotoType = false;
171 bool isVideoType = false;
172 for (auto type : mediaTypes) {
173 MEDIA_INFO_LOG("SetPickerWantParams current type is:%{public}s", type.c_str());
174 if (type.compare(std::string("photo")) == 0) {
175 isPhotoType = true;
176 } else if (type.compare(std::string("video")) == 0) {
177 isVideoType = true;
178 }
179 }
180
181 want.SetUri(pickerProfile.saveUri);
182 want.SetFlags(AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION | AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION);
183 wantParam.SetParam("ability.want.params.uiExtensionTargetType", AAFwk::String::Box("cameraPicker"));
184 wantParam.SetParam("callBundleName", AAFwk::String::Box(pickerContextProxy->GetBundleName().c_str()));
185 wantParam.SetParam("cameraPosition", AAFwk::Integer::Box(pickerProfile.cameraPosition));
186 wantParam.SetParam("videoDuration", AAFwk::Integer::Box(pickerProfile.videoDuration));
187 wantParam.SetParam("saveUri", AAFwk::String::Box(pickerProfile.saveUri.c_str()));
188 if (isPhotoType && isVideoType) {
189 wantParam.SetParam("supportMultiMode", AAFwk::Boolean::Box(true));
190 }
191 want.SetParams(wantParam);
192 if (isPhotoType) {
193 want.SetAction(CAMERA_PICKER_ABILITY_ACTION_PHOTO);
194 } else if (isVideoType) {
195 want.SetAction(CAMERA_PICKER_ABILITY_ACTION_VIDEO);
196 } else {
197 MEDIA_ERR_LOG("SetPickerWantParams set action fail!");
198 }
199 MEDIA_DEBUG_LOG("SetPickerWantParams end");
200 }
201
StartCameraAbility(std::shared_ptr<PickerContextProxy> pickerContextProxy,AAFwk::Want & want)202 static std::shared_ptr<UIExtensionCallback> StartCameraAbility(std::shared_ptr<PickerContextProxy> pickerContextProxy,
203 AAFwk::Want &want)
204 {
205 auto uiExtCallback = std::make_shared<UIExtensionCallback>(pickerContextProxy);
206 OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
207 [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); },
208 [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want &result) {
209 uiExtCallback->OnResult(resultCode, result);
210 },
211 [uiExtCallback](const OHOS::AAFwk::WantParams &request) { uiExtCallback->OnReceive(request); },
212 [uiExtCallback](int32_t errorCode, const std::string &name, const std::string &message) {
213 uiExtCallback->OnError(errorCode, name, message);
214 },
215 [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy> &uiProxy) {
216 uiExtCallback->OnRemoteReady(uiProxy);
217 },
218 [uiExtCallback]() { uiExtCallback->OnDestroy(); }};
219 AbilityRuntime::RuntimeTask task = [extensionCallbacks](const int32_t code, const AAFwk::Want &returnWant,
220 bool isInner) {
221 if (code == 0) {
222 extensionCallbacks.onResult(0, returnWant);
223 } else {
224 extensionCallbacks.onError(code, "", "");
225 }
226 MEDIA_INFO_LOG("picker StartCameraAbility get result %{public}d %{public}d", code, isInner);
227 };
228
229 auto ret = pickerContextProxy->StartAbilityForResult(want, 1, std::move(task));
230 if (ret != ERR_OK) {
231 MEDIA_ERR_LOG("picker StartCameraAbility is %{public}d", ret);
232 return nullptr;
233 }
234 return uiExtCallback;
235 }
236
IncrementAndGet(uint32_t & num)237 static int32_t IncrementAndGet(uint32_t &num)
238 {
239 int32_t temp = num & 0x00ffffff;
240 if (temp >= 0xffff) {
241 num = num & 0xff000000;
242 }
243 num++;
244 return num;
245 }
246
Pick(OHOS::AbilityRuntime::Context * context,CArrI32 pickerMediaTypes,CJPickerProfile pickerProfile,int64_t callbackId)247 void Pick(OHOS::AbilityRuntime::Context *context, CArrI32 pickerMediaTypes, CJPickerProfile pickerProfile,
248 int64_t callbackId)
249 {
250 auto cFunc = reinterpret_cast<void (*)(CJPickerResult result)>(callbackId);
251 onResultCallBack = [lambda = CJLambda::Create(cFunc)](int32_t resultCode, std::string uri,
252 std::string type) -> void {
253 auto resultUri = MallocCString(uri);
254 auto mediaType = StringToPickerMediaType(type);
255 lambda(CJPickerResult{resultCode, resultUri, mediaType});
256 free(resultUri);
257 };
258
259 MEDIA_INFO_LOG("CameraPicker::Pick is called");
260 std::unique_ptr<CameraPickerAsyncContext> asyncCtx = std::make_unique<CameraPickerAsyncContext>();
261 auto contextSharedPtr = context->shared_from_this();
262 auto abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(contextSharedPtr);
263 asyncCtx->funcName = "CameraPicker::Pick";
264 asyncCtx->taskId = IncrementAndGet(cameraPickerTaskId);
265 asyncCtx->contextProxy = make_shared<PickerContextProxy>(abilityContext);
266 if (asyncCtx->contextProxy == nullptr) {
267 MEDIA_ERR_LOG("GetAbilityContext failed");
268 return;
269 }
270 auto mediaTypes = CArrI32ToVector(pickerMediaTypes);
271 asyncCtx->pickerProfile.cameraPosition = static_cast<CameraPosition>(pickerProfile.cameraPosition);
272 asyncCtx->pickerProfile.videoDuration = pickerProfile.videoDuration;
273 asyncCtx->pickerProfile.saveUri = std::string(pickerProfile.saveUri);
274 MEDIA_INFO_LOG("GetPickerProfile cameraPosition: %{public}d, duration: %{public}d",
275 asyncCtx->pickerProfile.cameraPosition, asyncCtx->pickerProfile.videoDuration);
276 MEDIA_INFO_LOG("GetPickerProfile saveUri: %{public}s", asyncCtx->pickerProfile.saveUri.c_str());
277 SetPickerWantParams(asyncCtx->want, asyncCtx->contextProxy, mediaTypes, asyncCtx->pickerProfile);
278 asyncCtx->uiExtCallback = StartCameraAbility(asyncCtx->contextProxy, asyncCtx->want);
279 if (asyncCtx->uiExtCallback == nullptr) {
280 MEDIA_ERR_LOG("StartCameraAbility failed");
281 return;
282 }
283 return;
284 }
285 } // namespace OHOS::CameraStandard