ImsPhoneConnection.java revision 28f0b85be9cddf2c3c9ef268e3bf2781747a66f2
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony.imsphone; 18 19import android.content.Context; 20import android.net.Uri; 21import android.os.AsyncResult; 22import android.os.Handler; 23import android.os.Looper; 24import android.os.Message; 25import android.os.PowerManager; 26import android.os.Registrant; 27import android.os.SystemClock; 28import android.telecom.Log; 29import android.telephony.DisconnectCause; 30import android.telephony.PhoneNumberUtils; 31import android.telephony.Rlog; 32 33import com.android.ims.ImsException; 34import com.android.ims.ImsStreamMediaProfile; 35import com.android.internal.telephony.CallStateException; 36import com.android.internal.telephony.Connection; 37import com.android.internal.telephony.Phone; 38import com.android.internal.telephony.PhoneConstants; 39import com.android.internal.telephony.UUSInfo; 40 41import com.android.ims.ImsCall; 42import com.android.ims.ImsCallProfile; 43 44/** 45 * {@hide} 46 */ 47public class ImsPhoneConnection extends Connection { 48 private static final String LOG_TAG = "ImsPhoneConnection"; 49 private static final boolean DBG = true; 50 51 //***** Instance Variables 52 53 private ImsPhoneCallTracker mOwner; 54 private ImsPhoneCall mParent; 55 private ImsCall mImsCall; 56 57 private String mPostDialString; // outgoing calls only 58 private boolean mDisconnected; 59 60 /* 61 int mIndex; // index in ImsPhoneCallTracker.connections[], -1 if unassigned 62 // The GSM index is 1 + this 63 */ 64 65 /* 66 * These time/timespan values are based on System.currentTimeMillis(), 67 * i.e., "wall clock" time. 68 */ 69 private long mDisconnectTime; 70 71 private int mNextPostDialChar; // index into postDialString 72 73 private int mCause = DisconnectCause.NOT_DISCONNECTED; 74 private PostDialState mPostDialState = PostDialState.NOT_STARTED; 75 private UUSInfo mUusInfo; 76 private Handler mHandler; 77 78 private PowerManager.WakeLock mPartialWakeLock; 79 80 // The cached connect time of the connection when it turns into a conference. 81 private long mConferenceConnectTime = 0; 82 83 //***** Event Constants 84 private static final int EVENT_DTMF_DONE = 1; 85 private static final int EVENT_PAUSE_DONE = 2; 86 private static final int EVENT_NEXT_POST_DIAL = 3; 87 private static final int EVENT_WAKE_LOCK_TIMEOUT = 4; 88 89 //***** Constants 90 private static final int PAUSE_DELAY_MILLIS = 3 * 1000; 91 private static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000; 92 93 //***** Inner Classes 94 95 class MyHandler extends Handler { 96 MyHandler(Looper l) {super(l);} 97 98 @Override 99 public void 100 handleMessage(Message msg) { 101 102 switch (msg.what) { 103 case EVENT_NEXT_POST_DIAL: 104 case EVENT_DTMF_DONE: 105 case EVENT_PAUSE_DONE: 106 processNextPostDialChar(); 107 break; 108 case EVENT_WAKE_LOCK_TIMEOUT: 109 releaseWakeLock(); 110 break; 111 } 112 } 113 } 114 115 //***** Constructors 116 117 /** This is probably an MT call */ 118 /*package*/ 119 ImsPhoneConnection(Context context, ImsCall imsCall, ImsPhoneCallTracker ct, ImsPhoneCall parent) { 120 createWakeLock(context); 121 acquireWakeLock(); 122 123 mOwner = ct; 124 mHandler = new MyHandler(mOwner.getLooper()); 125 mImsCall = imsCall; 126 127 if ((imsCall != null) && (imsCall.getCallProfile() != null)) { 128 mAddress = imsCall.getCallProfile().getCallExtra(ImsCallProfile.EXTRA_OI); 129 mCnapName = imsCall.getCallProfile().getCallExtra(ImsCallProfile.EXTRA_CNA); 130 mNumberPresentation = ImsCallProfile.OIRToPresentation( 131 imsCall.getCallProfile().getCallExtraInt(ImsCallProfile.EXTRA_OIR)); 132 mCnapNamePresentation = ImsCallProfile.OIRToPresentation( 133 imsCall.getCallProfile().getCallExtraInt(ImsCallProfile.EXTRA_CNAP)); 134 updateMediaCapabilities(imsCall); 135 } else { 136 mNumberPresentation = PhoneConstants.PRESENTATION_UNKNOWN; 137 mCnapNamePresentation = PhoneConstants.PRESENTATION_UNKNOWN; 138 } 139 140 mIsIncoming = true; 141 mCreateTime = System.currentTimeMillis(); 142 mUusInfo = null; 143 144 //mIndex = index; 145 146 updateWifiState(); 147 148 mParent = parent; 149 mParent.attach(this, ImsPhoneCall.State.INCOMING); 150 } 151 152 /** This is an MO call, created when dialing */ 153 /*package*/ 154 ImsPhoneConnection(Context context, String dialString, ImsPhoneCallTracker ct, ImsPhoneCall parent) { 155 createWakeLock(context); 156 acquireWakeLock(); 157 158 mOwner = ct; 159 mHandler = new MyHandler(mOwner.getLooper()); 160 161 mDialString = dialString; 162 163 mAddress = PhoneNumberUtils.extractNetworkPortionAlt(dialString); 164 mPostDialString = PhoneNumberUtils.extractPostDialPortion(dialString); 165 166 //mIndex = -1; 167 168 mIsIncoming = false; 169 mCnapName = null; 170 mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED; 171 mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED; 172 mCreateTime = System.currentTimeMillis(); 173 174 mParent = parent; 175 parent.attachFake(this, ImsPhoneCall.State.DIALING); 176 } 177 178 public void dispose() { 179 } 180 181 static boolean 182 equalsHandlesNulls (Object a, Object b) { 183 return (a == null) ? (b == null) : a.equals (b); 184 } 185 186 @Override 187 public String getOrigDialString(){ 188 return mDialString; 189 } 190 191 @Override 192 public ImsPhoneCall getCall() { 193 return mParent; 194 } 195 196 @Override 197 public long getDisconnectTime() { 198 return mDisconnectTime; 199 } 200 201 @Override 202 public long getHoldingStartTime() { 203 return mHoldingStartTime; 204 } 205 206 @Override 207 public long getHoldDurationMillis() { 208 if (getState() != ImsPhoneCall.State.HOLDING) { 209 // If not holding, return 0 210 return 0; 211 } else { 212 return SystemClock.elapsedRealtime() - mHoldingStartTime; 213 } 214 } 215 216 @Override 217 public int getDisconnectCause() { 218 return mCause; 219 } 220 221 public void setDisconnectCause(int cause) { 222 mCause = cause; 223 } 224 225 public ImsPhoneCallTracker getOwner () { 226 return mOwner; 227 } 228 229 @Override 230 public ImsPhoneCall.State getState() { 231 if (mDisconnected) { 232 return ImsPhoneCall.State.DISCONNECTED; 233 } else { 234 return super.getState(); 235 } 236 } 237 238 @Override 239 public void hangup() throws CallStateException { 240 if (!mDisconnected) { 241 mOwner.hangup(this); 242 } else { 243 throw new CallStateException ("disconnected"); 244 } 245 } 246 247 @Override 248 public void separate() throws CallStateException { 249 throw new CallStateException ("not supported"); 250 } 251 252 @Override 253 public PostDialState getPostDialState() { 254 return mPostDialState; 255 } 256 257 @Override 258 public void proceedAfterWaitChar() { 259 if (mPostDialState != PostDialState.WAIT) { 260 Rlog.w(LOG_TAG, "ImsPhoneConnection.proceedAfterWaitChar(): Expected " 261 + "getPostDialState() to be WAIT but was " + mPostDialState); 262 return; 263 } 264 265 setPostDialState(PostDialState.STARTED); 266 267 processNextPostDialChar(); 268 } 269 270 @Override 271 public void proceedAfterWildChar(String str) { 272 if (mPostDialState != PostDialState.WILD) { 273 Rlog.w(LOG_TAG, "ImsPhoneConnection.proceedAfterWaitChar(): Expected " 274 + "getPostDialState() to be WILD but was " + mPostDialState); 275 return; 276 } 277 278 setPostDialState(PostDialState.STARTED); 279 280 // make a new postDialString, with the wild char replacement string 281 // at the beginning, followed by the remaining postDialString. 282 283 StringBuilder buf = new StringBuilder(str); 284 buf.append(mPostDialString.substring(mNextPostDialChar)); 285 mPostDialString = buf.toString(); 286 mNextPostDialChar = 0; 287 if (Phone.DEBUG_PHONE) { 288 Rlog.d(LOG_TAG, "proceedAfterWildChar: new postDialString is " + 289 mPostDialString); 290 } 291 292 processNextPostDialChar(); 293 } 294 295 @Override 296 public void cancelPostDial() { 297 setPostDialState(PostDialState.CANCELLED); 298 } 299 300 /** 301 * Called when this Connection is being hung up locally (eg, user pressed "end") 302 */ 303 void 304 onHangupLocal() { 305 mCause = DisconnectCause.LOCAL; 306 } 307 308 /** Called when the connection has been disconnected */ 309 public boolean 310 onDisconnect(int cause) { 311 Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause); 312 if (mCause != DisconnectCause.LOCAL) mCause = cause; 313 return onDisconnect(); 314 } 315 316 /*package*/ boolean 317 onDisconnect() { 318 boolean changed = false; 319 320 if (!mDisconnected) { 321 //mIndex = -1; 322 323 mDisconnectTime = System.currentTimeMillis(); 324 mDuration = SystemClock.elapsedRealtime() - mConnectTimeReal; 325 mDisconnected = true; 326 327 mOwner.mPhone.notifyDisconnect(this); 328 329 if (mParent != null) { 330 changed = mParent.connectionDisconnected(this); 331 } else { 332 Rlog.d(LOG_TAG, "onDisconnect: no parent"); 333 } 334 if (mImsCall != null) mImsCall.close(); 335 mImsCall = null; 336 } 337 releaseWakeLock(); 338 return changed; 339 } 340 341 /** 342 * An incoming or outgoing call has connected 343 */ 344 void 345 onConnectedInOrOut() { 346 mConnectTime = System.currentTimeMillis(); 347 mConnectTimeReal = SystemClock.elapsedRealtime(); 348 mDuration = 0; 349 350 if (Phone.DEBUG_PHONE) { 351 Rlog.d(LOG_TAG, "onConnectedInOrOut: connectTime=" + mConnectTime); 352 } 353 354 if (!mIsIncoming) { 355 // outgoing calls only 356 processNextPostDialChar(); 357 } 358 releaseWakeLock(); 359 } 360 361 /*package*/ void 362 onStartedHolding() { 363 mHoldingStartTime = SystemClock.elapsedRealtime(); 364 } 365 /** 366 * Performs the appropriate action for a post-dial char, but does not 367 * notify application. returns false if the character is invalid and 368 * should be ignored 369 */ 370 private boolean 371 processPostDialChar(char c) { 372 if (PhoneNumberUtils.is12Key(c)) { 373 mOwner.sendDtmf(c, mHandler.obtainMessage(EVENT_DTMF_DONE)); 374 } else if (c == PhoneNumberUtils.PAUSE) { 375 // From TS 22.101: 376 // It continues... 377 // Upon the called party answering the UE shall send the DTMF digits 378 // automatically to the network after a delay of 3 seconds( 20 ). 379 // The digits shall be sent according to the procedures and timing 380 // specified in 3GPP TS 24.008 [13]. The first occurrence of the 381 // "DTMF Control Digits Separator" shall be used by the ME to 382 // distinguish between the addressing digits (i.e. the phone number) 383 // and the DTMF digits. Upon subsequent occurrences of the 384 // separator, 385 // the UE shall pause again for 3 seconds ( 20 ) before sending 386 // any further DTMF digits. 387 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_PAUSE_DONE), 388 PAUSE_DELAY_MILLIS); 389 } else if (c == PhoneNumberUtils.WAIT) { 390 setPostDialState(PostDialState.WAIT); 391 } else if (c == PhoneNumberUtils.WILD) { 392 setPostDialState(PostDialState.WILD); 393 } else { 394 return false; 395 } 396 397 return true; 398 } 399 400 @Override 401 public String 402 getRemainingPostDialString() { 403 if (mPostDialState == PostDialState.CANCELLED 404 || mPostDialState == PostDialState.COMPLETE 405 || mPostDialString == null 406 || mPostDialString.length() <= mNextPostDialChar 407 ) { 408 return ""; 409 } 410 411 return mPostDialString.substring(mNextPostDialChar); 412 } 413 414 @Override 415 protected void finalize() 416 { 417 releaseWakeLock(); 418 } 419 420 private void 421 processNextPostDialChar() { 422 char c = 0; 423 Registrant postDialHandler; 424 425 if (mPostDialState == PostDialState.CANCELLED) { 426 //Rlog.d(LOG_TAG, "##### processNextPostDialChar: postDialState == CANCELLED, bail"); 427 return; 428 } 429 430 if (mPostDialString == null || mPostDialString.length() <= mNextPostDialChar) { 431 setPostDialState(PostDialState.COMPLETE); 432 433 // notifyMessage.arg1 is 0 on complete 434 c = 0; 435 } else { 436 boolean isValid; 437 438 setPostDialState(PostDialState.STARTED); 439 440 c = mPostDialString.charAt(mNextPostDialChar++); 441 442 isValid = processPostDialChar(c); 443 444 if (!isValid) { 445 // Will call processNextPostDialChar 446 mHandler.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget(); 447 // Don't notify application 448 Rlog.e(LOG_TAG, "processNextPostDialChar: c=" + c + " isn't valid!"); 449 return; 450 } 451 } 452 453 notifyPostDialListenersNextChar(c); 454 455 // TODO: remove the following code since the handler no longer executes anything. 456 postDialHandler = mOwner.mPhone.mPostDialHandler; 457 458 Message notifyMessage; 459 460 if (postDialHandler != null 461 && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { 462 // The AsyncResult.result is the Connection object 463 PostDialState state = mPostDialState; 464 AsyncResult ar = AsyncResult.forMessage(notifyMessage); 465 ar.result = this; 466 ar.userObj = state; 467 468 // arg1 is the character that was/is being processed 469 notifyMessage.arg1 = c; 470 471 //Rlog.v(LOG_TAG, "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); 472 notifyMessage.sendToTarget(); 473 } 474 } 475 476 /** 477 * Set post dial state and acquire wake lock while switching to "started" 478 * state, the wake lock will be released if state switches out of "started" 479 * state or after WAKE_LOCK_TIMEOUT_MILLIS. 480 * @param s new PostDialState 481 */ 482 private void setPostDialState(PostDialState s) { 483 if (mPostDialState != PostDialState.STARTED 484 && s == PostDialState.STARTED) { 485 acquireWakeLock(); 486 Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); 487 mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS); 488 } else if (mPostDialState == PostDialState.STARTED 489 && s != PostDialState.STARTED) { 490 mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); 491 releaseWakeLock(); 492 } 493 mPostDialState = s; 494 notifyPostDialListeners(); 495 } 496 497 private void 498 createWakeLock(Context context) { 499 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 500 mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 501 } 502 503 private void 504 acquireWakeLock() { 505 Rlog.d(LOG_TAG, "acquireWakeLock"); 506 mPartialWakeLock.acquire(); 507 } 508 509 void 510 releaseWakeLock() { 511 synchronized(mPartialWakeLock) { 512 if (mPartialWakeLock.isHeld()) { 513 Rlog.d(LOG_TAG, "releaseWakeLock"); 514 mPartialWakeLock.release(); 515 } 516 } 517 } 518 519 @Override 520 public int getNumberPresentation() { 521 return mNumberPresentation; 522 } 523 524 @Override 525 public UUSInfo getUUSInfo() { 526 return mUusInfo; 527 } 528 529 @Override 530 public Connection getOrigConnection() { 531 return null; 532 } 533 534 @Override 535 public boolean isMultiparty() { 536 return mImsCall != null && mImsCall.isMultiparty(); 537 } 538 539 /** 540 * Where {@link #isMultiparty()} is {@code true}, determines if this {@link ImsCall} is the 541 * origin of the conference call (i.e. {@code #isConferenceHost()} is {@code true}), or if this 542 * {@link ImsCall} is a member of a conference hosted on another device. 543 * 544 * @return {@code true} if this call is the origin of the conference call it is a member of, 545 * {@code false} otherwise. 546 */ 547 public boolean isConferenceHost() { 548 if (mImsCall == null) { 549 return false; 550 } 551 return mImsCall.isConferenceHost(); 552 } 553 554 /*package*/ ImsCall getImsCall() { 555 return mImsCall; 556 } 557 558 /*package*/ void setImsCall(ImsCall imsCall) { 559 mImsCall = imsCall; 560 } 561 562 /*package*/ void changeParent(ImsPhoneCall parent) { 563 mParent = parent; 564 } 565 566 /** 567 * @return {@code true} if the {@link ImsPhoneConnection} or its media capabilities have been 568 * changed, and {@code false} otherwise. 569 */ 570 /*package*/ boolean update(ImsCall imsCall, ImsPhoneCall.State state) { 571 if (state == ImsPhoneCall.State.ACTIVE) { 572 if (mParent.getState().isRinging() || mParent.getState().isDialing()) { 573 onConnectedInOrOut(); 574 } 575 576 if (mParent.getState().isRinging() || mParent == mOwner.mBackgroundCall) { 577 //mForegroundCall should be IDLE 578 //when accepting WAITING call 579 //before accept WAITING call, 580 //the ACTIVE call should be held ahead 581 mParent.detach(this); 582 mParent = mOwner.mForegroundCall; 583 mParent.attach(this); 584 } 585 } else if (state == ImsPhoneCall.State.HOLDING) { 586 onStartedHolding(); 587 } 588 589 boolean updateParent = mParent.update(this, imsCall, state); 590 boolean updateMediaCapabilities = updateMediaCapabilities(imsCall); 591 boolean updateWifiState = updateWifiState(); 592 593 return updateParent || updateMediaCapabilities || updateWifiState; 594 } 595 596 @Override 597 public int getPreciseDisconnectCause() { 598 return 0; 599 } 600 601 /** 602 * Notifies this Connection of a request to disconnect a participant of the conference managed 603 * by the connection. 604 * 605 * @param endpoint the {@link android.net.Uri} of the participant to disconnect. 606 */ 607 @Override 608 public void onDisconnectConferenceParticipant(Uri endpoint) { 609 ImsCall imsCall = getImsCall(); 610 if (imsCall == null) { 611 return; 612 } 613 try { 614 imsCall.removeParticipants(new String[]{endpoint.toString()}); 615 } catch (ImsException e) { 616 // No session in place -- no change 617 Rlog.e(LOG_TAG, "onDisconnectConferenceParticipant: no session in place. "+ 618 "Failed to disconnect endpoint = " + endpoint); 619 } 620 } 621 622 /** 623 * Sets the conference connect time. Used when an {@code ImsConference} is created to out of 624 * this phone connection. 625 * 626 * @param conferenceConnectTime The conference connect time. 627 */ 628 public void setConferenceConnectTime(long conferenceConnectTime) { 629 mConferenceConnectTime = conferenceConnectTime; 630 } 631 632 /** 633 * @return The conference connect time. 634 */ 635 public long getConferenceConnectTime() { 636 return mConferenceConnectTime; 637 } 638 639 /** 640 * Check for a change in the video capabilities and audio quality for the {@link ImsCall}, and 641 * update the {@link ImsPhoneConnection} with this information. 642 * 643 * @param imsCall The call to check for changes in media capabilities. 644 * @return Whether the media capabilities have been changed. 645 */ 646 private boolean updateMediaCapabilities(ImsCall imsCall) { 647 if (imsCall == null) { 648 return false; 649 } 650 651 boolean changed = false; 652 653 try { 654 // The actual call profile (negotiated between local and peer). 655 ImsCallProfile negotiatedCallProfile = imsCall.getCallProfile(); 656 // The capabilities of the local device. 657 ImsCallProfile localCallProfile = imsCall.getLocalCallProfile(); 658 // The capabilities of the peer device. 659 ImsCallProfile remoteCallProfile = imsCall.getRemoteCallProfile(); 660 661 if (negotiatedCallProfile != null) { 662 int oldVideoState = getVideoState(); 663 int newVideoState = ImsCallProfile 664 .getVideoStateFromImsCallProfile(negotiatedCallProfile); 665 666 if (oldVideoState != newVideoState) { 667 setVideoState(newVideoState); 668 changed = true; 669 } 670 } 671 672 if (localCallProfile != null) { 673 int callType = localCallProfile.mCallType; 674 675 boolean newLocalVideoCapable = callType == ImsCallProfile.CALL_TYPE_VT; 676 if (isLocalVideoCapable() != newLocalVideoCapable) { 677 setLocalVideoCapable(newLocalVideoCapable); 678 changed = true; 679 } 680 } 681 682 if (remoteCallProfile != null) { 683 boolean newRemoteVideoCapable = remoteCallProfile.mCallType 684 == ImsCallProfile.CALL_TYPE_VT; 685 686 if (isRemoteVideoCapable() != newRemoteVideoCapable) { 687 setRemoteVideoCapable(newRemoteVideoCapable); 688 changed = true; 689 } 690 } 691 692 int newAudioQuality = 693 getAudioQualityFromCallProfile(localCallProfile, remoteCallProfile); 694 if (getAudioQuality() != newAudioQuality) { 695 setAudioQuality(newAudioQuality); 696 changed = true; 697 } 698 699 // Check if call substate has changed. If so notify listeners of call state changed. 700 int callSubstate = getCallSubstate(); 701 int newCallSubstate = imsCall.getCallSubstate(); 702 703 if (callSubstate != newCallSubstate) { 704 setCallSubstate(newCallSubstate); 705 changed = true; 706 } 707 } catch (ImsException e) { 708 // No session in place -- no change 709 } 710 711 return changed; 712 } 713 714 /** 715 * Check for a change in the wifi state of the ImsPhoneCallTracker and update the 716 * {@link ImsPhoneConnection} with this information. 717 * 718 * @return Whether the ImsPhoneCallTracker's usage of wifi has been changed. 719 */ 720 public boolean updateWifiState() { 721 Rlog.d(LOG_TAG, "updateWifiState: " + mOwner.isVowifiEnabled()); 722 if (isWifi() != mOwner.isVowifiEnabled()) { 723 setWifi(mOwner.isVowifiEnabled()); 724 return true; 725 } 726 return false; 727 } 728 729 /** 730 * Determines the {@link ImsPhoneConnection} audio quality based on the local and remote 731 * {@link ImsCallProfile}. If indicate a HQ audio call if the local stream profile 732 * indicates AMR_WB or EVRC_WB and there is no remote restrict cause. 733 * 734 * @param localCallProfile The local call profile. 735 * @param remoteCallProfile The remote call profile. 736 * @return The audio quality. 737 */ 738 private int getAudioQualityFromCallProfile( 739 ImsCallProfile localCallProfile, ImsCallProfile remoteCallProfile) { 740 if (localCallProfile == null || remoteCallProfile == null 741 || localCallProfile.mMediaProfile == null) { 742 return AUDIO_QUALITY_STANDARD; 743 } 744 745 boolean isHighDef = (localCallProfile.mMediaProfile.mAudioQuality 746 == ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB 747 || localCallProfile.mMediaProfile.mAudioQuality 748 == ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB) 749 && remoteCallProfile.mRestrictCause == ImsCallProfile.CALL_RESTRICT_CAUSE_NONE; 750 return isHighDef ? AUDIO_QUALITY_HIGH_DEFINITION : AUDIO_QUALITY_STANDARD; 751 } 752 753 /** 754 * Provides a string representation of the {@link ImsPhoneConnection}. Primarily intended for 755 * use in log statements. 756 * 757 * @return String representation of call. 758 */ 759 @Override 760 public String toString() { 761 StringBuilder sb = new StringBuilder(); 762 sb.append("[ImsPhoneConnection objId: "); 763 sb.append(System.identityHashCode(this)); 764 sb.append(" address:"); 765 sb.append(Log.pii(getAddress())); 766 sb.append(" ImsCall:"); 767 if (mImsCall == null) { 768 sb.append("null"); 769 } else { 770 sb.append(mImsCall); 771 } 772 sb.append("]"); 773 return sb.toString(); 774 } 775} 776 777