• 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
16/**
17 * @file: call manager service
18 */
19import CallServiceProxy from '../model/CallServiceProxy';
20import TelephonyCall from './TelephonyApi';
21import commonEvent from '@ohos.commonEvent';
22import LogUtils from '../common/utils/LogUtils';
23import CallManager from '../model/CallManager';
24import VibrationAndProximityUtils from '../common/utils/VibrationAndProximityUtils';
25
26let subscriber;
27const TAG = 'CallManagerService';
28const CALL_BUNDLE_NAME = 'com.ohos.callui';
29const ABILITY_NAME = 'com.ohos.callui.MainAbility';
30const CALL_STATUS_INCOMING = 4;
31const CALL_STATUS_WAITING = 5;
32const CALL_STATUS_DIALING = 2;
33const CALL_STATUS_DISCONNECTED = 6;
34const CALL_STATUS_DISCONNECTING = 7;
35const CALL_EVENT = 0;
36const CALL_CLICK = 1;
37const CALL_SCREEN_OFF = 2;
38const events = ['callui.event.callEvent', 'callui.event.click', 'usual.event.SCREEN_OFF'];
39
40/**
41 * class CallManagerService
42 */
43export default class CallManagerService {
44  private mTelephonyCall: TelephonyCall;
45  private callData = null;
46  private callList = [];
47  private context;
48  private static sCallManagerService: CallManagerService;
49
50  public static getInstance(): CallManagerService {
51    if (!CallManagerService.sCallManagerService) {
52      CallManagerService.sCallManagerService = new CallManagerService();
53    }
54    return CallManagerService.sCallManagerService;
55  }
56
57  public constructor() {
58  }
59
60
61  public init(context): void {
62    this.mTelephonyCall = new TelephonyCall;
63    this.addRegisterListener();
64    this.addSubscriber();
65    this.context = context;
66    // voice
67    VibrationAndProximityUtils.addVoiceObserver();
68  }
69
70  /**
71   * add callui app subscriber
72   */
73  async addSubscriber(): Promise<void> {
74    LogUtils.i(TAG, 'addSubscriber');
75    subscriber = await new Promise((resolve) => {
76      commonEvent.createSubscriber({
77        events,
78        publisherPermission: 'ohos.permission.GET_TELEPHONY_STATE'
79      }, (err, data) => {
80        resolve(data);
81      });
82    });
83
84    commonEvent.subscribe(subscriber, (err, res) => {
85      if (err.code === 0) {
86        if (res.event === events[CALL_EVENT]) {
87          const obj = JSON.parse(res.data);
88          if (obj && obj.key === 'getInitCallData') {
89            this.publishData(this.callData);
90          }
91        }
92
93        if (res.event === events[CALL_CLICK]) {
94          const {callId, btnType} = res.parameters;
95          this.btnclickAgent(callId, btnType);
96        }
97
98        if (res.event === events[CALL_SCREEN_OFF]) {
99          VibrationAndProximityUtils.stopVibration();
100          CallServiceProxy.getInstance().muteRinger();
101        }
102      } else {
103        LogUtils.i(TAG, 'addSubscriber commonEvent.subscribe failed err :' + JSON.stringify(err));
104      }
105      subscriber.finishCommonEvent()
106        .then(() => {
107          LogUtils.i(TAG, 'addSubscriber finishCommonEvent');
108        });
109    });
110  }
111
112  /**
113   * click button agent
114   *
115   * @param { number } callId - call id
116   * @param { string } btnType - button type
117   */
118  btnclickAgent(callId, btnType): void {
119    LogUtils.i(TAG, 'btnclickAgent btnType :' + btnType);
120    this.getMapObj(btnType, callId);
121  }
122
123  getMapObj(typeKey, callId): void {
124    if (typeKey === 'answer') {
125      this.mTelephonyCall.acceptCall(callId);
126      this.startAbility(this.callData);
127    }
128    if (typeKey === 'reject') {
129      this.mTelephonyCall.rejectCall(callId);
130    }
131    if (typeKey === 'hangUp') {
132      this.mTelephonyCall.hangUpCall(callId);
133    }
134  }
135
136  /**
137   * add register listener
138   */
139  addRegisterListener(): void {
140    this.mTelephonyCall.registerCallStateCallback(this.getCallData.bind(this));
141  }
142
143  /**
144   * get callData
145   *
146   * @param { Object } callData - Object
147   */
148  getCallData(callData): void {
149    this.callData = callData;
150    this.updateCallList();
151    const {callState} = this.callData;
152
153    /**
154     * single call or dialing pull up the application
155     */
156    if (callState === CALL_STATUS_INCOMING || callState === CALL_STATUS_WAITING || callState === CALL_STATUS_DIALING) {
157      this.startAbility(callData);
158      if (this.callList.length > 1) {
159        this.publishData(callData);
160      }
161      if (callState === CALL_STATUS_DIALING) {
162        // add Proximity Listener
163        VibrationAndProximityUtils.suspendScreen();
164      }
165    } else if (callState !== CALL_STATUS_DISCONNECTING) {
166      this.publishData(callData);
167    }
168    if (callState === CALL_STATUS_INCOMING || callState === CALL_STATUS_WAITING) {
169      // incoming, vibration
170      VibrationAndProximityUtils.startVibration();
171    } else {
172      VibrationAndProximityUtils.stopVibration();
173    }
174  }
175
176  /**
177   * service disconnected
178   *
179   * @return void
180   */
181  public onDisconnected(): void {
182    if (this.callData != null && this.callData.callState === CALL_STATUS_DISCONNECTED) {
183      return;
184    } else {
185      this.callData.callState = CALL_STATUS_DISCONNECTED;
186      this.publishData(this.callData);
187    }
188  }
189
190  /**
191   * start ability
192   *
193   * @param { Object } callData - Object
194   */
195  startAbility(callData): void {
196    this.context.startAbility({
197      bundleName: CALL_BUNDLE_NAME,
198      abilityName: ABILITY_NAME,
199      parameters: callData
200    }).then((data) => {
201      LogUtils.i(TAG, 'callUI service startAbility data :' + JSON.stringify(data));
202    }).catch((err) => {
203      LogUtils.i(TAG, 'callUI service startAbility err :' + JSON.stringify(err));
204    });
205  }
206
207  /**
208   * update callList
209   */
210  updateCallList(): void {
211    const {callState, callId} = this.callData;
212    const targetObj = this.callList.find((v) => v.callId === callId);
213    if (targetObj) {
214      Object.assign(targetObj, {
215        ...this.callData
216      });
217    } else {
218      this.callList.push({
219        ...this.callData
220      });
221    }
222    if (callState === CALL_STATUS_DISCONNECTED) {
223      const index = this.callList.findIndex((v) => v.callId === callId);
224      this.callList.splice(index, 1);
225    }
226  }
227
228  /**
229   * commonEvent publish data
230   *
231   * @param { Object } callData - Object
232   */
233  publishData(callData): void {
234    CallManager.getInstance().update(callData);
235  }
236
237  /**
238   * unsubscribe
239   */
240  unsubscribe(): void {
241    commonEvent.unsubscribe(subscriber, (err) => {
242      if (err.code !== 0) {
243        LogUtils.i(TAG, 'unsubscribe commonEvent.unsubscribe err:' + JSON.stringify(err));
244      }
245    });
246  }
247
248  /**
249   * remove register listener
250   */
251  removeRegisterListener(): void {
252    this.mTelephonyCall.unRegisterCallStateCallback();
253  }
254}