1/** 2 * Copyright (c) 2022 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 */ 15import { HiLog } from '../../../../../../common/src/main/ets/util/HiLog'; 16import { StringUtil } from '../../../../../../common/src/main/ets/util/StringUtil'; 17import audio from '@ohos.multimedia.audio'; 18import router from '@ohos.router'; 19import observer from '@ohos.telephony.observer'; 20import PreferencesUtil from '../../util/PreferencesUtil'; 21import { PhoneNumber } from '../../../../../../feature/phonenumber/src/main/ets/PhoneNumber'; 22import IndexPresenter from '../IndexPresenter'; 23import CallRecordListDataSource from '../../model/bean/CallRecordListDataSource'; 24const TAG = 'DialerPresenter'; 25const SECRET_CODE_START: string = '*#*#'; 26const SECRET_CODE_END: string = '#*#*'; 27 28/** 29 * dialer presenter 30 */ 31export default class DialerPresenter { 32 private static mPresenter: DialerPresenter; 33 private _isCallStateChangeObserved = false; 34 readonly NUM_TEXT_MAX_LENGTH = 20; 35 readonly NUM_TEXT_MAXSIZE_LENGTH = 14; 36 readonly NUM_TEXT_FONT_SIZE_MAX = 38; 37 private timer: any = null; 38 btnShow: boolean = true; 39 isEmergencyNum: boolean = false; 40 tele_number: string = ''; 41 tele_num_size: number = this.NUM_TEXT_FONT_SIZE_MAX; 42 all_number: string = ''; 43 call_p: number = 134; 44 call_y: number = 6; 45 moveY: number = 336; 46 dialerButtonWidth = 48; 47 dialerButtonHeight = 48; 48 dialerRadius = 24; 49 refreshView: boolean; 50 callBtnClick: boolean; 51 secretCode: string = ''; 52 isPalyAudioing: boolean = false; 53 mAllCallRecordListDataSource: CallRecordListDataSource = new CallRecordListDataSource(); 54 callLogSearchList: any[] = []; 55 static getInstance() { 56 if (this.mPresenter == null) { 57 this.mPresenter = new DialerPresenter(); 58 } 59 return this.mPresenter; 60 } 61 62 aboutToAppear() { 63 if (!PreferencesUtil.isUsed() && !this._isCallStateChangeObserved) { 64 observer.on('callStateChange', (callback: { 65 state, 66 number, 67 }) => { 68 HiLog.i(TAG, 'callStateChange state' + callback.state); 69 if (callback.state === 0) { 70 HiLog.i(TAG, 'callback.state:' + callback.state); 71 this.refresh(); 72 } 73 }); 74 this._isCallStateChangeObserved = true; 75 } 76 } 77 78 refresh() { 79 if (!PreferencesUtil.isUsed()) { 80 PreferencesUtil.setIsUsed(true); 81 this.refreshView = !this.refreshView; 82 } 83 } 84 85 editPhoneNumber(phoneNum): void { 86 if (StringUtil.isEmpty(phoneNum)) { 87 return; 88 } 89 HiLog.i(TAG, 'editPhoneNumber'); 90 AppStorage.SetOrCreate('tele_number', phoneNum); 91 this.all_number = phoneNum; 92 this.viewNumberTextProc(); 93 this.deleteAddSpace(); 94// this.callHistorySearch() 95 } 96 97 onDestroy() { 98 } 99 100 /* 101 * Change the font size when deleting a number. 102 */ 103 deleteTeleNum() { 104// this.callHistorySearch() 105 let number: string = AppStorage.Get('tele_number'); 106 if (this.all_number.length < this.NUM_TEXT_MAX_LENGTH) { 107 AppStorage.SetOrCreate('tele_number', this.all_number); 108 } else { 109 AppStorage.SetOrCreate('tele_number', this.all_number.substr(this.all_number.length - this.NUM_TEXT_MAX_LENGTH)); 110 } 111 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 112 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX * this.NUM_TEXT_MAXSIZE_LENGTH / number.length; 113 } else if (number.length <= this.NUM_TEXT_MAXSIZE_LENGTH) { 114 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX; 115 } 116 } 117 118 /* 119 * Add formatting spaces when deleting a number. 120 */ 121 deleteAddSpace() { 122 let number: string = AppStorage.Get('tele_number'); 123 let teleNumberNoSpace = StringUtil.removeSpace(number); 124 this.all_number = StringUtil.removeSpace(this.all_number); 125 if (teleNumberNoSpace.length > this.NUM_TEXT_MAXSIZE_LENGTH - 2) { 126 AppStorage.SetOrCreate('tele_number', teleNumberNoSpace); 127 return; 128 } 129 if (this.checkNeedNumberSpace(number)) { 130 if (teleNumberNoSpace.length <= 3) { 131 AppStorage.SetOrCreate('tele_number', teleNumberNoSpace); 132 return; 133 } 134 if (teleNumberNoSpace.length > 3) { 135 let split1 = teleNumberNoSpace.substr(0, 3); 136 let split2 = teleNumberNoSpace.substr(3, teleNumberNoSpace.length - 3); 137 AppStorage.SetOrCreate('tele_number', split1 + ' ' + split2); 138 if (teleNumberNoSpace.length > 7) { 139 split2 = teleNumberNoSpace.substr(3, 4); 140 let split3 = teleNumberNoSpace.substr(7, teleNumberNoSpace.length - 7); 141 AppStorage.SetOrCreate('tele_number', split1 + ' ' + split2 + ' ' + split3); 142 } 143 } 144 } else { 145 if (teleNumberNoSpace.length > 8) { 146 let split4 = teleNumberNoSpace.substr(0, 8); 147 let split5 = teleNumberNoSpace.substr(8, teleNumberNoSpace.length - 8); 148 AppStorage.SetOrCreate('tele_number', split4 + ' ' + split5); 149 } 150 } 151 } 152 153 /* 154 * Check whether formatting spaces are required when entering a number. 155 */ 156 checkNeedNumberSpace(numText) { 157 let isSpace = /[\+;,#\*]/g; 158 let isRule = /^\+.*/; 159 if (isSpace.test(numText)) { 160 // If the number string contains special characters, no space is added. 161 if (isRule.test(numText)) { 162 return true; 163 } else { 164 return false; 165 } 166 } 167 return true; 168 } 169 170 dialing(phoneNumber, options?: any) { 171 this.editPhoneNumber(''); 172 PhoneNumber.fromString(phoneNumber).dial(options).then((rst) => { 173 this.refresh(); 174 }); 175 } 176 177 /* 178 * Key vibration 179 */ 180 pressVibrate() { 181 } 182 183 /* 184 * Add a space when entering a number. 185 */ 186 ifNeedSpace() { 187 let needNumber: string = AppStorage.Get('tele_number'); 188 switch (needNumber.length) { 189 case 3: 190 if (this.checkNeedNumberSpace(needNumber)) { 191 AppStorage.SetOrCreate('tele_number', needNumber + ' '); 192 } 193 break; 194 case 8: 195 AppStorage.SetOrCreate('tele_number', needNumber + ' '); 196 break; 197 default: 198 break; 199 } 200 } 201 202 /* 203 * Processing of Overlong Input Numbers 204 */ 205 viewNumberTextProc() { 206 let numStringNoSpace_all = StringUtil.removeSpace(this.all_number); 207 let number: string = AppStorage.Get('tele_number'); 208 AppStorage.SetOrCreate('tele_number', numStringNoSpace_all.length > this.NUM_TEXT_MAX_LENGTH ? 209 numStringNoSpace_all.substr(numStringNoSpace_all.length - this.NUM_TEXT_MAX_LENGTH) : number 210 ); 211 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 212 AppStorage.SetOrCreate('tele_number', StringUtil.removeSpace(number)); 213 } 214 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 215 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX * this.NUM_TEXT_MAXSIZE_LENGTH / (number.length); // 可视号码在16-25位时,适配font-size 216 } else { 217 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX; 218 } 219 } 220 221 /* 222 * Play different audio resources based on key digits. 223 */ 224 playAudio(number) { 225 switch (number.toString()) { 226 case '1': 227 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_1); 228 break; 229 case '2': 230 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_2); 231 break; 232 case '3': 233 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_3); 234 break; 235 case '4': 236 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_4); 237 break; 238 case '5': 239 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_5); 240 break; 241 case '6': 242 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_6); 243 break; 244 case '7': 245 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_7); 246 break; 247 case '8': 248 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_8); 249 break; 250 case '9': 251 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_9); 252 break; 253 case '0': 254 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_0); 255 break; 256 case '*': 257 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_S); 258 break; 259 case '#': 260 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_P); 261 break; 262 default: 263 HiLog.e(TAG, 'keytone src is error'); 264 } 265 } 266 267 async tonePlayer(type) { 268 HiLog.i(TAG, 'TonePlayer type: ' + type); 269 let that = this; 270 let tonePlayer = null; 271 let audioRendererInfo = { 272 content: audio.ContentType.CONTENT_TYPE_UNKNOWN, 273 usage: audio.StreamUsage.STREAM_USAGE_DTMF, 274 rendererFlags: 0 275 }; 276 277 if (!this.isPalyAudioing) { 278 this.isPalyAudioing = true; 279 tonePlayer = await audio.createTonePlayer(audioRendererInfo); 280 await tonePlayer.load(type); 281 await tonePlayer.start(); 282 setTimeout(async () => { 283 that.isPalyAudioing = false; 284 await tonePlayer.stop(); 285 await tonePlayer.release(); 286 }, 15) 287 } 288 }; 289 290 /* 291 * Jump to New Contact 292 */ 293 jumpToAccountants() { 294 router.push({ 295 url: 'pages/contacts/accountants/Accountants', 296 params: { 297 updataShow: false, 298 phoneNumbers: [{ 299 phoneNumber: AppStorage.Get('tele_number') 300 }] 301 }, 302 }) 303 } 304 305 sendMessage() { 306 let formatnum = PhoneNumber.fromString(this.all_number).format(); 307 PhoneNumber.fromString(this.all_number).sendMessage(formatnum, formatnum); 308 } 309 310 saveCallRecordExistingContact() { 311 HiLog.i(TAG, 'saveCallRecordExistingContact start.'); 312 router.pushUrl({ 313 url: 'pages/contacts/batchselectcontacts/SingleSelectContactPage', 314 params: { 315 phoneNumberShow: AppStorage.Get('tele_number'), 316 editContact: 2, 317 } 318 }); 319 } 320 321 dealSecretCode(value: string) { 322 let length = value.length; 323 if (length > 8 && value.startsWith(SECRET_CODE_START) && value.endsWith(SECRET_CODE_END)) { 324 let str = value.substring(SECRET_CODE_START.length, length - SECRET_CODE_END.length); 325 this.secretCode = str; 326 } else { 327 this.secretCode = ''; 328 } 329 } 330 331 callHistorySearch() { 332 let teleNumber: string = AppStorage.Get('tele_number'); 333 globalThis.DataWorker.sendRequest('getQueryT9PhoneNumbers', { 334 favoriteForm: JSON.stringify({favorite:{teleNumber:teleNumber.replace(/\s*/g,'')}}), 335 context: globalThis.context 336 }, (result) => { 337 let nameArray = []; 338 for (let i = 0; i < result.length; i++) { 339 nameArray.push(result[i].showName); 340 result[i].displayName = result[i]?.showName || result[i]?.phoneNumbers[0]?.phoneNumber || ''; 341 result[i].phoneNumber = result[i]?.phoneNumbers[0]?.phoneNumber || ''; 342 } 343 const queryCall = {context: globalThis.context,mergeRule: '', actionData: {teleNumber:teleNumber.replace(/\s*/g,''), nameArray}}; 344 globalThis.DataWorker?.sendRequest('getCallHistorySearch', queryCall, (data) => { 345 this.callLogSearchList = []; 346 if(data.callLogList.length > 0 || result.length > 0){ 347 this.callLogSearchList = [...this.callLogSearchList,...result] 348 for (let i = 0; i < data.callLogList.length; i++) { 349 const displayName = data?.callLogList[i]?.displayName || data?.callLogList[i]?.phoneNumber; 350 if(!nameArray.includes(displayName)){ 351 nameArray.push(displayName) 352 this.callLogSearchList.push({...data.callLogList[i], displayName}); 353 } 354 } 355 } 356 this.mAllCallRecordListDataSource.refreshAll(this.callLogSearchList.sort((a: any, b: any)=> (a.count || 0) - (b.count || 0))); 357 }) 358 }) 359 } 360 361 jumpToContactDetail(phoneNumber) { 362 router.pushUrl( 363 { 364 url: 'pages/contacts/details/ContactDetail', 365 params: { 366 sourceHasPhone: true, 367 phoneNumberShow: phoneNumber 368 } 369 } 370 ) 371 } 372}