• 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 byTrace from '@ohos.bytrace'
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    byTrace.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    byTrace.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    byTrace.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    byTrace.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 || v.callState === CallStateConst.callStateObj.CALL_STATUS_INCOMING) {
252          btnState = false;
253        }
254      });
255      return btnState;
256    } else {
257      return this.callState() !== CallStateConst.callStateObj.CALL_STATUS_WAITING
258      && this.callState() !== CallStateConst.callStateObj.CALL_STATUS_INCOMING
259    }
260  }
261
262  build() {
263    Flex({
264      direction: FlexDirection.Column,
265      alignItems: ItemAlign.Center,
266      justifyContent: FlexAlign.SpaceBetween
267    }) {
268      if (this.callList.length > 1) {
269        MultiContactCard({
270          callData: $callData,
271          isShowKeyboard: this.isShowKeyboard,
272          callList: $callList,
273          incomingData: $incomingData
274        })
275          .margin({ top: this.isShowKeyboard ? 0 : 56 })
276          .layoutWeight(this.isShowKeyboard ? 1 : 0)
277      } else {
278        ContactCard({
279          callData: $callData,
280          isShowKeyboard: this.isShowKeyboard,
281          callList: $callList
282        })
283          .margin({ top: this.isShowKeyboard ? 0 : 56 })
284          .layoutWeight(this.isShowKeyboard ? 1 : 0)
285      }
286
287      if (this.getBtnCallState()) {
288        Column() {
289          if (!this.isShowKeyboard) {
290            FuncBtnGroup({ callData: $callData, callList: $callList })
291              .margin({ bottom: 32 })
292          } else {
293            Keyboard({ callData: $callData })
294              .margin({ bottom: 32 })
295          }
296          BottomBtn({
297            callData: $callData,
298            callList: $callList,
299            hangup: $mHangup,
300            onItemClick: () => {
301              this.showKeyboard()
302            }
303          })
304        }
305      } else {
306        Column() {
307          IncomingCom({
308            callList: $callList,
309            callData: $callData,
310            hangup: $mHangup})
311
312          if (this.isTripleCall()) {
313            Column() {
314              Text($r('app.string.end_holding_call'))
315                .fontColor('#FFFFFF')
316                .fontSize(14)
317                .height(19)
318                .lineHeight(19)
319            }
320            .margin({ top: 16 })
321          }
322        }
323      }
324    }
325    .padding({ bottom: this.isTripleCall() ? 71 : 106 })
326    .width('100%')
327    .height('100%')
328    .backgroundImage('assets/picture/wallpaper.png', ImageRepeat.NoRepeat)
329    .backgroundImageSize(ImageSize.Cover)
330  }
331}
332