• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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