1/* 2 * Copyright (c) 2023-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 16import { configMgr, GlobalObject, GlobalThisHelper, GlobalThisStorageKey, MediaSizeHelper } from '@ohos/common'; 17import AppStorageHelper from '../Common/Adapter/AppStorageHelper'; 18import { Log } from '@ohos/common'; 19import { Constants, AppStorageKeyName, PreferencesKey } from '@ohos/common'; 20import type common from '@ohos.app.ability.common'; 21import PreferencesAdapter from '../Common/Adapter/PreferencesAdapter'; 22import bundleManager from '@ohos.bundle.bundleManager'; 23import PrintAdapter from '../Common/Adapter/PrintAdapter'; 24import { Configuration } from '@ohos.app.ability.Configuration'; 25import image from '@ohos.multimedia.image'; 26import Want from '@ohos.app.ability.Want'; 27import UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility'; 28import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; 29import CheckEmptyUtils from '@ohos/common'; 30import Queue from '@ohos.util.Queue'; 31import Util from '../Common/Utils/Util'; 32import type { PrintAttributes } from '@ohos/common'; 33 34const TAG = '[MainAbility]:'; 35 36export default class MainAbility extends UIExtensionAbility { 37 private lock: boolean = false; 38 private storeRequest = new Queue<RequestDialogModel>(); 39 private readonly PRIVACY_STATEMENT_STORE: string = 'privacyStatementStore'; 40 private session: UIExtensionContentSession | undefined = undefined; 41 42 onCreate(): void { 43 GlobalThisHelper.createValue<common.UIExtensionContext>(this.context, GlobalThisStorageKey.KEY_MAIN_ABILITY_CONTEXT, true); 44 MediaSizeHelper.init(this.context); 45 this.context.resourceManager.getConfiguration((error, value) => { 46 AppStorageHelper.createValue<string>(value.locale as string, AppStorageKeyName.CONFIG_LANGUAGE); 47 }); 48 49 bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT) 50 .then((bundleInfo) => { 51 AppStorageHelper.createValue<string>(bundleInfo.versionName as string, AppStorageKeyName.APP_VERSION); 52 }); 53 this.subscribe(); 54 } 55 56 onDestroy() { 57 // Main window is destroyed, release UI related resources 58 Log.info(TAG, 'onDestroy'); 59 let adapter = GlobalThisHelper.getValue<PrintAdapter>(GlobalThisStorageKey.KEY_PRINT_ADAPTER); 60 let previewPageInstances: number = AppStorageHelper.getValue(AppStorageKeyName.PREVIEW_PAGE_INSTANCE) as number; 61 if (previewPageInstances === 1) { 62 adapter?.getPrinterDiscCtl()?.stopDiscovery(''); 63 this.unsubscribe(); 64 } 65 AppStorageHelper.createValue<number>(previewPageInstances - 1, AppStorageKeyName.PREVIEW_PAGE_INSTANCE); 66 let pixelMap = GlobalThisHelper.getValue<image.PixelMap>(GlobalThisStorageKey.KEY_CURRENT_PIXELMAP); 67 if (pixelMap !== undefined) { 68 pixelMap.release().then(() => { 69 Log.info(TAG, 'onDestroy currentPixelMap release success'); 70 }); 71 } 72 GlobalObject.getInstance().removeObject(Constants.PREVIEW_IS_VERTICAL); 73 GlobalObject.getInstance().removeObject(Constants.PREVIEW_DIALOG_COUNT); 74 let res = AppStorageHelper.deleteValue(AppStorageKeyName.imageSourcesName); 75 Log.info(TAG, 'delete imageSources:' + res); 76 } 77 78 onSessionCreate(want: Want, session: UIExtensionContentSession): void { 79 Log.info(TAG + 'onSessionCreate, want: ' + JSON.stringify(want)); 80 this.session = session; 81 let fileList: string[] = []; 82 let callerPid: string = ''; 83 let pkgName: string = ''; 84 let docName: string = ''; 85 let attributes: string = ''; 86 let jobId: string = ''; 87 if (want.parameters !== undefined) { 88 fileList = want.parameters[Constants.WANT_FILE_LIST_KEY] as string[]; 89 Log.info(TAG + 'fileList: ' + JSON.stringify(fileList)); 90 91 callerPid = want.parameters[Constants.WANT_CALLERPID_KEY] as string; 92 pkgName = want.parameters[Constants.WANT_PKG_NAME_KEY] as string; 93 docName = want.parameters[Constants.WANT_DOCUMENT_NAME_KEY] as string; 94 attributes = want.parameters[Constants.wantPrintAttributeKey] as string; 95 jobId = want.parameters[Constants.WANT_JOB_ID_KEY] as string; 96 } 97 let printAttributes: PrintAttributes | undefined = undefined; 98 if (!CheckEmptyUtils.checkStrIsEmpty(attributes)) { 99 printAttributes = JSON.parse(attributes); 100 } 101 this.storeRequest.add(new RequestDialogModel(fileList, callerPid, pkgName, docName, printAttributes, jobId)); 102 this.consumeRequest(); 103 } 104 105 private consumeRequest(): void { 106 if (this.storeRequest.length === 0) { 107 Log.warn(TAG, 'no dialogRequest in queue.'); 108 return; 109 } 110 if (this.lock) { 111 Log.warn(TAG, 'consumer is busying: need waiting'); 112 return; 113 } 114 this.handleDialogRequest(this.storeRequest.pop(), this.requestCompleteCallback); 115 } 116 117 private async handleDialogRequest(model: RequestDialogModel, callback: (id: string) => void): Promise<void> { 118 GlobalThisHelper.createValue<string>(model.jobId, GlobalThisStorageKey.KEY_JOB_ID); 119 let dialogId = Util.getPreviewDialogId(model.jobId); 120 let pkgNameMap: Map<string, string> = AppStorageHelper.getValue<Map<string, string>>( 121 AppStorageKeyName.INGRESS_PACKAGE) ?? new Map<string, string>(); 122 let docNameMap: Map<string, string> = AppStorageHelper.getValue<Map<string, string>>( 123 AppStorageKeyName.DOCUMENT_NAME) ?? new Map<string, string>(); 124 let previewPageInstances: number = AppStorageHelper.getValue(AppStorageKeyName.PREVIEW_PAGE_INSTANCE) ?? 0; 125 pkgNameMap.set(dialogId, model.pkgName); 126 docNameMap.set(dialogId, model.docName); 127 AppStorageHelper.createValue<Map<string, string>>(pkgNameMap, AppStorageKeyName.INGRESS_PACKAGE); 128 AppStorageHelper.createValue<Map<string, string>>(docNameMap, AppStorageKeyName.DOCUMENT_NAME); 129 let storage: LocalStorage = new LocalStorage(); 130 storage.setOrCreate<string>(Constants.WANT_JOB_ID_KEY, model.jobId); 131 storage.setOrCreate(Constants.WANT_FILE_LIST_KEY, model.fileList ?? new Array<string>()); 132 storage.setOrCreate(Constants.wantPrintAttributeKey, model.printAttributes); 133 storage.setOrCreate(Constants.WINDOW_ID, dialogId); 134 storage.setOrCreate(Constants.SESSION, this.session); 135 136 let pageUrl = Constants.PRINT_PREVIEW_PAGE_URL; 137 await this.isFirstUsePrint().then((flag) => { 138 Log.info(TAG, 'isFirstUsePrint : ' + flag); 139 if (flag) { 140 pageUrl = Constants.PRIVACY_STATEMENT_PAGE_URL; 141 } else { 142 pageUrl = Constants.PRINT_PREVIEW_PAGE_URL; 143 } 144 }); 145 GlobalObject.getInstance().setObject(Constants.PREVIEW_DIALOG_COUNT, 146 (GlobalObject.getInstance().getObject(Constants.PREVIEW_DIALOG_COUNT) as number) + 1); 147 148 this.session?.loadContent(pageUrl, storage); 149 this.session?.setWindowBackgroundColor('#40000000'); 150 AppStorageHelper.createValue<number>(previewPageInstances + 1, AppStorageKeyName.PREVIEW_PAGE_INSTANCE); 151 callback(dialogId); 152 Log.debug(TAG, 'handleDialogRequest end.'); 153 } 154 155 private requestCompleteCallback = (dialogId: string): void => { 156 Log.info(TAG, `requestCompleteCallback CreateWindow:${JSON.stringify(dialogId)} completed`); 157 this.lock = false; 158 this.consumeRequest(); 159 }; 160 161 onConfigurationUpdated(config: Configuration): void { 162 Log.info(TAG, 'onConfigurationUpdated, language:' + config.language); 163 AppStorageHelper.createValue<string>(config.language as string, AppStorageKeyName.CONFIG_LANGUAGE); 164 } 165 166 onForeground() { 167 // Ability has brought to foreground 168 Log.info(TAG, 'onForeground'); 169 } 170 171 onBackground() { 172 // Ability has back to background 173 Log.info(TAG, 'onBackground'); 174 } 175 176 async isFirstUsePrint(): Promise<boolean> { 177 Log.info(TAG, 'isFirstUsePrint start'); 178 const success = await PreferencesAdapter.getInstance().getOrCreatePreferencesSync(this.PRIVACY_STATEMENT_STORE); 179 Log.info(TAG, 'isFirstUsePrint getOrCreatePreferencesSync success: ' + success); 180 if (success) { 181 const agreePrivacyStatement = await PreferencesAdapter.getInstance() 182 .getValue(PreferencesKey.KEY_PRIVACY_STATEMENT_PREFERENCES); 183 Log.info(TAG, 'isFirstUsePrint getValue agreePrivacyStatement: ' + agreePrivacyStatement); 184 if (agreePrivacyStatement) { 185 return false; 186 } else { 187 return true; 188 } 189 } else { 190 Log.info(TAG, 'isFirstUsePrint success is not'); 191 return true; 192 } 193 } 194 195 private subscribe(): void { 196 configMgr.onStart(this.context); 197 } 198 199 private unsubscribe(): void { 200 configMgr.onStop(); 201 } 202}; 203 204class RequestDialogModel { 205 fileList: Array<string>; 206 callerPid: string; 207 pkgName: string; 208 docName: string; 209 printAttributes: PrintAttributes | undefined; 210 jobId: string; 211 212 constructor(fileList: Array<string>, callerPid: string, pkgName: string, docName: string, 213 printAttributes: PrintAttributes | undefined, jobId: string) { 214 this.fileList = fileList; 215 this.callerPid = callerPid; 216 this.pkgName = pkgName; 217 this.docName = docName; 218 this.printAttributes = printAttributes; 219 this.jobId = jobId; 220 } 221} 222