1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/*
2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License.
6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at
7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and
14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License.
15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone;
18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
195cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brownimport android.animation.Animator;
205cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brownimport android.animation.AnimatorListenerAdapter;
21b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.ContentUris;
22b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
23b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.graphics.drawable.Drawable;
24b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.pim.ContactsAsyncHelper;
263d6d70562622660e581b53308e675386d299dd19Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
27f3602b0659d01fef19159e7111be76102549f7a1David Brownimport android.telephony.PhoneNumberUtils;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.TextUtils;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.format.DateUtils;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.AttributeSet;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.LayoutInflater;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.View;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.ViewGroup;
35dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brownimport android.view.accessibility.AccessibilityEvent;
366d5544932495d81ff7ce53f4678c4beb25acc1b0David Brownimport android.widget.Button;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.FrameLayout;
38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.ImageView;
39d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brownimport android.widget.RelativeLayout;
40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.TextView;
41b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
426b7d0da33af02960736da204eb7a25ccf91d5396David Brownimport com.android.internal.telephony.Call;
436b7d0da33af02960736da204eb7a25ccf91d5396David Brownimport com.android.internal.telephony.CallerInfo;
446b7d0da33af02960736da204eb7a25ccf91d5396David Brownimport com.android.internal.telephony.CallerInfoAsyncQuery;
456b7d0da33af02960736da204eb7a25ccf91d5396David Brownimport com.android.internal.telephony.Connection;
466b7d0da33af02960736da204eb7a25ccf91d5396David Brownimport com.android.internal.telephony.Phone;
478343169cc89621d46dce86449f5ee1ff5d3a4919John Wangimport com.android.internal.telephony.CallManager;
486b7d0da33af02960736da204eb7a25ccf91d5396David Brown
490fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Savilleimport java.util.List;
500fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
516b7d0da33af02960736da204eb7a25ccf91d5396David Brown
52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * "Call card" UI element: the in-call screen contains a tiled layout of call
54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * cards, each representing the state of a current "call" (ie. an active call,
55b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * a call on hold, or an incoming call.)
56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class CallCard extends FrameLayout
58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        implements CallTime.OnTickListener, CallerInfoAsyncQuery.OnQueryCompleteListener,
59507ee75639e41c17edd410ef787e0617778071aaDavid Brown                   ContactsAsyncHelper.OnImageLoadCompleteListener {
60796c70c99bc39295bf685061056f06ab8949c742David Brown    private static final String LOG_TAG = "CallCard";
61796c70c99bc39295bf685061056f06ab8949c742David Brown    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
62b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
638bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project    /**
648bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project     * Reference to the InCallScreen activity that owns us.  This may be
658bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project     * null if we haven't been initialized yet *or* after the InCallScreen
668bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project     * activity has been destroyed.
678bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project     */
688bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project    private InCallScreen mInCallScreen;
698bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project
700fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville    // Phone app instance
710fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville    private PhoneApp mApplication;
720fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Top-level subviews of the CallCard
74d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    private ViewGroup mCallInfoContainer;  // Container for info about the current call(s)
75d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    private ViewGroup mPrimaryCallInfo;  // "Call info" block #1 (the foreground or ringing call)
76d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    private ViewGroup mPrimaryCallBanner;  // "Call banner" for the primary call
77d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    private ViewGroup mSecondaryCallInfo;  // "Call info" block #2 (the background "on hold" call)
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown    // "Call state" widgets
8030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown    private TextView mCallStateLabel;
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private TextView mElapsedTime;
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
8334a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown    // Text colors, used for various labels / titles
849d14e16e8214b4a396dad293b6f0941608ee4798David Brown    private int mTextColorCallTypeSip;
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
860d315275d08cd33f801ae3a74e8fc265520f6246David Brown    // The main block of info about the "primary" or "active" call,
870d315275d08cd33f801ae3a74e8fc265520f6246David Brown    // including photo / name / phone number / etc.
88b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown    private InCallContactPhoto mPhoto;
89b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private TextView mName;
90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private TextView mPhoneNumber;
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private TextView mLabel;
929d14e16e8214b4a396dad293b6f0941608ee4798David Brown    private TextView mCallTypeLabel;
9329d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown    private TextView mSocialStatus;
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
950d315275d08cd33f801ae3a74e8fc265520f6246David Brown    // Info about the "secondary" call, which is the "call on hold" when
960d315275d08cd33f801ae3a74e8fc265520f6246David Brown    // two lines are in use.
970d315275d08cd33f801ae3a74e8fc265520f6246David Brown    private TextView mSecondaryCallName;
980d315275d08cd33f801ae3a74e8fc265520f6246David Brown    private TextView mSecondaryCallStatus;
99b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown    private InCallContactPhoto mSecondaryCallPhoto;
100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1019688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown    // Onscreen hint for the incoming call RotarySelector widget.
102ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller    private int mIncomingCallWidgetHintTextResId;
103ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller    private int mIncomingCallWidgetHintColorResId;
1049688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown
105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private CallTime mCallTime;
106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Track the state for the photo.
108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ContactsAsyncHelper.ImageTracker mPhotoTracker;
109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
11029d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown    // Cached DisplayMetrics density.
11129d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown    private float mDensity;
11229d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown
113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public CallCard(Context context, AttributeSet attrs) {
114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        super(context, attrs);
115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("CallCard constructor...");
117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("- this = " + this);
118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("- context " + context + ", attrs " + attrs);
119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Inflate the contents of this CallCard, and add it (to ourself) as a child.
121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LayoutInflater inflater = LayoutInflater.from(context);
122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        inflater.inflate(
123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                R.layout.call_card,  // resource
124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                this,                // root
125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                true);
126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1270fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        mApplication = PhoneApp.getInstance();
1280fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mCallTime = new CallTime(this);
130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // create a new object to track the state for the photo.
132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhotoTracker = new ContactsAsyncHelper.ImageTracker();
13329d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown
13429d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        mDensity = getResources().getDisplayMetrics().density;
13529d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        if (DBG) log("- Density: " + mDensity);
136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1388bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project    void setInCallScreenInstance(InCallScreen inCallScreen) {
1398bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project        mInCallScreen = inCallScreen;
1408bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project    }
1418bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project
142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void onTickForCallTimeElapsed(long timeElapsed) {
143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // While a call is in progress, update the elapsed time shown
144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // onscreen.
145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        updateElapsedTimeWidget(timeElapsed);
146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */
149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    void stopTimer() {
150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mCallTime.cancelTimer();
151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    @Override
154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    protected void onFinishInflate() {
155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        super.onFinishInflate();
156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("CallCard onFinishInflate(this = " + this + ")...");
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
159d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        mCallInfoContainer = (ViewGroup) findViewById(R.id.call_info_container);
1609033b29f9a5c890e676aebe957c368c3679aac3cDavid Brown        mPrimaryCallInfo = (ViewGroup) findViewById(R.id.call_info_1);
161d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        mPrimaryCallBanner = (ViewGroup) findViewById(R.id.call_banner_1);
1629033b29f9a5c890e676aebe957c368c3679aac3cDavid Brown        mSecondaryCallInfo = (ViewGroup) findViewById(R.id.call_info_2);
16330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        mCallStateLabel = (TextView) findViewById(R.id.callStateLabel);
164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mElapsedTime = (TextView) findViewById(R.id.elapsedTime);
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Text colors
1679d14e16e8214b4a396dad293b6f0941608ee4798David Brown        mTextColorCallTypeSip = getResources().getColor(R.color.incall_callTypeSip);
168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // "Caller info" area, including photo / name / phone numbers / etc
170b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown        mPhoto = (InCallContactPhoto) findViewById(R.id.photo);
171b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown        ImageView inset = (ImageView) findViewById(R.id.insetPhoto);
172b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown        mPhoto.setInsetImageView(inset);
173b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown
174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mName = (TextView) findViewById(R.id.name);
175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhoneNumber = (TextView) findViewById(R.id.phoneNumber);
176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mLabel = (TextView) findViewById(R.id.label);
1779d14e16e8214b4a396dad293b6f0941608ee4798David Brown        mCallTypeLabel = (TextView) findViewById(R.id.callTypeLabel);
17829d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        mSocialStatus = (TextView) findViewById(R.id.socialStatus);
179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1809033b29f9a5c890e676aebe957c368c3679aac3cDavid Brown        // Secondary info area, for the background ("on hold") call
1810d315275d08cd33f801ae3a74e8fc265520f6246David Brown        mSecondaryCallName = (TextView) findViewById(R.id.secondaryCallName);
1820d315275d08cd33f801ae3a74e8fc265520f6246David Brown        mSecondaryCallStatus = (TextView) findViewById(R.id.secondaryCallStatus);
183b424ca2073702aff4ac1d9297d8bbe73ee4cd8b9David Brown        mSecondaryCallPhoto = (InCallContactPhoto) findViewById(R.id.secondaryCallPhoto);
184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
186b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown    /**
187b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * Updates the state of all UI elements on the CallCard, based on the
188b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * current state of the phone.
189b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     */
1908343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    void updateState(CallManager cm) {
1918343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if (DBG) log("updateState(" + cm + ")...");
192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
193d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        // Update the onscreen UI based on the current state of the phone.
194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1958343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Phone.State state = cm.getState();  // IDLE, RINGING, or OFFHOOK
196091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan        Call ringingCall = cm.getFirstActiveRingingCall();
197091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan        Call fgCall = cm.getActiveFgCall();
198091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan        Call bgCall = cm.getFirstActiveBgCall();
199091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan
200d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        // Update the overall layout of the onscreen elements.
201d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        updateCallInfoLayout(state);
202d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown
2037f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        // If the FG call is dialing/alerting, we should display for that call
2047f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        // and ignore the ringing call. This case happens when the telephony
2057f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        // layer rejects the ringing call while the FG call is dialing/alerting,
2067f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        // but the incoming call *does* briefly exist in the DISCONNECTING or
2077f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        // DISCONNECTED state.
2087f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan        if ((ringingCall.getState() != Call.State.IDLE)
2097f09c1629141416c489ede69e70e2aa59453ddedHung-ying Tyan                && !fgCall.getState().isDialing()) {
210091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // A phone call is ringing, call waiting *or* being rejected
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // (ie. another call may also be active as well.)
2128343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            updateRingingCall(cm);
213091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan        } else if ((fgCall.getState() != Call.State.IDLE)
214091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan                || (bgCall.getState() != Call.State.IDLE)) {
215091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // We are here because either:
216091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // (1) the phone is off hook. At least one call exists that is
217091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // dialing, active, or holding, and no calls are ringing or waiting,
218091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // or:
219091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // (2) the phone is IDLE but a call just ended and it's still in
220091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // the DISCONNECTING or DISCONNECTED state. In this case, we want
221091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // the main CallCard to display "Hanging up" or "Call ended".
222091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // The normal "foreground call" code path handles both cases.
2238343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            updateForegroundCall(cm);
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
225091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // We don't have any DISCONNECTED calls, which means
226091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // that the phone is *truly* idle.
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //
228091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // It's very rare to be on the InCallScreen at all in this
229091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // state, but it can happen in some cases:
230091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // - A stray onPhoneStateChanged() event came in to the
231091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //   InCallScreen *after* it was dismissed.
232091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // - We're allowed to be on the InCallScreen because
233091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //   an MMI or USSD is running, but there's no actual "call"
234091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //   to display.
235091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // - We're displaying an error dialog to the user
236091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //   (explaining why the call failed), so we need to stay on
237091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //   the InCallScreen so that the dialog will be visible.
238091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            //
239091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            // In these cases, put the callcard into a sane but "blank" state:
240091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan            updateNoCall(cm);
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
245d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown     * Updates the overall size and positioning of mCallInfoContainer and
246d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown     * the "Call info" blocks, based on the phone state.
247d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown     */
248d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    private void updateCallInfoLayout(Phone.State state) {
249d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        boolean ringing = (state == Phone.State.RINGING);
250ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        if (DBG) log("updateCallInfoLayout()...  ringing = " + ringing);
251d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown
252507ee75639e41c17edd410ef787e0617778071aaDavid Brown        // Based on the current state, update the overall
253ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        // CallCard layout:
254ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown
255ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        // - Update the bottom margin of mCallInfoContainer to make sure
256ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        //   the call info area won't overlap with the touchable
257ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        //   controls on the bottom part of the screen.
258d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown
259507ee75639e41c17edd410ef787e0617778071aaDavid Brown        int reservedVerticalSpace = mInCallScreen.getInCallTouchUi().getTouchUiHeight();
260d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        ViewGroup.MarginLayoutParams callInfoLp =
261d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown                (ViewGroup.MarginLayoutParams) mCallInfoContainer.getLayoutParams();
262d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        callInfoLp.bottomMargin = reservedVerticalSpace;  // Equivalent to setting
263d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown                                                          // android:layout_marginBottom in XML
264ee6be3c53945e69acce6c2c852ce1ebf69015c9dDavid Brown        if (DBG) log("  ==> callInfoLp.bottomMargin: " + reservedVerticalSpace);
265d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown        mCallInfoContainer.setLayoutParams(callInfoLp);
266d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    }
267d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown
268d5f6f5f0c3dd6f4c939c1e432bc75fd4da0d4b74David Brown    /**
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the UI for the state where the phone is in use, but not ringing.
270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
2718343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    private void updateForegroundCall(CallManager cm) {
272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("updateForegroundCall()...");
27302d1c632adde606031c1fe6ea0e3be1e288fd6c6David Brown        // if (DBG) PhoneUtils.dumpCallManager();
2748343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
2758343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call fgCall = cm.getActiveFgCall();
2768343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call bgCall = cm.getFirstActiveBgCall();
2778343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
278091ccad8630a43e62d84fba9c7613441e9d0a597Hung-ying Tyan        if (fgCall.getState() == Call.State.IDLE) {
279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("updateForegroundCall: no active call, show holding call");
280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // TODO: make sure this case agrees with the latest UI spec.
281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Display the background call in the main info area of the
283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // CallCard, since there is no foreground call.  Note that
284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // displayMainCallStatus() will notice if the call we passed in is on
285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // hold, and display the "on hold" indication.
286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            fgCall = bgCall;
287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // And be sure to not display anything in the "on hold" box.
289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            bgCall = null;
290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2928343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        displayMainCallStatus(cm, fgCall);
2938343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
2948343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Phone phone = fgCall.getPhone();
2950fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
29679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        int phoneType = phone.getPhoneType();
29779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
29839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai            if ((mApplication.cdmaPhoneCallState.getCurrentCallState()
29939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
30039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    && mApplication.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
3018343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                displayOnHoldCallStatus(cm, fgCall);
3020fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            } else {
3030fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                //This is required so that even if a background call is not present
3040fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // we need to clean up the background call area.
3058343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                displayOnHoldCallStatus(cm, bgCall);
3060fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            }
307872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
308872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
3098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            displayOnHoldCallStatus(cm, bgCall);
3100fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the UI for the state where an incoming call is ringing (or
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * call waiting), regardless of whether the phone's already offhook.
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
3178343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    private void updateRingingCall(CallManager cm) {
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("updateRingingCall()...");
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3208343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call ringingCall = cm.getFirstActiveRingingCall();
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3226b7d0da33af02960736da204eb7a25ccf91d5396David Brown        // Display caller-id info and photo from the incoming call:
3238343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        displayMainCallStatus(cm, ringingCall);
3246b7d0da33af02960736da204eb7a25ccf91d5396David Brown
3256b7d0da33af02960736da204eb7a25ccf91d5396David Brown        // And even in the Call Waiting case, *don't* show any info about
3266b7d0da33af02960736da204eb7a25ccf91d5396David Brown        // the current ongoing call and/or the current call on hold.
3276b7d0da33af02960736da204eb7a25ccf91d5396David Brown        // (Since the caller-id info for the incoming call totally trumps
3286b7d0da33af02960736da204eb7a25ccf91d5396David Brown        // any info about the current call(s) in progress.)
3298343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        displayOnHoldCallStatus(cm, null);
330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the UI for the state where the phone is not in use.
334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This is analogous to updateForegroundCall() and updateRingingCall(),
335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * but for the (uncommon) case where the phone is
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * totally idle.  (See comments in updateState() above.)
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This puts the callcard into a sane but "blank" state.
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
3408343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    private void updateNoCall(CallManager cm) {
341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("updateNoCall()...");
342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3438343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        displayMainCallStatus(cm, null);
3448343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        displayOnHoldCallStatus(cm, null);
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the main block of caller info on the CallCard
3490d315275d08cd33f801ae3a74e8fc265520f6246David Brown     * (ie. the stuff in the primaryCallInfo block) based on the specified Call.
350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
3518343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    private void displayMainCallStatus(CallManager cm, Call call) {
35202d1c632adde606031c1fe6ea0e3be1e288fd6c6David Brown        if (DBG) log("displayMainCallStatus(call " + call + ")...");
353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (call == null) {
355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // There's no call to display, presumably because the phone is idle.
3560d315275d08cd33f801ae3a74e8fc265520f6246David Brown            mPrimaryCallInfo.setVisibility(View.GONE);
357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return;
358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
3590d315275d08cd33f801ae3a74e8fc265520f6246David Brown        mPrimaryCallInfo.setVisibility(View.VISIBLE);
360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call.State state = call.getState();
362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("  - call.state: " + call.getState());
363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (state) {
365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ACTIVE:
3665eff1e7d582679b3a85f580eb1d550b2e6ca111cDavid Brown            case DISCONNECTING:
367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // update timer field
368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("displayMainCallStatus: start periodicUpdateTimer");
369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.setActiveCallMode(call);
370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.reset();
371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.periodicUpdateTimer();
372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case HOLDING:
376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // update timer field
377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.cancelTimer();
378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DISCONNECTED:
382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Stop getting timer ticks from this call
383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.cancelTimer();
384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DIALING:
388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ALERTING:
389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Stop getting timer ticks from a previous call
390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.cancelTimer();
391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case INCOMING:
395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case WAITING:
396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Stop getting timer ticks from a previous call
397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallTime.cancelTimer();
398b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
399b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case IDLE:
402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // The "main CallCard" should never be trying to display
403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // an idle call!  In updateState(), if the phone is idle,
404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // we call updateNoCall(), which means that we shouldn't
405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // have passed a call into this method at all.
406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Log.w(LOG_TAG, "displayMainCallStatus: IDLE call in the main call card!");
407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // (It is possible, though, that we had a valid call which
409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // became idle *after* the check in updateState() but
410b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // before we get here...  So continue the best we can,
411b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // with whatever (stale) info we can get from the
412b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // passed-in Call object.)
413b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Log.w(LOG_TAG, "displayMainCallStatus: unexpected call state: " + state);
418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
42130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        updateCallStateWidgets(call);
422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (PhoneUtils.isConferenceCall(call)) {
424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Update onscreen info for a conference call.
425872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            updateDisplayForConference(call);
426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Update onscreen info for a regular call (which presumably
428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // has only one connection.)
4290fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            Connection conn = null;
4308343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            int phoneType = call.getPhone().getPhoneType();
43179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            if (phoneType == Phone.PHONE_TYPE_CDMA) {
4320fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                conn = call.getLatestConnection();
433872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            } else if ((phoneType == Phone.PHONE_TYPE_GSM)
434872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                  || (phoneType == Phone.PHONE_TYPE_SIP)) {
4350fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                conn = call.getEarliestConnection();
43679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            } else {
43779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                throw new IllegalStateException("Unexpected phone type: " + phoneType);
4380fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            }
439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (conn == null) {
441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("displayMainCallStatus: connection is null, using default values.");
442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the connection is null, we run through the behaviour
443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // we had in the past, which breaks down into trivial steps
444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // with the current implementation of getCallerInfo and
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // updateDisplayForPerson.
4464359358c4f430cbb986a5e7640ec506f08f1e332David Brown                CallerInfo info = PhoneUtils.getCallerInfo(getContext(), null /* conn */);
4475a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                updateDisplayForPerson(info, Connection.PRESENTATION_ALLOWED, false, call, conn);
448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("  - CONN: " + conn + ", state = " + conn.getState());
4504359358c4f430cbb986a5e7640ec506f08f1e332David Brown                int presentation = conn.getNumberPresentation();
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // make sure that we only make a new query when the current
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // callerinfo differs from what we've been requested to display.
454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                boolean runQuery = true;
455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Object o = conn.getUserData();
456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (o instanceof PhoneUtils.CallerInfoToken) {
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    runQuery = mPhotoTracker.isDifferentImageRequest(
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ((PhoneUtils.CallerInfoToken) o).currentInfo);
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    runQuery = mPhotoTracker.isDifferentImageRequest(conn);
461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
46346532b66a467f247380054270c6151aa3dc7a761Wink Saville                // Adding a check to see if the update was caused due to a Phone number update
46446532b66a467f247380054270c6151aa3dc7a761Wink Saville                // or CNAP update. If so then we need to start a new query
46579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneType == Phone.PHONE_TYPE_CDMA) {
46646532b66a467f247380054270c6151aa3dc7a761Wink Saville                    Object obj = conn.getUserData();
46746532b66a467f247380054270c6151aa3dc7a761Wink Saville                    String updatedNumber = conn.getAddress();
46846532b66a467f247380054270c6151aa3dc7a761Wink Saville                    String updatedCnapName = conn.getCnapName();
46946532b66a467f247380054270c6151aa3dc7a761Wink Saville                    CallerInfo info = null;
47046532b66a467f247380054270c6151aa3dc7a761Wink Saville                    if (obj instanceof PhoneUtils.CallerInfoToken) {
47146532b66a467f247380054270c6151aa3dc7a761Wink Saville                        info = ((PhoneUtils.CallerInfoToken) o).currentInfo;
47246532b66a467f247380054270c6151aa3dc7a761Wink Saville                    } else if (o instanceof CallerInfo) {
47346532b66a467f247380054270c6151aa3dc7a761Wink Saville                        info = (CallerInfo) o;
47446532b66a467f247380054270c6151aa3dc7a761Wink Saville                    }
47546532b66a467f247380054270c6151aa3dc7a761Wink Saville
47646532b66a467f247380054270c6151aa3dc7a761Wink Saville                    if (info != null) {
47746532b66a467f247380054270c6151aa3dc7a761Wink Saville                        if (updatedNumber != null && !updatedNumber.equals(info.phoneNumber)) {
47846532b66a467f247380054270c6151aa3dc7a761Wink Saville                            if (DBG) log("- displayMainCallStatus: updatedNumber = "
47946532b66a467f247380054270c6151aa3dc7a761Wink Saville                                    + updatedNumber);
48046532b66a467f247380054270c6151aa3dc7a761Wink Saville                            runQuery = true;
48146532b66a467f247380054270c6151aa3dc7a761Wink Saville                        }
48246532b66a467f247380054270c6151aa3dc7a761Wink Saville                        if (updatedCnapName != null && !updatedCnapName.equals(info.cnapName)) {
48346532b66a467f247380054270c6151aa3dc7a761Wink Saville                            if (DBG) log("- displayMainCallStatus: updatedCnapName = "
48446532b66a467f247380054270c6151aa3dc7a761Wink Saville                                    + updatedCnapName);
48546532b66a467f247380054270c6151aa3dc7a761Wink Saville                            runQuery = true;
48646532b66a467f247380054270c6151aa3dc7a761Wink Saville                        }
48746532b66a467f247380054270c6151aa3dc7a761Wink Saville                    }
48846532b66a467f247380054270c6151aa3dc7a761Wink Saville                }
48946532b66a467f247380054270c6151aa3dc7a761Wink Saville
490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (runQuery) {
491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("- displayMainCallStatus: starting CallerInfo query...");
492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.CallerInfoToken info =
493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            PhoneUtils.startGetCallerInfo(getContext(), conn, this, call);
4945a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    updateDisplayForPerson(info.currentInfo, presentation, !info.isFinal,
4955a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                                           call, conn);
496b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // No need to fire off a new query.  We do still need
498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // to update the display, though (since we might have
499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // previously been in the "conference call" state.)
500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("- displayMainCallStatus: using data we already have...");
501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (o instanceof CallerInfo) {
502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        CallerInfo ci = (CallerInfo) o;
503e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        // Update CNAP information if Phone state change occurred
504e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        ci.cnapName = conn.getCnapName();
505e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        ci.numberPresentation = conn.getNumberPresentation();
506e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        ci.namePresentation = conn.getCnapNamePresentation();
507e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        if (DBG) log("- displayMainCallStatus: CNAP data from Connection: "
508e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                                + "CNAP name=" + ci.cnapName
509e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                                + ", Number/Name Presentation=" + ci.numberPresentation);
510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (DBG) log("   ==> Got CallerInfo; updating display: ci = " + ci);
5115a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        updateDisplayForPerson(ci, presentation, false, call, conn);
512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (o instanceof PhoneUtils.CallerInfoToken){
513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        CallerInfo ci = ((PhoneUtils.CallerInfoToken) o).currentInfo;
514e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        if (DBG) log("- displayMainCallStatus: CNAP data from Connection: "
515e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                                + "CNAP name=" + ci.cnapName
516e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                                + ", Number/Name Presentation=" + ci.numberPresentation);
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (DBG) log("   ==> Got CallerInfoToken; updating display: ci = " + ci);
5185a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        updateDisplayForPerson(ci, presentation, true, call, conn);
519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.w(LOG_TAG, "displayMainCallStatus: runQuery was false, "
521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                              + "but we didn't have a cached CallerInfo object!  o = " + o);
522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // TODO: any easy way to recover here (given that
523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // the CallCard is probably displaying stale info
524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // right now?)  Maybe force the CallCard into the
525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // "Unknown" state?
526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // In some states we override the "photo" ImageView to be an
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // indication of the current state, rather than displaying the
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // regular photo as set above.
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        updatePhotoForCallState(call);
5359688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown
5369688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // One special feature of the "number" text field: For incoming
5379688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // calls, while the user is dragging the RotarySelector widget, we
5389688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // use mPhoneNumber to display a hint like "Rotate to answer".
539ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller        if (mIncomingCallWidgetHintTextResId != 0) {
5409688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown            // Display the hint!
541ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller            mPhoneNumber.setText(mIncomingCallWidgetHintTextResId);
542ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller            mPhoneNumber.setTextColor(getResources().getColor(mIncomingCallWidgetHintColorResId));
5439688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown            mPhoneNumber.setVisibility(View.VISIBLE);
5449688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown            mLabel.setVisibility(View.GONE);
5459688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        }
5469688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // If we don't have a hint to display, just don't touch
5479688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // mPhoneNumber and mLabel. (Their text / color / visibility have
5489688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // already been set correctly, by either updateDisplayForPerson()
5499688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown        // or updateDisplayForConference().)
550b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown    }
551b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown
552b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown    /**
553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Implemented for CallerInfoAsyncQuery.OnQueryCompleteListener interface.
554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * refreshes the CallCard data when it called.
555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("onQueryComplete: token " + token + ", cookie " + cookie + ", ci " + ci);
558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (cookie instanceof Call) {
560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // grab the call object and update the display for an individual call,
561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // as well as the successive call to update image via call state.
562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // If the object is a textview instead, we update it as we need to.
563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("callerinfo query complete, updating ui from displayMainCallStatus()");
564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Call call = (Call) cookie;
565a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai            Connection conn = null;
566872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            int phoneType = call.getPhone().getPhoneType();
567a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai            if (phoneType == Phone.PHONE_TYPE_CDMA) {
568a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai                conn = call.getLatestConnection();
569872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            } else if ((phoneType == Phone.PHONE_TYPE_GSM)
570872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                  || (phoneType == Phone.PHONE_TYPE_SIP)) {
571a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai                conn = call.getEarliestConnection();
572a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai            } else {
573a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai                throw new IllegalStateException("Unexpected phone type: " + phoneType);
574a0ea7a803c8953a14bc35d1fef0973fd1d9c64b9Abhishek Pillai            }
575e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            PhoneUtils.CallerInfoToken cit =
576e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                   PhoneUtils.startGetCallerInfo(getContext(), conn, this, null);
577e066d6979acb39dbc0ba79ecc10bc12e84a15195David Brown
578e066d6979acb39dbc0ba79ecc10bc12e84a15195David Brown            int presentation = Connection.PRESENTATION_ALLOWED;
579e066d6979acb39dbc0ba79ecc10bc12e84a15195David Brown            if (conn != null) presentation = conn.getNumberPresentation();
580e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            if (DBG) log("- onQueryComplete: presentation=" + presentation
581e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    + ", contactExists=" + ci.contactExists);
582e066d6979acb39dbc0ba79ecc10bc12e84a15195David Brown
583e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            // Depending on whether there was a contact match or not, we want to pass in different
584e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            // CallerInfo (for CNAP). Therefore if ci.contactExists then use the ci passed in.
585e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            // Otherwise, regenerate the CIT from the Connection and use the CallerInfo from there.
586e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            if (ci.contactExists) {
5875a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                updateDisplayForPerson(ci, Connection.PRESENTATION_ALLOWED, false, call, conn);
588e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            } else {
5895a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                updateDisplayForPerson(cit.currentInfo, presentation, false, call, conn);
590e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai            }
591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updatePhotoForCallState(call);
592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (cookie instanceof TextView){
594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("callerinfo query complete, updating ui from ongoing or onhold");
595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            ((TextView) cookie).setText(PhoneUtils.getCompactNameFromCallerInfo(ci, mContext));
596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Implemented for ContactsAsyncHelper.OnImageLoadCompleteListener interface.
601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * make sure that the call state is reflected after the image is loaded.
602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void onImageLoadComplete(int token, Object cookie, ImageView iView,
604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean imagePresent){
605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (cookie != null) {
606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updatePhotoForCallState((Call) cookie);
607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
61130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown     * Updates the "call state label" and the elapsed time widget based on the
61230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown     * current state of the call.
613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
61430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown    private void updateCallStateWidgets(Call call) {
61530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        if (DBG) log("updateCallStateWidgets(call " + call + ")...");
61630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        final Call.State state = call.getState();
61730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        final Context context = getContext();
61830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        final Phone phone = call.getPhone();
61930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        final int phoneType = phone.getPhoneType();
620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
62130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        String callStateLabel = null;  // Label to display as part of the call banner
62230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        int bluetoothIconId = 0;  // Icon to display alongside the call state label
62330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
62430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        switch (state) {
62530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case IDLE:
62630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // "Call state" is meaningless in this state.
62730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
62830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
62930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case ACTIVE:
63030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // We normally don't show a "call state label" at all in
63130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // this state (but see below for some special cases).
63230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
63330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
63430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case HOLDING:
63530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_on_hold);
63630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
63730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
63830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case DIALING:
63930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case ALERTING:
64030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_dialing);
64130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
64230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
64330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case INCOMING:
64430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case WAITING:
64530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_incoming_call);
64630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
64730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // Also, display a special icon (alongside the "Incoming call"
64830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // label) if there's an incoming call and audio will be routed
64930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // to bluetooth when you answer it.
65030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                if (mApplication.showBluetoothIndication()) {
65130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                    bluetoothIconId = R.drawable.ic_incoming_call_bluetooth;
65230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                }
65330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
65430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
65530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case DISCONNECTING:
65630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // While in the DISCONNECTING state we display a "Hanging up"
65730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // message in order to make the UI feel more responsive.  (In
65830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // GSM it's normal to see a delay of a couple of seconds while
65930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // negotiating the disconnect with the network, so the "Hanging
66030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // up" state at least lets the user know that we're doing
66130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // something.  This state is currently not used with CDMA.)
66230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_hanging_up);
66330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
66430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
66530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            case DISCONNECTED:
66630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = getCallFailedString(call);
66730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
66830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
66930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            default:
67030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                Log.wtf(LOG_TAG, "updateCallStateWidgets: unexpected call state: " + state);
67130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                break;
67230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        }
67330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
67430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        // Check a couple of other special cases (these are all CDMA-specific).
675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
67679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
67730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            if ((state == Call.State.ACTIVE)
67830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                && mApplication.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
67930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // Display "Dialing" while dialing a 3Way call, even
68030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // though the foreground call state is actually ACTIVE.
68130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_dialing);
68230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            } else if (PhoneApp.getInstance().notifier.getIsCdmaRedialCall()) {
68330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                callStateLabel = context.getString(R.string.card_title_redialing);
6843800ac871d6548790ac6119bb68b9be0640af261David Krause            }
68530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        }
68630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        if (PhoneUtils.isPhoneInEcm(phone)) {
68730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            // In emergency callback mode (ECM), use a special label
68830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            // that shows your own phone number.
68930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            callStateLabel = getECMCardTitle(context, phone);
69030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        }
69130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
69230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        if (DBG) log("==> callStateLabel: '" + callStateLabel
69330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                     + "', bluetoothIconId = " + bluetoothIconId);
69430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
69530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        // Update (or hide) the onscreen widget:
69630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        if (TextUtils.isEmpty(callStateLabel)) {
6975cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            // When hiding, do a smooth fade-out animation.
6985cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            Fade.hide(mCallStateLabel, View.GONE);
69979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
7005cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            // ... but when becoming visible, never animate (mainly to be
7015cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            // sure you don't see a fade-in at the very beginning of a
7025cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            // call.)
70330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            mCallStateLabel.setVisibility(View.VISIBLE);
7045cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
70530c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            mCallStateLabel.setText(callStateLabel);
70630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown
70730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            // ...and display the icon too if necessary.
70830c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            if (bluetoothIconId != 0) {
70930c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                mCallStateLabel.setCompoundDrawablesWithIntrinsicBounds(bluetoothIconId, 0, 0, 0);
71030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                mCallStateLabel.setCompoundDrawablePadding((int) (mDensity * 5));
71130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            } else {
71230c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // Clear out any icons
71330c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                mCallStateLabel.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
71430c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown            }
7153800ac871d6548790ac6119bb68b9be0640af261David Krause        }
716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
71730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        // ...and update the elapsed time widget too.
71834a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown        switch (state) {
71934a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown            case ACTIVE:
72034a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown            case DISCONNECTING:
72134a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                mElapsedTime.setVisibility(View.VISIBLE);
72234a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                long duration = CallTime.getCallDuration(call);  // msec
72334a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                updateElapsedTimeWidget(duration / 1000);
72434a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                // Also see onTickForCallTimeElapsed(), which updates this
72534a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                // widget once per second while the call is active.
72634a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                break;
72734a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown
72834a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown            case DISCONNECTED:
72934a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                // In the "Call ended" state, leave the mElapsedTime widget
73030c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // visible, but don't touch it (so we continue to see the
73130c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // elapsed time of the call that just ended.)
73234a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                mElapsedTime.setVisibility(View.VISIBLE);
73334a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                break;
73434a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown
73534a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown            default:
73630c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // In all other states (DIALING, INCOMING, HOLDING, etc.),
73730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown                // the "elapsed time" is meaningless, so don't show it.
73834a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                mElapsedTime.setVisibility(View.INVISIBLE);
73934a38b7ed4a63f8e6264030735911fdeadb21e5cDavid Brown                break;
740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates mElapsedTime based on the specified number of seconds.
745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * A timeElapsed value of zero means to not show an elapsed time at all.
746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void updateElapsedTimeWidget(long timeElapsed) {
748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if (DBG) log("updateElapsedTimeWidget: " + timeElapsed);
749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (timeElapsed == 0) {
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mElapsedTime.setText("");
751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mElapsedTime.setText(DateUtils.formatElapsedTime(timeElapsed));
753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the "on hold" box in the "other call" info area
7580d315275d08cd33f801ae3a74e8fc265520f6246David Brown     * (ie. the stuff in the secondaryCallInfo block)
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * based on the specified Call.
760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Or, clear out the "on hold" box if the specified call
761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * is null or idle.
762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
7638343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    private void displayOnHoldCallStatus(CallManager cm, Call call) {
764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("displayOnHoldCallStatus(call =" + call + ")...");
765af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville
766af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville        if ((call == null) || (PhoneApp.getInstance().isOtaCallInActiveState())) {
7670d315275d08cd33f801ae3a74e8fc265520f6246David Brown            mSecondaryCallInfo.setVisibility(View.GONE);
768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return;
769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7718da4d90151c882972e15429d4d48bdaa45095d72David Brown        boolean showSecondaryCallInfo = false;
772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call.State state = call.getState();
773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (state) {
774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case HOLDING:
775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Ok, there actually is a background call on hold.
776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Display the "on hold" box.
777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7780d315275d08cd33f801ae3a74e8fc265520f6246David Brown                // Note this case occurs only on GSM devices.  (On CDMA,
7790d315275d08cd33f801ae3a74e8fc265520f6246David Brown                // the "call on hold" is actually the 2nd connection of
7800d315275d08cd33f801ae3a74e8fc265520f6246David Brown                // that ACTIVE call; see the ACTIVE case below.)
7810d315275d08cd33f801ae3a74e8fc265520f6246David Brown
782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (PhoneUtils.isConferenceCall(call)) {
783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("==> conference call.");
7840d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    mSecondaryCallName.setText(getContext().getString(R.string.confCall));
7850d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    showImage(mSecondaryCallPhoto, R.drawable.picture_conference);
786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // perform query and update the name temporarily
788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // make sure we hand the textview we want updated to the
789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // callback function.
790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("==> NOT a conf call; call startGetCallerInfo...");
7910d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    PhoneUtils.CallerInfoToken infoToken = PhoneUtils.startGetCallerInfo(
7920d315275d08cd33f801ae3a74e8fc265520f6246David Brown                            getContext(), call, this, mSecondaryCallName);
7930d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    mSecondaryCallName.setText(
7940d315275d08cd33f801ae3a74e8fc265520f6246David Brown                            PhoneUtils.getCompactNameFromCallerInfo(infoToken.currentInfo,
7950d315275d08cd33f801ae3a74e8fc265520f6246David Brown                                                                    getContext()));
7960d315275d08cd33f801ae3a74e8fc265520f6246David Brown
7970d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // Also pull the photo out of the current CallerInfo.
7980d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // (Note we assume we already have a valid photo at
7990d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // this point, since *presumably* the caller-id query
8000d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // was already run at some point *before* this call
8010d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // got put on hold.  If there's no cached photo, just
8020d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // fall back to the default "unknown" image.)
8030d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    if (infoToken.isFinal) {
8040d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        showCachedImage(mSecondaryCallPhoto, infoToken.currentInfo);
8050d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    } else {
8060d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        showImage(mSecondaryCallPhoto, R.drawable.picture_unknown);
8070d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    }
808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
8108da4d90151c882972e15429d4d48bdaa45095d72David Brown                showSecondaryCallInfo = true;
811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
8140fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            case ACTIVE:
8150fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // CDMA: This is because in CDMA when the user originates the second call,
8160fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // although the Foreground call state is still ACTIVE in reality the network
8170fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // put the first call on hold.
81879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (mApplication.phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
8190fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    List<Connection> connections = call.getConnections();
8200fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    if (connections.size() > 2) {
8210fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // This means that current Mobile Originated call is the not the first 3-Way
8220fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // call the user is making, which in turn tells the PhoneApp that we no
8230fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // longer know which previous caller/party had dropped out before the user
8240fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // made this call.
8250d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        mSecondaryCallName.setText(
8260d315275d08cd33f801ae3a74e8fc265520f6246David Brown                                getContext().getString(R.string.card_title_in_call));
8270d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        showImage(mSecondaryCallPhoto, R.drawable.picture_unknown);
8280fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    } else {
8290fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // This means that the current Mobile Originated call IS the first 3-Way
8300fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // and hence we display the first callers/party's info here.
8310fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        Connection conn = call.getEarliestConnection();
832de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        PhoneUtils.CallerInfoToken infoToken = PhoneUtils.startGetCallerInfo(
8330d315275d08cd33f801ae3a74e8fc265520f6246David Brown                                getContext(), conn, this, mSecondaryCallName);
8340fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
835de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        // Get the compactName to be displayed, but then check that against
836de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        // the number presentation value for the call. If it's not an allowed
837de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        // presentation, then display the appropriate presentation string instead.
838de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        CallerInfo info = infoToken.currentInfo;
8390d315275d08cd33f801ae3a74e8fc265520f6246David Brown
8400d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        String name = PhoneUtils.getCompactNameFromCallerInfo(info, getContext());
8410d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        boolean forceGenericPhoto = false;
842de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        if (info != null && info.numberPresentation !=
843de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                                Connection.PRESENTATION_ALLOWED) {
844de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                            name = getPresentationString(info.numberPresentation);
8450d315275d08cd33f801ae3a74e8fc265520f6246David Brown                            forceGenericPhoto = true;
8460d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        }
8470d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        mSecondaryCallName.setText(name);
8480d315275d08cd33f801ae3a74e8fc265520f6246David Brown
8490d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // Also pull the photo out of the current CallerInfo.
8500d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // (Note we assume we already have a valid photo at
8510d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // this point, since *presumably* the caller-id query
8520d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // was already run at some point *before* this call
8530d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // got put on hold.  If there's no cached photo, just
8540d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        // fall back to the default "unknown" image.)
8550d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        if (!forceGenericPhoto && infoToken.isFinal) {
8560d315275d08cd33f801ae3a74e8fc265520f6246David Brown                            showCachedImage(mSecondaryCallPhoto, info);
8570d315275d08cd33f801ae3a74e8fc265520f6246David Brown                        } else {
8580d315275d08cd33f801ae3a74e8fc265520f6246David Brown                            showImage(mSecondaryCallPhoto, R.drawable.picture_unknown);
859de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        }
8600fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    }
8618da4d90151c882972e15429d4d48bdaa45095d72David Brown                    showSecondaryCallInfo = true;
8620fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
8630d315275d08cd33f801ae3a74e8fc265520f6246David Brown                } else {
8640d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    // We shouldn't ever get here at all for non-CDMA devices.
8650d315275d08cd33f801ae3a74e8fc265520f6246David Brown                    Log.w(LOG_TAG, "displayOnHoldCallStatus: ACTIVE state on non-CDMA device");
8668da4d90151c882972e15429d4d48bdaa45095d72David Brown                    showSecondaryCallInfo = false;
8670fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                }
8680fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                break;
8690fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // There's actually no call on hold.  (Presumably this call's
872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // state is IDLE, since any other state is meaningless for the
873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // background call.)
8748da4d90151c882972e15429d4d48bdaa45095d72David Brown                showSecondaryCallInfo = false;
875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
8778da4d90151c882972e15429d4d48bdaa45095d72David Brown
87872ed1d33448aebfd2dd9198e2d7384091fe2b9f7David Brown        // Show or hide the entire "secondary call" info area.
87972ed1d33448aebfd2dd9198e2d7384091fe2b9f7David Brown        mSecondaryCallInfo.setVisibility(showSecondaryCallInfo ? View.VISIBLE : View.GONE);
880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private String getCallFailedString(Call call) {
883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Connection c = call.getEarliestConnection();
884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int resID;
885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (c == null) {
887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("getCallFailedString: connection is null, using default values.");
888b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // if this connection is null, just assume that the
889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // default case occurs.
890b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            resID = R.string.card_title_call_ended;
891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
893b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Connection.DisconnectCause cause = c.getDisconnectCause();
894b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
895b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // TODO: The card *title* should probably be "Call ended" in all
896b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // cases, but if the DisconnectCause was an error condition we should
897b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // probably also display the specific failure reason somewhere...
898b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
899b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (cause) {
900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case BUSY:
901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_userBusy;
902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case CONGESTION:
905b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_congestion;
906b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
907b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
9081d0075e4a480a32e26a673c58b94bd706f997620Hung-ying Tyan                case TIMED_OUT:
9091d0075e4a480a32e26a673c58b94bd706f997620Hung-ying Tyan                    resID = R.string.callFailed_timedOut;
9101d0075e4a480a32e26a673c58b94bd706f997620Hung-ying Tyan                    break;
9111d0075e4a480a32e26a673c58b94bd706f997620Hung-ying Tyan
91268d060b8f52c6c1176d5c55358250b18d14f2b51Hung-ying Tyan                case SERVER_UNREACHABLE:
91368d060b8f52c6c1176d5c55358250b18d14f2b51Hung-ying Tyan                    resID = R.string.callFailed_server_unreachable;
91468d060b8f52c6c1176d5c55358250b18d14f2b51Hung-ying Tyan                    break;
91568d060b8f52c6c1176d5c55358250b18d14f2b51Hung-ying Tyan
9166c17cfbbf0b1b6fed8c9f32da48a854c20c24af8Hung-ying Tyan                case NUMBER_UNREACHABLE:
91768d060b8f52c6c1176d5c55358250b18d14f2b51Hung-ying Tyan                    resID = R.string.callFailed_number_unreachable;
9186c17cfbbf0b1b6fed8c9f32da48a854c20c24af8Hung-ying Tyan                    break;
9196c17cfbbf0b1b6fed8c9f32da48a854c20c24af8Hung-ying Tyan
9203a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                case INVALID_CREDENTIALS:
9213a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                    resID = R.string.callFailed_invalid_credentials;
9223a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                    break;
9233a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan
924a32036470be1cff3ce604c0dd83f0609243c6100Hung-ying Tyan                case SERVER_ERROR:
925a32036470be1cff3ce604c0dd83f0609243c6100Hung-ying Tyan                    resID = R.string.callFailed_server_error;
926a32036470be1cff3ce604c0dd83f0609243c6100Hung-ying Tyan                    break;
927a32036470be1cff3ce604c0dd83f0609243c6100Hung-ying Tyan
9283a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                case OUT_OF_NETWORK:
9293a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                    resID = R.string.callFailed_out_of_network;
9303a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan                    break;
9313a635c7dd2f3283f6a1bde0e9370977c4685882fHung-ying Tyan
932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case LOST_SIGNAL:
9333800ac871d6548790ac6119bb68b9be0640af261David Krause                case CDMA_DROP:
934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_noSignal;
935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case LIMIT_EXCEEDED:
938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_limitExceeded;
939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case POWER_OFF:
942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_powerOff;
943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
945a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville                case ICC_ERROR:
946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_simError;
947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case OUT_OF_SERVICE:
950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.callFailed_outOfService;
951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
95322e353c3d76a3dd649c6e87244c5d94cadf64c8eHung-ying Tyan                case INVALID_NUMBER:
9549eb2ffdf7b4752c7199eba6a3b88f63edc4a0ac8Naveen Kalla                case UNOBTAINABLE_NUMBER:
9559eb2ffdf7b4752c7199eba6a3b88f63edc4a0ac8Naveen Kalla                    resID = R.string.callFailed_unobtainable_number;
9569eb2ffdf7b4752c7199eba6a3b88f63edc4a0ac8Naveen Kalla                    break;
9579eb2ffdf7b4752c7199eba6a3b88f63edc4a0ac8Naveen Kalla
958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                default:
959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    resID = R.string.card_title_call_ended;
960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return getContext().getString(resID);
964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
966b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the name / photo / number / label fields on the CallCard
968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * based on the specified CallerInfo.
969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * If the current call is a conference call, use
971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * updateDisplayForConference() instead.
972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void updateDisplayForPerson(CallerInfo info,
9744b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                                        int presentation,
975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                        boolean isTemporary,
9765a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                                        Call call,
9775a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                                        Connection conn) {
978a1c2398ade0e01d0bcfe23212bdaa18e4c19a1e5Nicolas Catania        if (DBG) log("updateDisplayForPerson(" + info + ")\npresentation:" +
979a1c2398ade0e01d0bcfe23212bdaa18e4c19a1e5Nicolas Catania                     presentation + " isTemporary:" + isTemporary);
980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // inform the state machine that we are displaying a photo.
982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhotoTracker.setPhotoRequest(info);
983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhotoTracker.setPhotoState(ContactsAsyncHelper.ImageTracker.DISPLAY_IMAGE);
984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
985592fb0a9a5b079f168096907bd50822f94c69448David Brown        // The actual strings we're going to display onscreen:
986592fb0a9a5b079f168096907bd50822f94c69448David Brown        String displayName;
987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String displayNumber = null;
988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String label = null;
989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Uri personUri = null;
99029d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        String socialStatusText = null;
99129d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        Drawable socialStatusBadge = null;
992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (info != null) {
994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // It appears that there is a small change in behaviour with the
995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // PhoneUtils' startGetCallerInfo whereby if we query with an
996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // empty number, we will get a valid CallerInfo object, but with
997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // fields that are all null, and the isTemporary boolean input
998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // parameter as true.
999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // In the past, we would see a NULL callerinfo object, but this
1001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // ends up causing null pointer exceptions elsewhere down the
1002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // line in other cases, so we need to make this fix instead. It
1003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // appears that this was the ONLY call to PhoneUtils
1004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // .getCallerInfo() that relied on a NULL CallerInfo to indicate
1005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // an unknown contact.
1006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1007592fb0a9a5b079f168096907bd50822f94c69448David Brown            // Currently, info.phoneNumber may actually be a SIP address, and
1008592fb0a9a5b079f168096907bd50822f94c69448David Brown            // if so, it might sometimes include the "sip:" prefix.  That
1009592fb0a9a5b079f168096907bd50822f94c69448David Brown            // prefix isn't really useful to the user, though, so strip it off
1010592fb0a9a5b079f168096907bd50822f94c69448David Brown            // if present.  (For any other URI scheme, though, leave the
1011592fb0a9a5b079f168096907bd50822f94c69448David Brown            // prefix alone.)
1012592fb0a9a5b079f168096907bd50822f94c69448David Brown            // TODO: It would be cleaner for CallerInfo to explicitly support
1013592fb0a9a5b079f168096907bd50822f94c69448David Brown            // SIP addresses instead of overloading the "phoneNumber" field.
1014592fb0a9a5b079f168096907bd50822f94c69448David Brown            // Then we could remove this hack, and instead ask the CallerInfo
1015592fb0a9a5b079f168096907bd50822f94c69448David Brown            // for a "user visible" form of the SIP address.
1016592fb0a9a5b079f168096907bd50822f94c69448David Brown            String number = info.phoneNumber;
10179ec000a412524ed98d486ca4b160dd1e885db574David Brown            if ((number != null) && number.startsWith("sip:")) {
1018592fb0a9a5b079f168096907bd50822f94c69448David Brown                number = number.substring(4);
1019592fb0a9a5b079f168096907bd50822f94c69448David Brown            }
1020592fb0a9a5b079f168096907bd50822f94c69448David Brown
1021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (TextUtils.isEmpty(info.name)) {
1022592fb0a9a5b079f168096907bd50822f94c69448David Brown                // No valid "name" in the CallerInfo, so fall back to
1023592fb0a9a5b079f168096907bd50822f94c69448David Brown                // something else.
1024a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                // (Typically, we promote the phone number up to the "name" slot
1025a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                // onscreen, and possibly display a descriptive string in the
1026a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                // "number" slot.)
1027592fb0a9a5b079f168096907bd50822f94c69448David Brown                if (TextUtils.isEmpty(number)) {
1028a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    // No name *or* number!  Display a generic "unknown" string
1029a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    // (or potentially some other default based on the presentation.)
1030592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName =  getPresentationString(presentation);
1031a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==> no name *or* number! displayName = " + displayName);
1032e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                } else if (presentation != Connection.PRESENTATION_ALLOWED) {
1033e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // This case should never happen since the network should never send a phone #
1034e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // AND a restricted presentation. However we leave it here in case of weird
1035e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // network behavior
1036592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName = getPresentationString(presentation);
1037a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==> presentation not allowed! displayName = " + displayName);
1038e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                } else if (!TextUtils.isEmpty(info.cnapName)) {
1039a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    // No name, but we do have a valid CNAP name, so use that.
1040592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName = info.cnapName;
1041e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    info.name = info.cnapName;
1042592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayNumber = number;
1043a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==> cnapName available: displayName '"
1044a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                                 + displayName + "', displayNumber '" + displayNumber + "'");
1045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1046a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    // No name; all we have is a number.  This is the typical
10475a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // case when an incoming call doesn't match any contact,
10485a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // or if you manually dial an outgoing number using the
10495a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // dialpad.
1050a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown
10515a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // Promote the phone number up to the "name" slot:
1052592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName = number;
10535a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown
10545a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // ...and use the "number" slot for a geographical description
10555a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    // string if available (but only for incoming calls.)
10565a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    if ((conn != null) && (conn.isIncoming())) {
10575a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        // TODO (CallerInfoAsyncQuery cleanup): Fix the CallerInfo
10585a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        // query to only do the geoDescription lookup in the first
10595a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        // place for incoming calls.
10605a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                        displayNumber = info.geoDescription;  // may be null
10615a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown                    }
10625a4bc9222fc865b17e82c450fd878e9ee18bd643David Brown
1063a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==>  no name; falling back to number: displayName '"
1064a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                                 + displayName + "', displayNumber '" + displayNumber + "'");
1065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
1067592fb0a9a5b079f168096907bd50822f94c69448David Brown                // We do have a valid "name" in the CallerInfo.  Display that
1068592fb0a9a5b079f168096907bd50822f94c69448David Brown                // in the "name" slot, and the phone number in the "number" slot.
1069e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                if (presentation != Connection.PRESENTATION_ALLOWED) {
1070e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // This case should never happen since the network should never send a name
1071e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // AND a restricted presentation. However we leave it here in case of weird
1072e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    // network behavior
1073592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName = getPresentationString(presentation);
1074a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==> valid name, but presentation not allowed!"
1075a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                                 + " displayName = " + displayName);
1076e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                } else {
1077592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayName = info.name;
1078592fb0a9a5b079f168096907bd50822f94c69448David Brown                    displayNumber = number;
1079e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    label = info.phoneLabel;
1080a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                    if (DBG) log("  ==>  name is present in CallerInfo: displayName '"
1081a232063e9bb9f7b8875a24af212287ba0d2cd0c3David Brown                                 + displayName + "', displayNumber '" + displayNumber + "'");
1082e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                }
1083b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
10843d6d70562622660e581b53308e675386d299dd19Dmitri Plotnikov            personUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, info.person_id);
108502d1c632adde606031c1fe6ea0e3be1e288fd6c6David Brown            if (DBG) log("- got personUri: '" + personUri
108602d1c632adde606031c1fe6ea0e3be1e288fd6c6David Brown                         + "', based on info.person_id: " + info.person_id);
1087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1088592fb0a9a5b079f168096907bd50822f94c69448David Brown            displayName =  getPresentationString(presentation);
1089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
10900fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
10910fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        if (call.isGeneric()) {
10920fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            mName.setText(R.string.card_title_in_call);
10930fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        } else {
1094592fb0a9a5b079f168096907bd50822f94c69448David Brown            mName.setText(displayName);
10950fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
1096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mName.setVisibility(View.VISIBLE);
1097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Update mPhoto
1099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if the temporary flag is set, we know we'll be getting another call after
1100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the CallerInfo has been correctly updated.  So, we can skip the image
1101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // loading until then.
1102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // If the photoResource is filled in for the CallerInfo, (like with the
1104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Emergency Number case), then we can just set the photo image without
1105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // requesting for an image load. Please refer to CallerInfoAsyncQuery.java
1106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // for cases where CallerInfo.photoResource may be set.  We can also avoid
1107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the image load step if the image data is cached.
1108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isTemporary && (info == null || !info.isCachedPhotoCurrent)) {
1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhoto.setVisibility(View.INVISIBLE);
1110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (info != null && info.photoResource != 0){
1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            showImage(mPhoto, info.photoResource);
1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (!showCachedImage(mPhoto, info)) {
1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Load the image with a callback to update the image state.
1114a1c2398ade0e01d0bcfe23212bdaa18e4c19a1e5Nicolas Catania            // Use the default unknown picture while the query is running.
1115a1c2398ade0e01d0bcfe23212bdaa18e4c19a1e5Nicolas Catania            ContactsAsyncHelper.updateImageViewWithContactPhotoAsync(
1116a1c2398ade0e01d0bcfe23212bdaa18e4c19a1e5Nicolas Catania                info, 0, this, call, getContext(), mPhoto, personUri, R.drawable.picture_unknown);
1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
11186d5544932495d81ff7ce53f4678c4beb25acc1b0David Brown
11190fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        if (displayNumber != null && !call.isGeneric()) {
1120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhoneNumber.setText(displayNumber);
1121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhoneNumber.setVisibility(View.VISIBLE);
1122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhoneNumber.setVisibility(View.GONE);
1124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1126153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        if (label != null && !call.isGeneric()) {
1127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLabel.setText(label);
1128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLabel.setVisibility(View.VISIBLE);
1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLabel.setVisibility(View.GONE);
1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
11339d14e16e8214b4a396dad293b6f0941608ee4798David Brown        // Other text fields:
11349d14e16e8214b4a396dad293b6f0941608ee4798David Brown        updateCallTypeLabel(call);
11359d14e16e8214b4a396dad293b6f0941608ee4798David Brown        updateSocialStatus(socialStatusText, socialStatusBadge, call);  // Currently unused
113629d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown    }
1137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
11384b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project    private String getPresentationString(int presentation) {
11394b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project        String name = getContext().getString(R.string.unknown);
11404b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project        if (presentation == Connection.PRESENTATION_RESTRICTED) {
11414b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project            name = getContext().getString(R.string.private_num);
11424b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project        } else if (presentation == Connection.PRESENTATION_PAYPHONE) {
11434b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project            name = getContext().getString(R.string.payphone);
11444b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project        }
11454b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project        return name;
11464b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project    }
11474b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project
1148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the name / photo / number / label fields
1150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * for the special "conference call" state.
1151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * If the current call has only a single connection, use
1153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * updateDisplayForPerson() instead.
1154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1155872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan    private void updateDisplayForConference(Call call) {
1156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("updateDisplayForConference()...");
1157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1158872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        int phoneType = call.getPhone().getPhoneType();
115979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
11600fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // This state corresponds to both 3-Way merged call and
11610fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // Call Waiting accepted call.
116229d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown            // In this case we display the UI in a "generic" state, with
116329d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown            // the generic "dialing" icon and no caller information,
116429d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown            // because in this state in CDMA the user does not really know
116529d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown            // which caller party he is talking to.
11660fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            showImage(mPhoto, R.drawable.picture_dialing);
11670fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            mName.setText(R.string.card_title_in_call);
1168872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
1169872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
1170507ee75639e41c17edd410ef787e0617778071aaDavid Brown            // Normal GSM (or possibly SIP?) conference call.
1171507ee75639e41c17edd410ef787e0617778071aaDavid Brown            // Display the "conference call" image as the contact photo.
1172507ee75639e41c17edd410ef787e0617778071aaDavid Brown            // TODO: Better visual treatment for contact photos in a
1173507ee75639e41c17edd410ef787e0617778071aaDavid Brown            // conference call (see bug 1313252).
1174507ee75639e41c17edd410ef787e0617778071aaDavid Brown            showImage(mPhoto, R.drawable.picture_conference);
11750fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            mName.setText(R.string.card_title_conf_call);
117679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
117779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            throw new IllegalStateException("Unexpected phone type: " + phoneType);
11780fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
1179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mName.setVisibility(View.VISIBLE);
1181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // TODO: For a conference call, the "phone number" slot is specced
1183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // to contain a summary of who's on the call, like "Bill Foldes
1184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // and Hazel Nutt" or "Bill Foldes and 2 others".
1185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // But for now, just hide it:
1186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhoneNumber.setVisibility(View.GONE);
1187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mLabel.setVisibility(View.GONE);
1188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
11899d14e16e8214b4a396dad293b6f0941608ee4798David Brown        // Other text fields:
11909d14e16e8214b4a396dad293b6f0941608ee4798David Brown        updateCallTypeLabel(call);
11919d14e16e8214b4a396dad293b6f0941608ee4798David Brown        updateSocialStatus(null, null, null);  // socialStatus is never visible in this state
119229d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown
119329d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        // TODO: for a GSM conference call, since we do actually know who
119429d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        // you're talking to, consider also showing names / numbers /
119529d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        // photos of some of the people on the conference here, so you can
119629d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        // see that info without having to click "Manage conference".  We
119729d71cebdbcfe433f851899b91a650ad9352c15fDavid Brown        // probably have enough space to show info for 2 people, at least.
1198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
1199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // To do this, our caller would pass us the activeConnections
1200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // list, and we'd call PhoneUtils.getCallerInfo() separately for
1201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // each connection.
1202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the CallCard "photo" IFF the specified Call is in a state
1206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * that needs a special photo (like "busy" or "dialing".)
1207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * If the current call does not require a special image in the "photo"
1209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * slot onscreen, don't do anything, since presumably the photo image
1210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * has already been set (to the photo of the person we're talking, or
1211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * the generic "picture_unknown" image, or the "conference call"
1212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * image.)
1213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void updatePhotoForCallState(Call call) {
1215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("updatePhotoForCallState(" + call + ")...");
1216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int photoImageResource = 0;
1217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Check for the (relatively few) telephony states that need a
1219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // special image in the "photo" slot.
1220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call.State state = call.getState();
1221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (state) {
1222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DISCONNECTED:
1223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Display the special "busy" photo for BUSY or CONGESTION.
1224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Otherwise (presumably the normal "call ended" state)
1225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // leave the photo alone.
1226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Connection c = call.getEarliestConnection();
1227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the connection is null, we assume the default case,
1228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // otherwise update the image resource normally.
1229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (c != null) {
1230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Connection.DisconnectCause cause = c.getDisconnectCause();
1231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((cause == Connection.DisconnectCause.BUSY)
1232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        || (cause == Connection.DisconnectCause.CONGESTION)) {
1233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        photoImageResource = R.drawable.picture_busy;
1234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (DBG) {
1236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    log("updatePhotoForCallState: connection is null, ignoring.");
1237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // TODO: add special images for any other DisconnectCauses?
1240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
1241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ALERTING:
124344e42e4eccd8ecdcdcca166c9f6f35a4d6c65591Nicolas Catania            case DIALING:
1244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
1245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Leave the photo alone in all other states.
1246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // If this call is an individual call, and the image is currently
1247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // displaying a state, (rather than a photo), we'll need to update
1248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // the image.
1249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This is for the case where we've been displaying the state and
1250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // now we need to restore the photo.  This can happen because we
1251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // only query the CallerInfo once, and limit the number of times
1252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // the image is loaded. (So a state image may overwrite the photo
1253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // and we would otherwise have no way of displaying the photo when
1254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // the state goes away.)
1255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the photoResource field is filled-in in the Connection's
1257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // caller info, then we can just use that instead of requesting
1258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // for a photo load.
1259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // look for the photoResource if it is available.
1261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                CallerInfo ci = null;
1262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                {
12630fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    Connection conn = null;
1264872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                    int phoneType = call.getPhone().getPhoneType();
126579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                    if (phoneType == Phone.PHONE_TYPE_CDMA) {
12660fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        conn = call.getLatestConnection();
1267872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                    } else if ((phoneType == Phone.PHONE_TYPE_GSM)
1268872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                            || (phoneType == Phone.PHONE_TYPE_SIP)) {
12690fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        conn = call.getEarliestConnection();
127079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                    } else {
127179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        throw new IllegalStateException("Unexpected phone type: " + phoneType);
12720fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    }
12730fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
1274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (conn != null) {
1275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Object o = conn.getUserData();
1276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (o instanceof CallerInfo) {
1277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ci = (CallerInfo) o;
1278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else if (o instanceof PhoneUtils.CallerInfoToken) {
1279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ci = ((PhoneUtils.CallerInfoToken) o).currentInfo;
1280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (ci != null) {
1285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    photoImageResource = ci.photoResource;
1286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // If no photoResource found, check to see if this is a conference call. If
1289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // it is not a conference call:
1290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   1. Try to show the cached image
1291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   2. If the image is not cached, check to see if a load request has been
1292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      made already.
1293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   3. If the load request has not been made [DISPLAY_DEFAULT], start the
1294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      request and note that it has started by updating photo state with
1295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      [DISPLAY_IMAGE].
1296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Load requests started in (3) use a placeholder image of -1 to hide the
1297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // image by default.  Please refer to CallerInfoAsyncQuery.java for cases
1298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // where CallerInfo.photoResource may be set.
1299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (photoImageResource == 0) {
1300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (!PhoneUtils.isConferenceCall(call)) {
1301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (!showCachedImage(mPhoto, ci) && (mPhotoTracker.getPhotoState() ==
1302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                ContactsAsyncHelper.ImageTracker.DISPLAY_DEFAULT)) {
1303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ContactsAsyncHelper.updateImageViewWithContactPhotoAsync(ci,
1304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    getContext(), mPhoto, mPhotoTracker.getPhotoUri(), -1);
1305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mPhotoTracker.setPhotoState(
1306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    ContactsAsyncHelper.ImageTracker.DISPLAY_IMAGE);
1307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    showImage(mPhoto, photoImageResource);
1311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mPhotoTracker.setPhotoState(ContactsAsyncHelper.ImageTracker.DISPLAY_IMAGE);
1312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return;
1313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
1315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (photoImageResource != 0) {
1318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("- overrriding photo image: " + photoImageResource);
1319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            showImage(mPhoto, photoImageResource);
1320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Track the image state.
1321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhotoTracker.setPhotoState(ContactsAsyncHelper.ImageTracker.DISPLAY_DEFAULT);
1322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Try to display the cached image from the callerinfo object.
1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  @return true if we were able to find the image in the cache, false otherwise.
1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
13300d315275d08cd33f801ae3a74e8fc265520f6246David Brown    private static final boolean showCachedImage(ImageView view, CallerInfo ci) {
1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if ((ci != null) && ci.isCachedPhotoCurrent) {
1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (ci.cachedPhoto != null) {
1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                showImage(view, ci.cachedPhoto);
1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                showImage(view, R.drawable.picture_unknown);
1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Helper function to display the resource in the imageview AND ensure its visibility.*/
1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final void showImage(ImageView view, int resource) {
1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        view.setImageResource(resource);
1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        view.setVisibility(View.VISIBLE);
1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Helper function to display the drawable in the imageview AND ensure its visibility.*/
1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final void showImage(ImageView view, Drawable drawable) {
1350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        view.setImageDrawable(drawable);
1351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        view.setVisibility(View.VISIBLE);
1352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Sets the left and right margins of the specified ViewGroup (whose
1356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * LayoutParams object which must inherit from
1357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * ViewGroup.MarginLayoutParams.)
1358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * TODO: Is there already a convenience method like this somewhere?
1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void setSideMargins(ViewGroup vg, int margin) {
1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        ViewGroup.MarginLayoutParams lp =
1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                (ViewGroup.MarginLayoutParams) vg.getLayoutParams();
1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Equivalent to setting android:layout_marginLeft/Right in XML
1365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        lp.leftMargin = margin;
1366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        lp.rightMargin = margin;
1367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        vg.setLayoutParams(lp);
1368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
13708bb467d9a1106dedd79e42166c7b6e9fc9a897a7The Android Open Source Project    /**
1371f3602b0659d01fef19159e7111be76102549f7a1David Brown     * Returns the special card title used in emergency callback mode (ECM),
1372f3602b0659d01fef19159e7111be76102549f7a1David Brown     * which shows your own phone number.
1373f3602b0659d01fef19159e7111be76102549f7a1David Brown     */
1374f3602b0659d01fef19159e7111be76102549f7a1David Brown    private String getECMCardTitle(Context context, Phone phone) {
1375f3602b0659d01fef19159e7111be76102549f7a1David Brown        String rawNumber = phone.getLine1Number();  // may be null or empty
1376f3602b0659d01fef19159e7111be76102549f7a1David Brown        String formattedNumber;
1377f3602b0659d01fef19159e7111be76102549f7a1David Brown        if (!TextUtils.isEmpty(rawNumber)) {
1378f3602b0659d01fef19159e7111be76102549f7a1David Brown            formattedNumber = PhoneNumberUtils.formatNumber(rawNumber);
1379f3602b0659d01fef19159e7111be76102549f7a1David Brown        } else {
1380f3602b0659d01fef19159e7111be76102549f7a1David Brown            formattedNumber = context.getString(R.string.unknown);
1381f3602b0659d01fef19159e7111be76102549f7a1David Brown        }
1382f3602b0659d01fef19159e7111be76102549f7a1David Brown        String titleFormat = context.getString(R.string.card_title_my_phone_number);
1383f3602b0659d01fef19159e7111be76102549f7a1David Brown        return String.format(titleFormat, formattedNumber);
1384f3602b0659d01fef19159e7111be76102549f7a1David Brown    }
1385f3602b0659d01fef19159e7111be76102549f7a1David Brown
1386f3602b0659d01fef19159e7111be76102549f7a1David Brown    /**
13879d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * Updates the "Call type" label, based on the current foreground call.
13889d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * This is a special label and/or branding we display for certain
13899d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * kinds of calls.
13909d14e16e8214b4a396dad293b6f0941608ee4798David Brown     *
13919d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * (So far, this is used only for SIP calls, which get an
13929d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * "Internet call" label.  TODO: But eventually, the telephony
13939d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * layer might allow each pluggable "provider" to specify a string
13949d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * and/or icon to be displayed here.)
13959d14e16e8214b4a396dad293b6f0941608ee4798David Brown     */
13969d14e16e8214b4a396dad293b6f0941608ee4798David Brown    private void updateCallTypeLabel(Call call) {
13979d14e16e8214b4a396dad293b6f0941608ee4798David Brown        int phoneType = (call != null) ? call.getPhone().getPhoneType() : Phone.PHONE_TYPE_NONE;
13989d14e16e8214b4a396dad293b6f0941608ee4798David Brown        if (phoneType == Phone.PHONE_TYPE_SIP) {
13999d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mCallTypeLabel.setVisibility(View.VISIBLE);
14009d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mCallTypeLabel.setText(R.string.incall_call_type_label_sip);
14019d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mCallTypeLabel.setTextColor(mTextColorCallTypeSip);
14029d14e16e8214b4a396dad293b6f0941608ee4798David Brown            // If desired, we could also display a "badge" next to the label, as follows:
14039d14e16e8214b4a396dad293b6f0941608ee4798David Brown            //   mCallTypeLabel.setCompoundDrawablesWithIntrinsicBounds(
14049d14e16e8214b4a396dad293b6f0941608ee4798David Brown            //           callTypeSpecificBadge, null, null, null);
14059d14e16e8214b4a396dad293b6f0941608ee4798David Brown            //   mCallTypeLabel.setCompoundDrawablePadding((int) (mDensity * 6));
14069d14e16e8214b4a396dad293b6f0941608ee4798David Brown        } else {
14079d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mCallTypeLabel.setVisibility(View.GONE);
14089d14e16e8214b4a396dad293b6f0941608ee4798David Brown        }
14099d14e16e8214b4a396dad293b6f0941608ee4798David Brown    }
14109d14e16e8214b4a396dad293b6f0941608ee4798David Brown
14119d14e16e8214b4a396dad293b6f0941608ee4798David Brown    /**
14129d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * Updates the "social status" label with the specified text and
14139d14e16e8214b4a396dad293b6f0941608ee4798David Brown     * (optional) badge.
14149d14e16e8214b4a396dad293b6f0941608ee4798David Brown     */
14159d14e16e8214b4a396dad293b6f0941608ee4798David Brown    private void updateSocialStatus(String socialStatusText,
14169d14e16e8214b4a396dad293b6f0941608ee4798David Brown                                    Drawable socialStatusBadge,
14179d14e16e8214b4a396dad293b6f0941608ee4798David Brown                                    Call call) {
14189d14e16e8214b4a396dad293b6f0941608ee4798David Brown        // The socialStatus field is *only* visible while an incoming call
14199d14e16e8214b4a396dad293b6f0941608ee4798David Brown        // is ringing, never in any other call state.
14209d14e16e8214b4a396dad293b6f0941608ee4798David Brown        if ((socialStatusText != null)
14219d14e16e8214b4a396dad293b6f0941608ee4798David Brown                && (call != null)
14229d14e16e8214b4a396dad293b6f0941608ee4798David Brown                && call.isRinging()
14239d14e16e8214b4a396dad293b6f0941608ee4798David Brown                && !call.isGeneric()) {
14249d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mSocialStatus.setVisibility(View.VISIBLE);
14259d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mSocialStatus.setText(socialStatusText);
14269d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mSocialStatus.setCompoundDrawablesWithIntrinsicBounds(
14279d14e16e8214b4a396dad293b6f0941608ee4798David Brown                    socialStatusBadge, null, null, null);
14289d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mSocialStatus.setCompoundDrawablePadding((int) (mDensity * 6));
14299d14e16e8214b4a396dad293b6f0941608ee4798David Brown        } else {
14309d14e16e8214b4a396dad293b6f0941608ee4798David Brown            mSocialStatus.setVisibility(View.GONE);
14319d14e16e8214b4a396dad293b6f0941608ee4798David Brown        }
14329d14e16e8214b4a396dad293b6f0941608ee4798David Brown    }
14339d14e16e8214b4a396dad293b6f0941608ee4798David Brown
14349d14e16e8214b4a396dad293b6f0941608ee4798David Brown    /**
1435af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * Hides the top-level UI elements of the call card:  The "main
1436af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * call card" element representing the current active or ringing call,
1437af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * and also the info areas for "ongoing" or "on hold" calls in some
1438af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * states.
1439af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     *
1440af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * This is intended to be used in special states where the normal
1441af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * in-call UI is totally replaced by some other UI, like OTA mode on a
1442af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * CDMA device.
1443af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     *
1444af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * To bring back the regular CallCard UI, just re-run the normal
1445af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     * updateState() call sequence.
1446af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville     */
1447af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville    public void hideCallCardElements() {
14480d315275d08cd33f801ae3a74e8fc265520f6246David Brown        mPrimaryCallInfo.setVisibility(View.GONE);
14490d315275d08cd33f801ae3a74e8fc265520f6246David Brown        mSecondaryCallInfo.setVisibility(View.GONE);
1450af684393e2c6d0c051b9d5a189c2cd1de2506831Wink Saville    }
1451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
14529688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown    /*
14539688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown     * Updates the hint (like "Rotate to answer") that we display while
14549688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown     * the user is dragging the incoming call RotarySelector widget.
14559688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown     */
1456ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller    /* package */ void setIncomingCallWidgetHint(int hintTextResId, int hintColorResId) {
1457ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller        mIncomingCallWidgetHintTextResId = hintTextResId;
1458ea505da2d0ebae37b07fece15297b5432fe96c5dJim Miller        mIncomingCallWidgetHintColorResId = hintColorResId;
14599688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown    }
14609688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown
1461dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    // Accessibility event support.
1462dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    // Since none of the CallCard elements are focusable, we need to manually
1463dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    // fill in the AccessibilityEvent here (so that the name / number / etc will
1464dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    // get pronounced by a screen reader, for example.)
1465dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    @Override
1466dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
146730c2867bb3341e2b10cb95359e7c5b3b1dc0a6e0David Brown        dispatchPopulateAccessibilityEvent(event, mCallStateLabel);
1468dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mPhoto);
1469dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mName);
1470dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mPhoneNumber);
1471dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mLabel);
1472dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mSocialStatus);
1473dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mSecondaryCallName);
1474dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mSecondaryCallStatus);
1475dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        dispatchPopulateAccessibilityEvent(event, mSecondaryCallPhoto);
1476dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        return true;
1477dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    }
1478dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown
1479dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    private void dispatchPopulateAccessibilityEvent(AccessibilityEvent event, View view) {
1480dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        List<CharSequence> eventText = event.getText();
1481dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        int size = eventText.size();
1482dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        view.dispatchPopulateAccessibilityEvent(event);
1483dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        // if no text added write null to keep relative position
1484dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        if (size == eventText.size()) {
1485dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown            eventText.add(null);
1486dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown        }
1487dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown    }
1488dc66301e77d854b6cef2101bf7029c9bbb816f3eDavid Brown
14895cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown    /**
14905cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown     * Simple Utility class that runs fading animations on specified views.
14915cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown     */
14925cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown    public static class Fade {
14935cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        private static final boolean FADE_DBG = false;
14945cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        private static final long DURATION = 250;  // msec
14955cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
14965cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        // View tag that's set during the fade-out animation; see hide() and
14975cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        // isFadingOut().
14985cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        private static final int FADE_STATE_KEY = R.id.fadeState;
14995cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        private static final String FADING_OUT = "fading_out";
15005cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15015cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        /**
15025cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * Sets the visibility of the specified view to View.VISIBLE and then
15035cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * fades it in. If the view is already visible (and not in the middle
15045cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * of a fade-out animation), this method will return without doing
15055cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * anything.
15065cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         *
15075cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * @param view The view to be faded in
15085cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         */
15095cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        public static void show(final View view) {
15105cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (FADE_DBG) log("Fade: SHOW view " + view + "...");
15115cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (FADE_DBG) log("Fade: - visibility = " + view.getVisibility());
15125cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if ((view.getVisibility() != View.VISIBLE) || isFadingOut(view)) {
15135cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().cancel();
15145cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                // ...and clear the FADE_STATE_KEY tag in case we just
15155cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                // canceled an in-progress fade-out animation.
15165cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.setTag(FADE_STATE_KEY, null);
15175cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15185cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.setAlpha(0);
15195cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.setVisibility(View.VISIBLE);
15205cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().setDuration(DURATION);
15215cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().alpha(1);
15225cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                if (FADE_DBG) log("Fade: ==> SHOW " + view
15235cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                                  + " DONE.  Set visibility = " + View.VISIBLE);
15245cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            } else {
15255cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                if (FADE_DBG) log("Fade: ==> Ignoring, already visible AND not fading out.");
15265cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            }
15275cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        }
15285cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15295cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        /**
15305cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * Fades out the specified view and then sets its visibility to the
15315cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * specified value (either View.INVISIBLE or View.GONE). If the view
15325cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * is not currently visibile, the method will return without doing
15335cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * anything.
15345cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         *
15355cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * Note that *during* the fade-out the view itself will still have
15365cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * visibility View.VISIBLE, although the isFadingOut() method will
15375cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * return true (in case the UI code needs to detect this state.)
15385cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         *
15395cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * @param view The view to be hidden
15405cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * @param visibility The value to which the view's visibility will be
15415cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         *                   set after it fades out.
15425cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * Must be either View.VISIBLE or View.INVISIBLE.
15435cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         */
15445cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        public static void hide(final View view, final int visibility) {
15455cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (FADE_DBG) log("Fade: HIDE view " + view + "...");
15465cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (view.getVisibility() == View.VISIBLE &&
15475cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                (visibility == View.INVISIBLE || visibility == View.GONE)) {
15485cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15495cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                // Use a view tag to mark this view as being in the middle
15505cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                // of a fade-out animation.
15515cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.setTag(FADE_STATE_KEY, FADING_OUT);
15525cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15535cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().cancel();
15545cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().setDuration(DURATION);
15555cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                view.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
15565cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                        public void onAnimationEnd(Animator animation) {
15575cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            view.setAlpha(1);
15585cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            view.setVisibility(visibility);
15595cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            view.animate().setListener(null);
15605cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            // ...and we're done with the fade-out, so clear the view tag.
15615cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            view.setTag(FADE_STATE_KEY, null);
15625cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                            if (FADE_DBG) log("Fade: HIDE " + view
15635cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                                              + " DONE.  Set visibility = " + visibility);
15645cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                        }
15655cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                    });
15665cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            }
15675cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        }
15685cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15695cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        /**
15705cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * @return true if the specified view is currently in the middle
15715cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * of a fade-out animation.  (During the fade-out, the view's
15725cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * visibility is still VISIBLE, although in many cases the UI
15735cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * should behave as if it's already invisible or gone.  This
15745cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * method allows the UI code to detect that state.)
15755cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         *
15765cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         * @see hide()
15775cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown         */
15785cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        public static boolean isFadingOut(final View view) {
15795cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (FADE_DBG) {
15805cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                log("Fade: isFadingOut view " + view + "...");
15815cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                log("Fade:   - getTag() returns: " + view.getTag(FADE_STATE_KEY));
15825cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                log("Fade:   - returning: " + (view.getTag(FADE_STATE_KEY) == FADING_OUT));
15835cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            }
15845cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            return (view.getTag(FADE_STATE_KEY) == FADING_OUT);
15855cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        }
15865cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15875cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown    }
15885cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown
15899688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown
1590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Debugging / testing code
1591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
15925cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown    private static void log(String msg) {
1593796c70c99bc39295bf685061056f06ab8949c742David Brown        Log.d(LOG_TAG, msg);
1594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
1596