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 16import { addAirPlaneModeListener, removeAirPlaneModeListener, turnOffAirPlaneMode } from '../common/utils/AirplaneMode'; 17import ConfirmDialogEx from './dialog/ConfirmDialogEx'; 18import mediaQuery from '@ohos.mediaquery'; 19import wantAgent from '@ohos.wantAgent'; 20import ContactCard from '../common/components/ContactCard'; 21import FuncBtnGroup from '../common/components/FuncBtnGroup'; 22import BottomBtn from '../common/components/BottomBtn'; 23import Keyboard from '../common/components/Keyboard'; 24import IncomingCom from '../common/components/IncomingCom'; 25import CallStateConst from '../common/constant/CallStateConst'; 26import LogUtils from '../common/utils/LogUtils'; 27import hiTraceMeter from '@ohos.hiTraceMeter'; 28import NotificationManager from '../model/NotificationManager'; 29import CallManager from '../model/CallManager'; 30import backgroundTaskManager from '@ohos.backgroundTaskManager'; 31import * as Constants from '../common/utils/Constants'; 32import CallDataManager from '../model/CallDataManager'; 33import MultiContactCard from '../common/components/MultiContactCard'; 34import DefaultCallData from '../common/struct/TypeUtils' 35import CallListStruct from '../common/struct/CallListStruct' 36import CallTimeListStruct from '../common/struct/CallTimeListStruct' 37 38const AIRPLANE_MODE = 1; 39const TAG = 'Index'; 40 41/** 42 * @file: Main interface 43 */ 44@Entry 45@Component 46struct Index { 47 @State callData: DefaultCallData = new DefaultCallData(); 48 @State isShowKeyboard: boolean = false; 49 @State callList: Array<CallListStruct> = []; 50 @State callTimeList: Array<CallTimeListStruct> = []; 51 private notificationManager: NotificationManager; 52 private mCallDataManager: CallDataManager; 53 @State curBp: string = 'md'; 54 @State incomingData: DefaultCallData = new DefaultCallData(); 55 @State mHangup: boolean = false; 56 private smListener: mediaQuery.MediaQueryListener; 57 private mdListener: mediaQuery.MediaQueryListener; 58 private lgListener: mediaQuery.MediaQueryListener; 59 private isNeedCallAgain: boolean = false; 60 61 airplaneModeDialogController: CustomDialogController = new CustomDialogController({ 62 //Components shared by the TIP for creating or updating a contact by mistake and the TIP for deleting a contact 63 builder: ConfirmDialogEx({ 64 cancel: () => { 65 this.airplaneModeDialogController.close(); 66 LogUtils.i(TAG, 'dial airplaneModeDialogController cancel'); 67 this.mCallDataManager.clearCall(this.callData); 68 }, 69 confirm: () => { 70 LogUtils.i(TAG, 'dial airplaneModeDialogController confirm'); 71 this.airplaneModeDialogController.close(); 72 this.isNeedCallAgain = true; 73 turnOffAirPlaneMode(); 74 }, 75 title: $r('app.string.turn_off_airplane_and_calls'), 76 cancelText: $r('app.string.cancel'), 77 confirmText: $r('app.string.shutDown') 78 }), 79 autoCancel: false, 80 alignment: DialogAlignment.Bottom, 81 offset: { dx: 0, dy: -16 } 82 }); 83 84 isBreakpointSM = (mediaQueryResult) => { 85 if (mediaQueryResult.matches) { 86 this.curBp = 'sm' 87 AppStorage.SetOrCreate('curBp', this.curBp) 88 } 89 } 90 isBreakpointMD = (mediaQueryResult) => { 91 if (mediaQueryResult.matches) { 92 this.curBp = 'md' 93 AppStorage.SetOrCreate('curBp', this.curBp) 94 } 95 } 96 isBreakpointLG = (mediaQueryResult) => { 97 if (mediaQueryResult.matches) { 98 this.curBp = 'lg' 99 AppStorage.SetOrCreate('curBp', this.curBp) 100 } 101 } 102 103 aboutToAppear(): void { 104 LogUtils.i(TAG, 'aboutToAppear') 105 hiTraceMeter.startTrace('aboutToAppear', 0); 106 this.notificationManager = new NotificationManager(); 107 CallManager.getInstance()?.init(this); 108 AppStorage.SetOrCreate<NotificationManager>('notificationManager', this.notificationManager); 109 this.mCallDataManager = CallDataManager.getInstance(); 110 hiTraceMeter.finishTrace('aboutToAppear', 0); 111 this.smListener = mediaQuery.matchMediaSync('(320vp<width<=520vp)'); 112 this.smListener?.on('change', this.isBreakpointSM); 113 this.mdListener = mediaQuery.matchMediaSync('(520vp<width<=840vp)'); 114 this.mdListener?.on('change', this.isBreakpointMD); 115 this.lgListener = mediaQuery.matchMediaSync('(840vp<width)'); 116 this.lgListener?.on('change', this.isBreakpointLG); 117 this.initAirPlaneMode(); 118 } 119 120 onPageShow() { 121 LogUtils.i(TAG, 'onPageShow'); 122 hiTraceMeter.startTrace('onPageShow', 1); 123 globalThis.appInactiveState = false; 124 this.stopBackgroundRunning(); 125 this.notificationManager?.cancelNotification(); 126 this.notificationManager?.sendCapsuleNotification(this.incomingData ? this.callData : this.incomingData, false); 127 hiTraceMeter.finishTrace('onPageShow', 1); 128 LogUtils.i(TAG, 'onPageShow end'); 129 } 130 131 initAirPlaneMode() { 132 LogUtils.i(TAG, 'initAirPlaneMode'); 133 try { 134 addAirPlaneModeListener((data) => { 135 LogUtils.i(TAG, 'initAirPlaneMode callback'); 136 if (data == AIRPLANE_MODE) { 137 this.airplaneModeDialogController.open(); 138 AppStorage.SetOrCreate('AirplaneMode', true); 139 } else if (this.isNeedCallAgain) { 140 this.isNeedCallAgain = false; 141 AppStorage.SetOrCreate('AirplaneMode', false); 142 this.mCallDataManager.clearCall(this.callData); 143 } 144 }); 145 } catch (err) { 146 LogUtils.e(TAG, `initAirPlaneMode err = ${JSON.stringify(err)}`); 147 } 148 } 149 150 onPageHide() { 151 LogUtils.i(TAG, 'onPageHide'); 152 if (!this.mHangup) { 153 globalThis.appInactiveState = true; 154 this.updateNotification(); 155 } 156 LogUtils.i(TAG, 'onPageHide end'); 157 } 158 159 updateNotification() { 160 const {callState, callId} = this.callData; 161 if (callState !== CallStateConst.callStateObj.CALL_STATUS_DISCONNECTED && callId) { 162 if (this.mCallDataManager.hasAliveCall()) { 163 this.startBackgroundRunning(); 164 } 165 this.notificationManager?.sendNotification(this.incomingData ? this.callData : this.incomingData); 166 this.notificationManager?.sendCapsuleNotification(this.incomingData ? this.callData : this.incomingData, true); 167 } 168 } 169 170 aboutToDisappear() { 171 LogUtils.i(TAG, 'aboutToDisappear'); 172 this.stopBackgroundRunning(); 173 this.smListener?.off('change', this.isBreakpointSM); 174 this.mdListener?.off('change', this.isBreakpointMD); 175 this.lgListener?.off('change', this.isBreakpointLG); 176 removeAirPlaneModeListener(); 177 this.airplaneModeDialogController = null; 178 } 179 180 onBackPress() { 181 LogUtils.i(TAG, 'onBackPress'); 182 } 183 184 private stopBackgroundRunning() { 185 backgroundTaskManager.stopBackgroundRunning(globalThis.calluiAbilityContext).then(() => { 186 LogUtils.i(TAG, 'stopBackgroundRunning succeeded'); 187 }).catch((err) => { 188 LogUtils.i(TAG, 'stopBackgroundRunning failed'); 189 }); 190 } 191 192 private startBackgroundRunning() { 193 let wantAgentInfo = { 194 wants: [{ 195 bundleName: Constants.CALL_BUNDLE_NAME, 196 abilityName: Constants.CALL_ABILITY_NAME, 197 }], 198 requestCode: 0, 199 operationType: wantAgent.OperationType.START_ABILITY, 200 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 201 }; 202 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 203 backgroundTaskManager.startBackgroundRunning(globalThis.calluiAbilityContext, 204 backgroundTaskManager.BackgroundMode.VOIP, wantAgentObj).then(() => { 205 LogUtils.i(TAG, 'startBackgroundRunning succeeded') 206 }).catch((err) => { 207 LogUtils.i(TAG, 'startBackgroundRunning failed cause:' + JSON.stringify(err)) 208 }); 209 }); 210 } 211 212 /** 213 * method to control the display of DTMF keyboard 214 * 215 * parent component pass by value child component 216 */ 217 public showKeyboard() { 218 this.isShowKeyboard = !this.isShowKeyboard; 219 } 220 221 /** 222 * Call status 223 * 224 * @return {number} - callState 225 */ 226 private callState() { 227 LogUtils.i(TAG, 'callState : ' + this.callData.callState) 228 return this.callData.callState; 229 } 230 231 /** 232 * is Triple Call 233 * 234 * @return {boolean} - isTripleCall 235 */ 236 private isTripleCall() { 237 return (this.callData.callState === CallStateConst.callStateObj.CALL_STATUS_WAITING || 238 this.callData.callState === CallStateConst.callStateObj.CALL_STATUS_INCOMING) && 239 this.callList.length === 3; 240 } 241 242 pageTransition() { 243 PageTransitionEnter({ duration: 0 }); 244 PageTransitionExit({ duration: 0 }); 245 } 246 247 getBtnCallState() { 248 if (this.callList.length > 1) { 249 let btnState = true; 250 this.callList.forEach((v) => { 251 if (v.callState === CallStateConst.callStateObj.CALL_STATUS_WAITING || 252 v.callState === CallStateConst.callStateObj.CALL_STATUS_INCOMING) { 253 btnState = false; 254 } 255 }); 256 return btnState; 257 } else { 258 return this.callState() !== CallStateConst.callStateObj.CALL_STATUS_WAITING && 259 this.callState() !== CallStateConst.callStateObj.CALL_STATUS_INCOMING 260 } 261 } 262 263 build() { 264 Flex({ 265 direction: FlexDirection.Column, 266 alignItems: ItemAlign.Center, 267 justifyContent: FlexAlign.SpaceBetween 268 }) { 269 if (this.callList.length > 1) { 270 MultiContactCard({ 271 callData: $callData, 272 isShowKeyboard: this.isShowKeyboard, 273 callList: $callList, 274 incomingData: $incomingData 275 }) 276 .margin({ top: this.isShowKeyboard ? 0 : 56 }) 277 .layoutWeight(this.isShowKeyboard ? 1 : 0) 278 } else { 279 ContactCard({ 280 callData: $callData, 281 isShowKeyboard: this.isShowKeyboard, 282 callList: $callList 283 }) 284 .margin({ top: this.isShowKeyboard ? 0 : 56 }) 285 .layoutWeight(this.isShowKeyboard ? 1 : 0) 286 } 287 288 if (this.getBtnCallState()) { 289 Column() { 290 if (!this.isShowKeyboard) { 291 FuncBtnGroup({ callData: $callData, callList: $callList }) 292 .margin({ bottom: 32 }) 293 } else { 294 Keyboard({ callData: $callData }) 295 .margin({ bottom: 32 }) 296 } 297 BottomBtn({ 298 callData: $callData, 299 callList: $callList, 300 hangup: $mHangup, 301 onItemClick: () => { 302 this.showKeyboard() 303 } 304 }) 305 } 306 } else { 307 Column() { 308 IncomingCom({ 309 callList: $callList, 310 callData: $callData, 311 hangup: $mHangup}) 312 313 if (this.isTripleCall()) { 314 Column() { 315 Text($r('app.string.end_holding_call')) 316 .fontColor('#FFFFFF') 317 .fontSize(14) 318 .height(19) 319 .lineHeight(19) 320 } 321 .margin({ top: 16 }) 322 } 323 } 324 } 325 } 326 .padding({ bottom: this.isTripleCall() ? 71 : 106 }) 327 .width('100%') 328 .height('100%') 329 .backgroundImage('assets/picture/wallpaper.png', ImageRepeat.NoRepeat) 330 .backgroundImageSize(ImageSize.Cover) 331 } 332} 333