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