/** * Update the "permanent" position (ie. the actual layout params) of the sliding card based on the * current call state. * * <p>This method sets mCardAtTop, mCallEndedState, mCardPreferredX, and mCardPreferredY. It also * repositions the PopupWindow if it's showing. * * <p>Note that *while sliding* we manually reposition the card on every motion event that comes * in. The x/y position we set here determines where the card should be while *not* sliding. * * <p>TODO: If the card position changes for some reason *other* than user action (i.e. as a * result of an onPhoneStateChanged() callback), we should smoothly animate the position change! * (For example, if you're in a call and the other end hangs up, the card should switch to "Call * ended" mode and smoothly animate to the bottom position.) */ public /* package */ void updateCardPreferredPosition() { if (DBG) log("updateCardPreferredPosition()..."); // if (DBG) log("- card's LayoutParams: " + mCallCard.getLayoutParams()); // Bail out if our View hierarchy isn't attached to a Window yet // (since the mMainFrame.getLocationOnScreen() call below // will fail.) if (mMainFrame.getWindowToken() == null) { if (DBG) log("updateCardPreferredPosition: View hierarchy unattached; bailing..."); return; } /* if (mMainFrame.getHeight() == 0) { // The code here needs to know the sizes and positions of some // views in the mMainFrame view hierarchy, so you're only // allowed to call this method *after* the whole in-call UI // has been measured and laid out. // (This is why we defer calling showPopup() until an // onGlobalLayout() call comes in.) throw new IllegalStateException( "updateCardPreferredPosition: main frame not measured yet"); } */ // Given the current state of the Phone and the UI, decide whether // the card should be at the TOP or BOTTOM of the screen right now. // Compute the possible coordinates onscreen for the popup. // TODO: this block is duplicated below; use a single helper method instead. mMainFrame.getLocationInWindow(mTempLocation); final int mainFrameX = mTempLocation[0]; final int mainFrameY = 0; // mTempLocation[1]; if (DBG) log("- mMainFrame loc in window: " + mainFrameX + ", " + mainFrameY); // In the "top" position the CallCard is aligned exactly with the // top edge of the main frame. final int popupTopPosY = mainFrameY; // And in the "bottom" position, the bottom of the CallCard is // aligned exactly with the bottom of the main frame. if (height == 0) { height = mCallCard.getHeight(); // Reposition the "slide hints". RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mSlideUp.getLayoutParams(); // Equivalent to setting android:layout_marginTop in XML lp.bottomMargin = height; mSlideUp.setLayoutParams(lp); lp = (RelativeLayout.LayoutParams) mSlideDown.getLayoutParams(); // Equivalent to setting android:layout_marginTop in XML lp.topMargin = height; mSlideDown.setLayoutParams(lp); height += 10; } final int popupBottomPosY = mainFrameY + mMainFrame.getHeight() - height; if (Receiver.ccCall != null && Receiver.ccCall.getState() != Call.State.DISCONNECTED) { // When the phone is in use, the position of the card is // determined solely by whether an incoming call is ringing or // not. final boolean hasRingingCall = Receiver.ccCall.getState() == Call.State.INCOMING; mCardAtTop = !hasRingingCall; mCallEndedState = false; } else { // Phone is completely idle! Display the CALL ENDED state // with the card at the bottom of the screen. mCardAtTop = false; mCallEndedState = true; } mCardPreferredX = mainFrameX; mCardPreferredY = mCardAtTop ? popupTopPosY : popupBottomPosY; if (DBG) log( "==> Setting card preferred position (mCardAtTop = " + mCardAtTop + ") to: " + mCardPreferredX + ", " + mCardPreferredY); // This is a no-op if the PopupWindow isn't showing. mCallCard.update(mCardPreferredX, mCardPreferredY, -1, -1); }