blob: f597030cb4b8ed679dc24366318812ff3b9eb302 [file] [log] [blame]
Santos Cordone3d76ab2014-01-28 17:25:20 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.telecomm;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.IBinder;
24import android.os.RemoteException;
25import android.telecomm.IInCallService;
26import android.util.Log;
27
28/**
29 * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it
30 * can send updates to the in-call app. This class is created and owned by CallsManager and retains
31 * a binding to the {@link IInCallService} (implemented by the in-call app) until CallsManager
32 * explicitly disconnects it. CallsManager starts the connection by calling {@link #connect} and
33 * retains the connection as long as it has calls which need UI. When all calls are disconnected,
34 * CallsManager will invoke {@link #disconnect} to sever the binding until the in-call UI is needed
35 * again.
36 */
37public final class InCallController {
38 /**
39 * Used to bind to the in-call app and triggers the start of communication between
40 * CallsManager and in-call app.
41 */
42 private class InCallServiceConnection implements ServiceConnection {
43 /** {@inheritDoc} */
44 @Override public void onServiceConnected(ComponentName name, IBinder service) {
45 onConnected(service);
46 }
47
48 /** {@inheritDoc} */
49 @Override public void onServiceDisconnected(ComponentName name) {
50 onDisconnected();
51 }
52 }
53
54 private static final String TAG = InCallController.class.getSimpleName();
55
56 /**
57 * Package name of the in-call app. Although in-call code in kept in its own namespace, it is
58 * ultimately compiled into the dialer apk, hence the difference in namespaces between this and
59 * {@link IN_CALL_SERVICE_CLASS_NAME}.
60 * TODO(santoscordon): Change this into config.xml resource entry.
61 */
62 private static final String IN_CALL_PACKAGE_NAME = "com.google.android.dialer";
63
64 /**
65 * Class name of the component within in-call app which implements {@link IInCallService}.
66 */
67 private static final String IN_CALL_SERVICE_CLASS_NAME = "com.android.incall.InCallService";
68
69 /** Maintains a binding connection to the in-call app. */
70 private final InCallServiceConnection mConnection = new InCallServiceConnection();
71
72 private final CallsManager mCallsManager;
73
74 /** The in-call app implementation, see {@link IInCallService}. */
75 private IInCallService mInCallService;
76
77 /**
78 * Persists the specified parameters.
Santos Cordone3d76ab2014-01-28 17:25:20 -080079 */
Santos Cordon681663d2014-01-30 04:32:15 -080080 InCallController() {
81 mCallsManager = CallsManager.getInstance();
Santos Cordone3d76ab2014-01-28 17:25:20 -080082 }
83
84 // TODO(santoscordon): May be better to expose the IInCallService methods directly from this
85 // class as its own method to make the CallsManager code easier to read.
86 IInCallService getService() {
87 return mInCallService;
88 }
89
90 /**
91 * Binds to the in-call app if not already connected by binding directly to the saved
92 * component name of the {@link IInCallService} implementation.
93 *
94 * @param context The application context.
95 */
96 void connect(Context context) {
97 ThreadUtil.checkOnMainThread();
98 if (mInCallService == null) {
99 ComponentName component =
100 new ComponentName(IN_CALL_PACKAGE_NAME, IN_CALL_SERVICE_CLASS_NAME);
101
102 Intent serviceIntent = new Intent(IInCallService.class.getName());
103 serviceIntent.setComponent(component);
104
105 if (!context.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
106 Log.e(TAG, "Could not connect to the in-call app (" + component + ")");
107
108 // TODO(santoscordon): Implement retry or fall-back-to-default logic.
109 }
110 }
111 }
112
113 /**
114 * Unbinds an existing bound connection to the in-call app.
115 *
116 * @param context The application context.
117 */
118 void disconnect(Context context) {
119 ThreadUtil.checkOnMainThread();
120 if (mInCallService != null) {
121 context.unbindService(mConnection);
122 mInCallService = null;
123 }
124 }
125
126 /**
127 * Persists the {@link IInCallService} instance and starts the communication between
128 * CallsManager and in-call app by sending the first update to in-call app. This method is
129 * called after a successful binding connection is established.
130 *
131 * @param service The {@link IInCallService} implementation.
132 */
133 private void onConnected(IBinder service) {
134 ThreadUtil.checkOnMainThread();
135 mInCallService = IInCallService.Stub.asInterface(service);
136
137 try {
138 mInCallService.setInCallAdapter(new InCallAdapter(mCallsManager));
139 } catch (RemoteException e) {
140 Log.e(TAG, "Failed to set the in-call adapter.", e);
141 mInCallService = null;
142 }
143
144 update();
145 }
146
147 /**
148 * Cleans up the instance of in-call app after the service has been unbound.
149 */
150 private void onDisconnected() {
151 ThreadUtil.checkOnMainThread();
152 mInCallService = null;
153 }
154
155 /**
156 * Gathers the list of current calls from CallsManager and sends them to the in-call app.
157 */
158 private void update() {
159 // TODO(santoscordon): mInCallService.sendCalls(CallsManager.getCallList());
160 }
161}