1 /* 2 * Copyright (C) 2006 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 17 package com.android.internal.telephony.gsm; 18 import android.content.Context; 19 import android.os.AsyncResult; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Message; 23 import android.os.PowerManager; 24 import android.os.Registrant; 25 import android.os.SystemClock; 26 import android.telephony.DisconnectCause; 27 import android.telephony.Rlog; 28 import android.telephony.PhoneNumberUtils; 29 import android.telephony.ServiceState; 30 import android.text.TextUtils; 31 32 import com.android.internal.telephony.*; 33 import com.android.internal.telephony.uicc.UiccCardApplication; 34 import com.android.internal.telephony.uicc.UiccController; 35 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 36 37 /** 38 * {@hide} 39 */ 40 public class GsmConnection extends Connection { 41 private static final String LOG_TAG = "GsmConnection"; 42 private static final boolean DBG = true; 43 44 //***** Instance Variables 45 46 GsmCallTracker mOwner; 47 GsmCall mParent; 48 49 String mPostDialString; // outgoing calls only 50 boolean mDisconnected; 51 52 int mIndex; // index in GsmCallTracker.connections[], -1 if unassigned 53 // The GSM index is 1 + this 54 55 /* 56 * These time/timespan values are based on System.currentTimeMillis(), 57 * i.e., "wall clock" time. 58 */ 59 long mDisconnectTime; 60 61 int mNextPostDialChar; // index into postDialString 62 63 int mCause = DisconnectCause.NOT_DISCONNECTED; 64 PostDialState mPostDialState = PostDialState.NOT_STARTED; 65 UUSInfo mUusInfo; 66 int mPreciseCause = 0; 67 68 Connection mOrigConnection; 69 70 Handler mHandler; 71 72 private PowerManager.WakeLock mPartialWakeLock; 73 74 //***** Event Constants 75 static final int EVENT_DTMF_DONE = 1; 76 static final int EVENT_PAUSE_DONE = 2; 77 static final int EVENT_NEXT_POST_DIAL = 3; 78 static final int EVENT_WAKE_LOCK_TIMEOUT = 4; 79 80 //***** Constants 81 static final int PAUSE_DELAY_MILLIS = 3 * 1000; 82 static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000; 83 84 //***** Inner Classes 85 86 class MyHandler extends Handler { 87 MyHandler(Looper l) {super(l);} 88 89 @Override 90 public void 91 handleMessage(Message msg) { 92 93 switch (msg.what) { 94 case EVENT_NEXT_POST_DIAL: 95 case EVENT_DTMF_DONE: 96 case EVENT_PAUSE_DONE: 97 processNextPostDialChar(); 98 break; 99 case EVENT_WAKE_LOCK_TIMEOUT: 100 releaseWakeLock(); 101 break; 102 } 103 } 104 } 105 106 //***** Constructors 107 108 /** This is probably an MT call that we first saw in a CLCC response */ 109 /*package*/ 110 GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) { 111 createWakeLock(context); 112 acquireWakeLock(); 113 114 mOwner = ct; 115 mHandler = new MyHandler(mOwner.getLooper()); 116 117 mAddress = dc.number; 118 119 mIsIncoming = dc.isMT; 120 mCreateTime = System.currentTimeMillis(); 121 mCnapName = dc.name; 122 mCnapNamePresentation = dc.namePresentation; 123 mNumberPresentation = dc.numberPresentation; 124 mUusInfo = dc.uusInfo; 125 126 mIndex = index; 127 128 mParent = parentFromDCState (dc.state); 129 mParent.attach(this, dc); 130 } 131 132 /** This is an MO call, created when dialing */ 133 /*package*/ 134 GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall parent) { 135 createWakeLock(context); 136 acquireWakeLock(); 137 138 mOwner = ct; 139 mHandler = new MyHandler(mOwner.getLooper()); 140 141 mDialString = dialString; 142 143 mAddress = PhoneNumberUtils.extractNetworkPortionAlt(dialString); 144 mPostDialString = PhoneNumberUtils.extractPostDialPortion(dialString); 145 146 mIndex = -1; 147 148 mIsIncoming = false; 149 mCnapName = null; 150 mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED; 151 mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED; 152 mCreateTime = System.currentTimeMillis(); 153 154 mParent = parent; 155 parent.attachFake(this, GsmCall.State.DIALING); 156 } 157 158 public void dispose() { 159 } 160 161 static boolean 162 equalsHandlesNulls (Object a, Object b) { 163 return (a == null) ? (b == null) : a.equals (b); 164 } 165 166 /*package*/ boolean 167 compareTo(DriverCall c) { 168 // On mobile originated (MO) calls, the phone number may have changed 169 // due to a SIM Toolkit call control modification. 170 // 171 // We assume we know when MO calls are created (since we created them) 172 // and therefore don't need to compare the phone number anyway. 173 if (! (mIsIncoming || c.isMT)) return true; 174 175 // A new call appearing by SRVCC may have invalid number 176 // if IMS service is not tightly coupled with cellular modem stack. 177 // Thus we prefer the preexisting handover connection instance. 178 if (mOrigConnection != null) return true; 179 180 // ... but we can compare phone numbers on MT calls, and we have 181 // no control over when they begin, so we might as well 182 183 String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); 184 return mIsIncoming == c.isMT && equalsHandlesNulls(mAddress, cAddress); 185 } 186 187 @Override 188 public GsmCall getCall() { 189 return mParent; 190 } 191 192 @Override 193 public long getDisconnectTime() { 194 return mDisconnectTime; 195 } 196 197 @Override 198 public long getHoldDurationMillis() { 199 if (getState() != GsmCall.State.HOLDING) { 200 // If not holding, return 0 201 return 0; 202 } else { 203 return SystemClock.elapsedRealtime() - mHoldingStartTime; 204 } 205 } 206 207 @Override 208 public int getDisconnectCause() { 209 return mCause; 210 } 211 212 @Override 213 public GsmCall.State getState() { 214 if (mDisconnected) { 215 return GsmCall.State.DISCONNECTED; 216 } else { 217 return super.getState(); 218 } 219 } 220 221 @Override 222 public void hangup() throws CallStateException { 223 if (!mDisconnected) { 224 mOwner.hangup(this); 225 } else { 226 throw new CallStateException ("disconnected"); 227 } 228 } 229 230 @Override 231 public void separate() throws CallStateException { 232 if (!mDisconnected) { 233 mOwner.separate(this); 234 } else { 235 throw new CallStateException ("disconnected"); 236 } 237 } 238 239 @Override 240 public PostDialState getPostDialState() { 241 return mPostDialState; 242 } 243 244 @Override 245 public void proceedAfterWaitChar() { 246 if (mPostDialState != PostDialState.WAIT) { 247 Rlog.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " 248 + "getPostDialState() to be WAIT but was " + mPostDialState); 249 return; 250 } 251 252 setPostDialState(PostDialState.STARTED); 253 254 processNextPostDialChar(); 255 } 256 257 @Override 258 public void proceedAfterWildChar(String str) { 259 if (mPostDialState != PostDialState.WILD) { 260 Rlog.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " 261 + "getPostDialState() to be WILD but was " + mPostDialState); 262 return; 263 } 264 265 setPostDialState(PostDialState.STARTED); 266 267 // make a new postDialString, with the wild char replacement string 268 // at the beginning, followed by the remaining postDialString. 269 270 StringBuilder buf = new StringBuilder(str); 271 buf.append(mPostDialString.substring(mNextPostDialChar)); 272 mPostDialString = buf.toString(); 273 mNextPostDialChar = 0; 274 if (Phone.DEBUG_PHONE) { 275 log("proceedAfterWildChar: new postDialString is " + 276 mPostDialString); 277 } 278 279 processNextPostDialChar(); 280 } 281 282 @Override 283 public void cancelPostDial() { 284 setPostDialState(PostDialState.CANCELLED); 285 } 286 287 /** 288 * Called when this Connection is being hung up locally (eg, user pressed "end") 289 * Note that at this point, the hangup request has been dispatched to the radio 290 * but no response has yet been received so update() has not yet been called 291 */ 292 void 293 onHangupLocal() { 294 mCause = DisconnectCause.LOCAL; 295 mPreciseCause = 0; 296 } 297 298 /** 299 * Maps RIL call disconnect code to {@link DisconnectCause}. 300 * @param causeCode RIL disconnect code 301 * @return the corresponding value from {@link DisconnectCause} 302 */ 303 int disconnectCauseFromCode(int causeCode) { 304 /** 305 * See 22.001 Annex F.4 for mapping of cause codes 306 * to local tones 307 */ 308 309 switch (causeCode) { 310 case CallFailCause.USER_BUSY: 311 return DisconnectCause.BUSY; 312 313 case CallFailCause.NO_CIRCUIT_AVAIL: 314 case CallFailCause.TEMPORARY_FAILURE: 315 case CallFailCause.SWITCHING_CONGESTION: 316 case CallFailCause.CHANNEL_NOT_AVAIL: 317 case CallFailCause.QOS_NOT_AVAIL: 318 case CallFailCause.BEARER_NOT_AVAIL: 319 return DisconnectCause.CONGESTION; 320 321 case CallFailCause.ACM_LIMIT_EXCEEDED: 322 return DisconnectCause.LIMIT_EXCEEDED; 323 324 case CallFailCause.CALL_BARRED: 325 return DisconnectCause.CALL_BARRED; 326 327 case CallFailCause.FDN_BLOCKED: 328 return DisconnectCause.FDN_BLOCKED; 329 330 case CallFailCause.UNOBTAINABLE_NUMBER: 331 return DisconnectCause.UNOBTAINABLE_NUMBER; 332 333 case CallFailCause.DIAL_MODIFIED_TO_USSD: 334 return DisconnectCause.DIAL_MODIFIED_TO_USSD; 335 336 case CallFailCause.DIAL_MODIFIED_TO_SS: 337 return DisconnectCause.DIAL_MODIFIED_TO_SS; 338 339 case CallFailCause.DIAL_MODIFIED_TO_DIAL: 340 return DisconnectCause.DIAL_MODIFIED_TO_DIAL; 341 342 case CallFailCause.ERROR_UNSPECIFIED: 343 case CallFailCause.NORMAL_CLEARING: 344 default: 345 GSMPhone phone = mOwner.mPhone; 346 int serviceState = phone.getServiceState().getState(); 347 UiccCardApplication cardApp = phone.getUiccCardApplication(); 348 AppState uiccAppState = (cardApp != null) ? cardApp.getState() : 349 AppState.APPSTATE_UNKNOWN; 350 if (serviceState == ServiceState.STATE_POWER_OFF) { 351 return DisconnectCause.POWER_OFF; 352 } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE 353 || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { 354 return DisconnectCause.OUT_OF_SERVICE; 355 } else if (uiccAppState != AppState.APPSTATE_READY) { 356 return DisconnectCause.ICC_ERROR; 357 } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) { 358 if (phone.mSST.mRestrictedState.isCsRestricted()) { 359 return DisconnectCause.CS_RESTRICTED; 360 } else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) { 361 return DisconnectCause.CS_RESTRICTED_EMERGENCY; 362 } else if (phone.mSST.mRestrictedState.isCsNormalRestricted()) { 363 return DisconnectCause.CS_RESTRICTED_NORMAL; 364 } else { 365 return DisconnectCause.ERROR_UNSPECIFIED; 366 } 367 } else if (causeCode == CallFailCause.NORMAL_CLEARING) { 368 return DisconnectCause.NORMAL; 369 } else { 370 // If nothing else matches, report unknown call drop reason 371 // to app, not NORMAL call end. 372 return DisconnectCause.ERROR_UNSPECIFIED; 373 } 374 } 375 } 376 377 /*package*/ void 378 onRemoteDisconnect(int causeCode) { 379 this.mPreciseCause = causeCode; 380 onDisconnect(disconnectCauseFromCode(causeCode)); 381 } 382 383 /** 384 * Called when the radio indicates the connection has been disconnected. 385 * @param cause call disconnect cause; values are defined in {@link DisconnectCause} 386 */ 387 /*package*/ boolean onDisconnect(int cause) { 388 boolean changed = false; 389 390 mCause = cause; 391 392 if (!mDisconnected) { 393 mIndex = -1; 394 395 mDisconnectTime = System.currentTimeMillis(); 396 mDuration = SystemClock.elapsedRealtime() - mConnectTimeReal; 397 mDisconnected = true; 398 399 if (DBG) Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause); 400 401 mOwner.mPhone.notifyDisconnect(this); 402 403 if (mParent != null) { 404 changed = mParent.connectionDisconnected(this); 405 } 406 407 mOrigConnection = null; 408 } 409 clearPostDialListeners(); 410 releaseWakeLock(); 411 return changed; 412 } 413 414 // Returns true if state has changed, false if nothing changed 415 /*package*/ boolean 416 update (DriverCall dc) { 417 GsmCall newParent; 418 boolean changed = false; 419 boolean wasConnectingInOrOut = isConnectingInOrOut(); 420 boolean wasHolding = (getState() == GsmCall.State.HOLDING); 421 422 newParent = parentFromDCState(dc.state); 423 424 //Ignore dc.number and dc.name in case of a handover connection 425 if (mOrigConnection != null) { 426 if (Phone.DEBUG_PHONE) log("update: mOrigConnection is not null"); 427 } else { 428 log(" mNumberConverted " + mNumberConverted); 429 if (!equalsHandlesNulls(mAddress, dc.number) && (!mNumberConverted 430 || !equalsHandlesNulls(mConvertedNumber, dc.number))) { 431 if (Phone.DEBUG_PHONE) log("update: phone # changed!"); 432 mAddress = dc.number; 433 changed = true; 434 } 435 } 436 437 // A null cnapName should be the same as "" 438 if (TextUtils.isEmpty(dc.name)) { 439 if (!TextUtils.isEmpty(mCnapName)) { 440 changed = true; 441 mCnapName = ""; 442 } 443 } else if (!dc.name.equals(mCnapName)) { 444 changed = true; 445 mCnapName = dc.name; 446 } 447 448 if (Phone.DEBUG_PHONE) log("--dssds----"+mCnapName); 449 mCnapNamePresentation = dc.namePresentation; 450 mNumberPresentation = dc.numberPresentation; 451 452 if (newParent != mParent) { 453 if (mParent != null) { 454 mParent.detach(this); 455 } 456 newParent.attach(this, dc); 457 mParent = newParent; 458 changed = true; 459 } else { 460 boolean parentStateChange; 461 parentStateChange = mParent.update (this, dc); 462 changed = changed || parentStateChange; 463 } 464 465 /** Some state-transition events */ 466 467 if (Phone.DEBUG_PHONE) log( 468 "update: parent=" + mParent + 469 ", hasNewParent=" + (newParent != mParent) + 470 ", wasConnectingInOrOut=" + wasConnectingInOrOut + 471 ", wasHolding=" + wasHolding + 472 ", isConnectingInOrOut=" + isConnectingInOrOut() + 473 ", changed=" + changed); 474 475 476 if (wasConnectingInOrOut && !isConnectingInOrOut()) { 477 onConnectedInOrOut(); 478 } 479 480 if (changed && !wasHolding && (getState() == GsmCall.State.HOLDING)) { 481 // We've transitioned into HOLDING 482 onStartedHolding(); 483 } 484 485 return changed; 486 } 487 488 /** 489 * Called when this Connection is in the foregroundCall 490 * when a dial is initiated. 491 * We know we're ACTIVE, and we know we're going to end up 492 * HOLDING in the backgroundCall 493 */ 494 void 495 fakeHoldBeforeDial() { 496 if (mParent != null) { 497 mParent.detach(this); 498 } 499 500 mParent = mOwner.mBackgroundCall; 501 mParent.attachFake(this, GsmCall.State.HOLDING); 502 503 onStartedHolding(); 504 } 505 506 /*package*/ int 507 getGSMIndex() throws CallStateException { 508 if (mIndex >= 0) { 509 return mIndex + 1; 510 } else { 511 throw new CallStateException ("GSM index not yet assigned"); 512 } 513 } 514 515 /** 516 * An incoming or outgoing call has connected 517 */ 518 void 519 onConnectedInOrOut() { 520 mConnectTime = System.currentTimeMillis(); 521 mConnectTimeReal = SystemClock.elapsedRealtime(); 522 mDuration = 0; 523 524 // bug #678474: incoming call interpreted as missed call, even though 525 // it sounds like the user has picked up the call. 526 if (Phone.DEBUG_PHONE) { 527 log("onConnectedInOrOut: connectTime=" + mConnectTime); 528 } 529 530 if (!mIsIncoming) { 531 // outgoing calls only 532 processNextPostDialChar(); 533 } 534 releaseWakeLock(); 535 } 536 537 /*package*/ void 538 onStartedHolding() { 539 mHoldingStartTime = SystemClock.elapsedRealtime(); 540 } 541 /** 542 * Performs the appropriate action for a post-dial char, but does not 543 * notify application. returns false if the character is invalid and 544 * should be ignored 545 */ 546 private boolean 547 processPostDialChar(char c) { 548 if (PhoneNumberUtils.is12Key(c)) { 549 mOwner.mCi.sendDtmf(c, mHandler.obtainMessage(EVENT_DTMF_DONE)); 550 } else if (c == PhoneNumberUtils.PAUSE) { 551 // From TS 22.101: 552 // It continues... 553 // Upon the called party answering the UE shall send the DTMF digits 554 // automatically to the network after a delay of 3 seconds( 20 ). 555 // The digits shall be sent according to the procedures and timing 556 // specified in 3GPP TS 24.008 [13]. The first occurrence of the 557 // "DTMF Control Digits Separator" shall be used by the ME to 558 // distinguish between the addressing digits (i.e. the phone number) 559 // and the DTMF digits. Upon subsequent occurrences of the 560 // separator, 561 // the UE shall pause again for 3 seconds ( 20 ) before sending 562 // any further DTMF digits. 563 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_PAUSE_DONE), 564 PAUSE_DELAY_MILLIS); 565 } else if (c == PhoneNumberUtils.WAIT) { 566 setPostDialState(PostDialState.WAIT); 567 } else if (c == PhoneNumberUtils.WILD) { 568 setPostDialState(PostDialState.WILD); 569 } else { 570 return false; 571 } 572 573 return true; 574 } 575 576 @Override 577 public String 578 getRemainingPostDialString() { 579 if (mPostDialState == PostDialState.CANCELLED 580 || mPostDialState == PostDialState.COMPLETE 581 || mPostDialString == null 582 || mPostDialString.length() <= mNextPostDialChar 583 ) { 584 return ""; 585 } 586 587 return mPostDialString.substring(mNextPostDialChar); 588 } 589 590 @Override 591 protected void finalize() 592 { 593 /** 594 * It is understood that This finializer is not guaranteed 595 * to be called and the release lock call is here just in 596 * case there is some path that doesn't call onDisconnect 597 * and or onConnectedInOrOut. 598 */ 599 if (mPartialWakeLock.isHeld()) { 600 Rlog.e(LOG_TAG, "[GSMConn] UNEXPECTED; mPartialWakeLock is held when finalizing."); 601 } 602 clearPostDialListeners(); 603 releaseWakeLock(); 604 } 605 606 private void 607 processNextPostDialChar() { 608 char c = 0; 609 Registrant postDialHandler; 610 611 if (mPostDialState == PostDialState.CANCELLED) { 612 //Rlog.v("GSM", "##### processNextPostDialChar: postDialState == CANCELLED, bail"); 613 return; 614 } 615 616 if (mPostDialString == null || 617 mPostDialString.length() <= mNextPostDialChar) { 618 setPostDialState(PostDialState.COMPLETE); 619 620 // notifyMessage.arg1 is 0 on complete 621 c = 0; 622 } else { 623 boolean isValid; 624 625 setPostDialState(PostDialState.STARTED); 626 627 c = mPostDialString.charAt(mNextPostDialChar++); 628 629 isValid = processPostDialChar(c); 630 631 if (!isValid) { 632 // Will call processNextPostDialChar 633 mHandler.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget(); 634 // Don't notify application 635 Rlog.e("GSM", "processNextPostDialChar: c=" + c + " isn't valid!"); 636 return; 637 } 638 } 639 640 notifyPostDialListenersNextChar(c); 641 642 // TODO: remove the following code since the handler no longer executes anything. 643 postDialHandler = mOwner.mPhone.mPostDialHandler; 644 645 Message notifyMessage; 646 647 if (postDialHandler != null 648 && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { 649 // The AsyncResult.result is the Connection object 650 PostDialState state = mPostDialState; 651 AsyncResult ar = AsyncResult.forMessage(notifyMessage); 652 ar.result = this; 653 ar.userObj = state; 654 655 // arg1 is the character that was/is being processed 656 notifyMessage.arg1 = c; 657 658 //Rlog.v("GSM", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); 659 notifyMessage.sendToTarget(); 660 } 661 } 662 663 664 /** "connecting" means "has never been ACTIVE" for both incoming 665 * and outgoing calls 666 */ 667 private boolean 668 isConnectingInOrOut() { 669 return mParent == null || mParent == mOwner.mRingingCall 670 || mParent.mState == GsmCall.State.DIALING 671 || mParent.mState == GsmCall.State.ALERTING; 672 } 673 674 private GsmCall 675 parentFromDCState (DriverCall.State state) { 676 switch (state) { 677 case ACTIVE: 678 case DIALING: 679 case ALERTING: 680 return mOwner.mForegroundCall; 681 //break; 682 683 case HOLDING: 684 return mOwner.mBackgroundCall; 685 //break; 686 687 case INCOMING: 688 case WAITING: 689 return mOwner.mRingingCall; 690 //break; 691 692 default: 693 throw new RuntimeException("illegal call state: " + state); 694 } 695 } 696 697 /** 698 * Set post dial state and acquire wake lock while switching to "started" 699 * state, the wake lock will be released if state switches out of "started" 700 * state or after WAKE_LOCK_TIMEOUT_MILLIS. 701 * @param s new PostDialState 702 */ 703 private void setPostDialState(PostDialState s) { 704 if (mPostDialState != PostDialState.STARTED 705 && s == PostDialState.STARTED) { 706 acquireWakeLock(); 707 Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); 708 mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS); 709 } else if (mPostDialState == PostDialState.STARTED 710 && s != PostDialState.STARTED) { 711 mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); 712 releaseWakeLock(); 713 } 714 mPostDialState = s; 715 notifyPostDialListeners(); 716 } 717 718 private void 719 createWakeLock(Context context) { 720 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 721 mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 722 } 723 724 private void 725 acquireWakeLock() { 726 log("acquireWakeLock"); 727 mPartialWakeLock.acquire(); 728 } 729 730 private void 731 releaseWakeLock() { 732 synchronized(mPartialWakeLock) { 733 if (mPartialWakeLock.isHeld()) { 734 log("releaseWakeLock"); 735 mPartialWakeLock.release(); 736 } 737 } 738 } 739 740 private void log(String msg) { 741 Rlog.d(LOG_TAG, "[GSMConn] " + msg); 742 } 743 744 @Override 745 public int getNumberPresentation() { 746 return mNumberPresentation; 747 } 748 749 @Override 750 public UUSInfo getUUSInfo() { 751 return mUusInfo; 752 } 753 754 public int getPreciseDisconnectCause() { 755 return mPreciseCause; 756 } 757 758 @Override 759 public void migrateFrom(Connection c) { 760 if (c == null) return; 761 762 super.migrateFrom(c); 763 764 this.mUusInfo = c.getUUSInfo(); 765 766 this.setUserData(c.getUserData()); 767 } 768 769 @Override 770 public Connection getOrigConnection() { 771 return mOrigConnection; 772 } 773 774 @Override 775 public boolean isMultiparty() { 776 if (mOrigConnection != null) { 777 return mOrigConnection.isMultiparty(); 778 } 779 780 return false; 781 } 782 } 783