blob: 7b48d95835aac2aacc3a4c1af6de6840b0c7fd36 [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.
79 *
80 * @param callsManager The singleton calls manager instance.
81 */
82 InCallController(CallsManager callsManager) {
83 mCallsManager = callsManager;
84 }
85
86 // TODO(santoscordon): May be better to expose the IInCallService methods directly from this
87 // class as its own method to make the CallsManager code easier to read.
88 IInCallService getService() {
89 return mInCallService;
90 }
91
92 /**
93 * Binds to the in-call app if not already connected by binding directly to the saved
94 * component name of the {@link IInCallService} implementation.
95 *
96 * @param context The application context.
97 */
98 void connect(Context context) {
99 ThreadUtil.checkOnMainThread();
100 if (mInCallService == null) {
101 ComponentName component =
102 new ComponentName(IN_CALL_PACKAGE_NAME, IN_CALL_SERVICE_CLASS_NAME);
103
104 Intent serviceIntent = new Intent(IInCallService.class.getName());
105 serviceIntent.setComponent(component);
106
107 if (!context.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
108 Log.e(TAG, "Could not connect to the in-call app (" + component + ")");
109
110 // TODO(santoscordon): Implement retry or fall-back-to-default logic.
111 }
112 }
113 }
114
115 /**
116 * Unbinds an existing bound connection to the in-call app.
117 *
118 * @param context The application context.
119 */
120 void disconnect(Context context) {
121 ThreadUtil.checkOnMainThread();
122 if (mInCallService != null) {
123 context.unbindService(mConnection);
124 mInCallService = null;
125 }
126 }
127
128 /**
129 * Persists the {@link IInCallService} instance and starts the communication between
130 * CallsManager and in-call app by sending the first update to in-call app. This method is
131 * called after a successful binding connection is established.
132 *
133 * @param service The {@link IInCallService} implementation.
134 */
135 private void onConnected(IBinder service) {
136 ThreadUtil.checkOnMainThread();
137 mInCallService = IInCallService.Stub.asInterface(service);
138
139 try {
140 mInCallService.setInCallAdapter(new InCallAdapter(mCallsManager));
141 } catch (RemoteException e) {
142 Log.e(TAG, "Failed to set the in-call adapter.", e);
143 mInCallService = null;
144 }
145
146 update();
147 }
148
149 /**
150 * Cleans up the instance of in-call app after the service has been unbound.
151 */
152 private void onDisconnected() {
153 ThreadUtil.checkOnMainThread();
154 mInCallService = null;
155 }
156
157 /**
158 * Gathers the list of current calls from CallsManager and sends them to the in-call app.
159 */
160 private void update() {
161 // TODO(santoscordon): mInCallService.sendCalls(CallsManager.getCallList());
162 }
163}