1/* 2 * Copyright (c) 2025-2025 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 UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; 17import opp from '@ohos.bluetooth.opp'; 18import common from '@ohos.app.ability.common'; 19import fs from '@ohos.file.fs'; 20 21export const CLOSE = 1; 22 23export const BACK = 0; 24 25const TAG: string = 'BluetoothShare: '; 26const BUNDLE_NAME: string = 'com.huawei.hmos.settings'; 27const ABILITY_NAME: string = 'BluetoothOppServiceUIExtensionAbility'; 28 29@Entry 30@Component 31export struct BtServicesComponent { 32 uiExtensionProxy?: UIExtensionProxy; 33 private serverMac: string = ''; 34 private fileHolders: Array<opp.FileHolder> = []; 35 36 build() { 37 Column() { 38 UIExtensionComponent({ 39 bundleName: BUNDLE_NAME, 40 abilityName: ABILITY_NAME, 41 parameters: { 42 'ability.want.params.uiExtensionType': 'sys/commonUI', 43 } 44 }) 45 .backgroundColor('#01111111') 46 .onRemoteReady((proxy) => { 47 console.log(TAG, 'onRemoteReady.'); 48 this.uiExtensionProxy = proxy; 49 }) 50 .onError((error) => { 51 console.log(TAG, `onError code: ${error?.code} message: ${error?.message}`); 52 }) 53 .onTerminated(() => { 54 }) 55 .onReceive((data: Record<string, string | Object>) => { 56 console.log(TAG, 'onReceive: ' + data?.action); 57 if (!data) { 58 console.error(TAG, 'onReceive error'); 59 return; 60 } 61 this.dealReceivedData(data); 62 }) 63 .size({ width: '100%', height: '100%'}) 64 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM, SafeAreaEdge.TOP]) 65 } 66 } 67 68 /** 69 * 关闭、退出蓝牙分享页面 70 */ 71 private closeSheetPage(session: UIExtensionContentSession, code: number, message?: string) { 72 if (!session) { 73 console.log(TAG, `invalid session`); 74 return; 75 } 76 console.log(TAG, `closeSheetPage start`); 77 let result: common.AbilityResult = { 78 resultCode: code 79 }; 80 if (message) { 81 result.want = { 82 parameters: { 83 message: message 84 } 85 } 86 } 87 try { 88 session?.terminateSelfWithResult(result).then(() => { 89 console.log(TAG, `terminateSelfWithResult success`); 90 }).catch((error: Error) => { 91 console.log(TAG, `terminateSelfWithResult failed, err name: ${error?.name}`); 92 }); 93 } catch (err) { 94 console.log(TAG, `closeSheetPage error, msg: ${err.message}`); 95 } 96 } 97 98 aboutToAppear(): void { 99 console.log(TAG, 'aboutToAppear.'); 100 } 101 102 aboutToDisappear(): void { 103 console.log(TAG, 'aboutToDisappear.'); 104 } 105 106 private async dealReceivedData(data: Record<string, Object>): Promise<void> { 107 const session: UIExtensionContentSession | undefined = LocalStorage.getShared()?.get<UIExtensionContentSession>('session'); 108 if (session === undefined) { 109 console.log(TAG, 'cannot get session.'); 110 return; 111 } 112 if (data['action'] === 'sendDeviceInfo') { 113 console.log(TAG, 'sendDeviceInfo message.'); 114 let serverMac: string = data['deviceInfo'] as string; 115 this.serverMac = serverMac; 116 this.sendData(); 117 } 118 if (data['action'] === 'closeSheet') { 119 console.log(TAG, 'closeSheet message.'); 120 this.closeSheetPage(session, CLOSE); 121 } 122 if (data['action'] === 'backSheet') { 123 console.log(TAG, 'backSheet message.'); 124 this.closeSheetPage(session, BACK); 125 } 126 } 127 128 private async sendData(): Promise<void> { 129 console.log(`${TAG} sendData is called.`); 130 let fileUris = AppStorage.Get('sendFileUris'); 131 let length = AppStorage.Get('sendFileUrisLength'); 132 try { 133 let oppProfile = opp.createOppServerProfile(); 134 for (let i = 0; i < length; i++) { 135 let filePath = decodeURIComponent(fileUris[i]); 136 let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY); 137 console.log(`${TAG} deal file:` + file.fd); 138 let stat: fs.Stat = fs.statSync(file.fd); 139 let fileHolder: opp.FileHolder = { 140 filePath: filePath, 141 fileSize: stat.size, 142 fileFd: file.fd 143 }; 144 this.fileHolders.push(fileHolder); 145 console.log(`${TAG} fileHolder info: ` + JSON.stringify(fileHolder)); 146 } 147 await oppProfile.sendFile(this.serverMac, this.fileHolders); 148 const session: UIExtensionContentSession | undefined = 149 LocalStorage.getShared()?.get<UIExtensionContentSession>('session'); 150 for (let i = 0; i < this.fileHolders.length; i++) { 151 console.log(TAG, 'close fileHolders fd.'); 152 if (this.fileHolders[i].fileFd != -1) { 153 fs.close(this.fileHolders[i].fileFd); 154 this.fileHolders[i].fileFd = -1; 155 } 156 } 157 if (session === undefined) { 158 console.log(TAG, 'cannot get session.'); 159 return; 160 } 161 this.closeSheetPage(session, CLOSE); 162 } catch (err) { 163 console.error(`${TAG} sendData err`); 164 } 165 } 166}