• 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 EnvironmentProp from './dialog/EnvironmentProp';
19import mediaQuery from '@ohos.mediaquery';
20import wantAgent from '@ohos.wantAgent';
21import ContactCard from '../common/components/ContactCard';
22import FuncBtnGroup from '../common/components/FuncBtnGroup';
23import BottomBtn from '../common/components/BottomBtn';
24import Keyboard from '../common/components/Keyboard';
25import IncomingCom from '../common/components/IncomingCom';
26import CallStateConst from '../common/constant/CallStateConst';
27import LogUtils from '../common/utils/LogUtils';
28import byTrace from "@ohos.bytrace"
29import NotificationManager from '../model/NotificationManager';
30import CallManager from '../model/CallManager';
31import backgroundTaskManager from '@ohos.backgroundTaskManager';
32import * as Constants from '../common/utils/Constants';
33import CallDataManager from '../model/CallDataManager';
34import MultiContactCard from '../common/components/MultiContactCard';
35import DefaultCallData from '../common/struct/TypeUtils'
36import CallListStruct from '../common/struct/CallListStruct'
37import CallTimeListStruct from '../common/struct/CallTimeListStruct'
38
39const AIRPLANE_MODE = 1;
40const TAG = "Index";
41
42/**
43 * @file: Main interface
44 */
45@Entry
46@Component
47struct Index {
48  @State callData: DefaultCallData = new DefaultCallData();
49  @State isShowKeyboard: boolean = false;
50  @State callList: Array<CallListStruct> = [];
51  @State callTimeList: Array<CallTimeListStruct> = [];
52  private notificationManager: NotificationManager;
53  private mCallDataManager: CallDataManager;
54  @State curBp: string = 'md';
55  @State incomingData: DefaultCallData = new DefaultCallData();
56  @State mHangup: boolean = false;
57  private smListener: mediaQuery.MediaQueryListener;
58  private mdListener: mediaQuery.MediaQueryListener;
59  private lgListener: mediaQuery.MediaQueryListener;
60  private isNeedCallAgain: boolean = false;
61
62  airplaneModeDialogController: CustomDialogController = new CustomDialogController({
63    //Components shared by the TIP for creating or updating a contact by mistake and the TIP for deleting a contact
64    builder: ConfirmDialogEx({
65      cancel: () => {
66        this.airplaneModeDialogController.close();
67        LogUtils.i(TAG, 'dial airplaneModeDialogController cancel');
68        this.mCallDataManager.clearCall(this.callData);
69      },
70      confirm: () => {
71        LogUtils.i(TAG, 'dial airplaneModeDialogController confirm');
72        this.airplaneModeDialogController.close();
73        this.isNeedCallAgain = true;
74        turnOffAirPlaneMode();
75      },
76      title: $r('app.string.turn_off_airplane_and_calls'),
77      cancelText: $r('app.string.cancel'),
78      confirmText: $r('app.string.shutDown')
79    }),
80    autoCancel: false,
81    alignment: (EnvironmentProp.isTablet() ? DialogAlignment.Center : DialogAlignment.Bottom),
82    offset: { dx: 0, dy: -16 }
83  });
84
85  isBreakpointSM = (mediaQueryResult) => {
86    if (mediaQueryResult.matches) {
87      this.curBp = 'sm'
88      AppStorage.SetOrCreate('curBp', this.curBp)
89    }
90  }
91  isBreakpointMD = (mediaQueryResult) => {
92    if (mediaQueryResult.matches) {
93      this.curBp = 'md'
94      AppStorage.SetOrCreate('curBp', this.curBp)
95    }
96  }
97  isBreakpointLG = (mediaQueryResult) => {
98    if (mediaQueryResult.matches) {
99      this.curBp = 'lg'
100      AppStorage.SetOrCreate('curBp', this.curBp)
101    }
102  }
103
104  aboutToAppear(): void {
105    LogUtils.i(TAG, "aboutToAppear")
106    byTrace.startTrace('aboutToAppear', 0);
107    this.notificationManager = new NotificationManager();
108    CallManager.getInstance()?.init(this);
109    AppStorage.SetOrCreate<NotificationManager>('notificationManager', this.notificationManager);
110    this.mCallDataManager = CallDataManager.getInstance();
111    byTrace.finishTrace('aboutToAppear', 0);
112    this.smListener = mediaQuery.matchMediaSync('(320vp<width<=520vp)');
113    this.smListener?.on("change", this.isBreakpointSM);
114    this.mdListener = mediaQuery.matchMediaSync('(520vp<width<=840vp)');
115    this.mdListener?.on("change", this.isBreakpointMD);
116    this.lgListener = mediaQuery.matchMediaSync('(840vp<width)');
117    this.lgListener?.on("change", this.isBreakpointLG);
118    this.initAirPlaneMode();
119  }
120
121  onPageShow() {
122    LogUtils.i(TAG, "onPageShow");
123    byTrace.startTrace('onPageShow', 1);
124    globalThis.appInactiveState = false;
125    this.stopBackgroundRunning();
126    this.notificationManager?.cancelNotification();
127    this.notificationManager?.sendCapsuleNotification(this.incomingData ? this.callData : this.incomingData, false);
128    byTrace.finishTrace('onPageShow', 1);
129    LogUtils.i(TAG, "onPageShow end");
130  }
131
132  initAirPlaneMode() {
133    LogUtils.i(TAG, 'initAirPlaneMode');
134    try {
135      addAirPlaneModeListener((data) => {
136        LogUtils.i(TAG, 'initAirPlaneMode callback');
137        if (data == AIRPLANE_MODE) {
138          this.airplaneModeDialogController.open();
139          AppStorage.SetOrCreate('AirplaneMode', true);
140        } else if (this.isNeedCallAgain) {
141          this.isNeedCallAgain = false;
142          AppStorage.SetOrCreate('AirplaneMode', false);
143          this.mCallDataManager.clearCall(this.callData);
144        }
145      });
146    } catch(err) {
147      LogUtils.e(TAG, `initAirPlaneMode err = ${JSON.stringify(err)}`);
148    }
149  }
150
151  onPageHide() {
152    LogUtils.i(TAG, "onPageHide");
153    if (!this.mHangup) {
154      globalThis.appInactiveState = true;
155      this.updateNotification();
156    }
157    LogUtils.i(TAG, "onPageHide end");
158  }
159
160  updateNotification() {
161    const {callState, callId} = this.callData;
162    if (callState !== CallStateConst.callStateObj.CALL_STATUS_DISCONNECTED && callId) {
163      if (this.mCallDataManager.hasAliveCall()) {
164        this.startBackgroundRunning();
165      }
166      this.notificationManager?.sendNotification(this.incomingData ? this.callData : this.incomingData);
167      this.notificationManager?.sendCapsuleNotification(this.incomingData ? this.callData : this.incomingData, true);
168    }
169  }
170
171  aboutToDisappear() {
172    LogUtils.i(TAG, "aboutToDisappear");
173    this.stopBackgroundRunning();
174    this.smListener?.off('change', this.isBreakpointSM);
175    this.mdListener?.off('change', this.isBreakpointMD);
176    this.lgListener?.off('change', this.isBreakpointLG);
177    removeAirPlaneModeListener();
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