189647a60693ebdd94a0fc60da557d17d19847942Santos Cordon/*
289647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * Copyright (C) 2013 The Android Open Source Project
389647a60693ebdd94a0fc60da557d17d19847942Santos Cordon *
489647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * you may not use this file except in compliance with the License.
689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * You may obtain a copy of the License at
789647a60693ebdd94a0fc60da557d17d19847942Santos Cordon *
889647a60693ebdd94a0fc60da557d17d19847942Santos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
989647a60693ebdd94a0fc60da557d17d19847942Santos Cordon *
1089647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * Unless required by applicable law or agreed to in writing, software
1189647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
1289647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1389647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * See the License for the specific language governing permissions and
1489647a60693ebdd94a0fc60da557d17d19847942Santos Cordon * limitations under the License.
1589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon */
1689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
1789647a60693ebdd94a0fc60da557d17d19847942Santos Cordonpackage com.android.phone;
1889647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
197984000187238151f2a5c46c7289db87df923050Yorke Leeimport android.Manifest;
2089647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.content.ComponentName;
2189647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.content.Context;
2289647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.content.Intent;
2389647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.content.ServiceConnection;
2411a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Chengimport android.content.pm.PackageManager;
2511a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Chengimport android.content.pm.ResolveInfo;
267984000187238151f2a5c46c7289db87df923050Yorke Leeimport android.content.pm.ServiceInfo;
2789647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.os.Handler;
2889647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.os.IBinder;
2989647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.os.Message;
3026c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Chengimport android.os.PowerManager;
3189647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.os.RemoteException;
3226c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Chengimport android.os.SystemClock;
3389647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.os.SystemProperties;
34de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Leeimport android.text.TextUtils;
3589647a60693ebdd94a0fc60da557d17d19847942Santos Cordonimport android.util.Log;
3689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
37de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Leeimport com.android.internal.telephony.Connection;
38de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Leeimport com.android.internal.telephony.Connection.PostDialState;
399b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordonimport com.android.phone.AudioRouter.AudioModeListener;
40362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Leeimport com.android.phone.NotificationMgr.StatusBarHelper;
419b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordonimport com.android.services.telephony.common.AudioMode;
42f404688cbde8e73c68c3b285cdd144c0b8580f8fSantos Cordonimport com.android.services.telephony.common.Call;
43345350ee0b6fa5c510e64b4b8cfb5ed1e5d70851Santos Cordonimport com.android.services.telephony.common.ICallHandlerService;
446c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Chengimport com.google.common.collect.Lists;
4589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
46a3d0514c3480db25a813d8841c39e965f2925180Santos Cordonimport java.util.List;
47a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon
4889647a60693ebdd94a0fc60da557d17d19847942Santos Cordon/**
49345350ee0b6fa5c510e64b4b8cfb5ed1e5d70851Santos Cordon * This class is responsible for passing through call state changes to the CallHandlerService.
5089647a60693ebdd94a0fc60da557d17d19847942Santos Cordon */
516c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Chengpublic class CallHandlerServiceProxy extends Handler
526c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        implements CallModeler.Listener, AudioModeListener {
5389647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
54345350ee0b6fa5c510e64b4b8cfb5ed1e5d70851Santos Cordon    private static final String TAG = CallHandlerServiceProxy.class.getSimpleName();
5571d5c6e4d0036e30eaa6a23faf0c246934ef8e6bSantos Cordon    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt(
566c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            "ro.debuggable", 0) == 1);
57e41661cbc5db3cbb8e60e0137fbac3f3a1f506a5Chiao Cheng
586c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    public static final int RETRY_DELAY_MILLIS = 2000;
5970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    public static final int RETRY_DELAY_LONG_MILLIS = 30 * 1000; // 30 seconds
606c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private static final int BIND_RETRY_MSG = 1;
6170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    private static final int MAX_SHORT_DELAY_RETRY_COUNT = 5;
6289647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
63593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    private AudioRouter mAudioRouter;
64593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    private CallCommandService mCallCommandService;
6563a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon    private CallModeler mCallModeler;
66593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    private Context mContext;
67f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon    private boolean mFullUpdateOnConnect;
68d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng
696c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private ICallHandlerService mCallHandlerServiceGuarded;  // Guarded by mServiceAndQueueLock
70d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    // Single queue to guarantee ordering
71d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    private List<QueueParams> mQueue;                        // Guarded by mServiceAndQueueLock
72d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng
736c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private final Object mServiceAndQueueLock = new Object();
746c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private int mBindRetryCount = 0;
756c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng
766c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    @Override
776c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    public void handleMessage(Message msg) {
786c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        super.handleMessage(msg);
796c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng
806c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        switch (msg.what) {
816c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            case BIND_RETRY_MSG:
8270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                handleConnectRetry();
836c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                break;
846c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        }
856c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    }
8689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
8763a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon    public CallHandlerServiceProxy(Context context, CallModeler callModeler,
88593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            CallCommandService callCommandService, AudioRouter audioRouter) {
896c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        if (DBG) {
906c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.d(TAG, "init CallHandlerServiceProxy");
916c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        }
9289647a60693ebdd94a0fc60da557d17d19847942Santos Cordon        mContext = context;
93cba1b444f3c4f94b7be1e07b39ba4873a11f379fSantos Cordon        mCallCommandService = callCommandService;
9463a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon        mCallModeler = callModeler;
95593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon        mAudioRouter = audioRouter;
9689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
97593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon        mAudioRouter.addAudioModeListener(this);
98daf7bf63f4f104977b01623e4f36a50db190d47cChristine Chen        mCallModeler.addListener(this);
9963a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon    }
10063a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon
10163a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon    @Override
102995c816b6a596ccd48628c1da4199ea9e8a830b2Santos Cordon    public void onDisconnect(Call call) {
10326c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng        // Wake up in case the screen was off.
10426c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng        wakeUpScreen();
1053e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        synchronized (mServiceAndQueueLock) {
1063e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mCallHandlerServiceGuarded == null) {
1073e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (DBG) {
1083e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    Log.d(TAG, "CallHandlerService not connected.  Enqueue disconnect");
1096c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                }
1103e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                enqueueDisconnect(call);
1113e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                setupServiceConnection();
1123e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                return;
11363a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon            }
1143e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
1153e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        processDisconnect(call);
1163e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
1173e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
11826c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng    private void wakeUpScreen() {
11926c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng        Log.d(TAG, "wakeUpScreen()");
12026c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
12126c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng        pm.wakeUp(SystemClock.uptimeMillis());
12226c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng    }
12326c6e92b6bb096e7f4a863f8dba2c64bdb5c34b0Chiao Cheng
1243e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private void processDisconnect(Call call) {
1253e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        try {
1266c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            if (DBG) {
1276c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                Log.d(TAG, "onDisconnect: " + call);
12863a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon            }
1293e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            synchronized (mServiceAndQueueLock) {
1303e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (mCallHandlerServiceGuarded != null) {
1313e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    mCallHandlerServiceGuarded.onDisconnect(call);
1323e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                }
1333e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            }
1343e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (!mCallModeler.hasLiveCall()) {
1353e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                unbind();
1363e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            }
1376c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        } catch (Exception e) {
1386c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.e(TAG, "Remote exception handling onDisconnect ", e);
13989647a60693ebdd94a0fc60da557d17d19847942Santos Cordon        }
14089647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    }
14189647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
142a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon    @Override
1436c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    public void onIncoming(Call call) {
14470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        // for new incoming calls, reset the retry count.
14570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        resetConnectRetryCount();
14670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
1473e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        synchronized (mServiceAndQueueLock) {
1483e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mCallHandlerServiceGuarded == null) {
1493e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (DBG) {
1503e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    Log.d(TAG, "CallHandlerService not connected.  Enqueue incoming.");
1516c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                }
1523e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                enqueueIncoming(call);
1533e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                setupServiceConnection();
1543e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                return;
1556c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            }
1563e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
1573e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        processIncoming(call);
1583e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
1593e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
1603e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private void processIncoming(Call call) {
1613e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        if (DBG) {
1623e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            Log.d(TAG, "onIncoming: " + call);
1633e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
1643e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        try {
1653e0f0414daa2266dc51b77198fe433797f7d610aChristine Chen            // TODO: check RespondViaSmsManager.allowRespondViaSmsForCall()
1666c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            // must refactor call method to accept proper call object.
1673e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            synchronized (mServiceAndQueueLock) {
1683e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (mCallHandlerServiceGuarded != null) {
1693e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    mCallHandlerServiceGuarded.onIncoming(call,
1703e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            RejectWithTextMessageManager.loadCannedResponses());
1713e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                }
1723e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            }
1736c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        } catch (Exception e) {
1746c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.e(TAG, "Remote exception handling onUpdate", e);
175ee09a49b24b2228f7ea7fb3d3be7a551120abb1aChristine Chen        }
176ee09a49b24b2228f7ea7fb3d3be7a551120abb1aChristine Chen    }
177ee09a49b24b2228f7ea7fb3d3be7a551120abb1aChristine Chen
178ee09a49b24b2228f7ea7fb3d3be7a551120abb1aChristine Chen    @Override
1796c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    public void onUpdate(List<Call> calls) {
1803e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        synchronized (mServiceAndQueueLock) {
1813e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mCallHandlerServiceGuarded == null) {
1823e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (DBG) {
1833e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    Log.d(TAG, "CallHandlerService not connected.  Enqueue update.");
1843e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                }
1853e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                enqueueUpdate(calls);
1863e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                setupServiceConnection();
1873e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                return;
1883e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            }
1893e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
1903e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        processUpdate(calls);
1913e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
1923e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
1933e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private void processUpdate(List<Call> calls) {
1943e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        if (DBG) {
1953e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            Log.d(TAG, "onUpdate: " + calls.toString());
1963e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
1976c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        try {
1986c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            synchronized (mServiceAndQueueLock) {
1993e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                if (mCallHandlerServiceGuarded != null) {
2003e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    mCallHandlerServiceGuarded.onUpdate(calls);
2016c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                }
202a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon            }
2033e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (!mCallModeler.hasLiveCall()) {
2043e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                // TODO: unbinding happens in both onUpdate and onDisconnect because the ordering
2053e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                // is not deterministic.  Unbinding in both ensures that the service is unbound.
2063e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                // But it also makes this in-efficient because we are unbinding twice, which leads
2073e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                // to the CallHandlerService performing onCreate() and onDestroy() twice for each
2083e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                // disconnect.
2093e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                unbind();
210a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon            }
2116c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        } catch (Exception e) {
2126c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.e(TAG, "Remote exception handling onUpdate", e);
213a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon        }
214a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon    }
215a3d0514c3480db25a813d8841c39e965f2925180Santos Cordon
2163f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng
2173f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng    @Override
218de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Lee    public void onPostDialAction(Connection.PostDialState state, int callId, String remainingChars,
219de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Lee            char currentChar) {
220de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Lee        if (state != PostDialState.WAIT) return;
2213f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng        try {
2223f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng            synchronized (mServiceAndQueueLock) {
2233f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                if (mCallHandlerServiceGuarded == null) {
2243f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                    if (DBG) {
2253f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                        Log.d(TAG, "CallHandlerService not conneccted. Skipping "
2263f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                                + "onPostDialWait().");
2273f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                    }
2283f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                    return;
2293f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng                }
2303f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng            }
2313f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng
2323f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng            mCallHandlerServiceGuarded.onPostDialWait(callId, remainingChars);
2333f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng        } catch (Exception e) {
2343f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng            Log.e(TAG, "Remote exception handling onUpdate", e);
2353f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng        }
2363f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng    }
2373f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng
2389b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon    @Override
239cd95f62ea9f94c06d01debfcd1f01fd2cd6e2708Santos Cordon    public void onAudioModeChange(int newMode, boolean muted) {
2406c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        try {
2416c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            synchronized (mServiceAndQueueLock) {
2426c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                if (mCallHandlerServiceGuarded == null) {
2436c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    if (DBG) {
2446c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                        Log.d(TAG, "CallHandlerService not conneccted. Skipping "
2456c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                                + "onAudioModeChange().");
2466c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    }
2476c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    return;
2486c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                }
2496c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            }
2509b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon
2516c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            // Just do a simple log for now.
2526c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.i(TAG, "Updating with new audio mode: " + AudioMode.toString(newMode) +
253cd95f62ea9f94c06d01debfcd1f01fd2cd6e2708Santos Cordon                    " with mute " + muted);
254593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon
255cd95f62ea9f94c06d01debfcd1f01fd2cd6e2708Santos Cordon            mCallHandlerServiceGuarded.onAudioModeChange(newMode, muted);
2566c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        } catch (Exception e) {
2576c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.e(TAG, "Remote exception handling onAudioModeChange", e);
2589b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon        }
2599b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon    }
2609b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon
261593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    @Override
262593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    public void onSupportedAudioModeChange(int modeMask) {
2636c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        try {
2646c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            synchronized (mServiceAndQueueLock) {
2656c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                if (mCallHandlerServiceGuarded == null) {
2666c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    if (DBG) {
2676c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                        Log.d(TAG, "CallHandlerService not conneccted. Skipping"
2686c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                                + "onSupportedAudioModeChange().");
2696c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    }
2706c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    return;
2716c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                }
272593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            }
273593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon
2746c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            if (DBG) {
2756c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                Log.d(TAG, "onSupportAudioModeChange: " + AudioMode.toString(modeMask));
276593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            }
27789647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
2786c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            mCallHandlerServiceGuarded.onSupportedAudioModeChange(modeMask);
2796c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        } catch (Exception e) {
2806c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.e(TAG, "Remote exception handling onAudioModeChange", e);
281593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon        }
282af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
283593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon    }
284406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon
2853e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private ServiceConnection mConnection = null;
2863e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
2873e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private class InCallServiceConnection implements ServiceConnection {
2886c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        @Override public void onServiceConnected (ComponentName className, IBinder service){
2896c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            if (DBG) {
2906c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                Log.d(TAG, "Service Connected");
29189647a60693ebdd94a0fc60da557d17d19847942Santos Cordon            }
2926c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            onCallHandlerServiceConnected(ICallHandlerService.Stub.asInterface(service));
29370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            resetConnectRetryCount();
29489647a60693ebdd94a0fc60da557d17d19847942Santos Cordon        }
29589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
2966c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        @Override public void onServiceDisconnected (ComponentName className){
2976c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            Log.i(TAG, "Disconnected from UI service.");
2986c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            synchronized (mServiceAndQueueLock) {
2996c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                // Technically, unbindService is un-necessary since the framework will schedule and
3006c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                // restart the crashed service.  But there is a exponential backoff for the restart.
3016c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                // Unbind explicitly and setup again to avoid the backoff since it's important to
3026c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                // always have an in call ui.
3033e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                unbind();
3043e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
305f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon                reconnectOnRemainingCalls();
306af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon            }
307af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon        }
3083e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
3096c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng
310bcf2099b92870b863f53e79288d4c8e73a4dc42dMakoto Onuki    public void bringToForeground(boolean showDialpad) {
311406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon        // only support this call if the service is already connected.
31219d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon        synchronized (mServiceAndQueueLock) {
31319d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon            if (mCallHandlerServiceGuarded != null && mCallModeler.hasLiveCall()) {
31419d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon                try {
315bcf2099b92870b863f53e79288d4c8e73a4dc42dMakoto Onuki                    if (DBG) Log.d(TAG, "bringToForeground: " + showDialpad);
316bcf2099b92870b863f53e79288d4c8e73a4dc42dMakoto Onuki                    mCallHandlerServiceGuarded.bringToForeground(showDialpad);
31719d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon                } catch (RemoteException e) {
31819d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon                    Log.e(TAG, "Exception handling bringToForeground", e);
31919d814b12a6ba77ba93ee5d8f3b46ca979d8e5caSantos Cordon                }
320406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon            }
321406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon        }
322406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon    }
323593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon
3243e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private static Intent getInCallServiceIntent(Context context) {
3253e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        final Intent serviceIntent = new Intent(ICallHandlerService.class.getName());
3263e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        final ComponentName component = new ComponentName(context.getResources().getString(
327d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                R.string.ui_default_package), context.getResources().getString(
328d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                R.string.incall_default_class));
3293e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        serviceIntent.setComponent(component);
3303e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        return serviceIntent;
3313e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
3323e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
33389647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    /**
334345350ee0b6fa5c510e64b4b8cfb5ed1e5d70851Santos Cordon     * Sets up the connection with ICallHandlerService
33589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon     */
33689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    private void setupServiceConnection() {
3373e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        if (!PhoneGlobals.sVoiceCapable) {
3383e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            return;
3393e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
34011a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Cheng
3413e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        final Intent serviceIntent = getInCallServiceIntent(mContext);
34211a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Cheng        if (DBG) {
34311a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Cheng            Log.d(TAG, "binding to service " + serviceIntent);
34411a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Cheng        }
34511a4b650d5b5203045d82f37a10b2eb7623cf639Chiao Cheng
3466c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        synchronized (mServiceAndQueueLock) {
3473e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mConnection == null) {
3483e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                mConnection = new InCallServiceConnection();
3493e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
35070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                boolean failedConnection = false;
3513e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                final PackageManager packageManger = mContext.getPackageManager();
3523e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                final List<ResolveInfo> services = packageManger.queryIntentServices(serviceIntent,
3533e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                        0);
3547984000187238151f2a5c46c7289db87df923050Yorke Lee
3557984000187238151f2a5c46c7289db87df923050Yorke Lee                ServiceInfo serviceInfo = null;
3567984000187238151f2a5c46c7289db87df923050Yorke Lee
3577984000187238151f2a5c46c7289db87df923050Yorke Lee                for (int i = 0; i < services.size(); i++) {
3587984000187238151f2a5c46c7289db87df923050Yorke Lee                    final ResolveInfo info = services.get(i);
3597984000187238151f2a5c46c7289db87df923050Yorke Lee                    if (info.serviceInfo != null) {
3607984000187238151f2a5c46c7289db87df923050Yorke Lee                        if (Manifest.permission.BIND_CALL_SERVICE.equals(
3617984000187238151f2a5c46c7289db87df923050Yorke Lee                                info.serviceInfo.permission)) {
3627984000187238151f2a5c46c7289db87df923050Yorke Lee                            serviceInfo = info.serviceInfo;
3637984000187238151f2a5c46c7289db87df923050Yorke Lee                            break;
3647984000187238151f2a5c46c7289db87df923050Yorke Lee                        }
3657984000187238151f2a5c46c7289db87df923050Yorke Lee                    }
3667984000187238151f2a5c46c7289db87df923050Yorke Lee                }
3677984000187238151f2a5c46c7289db87df923050Yorke Lee
3687984000187238151f2a5c46c7289db87df923050Yorke Lee                if (serviceInfo == null) {
3693e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    // Service not found, retry again after some delay
3703e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    // This can happen if the service is being installed by the package manager.
3713e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    // Between deletes and installs, bindService could get a silent service not
3723e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    // found error.
37370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    Log.w(TAG, "Default call handler service not found.");
37470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    failedConnection = true;
37570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                } else {
3763e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
37770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    serviceIntent.setComponent(new ComponentName(serviceInfo.packageName,
37870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                            serviceInfo.name));
37970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    if (DBG) {
38070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                        Log.d(TAG, "binding to service " + serviceIntent);
38170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    }
38270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    if (!mContext.bindService(serviceIntent, mConnection,
38370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                            Context.BIND_AUTO_CREATE)) {
38470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                        // This happens when the in-call package is in the middle of being installed
38570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                        Log.w(TAG, "Could not bind to default call handler service: " +
38670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                                serviceIntent.getComponent());
38770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                        failedConnection = true;
3886c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng                    }
38989647a60693ebdd94a0fc60da557d17d19847942Santos Cordon                }
3903e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
39170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                if (failedConnection) {
39270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    mConnection = null;
39370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    enqueueConnectRetry();
39470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                }
3953e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            } else {
3963e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                Log.d(TAG, "Service connection to in call service already started.");
3973e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            }
3983e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        }
3993e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    }
4003e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng
40170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    private void resetConnectRetryCount() {
40270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        mBindRetryCount = 0;
40370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    }
40470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
40570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    private void incrementRetryCount() {
40670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        // Reset to the short delay retry count to avoid overflow
40770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        if (Integer.MAX_VALUE == mBindRetryCount) {
40870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            mBindRetryCount = MAX_SHORT_DELAY_RETRY_COUNT;
40970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        }
41070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
41170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        mBindRetryCount++;
41270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    }
41370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
41470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    private void handleConnectRetry() {
41570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        // Remove any pending messages since we're already performing the action.
41670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        // If the call to setupServiceConnection() fails, it will queue up another retry.
41770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        removeMessages(BIND_RETRY_MSG);
41870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
41970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        // Something else triggered the connection, cancel.
42070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        if (mConnection != null) {
42170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            Log.i(TAG, "Retry: already connected.");
42270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            return;
42370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        }
42470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
42570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        if (mCallModeler.hasLiveCall()) {
42670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // Update the count when we are actually trying the retry instead of when the
42770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // retry is queued up.
42870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            incrementRetryCount();
42970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
43070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            Log.i(TAG, "Retrying connection: " + mBindRetryCount);
43170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            setupServiceConnection();
43270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        } else {
43370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            Log.i(TAG, "Canceling connection retry since there are no calls.");
43470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // We are not currently connected and there is no call so lets not bother
43570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // with the retry. Also, empty the queue of pending messages to send
43670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // to the UI.
43770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            synchronized (mServiceAndQueueLock) {
43870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                if (mQueue != null) {
43970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                    mQueue.clear();
44070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                }
44170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            }
44270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
44370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            // Since we have no calls, reset retry count.
44470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon            resetConnectRetryCount();
44570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        }
44670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    }
44770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
44870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    /**
44970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon     * Called after the connection failed and a retry is needed.
45070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon     * Queues up a retry to happen with a delay.
45170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon     */
45270d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    private void enqueueConnectRetry() {
45370d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        final boolean isLongDelay = (mBindRetryCount > MAX_SHORT_DELAY_RETRY_COUNT);
45470d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        final int delay = isLongDelay ? RETRY_DELAY_LONG_MILLIS : RETRY_DELAY_MILLIS;
45570d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
45670d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        Log.w(TAG, "InCallUI Connection failed. Enqueuing delayed retry for " + delay + " ms." +
45770d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon                " retries(" + mBindRetryCount + ")");
45870d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
45970d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon        sendEmptyMessageDelayed(BIND_RETRY_MSG, delay);
46070d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon    }
46170d3866b170effeb64cacbdb59e3a5161447c944Santos Cordon
4623e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng    private void unbind() {
4633e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        synchronized (mServiceAndQueueLock) {
464362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee            // On unbind, reenable the notification shade and navigation bar just in case the
465362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee            // in-call UI crashed on an incoming call.
466362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee            final StatusBarHelper statusBarHelper = PhoneGlobals.getInstance().notificationMgr.
467362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee                    statusBarHelper;
468362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee            statusBarHelper.enableSystemBarNavigation(true);
469362cec21b259ce1a8bfe69a873a7e90293f8b33dYorke Lee            statusBarHelper.enableExpandedView(true);
4703e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mCallHandlerServiceGuarded != null) {
4713e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                Log.d(TAG, "Unbinding service.");
4723e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                mCallHandlerServiceGuarded = null;
4733e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                mContext.unbindService(mConnection);
47489647a60693ebdd94a0fc60da557d17d19847942Santos Cordon            }
4753e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            mConnection = null;
476af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon        }
477af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon    }
478af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
479af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon    /**
480cba1b444f3c4f94b7be1e07b39ba4873a11f379fSantos Cordon     * Called when the in-call UI service is connected.  Send command interface to in-call.
481cba1b444f3c4f94b7be1e07b39ba4873a11f379fSantos Cordon     */
48263a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon    private void onCallHandlerServiceConnected(ICallHandlerService callHandlerService) {
483d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng
4846c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        synchronized (mServiceAndQueueLock) {
4856c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            mCallHandlerServiceGuarded = callHandlerService;
48689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
487ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon            // Before we send any updates, we need to set up the initial service calls.
488ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon            makeInitialServiceCalls();
489ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon
490d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng            processQueue();
491f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon
492f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon            if (mFullUpdateOnConnect) {
493f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon                mFullUpdateOnConnect = false;
494f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon                onUpdate(mCallModeler.getFullList());
495f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon            }
496f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon        }
497f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon    }
498f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon
499f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon    /**
500f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon     * Checks to see if there are any live calls left, and if so, try reconnecting the UI.
501f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon     */
502f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon    private void reconnectOnRemainingCalls() {
503f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon        if (mCallModeler.hasLiveCall()) {
504f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon            mFullUpdateOnConnect = true;
505f9ad0640b8f71c0f3ee0d5a46e6f709b0827f544Santos Cordon            setupServiceConnection();
5066c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        }
507ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon    }
508af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
509ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon    /**
510ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon     * Makes initial service calls to set up callcommandservice and audio modes.
511ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon     */
512ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon    private void makeInitialServiceCalls() {
5136c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        try {
51412a03aa7bf49224d531f7469cdcd019e1b0f155eSantos Cordon            mCallHandlerServiceGuarded.startCallService(mCallCommandService);
515ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon
516ad07819ef0a3968cf562ccc87c2be9417db08328Santos Cordon            onSupportedAudioModeChange(mAudioRouter.getSupportedAudioModes());
5178fd0ec73400aed9ad5e46d46befb20b2b1008338Santos Cordon            onAudioModeChange(mAudioRouter.getAudioMode(), mAudioRouter.getMute());
518cba1b444f3c4f94b7be1e07b39ba4873a11f379fSantos Cordon        } catch (RemoteException e) {
51963a8424848966c0e94a78c4200bb091366dca3b8Santos Cordon            Log.e(TAG, "Remote exception calling CallHandlerService::setCallCommandService", e);
52089647a60693ebdd94a0fc60da557d17d19847942Santos Cordon        }
52189647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    }
522af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
523d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    private List<QueueParams> getQueue() {
524d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        if (mQueue == null) {
525d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng            mQueue = Lists.newArrayList();
526d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        }
527d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        return mQueue;
528d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    }
52989647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
5306c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private void enqueueDisconnect(Call call) {
531d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        getQueue().add(new QueueParams(QueueParams.METHOD_DISCONNECT, new Call(call)));
53289647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    }
53389647a60693ebdd94a0fc60da557d17d19847942Santos Cordon
5346c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private void enqueueIncoming(Call call) {
535d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        getQueue().add(new QueueParams(QueueParams.METHOD_INCOMING, new Call(call)));
536af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon    }
537af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
5386c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    private void enqueueUpdate(List<Call> calls) {
5396c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        final List<Call> copy = Lists.newArrayList();
5406c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        for (Call call : calls) {
5416c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            copy.add(new Call(call));
5426c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        }
543c340ba99a03178987c15789cbca0994190c15fd6Chiao Cheng        getQueue().add(new QueueParams(QueueParams.METHOD_UPDATE, copy));
544af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon    }
545af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
546d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    private void processQueue() {
5473e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng        synchronized (mServiceAndQueueLock) {
5483e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng            if (mQueue != null) {
5493e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                for (QueueParams params : mQueue) {
5503e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    switch (params.mMethod) {
5513e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                        case QueueParams.METHOD_INCOMING:
5523e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            processIncoming((Call) params.mArg);
5533e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            break;
5543e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                        case QueueParams.METHOD_UPDATE:
5553e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            processUpdate((List<Call>) params.mArg);
5563e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            break;
5573e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                        case QueueParams.METHOD_DISCONNECT:
5583e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            processDisconnect((Call) params.mArg);
5593e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            break;
5603e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                        default:
5613e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                            throw new IllegalArgumentException("Method type " + params.mMethod +
5623e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                                    " not recognized.");
5633e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                    }
5643e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                }
5653e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                mQueue.clear();
5663e6486e012ce6c15675cd0d2f20155e5a49ed0aeChiao Cheng                mQueue = null;
5676c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng            }
5686c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng        }
5696c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng    }
570cba1b444f3c4f94b7be1e07b39ba4873a11f379fSantos Cordon
571d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    /**
572d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng     * Holds method parameters.
573d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng     */
574d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng    private static class QueueParams {
575d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private static final int METHOD_INCOMING = 1;
576d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private static final int METHOD_UPDATE = 2;
577d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private static final int METHOD_DISCONNECT = 3;
578af763a15f376f8248684b02695d38a5a08e61ac3Santos Cordon
579d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private final int mMethod;
580d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private final Object mArg;
581d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng
582d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng        private QueueParams(int method, Object arg) {
583d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng            mMethod = method;
584d38eebcd68a92b7ba1ebb1b79530b98b594e04c2Chiao Cheng            this.mArg = arg;
58589647a60693ebdd94a0fc60da557d17d19847942Santos Cordon        }
58689647a60693ebdd94a0fc60da557d17d19847942Santos Cordon    }
58789647a60693ebdd94a0fc60da557d17d19847942Santos Cordon}
588