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 mAllCallRecordListDataSource: CallRecordListDataSource = new CallRecordListDataSource(); 53 callLogSearchList: any[] = []; 54 static getInstance() { 55 if (this.mPresenter == null) { 56 this.mPresenter = new DialerPresenter(); 57 } 58 return this.mPresenter; 59 } 60 61 aboutToAppear() { 62 if (!PreferencesUtil.isUsed() && !this._isCallStateChangeObserved) { 63 observer.on('callStateChange', (callback: { 64 state, 65 number, 66 }) => { 67 HiLog.i(TAG, 'callStateChange state' + callback.state); 68 if (callback.state === 0) { 69 HiLog.i(TAG, "callback.state:" + callback.state); 70 this.refresh(); 71 } 72 }); 73 this._isCallStateChangeObserved = true; 74 } 75 } 76 77 refresh() { 78 if (!PreferencesUtil.isUsed()) { 79 PreferencesUtil.setIsUsed(true); 80 this.refreshView = !this.refreshView; 81 } 82 } 83 84 editPhoneNumber(phoneNum): void { 85 if (StringUtil.isEmpty(phoneNum)) { 86 return; 87 } 88 HiLog.i(TAG, 'editPhoneNumber'); 89 AppStorage.SetOrCreate("tele_number", phoneNum); 90 this.all_number = phoneNum; 91 this.viewNumberTextProc(); 92 this.deleteAddSpace(); 93// this.callHistorySearch() 94 } 95 96 onDestroy() { 97 } 98 99 /* 100 * Change the font size when deleting a number. 101 */ 102 deleteTeleNum() { 103// this.callHistorySearch() 104 let number: string = AppStorage.Get("tele_number"); 105 if (this.all_number.length < this.NUM_TEXT_MAX_LENGTH) { 106 AppStorage.SetOrCreate("tele_number", this.all_number); 107 } else { 108 AppStorage.SetOrCreate("tele_number", this.all_number.substr(this.all_number.length - this.NUM_TEXT_MAX_LENGTH)); 109 } 110 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 111 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX * this.NUM_TEXT_MAXSIZE_LENGTH / number.length; 112 } else if (number.length <= this.NUM_TEXT_MAXSIZE_LENGTH) { 113 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX; 114 } 115 } 116 117 /* 118 * Add formatting spaces when deleting a number. 119 */ 120 deleteAddSpace() { 121 let number: string = AppStorage.Get("tele_number"); 122 let teleNumberNoSpace = StringUtil.removeSpace(number); 123 this.all_number = StringUtil.removeSpace(this.all_number); 124 if (teleNumberNoSpace.length > this.NUM_TEXT_MAXSIZE_LENGTH - 2) { 125 AppStorage.SetOrCreate("tele_number", teleNumberNoSpace); 126 return; 127 } 128 if (this.checkNeedNumberSpace(number)) { 129 if (teleNumberNoSpace.length <= 3) { 130 AppStorage.SetOrCreate("tele_number", teleNumberNoSpace); 131 return; 132 } 133 if (teleNumberNoSpace.length > 3) { 134 let split1 = teleNumberNoSpace.substr(0, 3); 135 let split2 = teleNumberNoSpace.substr(3, teleNumberNoSpace.length - 3); 136 AppStorage.SetOrCreate("tele_number", split1 + ' ' + split2); 137 if (teleNumberNoSpace.length > 7) { 138 split2 = teleNumberNoSpace.substr(3, 4); 139 let split3 = teleNumberNoSpace.substr(7, teleNumberNoSpace.length - 7); 140 AppStorage.SetOrCreate("tele_number", split1 + ' ' + split2 + ' ' + split3); 141 } 142 } 143 } else { 144 if (teleNumberNoSpace.length > 8) { 145 let split4 = teleNumberNoSpace.substr(0, 8); 146 let split5 = teleNumberNoSpace.substr(8, teleNumberNoSpace.length - 8); 147 AppStorage.SetOrCreate("tele_number", split4 + ' ' + split5); 148 } 149 } 150 } 151 152 /* 153 * Check whether formatting spaces are required when entering a number. 154 */ 155 checkNeedNumberSpace(numText) { 156 let isSpace = /[\+;,#\*]/g; 157 let isRule = /^\+.*/; 158 if (isSpace.test(numText)) { 159 // If the number string contains special characters, no space is added. 160 if (isRule.test(numText)) { 161 return true; 162 } else { 163 return false; 164 } 165 } 166 return true; 167 } 168 169 dialing(phoneNumber, options?: any) { 170 this.editPhoneNumber(""); 171 PhoneNumber.fromString(phoneNumber).dial(options).then((rst) => { 172 this.refresh(); 173 }); 174 } 175 176 /* 177 * Key vibration 178 */ 179 pressVibrate() { 180 } 181 182 /* 183 * Add a space when entering a number. 184 */ 185 ifNeedSpace() { 186 let needNumber: string = AppStorage.Get("tele_number"); 187 switch (needNumber.length) { 188 case 3: 189 if (this.checkNeedNumberSpace(needNumber)) { 190 AppStorage.SetOrCreate("tele_number", needNumber + ' '); 191 } 192 break; 193 case 8: 194 AppStorage.SetOrCreate("tele_number", needNumber + ' '); 195 break; 196 default: 197 break; 198 } 199 } 200 201 /* 202 * Processing of Overlong Input Numbers 203 */ 204 viewNumberTextProc() { 205 let numStringNoSpace_all = StringUtil.removeSpace(this.all_number); 206 let number: string = AppStorage.Get("tele_number"); 207 AppStorage.SetOrCreate("tele_number", numStringNoSpace_all.length > this.NUM_TEXT_MAX_LENGTH ? 208 numStringNoSpace_all.substr(numStringNoSpace_all.length - this.NUM_TEXT_MAX_LENGTH) : number 209 ); 210 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 211 AppStorage.SetOrCreate("tele_number", StringUtil.removeSpace(number)); 212 } 213 if (number.length > this.NUM_TEXT_MAXSIZE_LENGTH) { 214 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX * this.NUM_TEXT_MAXSIZE_LENGTH / (number.length); // 可视号码在16-25位时,适配font-size 215 } else { 216 this.tele_num_size = this.NUM_TEXT_FONT_SIZE_MAX; 217 } 218 } 219 220 /* 221 * Play different audio resources based on key digits. 222 */ 223 playAudio(number) { 224 switch (number.toString()) { 225 case '1': 226 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_1); 227 break; 228 case '2': 229 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_2); 230 break; 231 case '3': 232 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_3); 233 break; 234 case '4': 235 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_4); 236 break; 237 case '5': 238 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_5); 239 break; 240 case '6': 241 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_6); 242 break; 243 case '7': 244 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_7); 245 break; 246 case '8': 247 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_8); 248 break; 249 case '9': 250 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_9); 251 break; 252 case '0': 253 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_0); 254 break; 255 case '*': 256 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_S); 257 break; 258 case '#': 259 this.tonePlayer(audio.ToneType.TONE_TYPE_DIAL_P); 260 break; 261 default: 262 HiLog.e(TAG, "keytone src is error"); 263 } 264 } 265 266 async tonePlayer(type) { 267 HiLog.i(TAG, 'TonePlayer'); 268 if (this.timer) clearTimeout(this.timer); 269 let tonePlayer = null; 270 let audioRendererInfo = { 271 content: 5, 272 usage: 6, 273 rendererFlags: 0 274 }; 275 this.timer = setTimeout(async () => { 276 try { 277 tonePlayer = await audio.createTonePlayer(audioRendererInfo); 278 await tonePlayer.load(type); 279 await tonePlayer.start(); 280 setTimeout(async () => { 281 await tonePlayer.stop(); 282 await tonePlayer.release(); 283 }, 30) 284 } catch (err) { 285 HiLog.e(TAG, 'tonePlayer err = ' + JSON.stringify(err)); 286 } 287 }, 50) 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}