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