blob: ae5cd464d72c17bfd990be270dfc7144449ddc5f [file] [log] [blame]
Ihab Awadb8e85c72014-08-23 20:34:57 -07001/*
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
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Ihab Awadb8e85c72014-08-23 20:34:57 -070018
Tyler Gunnef9f6f92014-09-12 22:16:17 -070019import com.android.internal.telecom.IConnectionService;
Ihab Awadb8e85c72014-08-23 20:34:57 -070020
Santos Cordon6b7f9552015-05-27 17:21:45 -070021import android.annotation.Nullable;
Yorke Lee4af59352015-05-13 14:14:54 -070022import android.annotation.SystemApi;
Santos Cordon6b7f9552015-05-27 17:21:45 -070023import android.os.Bundle;
Andrew Lee011728f2015-04-23 15:47:06 -070024import android.os.Handler;
Ihab Awadb8e85c72014-08-23 20:34:57 -070025import android.os.RemoteException;
Ihab Awadb8e85c72014-08-23 20:34:57 -070026
Ihab Awad50e35062014-09-30 09:17:03 -070027import java.util.ArrayList;
Ihab Awadb8e85c72014-08-23 20:34:57 -070028import java.util.Collections;
29import java.util.List;
30import java.util.Set;
31import java.util.concurrent.CopyOnWriteArrayList;
32import java.util.concurrent.CopyOnWriteArraySet;
33
34/**
Santos Cordon895d4b82015-06-25 16:41:48 -070035 * A conference provided to a {@link ConnectionService} by another {@code ConnectionService} through
36 * {@link ConnectionService#conferenceRemoteConnections}. Once created, a {@code RemoteConference}
37 * can be used to control the conference call or monitor changes through
38 * {@link RemoteConnection.Callback}.
Santos Cordonb804f8d2015-05-12 12:09:47 -070039 *
40 * @see ConnectionService#onRemoteConferenceAdded
Ihab Awadb8e85c72014-08-23 20:34:57 -070041 */
42public final class RemoteConference {
43
Santos Cordon895d4b82015-06-25 16:41:48 -070044 /**
45 * Callback base class for {@link RemoteConference}.
46 */
Nancy Chen1d834f52014-09-05 11:03:21 -070047 public abstract static class Callback {
Santos Cordon895d4b82015-06-25 16:41:48 -070048 /**
49 * Invoked when the state of this {@code RemoteConferece} has changed. See
50 * {@link #getState()}.
51 *
52 * @param conference The {@code RemoteConference} invoking this method.
53 * @param oldState The previous state of the {@code RemoteConference}.
54 * @param newState The new state of the {@code RemoteConference}.
55 */
Ihab Awadb8e85c72014-08-23 20:34:57 -070056 public void onStateChanged(RemoteConference conference, int oldState, int newState) {}
Santos Cordon895d4b82015-06-25 16:41:48 -070057
58 /**
59 * Invoked when this {@code RemoteConference} is disconnected.
60 *
61 * @param conference The {@code RemoteConference} invoking this method.
62 * @param disconnectCause The ({@see DisconnectCause}) associated with this failed
63 * conference.
64 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -070065 public void onDisconnected(RemoteConference conference, DisconnectCause disconnectCause) {}
Santos Cordon895d4b82015-06-25 16:41:48 -070066
67 /**
68 * Invoked when a {@link RemoteConnection} is added to the conference call.
69 *
70 * @param conference The {@code RemoteConference} invoking this method.
71 * @param connection The {@link RemoteConnection} being added.
72 */
Ihab Awadb8e85c72014-08-23 20:34:57 -070073 public void onConnectionAdded(RemoteConference conference, RemoteConnection connection) {}
Santos Cordon895d4b82015-06-25 16:41:48 -070074
75 /**
76 * Invoked when a {@link RemoteConnection} is removed from the conference call.
77 *
78 * @param conference The {@code RemoteConference} invoking this method.
79 * @param connection The {@link RemoteConnection} being removed.
80 */
Ihab Awadb8e85c72014-08-23 20:34:57 -070081 public void onConnectionRemoved(RemoteConference conference, RemoteConnection connection) {}
Santos Cordon895d4b82015-06-25 16:41:48 -070082
83 /**
84 * Indicates that the call capabilities of this {@code RemoteConference} have changed.
85 * See {@link #getConnectionCapabilities()}.
86 *
87 * @param conference The {@code RemoteConference} invoking this method.
88 * @param connectionCapabilities The new capabilities of the {@code RemoteConference}.
89 */
Ihab Awad5c9c86e2014-11-12 13:41:16 -080090 public void onConnectionCapabilitiesChanged(
91 RemoteConference conference,
92 int connectionCapabilities) {}
Santos Cordon895d4b82015-06-25 16:41:48 -070093
94 /**
95 * Invoked when the set of {@link RemoteConnection}s which can be added to this conference
96 * call have changed.
97 *
98 * @param conference The {@code RemoteConference} invoking this method.
99 * @param conferenceableConnections The list of conferenceable {@link RemoteConnection}s.
100 */
Ihab Awad50e35062014-09-30 09:17:03 -0700101 public void onConferenceableConnectionsChanged(
102 RemoteConference conference,
103 List<RemoteConnection> conferenceableConnections) {}
Santos Cordon895d4b82015-06-25 16:41:48 -0700104
105 /**
106 * Indicates that this {@code RemoteConference} has been destroyed. No further requests
107 * should be made to the {@code RemoteConference}, and references to it should be cleared.
108 *
109 * @param conference The {@code RemoteConference} invoking this method.
110 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700111 public void onDestroyed(RemoteConference conference) {}
Santos Cordon895d4b82015-06-25 16:41:48 -0700112
113 /**
114 * Handles changes to the {@code RemoteConference} extras.
115 *
116 * @param conference The {@code RemoteConference} invoking this method.
117 * @param extras The extras containing other information associated with the conference.
118 */
Santos Cordon6b7f9552015-05-27 17:21:45 -0700119 public void onExtrasChanged(RemoteConference conference, @Nullable Bundle extras) {}
Ihab Awadb8e85c72014-08-23 20:34:57 -0700120 }
121
122 private final String mId;
123 private final IConnectionService mConnectionService;
124
Andrew Lee011728f2015-04-23 15:47:06 -0700125 private final Set<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArraySet<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700126 private final List<RemoteConnection> mChildConnections = new CopyOnWriteArrayList<>();
127 private final List<RemoteConnection> mUnmodifiableChildConnections =
128 Collections.unmodifiableList(mChildConnections);
Ihab Awad50e35062014-09-30 09:17:03 -0700129 private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>();
130 private final List<RemoteConnection> mUnmodifiableConferenceableConnections =
131 Collections.unmodifiableList(mConferenceableConnections);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700132
133 private int mState = Connection.STATE_NEW;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700134 private DisconnectCause mDisconnectCause;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800135 private int mConnectionCapabilities;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700136 private Bundle mExtras;
Ihab Awadb8e85c72014-08-23 20:34:57 -0700137
Santos Cordonb804f8d2015-05-12 12:09:47 -0700138 /** @hide */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700139 RemoteConference(String id, IConnectionService connectionService) {
140 mId = id;
141 mConnectionService = connectionService;
142 }
143
Santos Cordonb804f8d2015-05-12 12:09:47 -0700144 /** @hide */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700145 String getId() {
146 return mId;
147 }
148
Santos Cordonb804f8d2015-05-12 12:09:47 -0700149 /** @hide */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700150 void setDestroyed() {
151 for (RemoteConnection connection : mChildConnections) {
152 connection.setConference(null);
153 }
Andrew Lee011728f2015-04-23 15:47:06 -0700154 for (CallbackRecord<Callback> record : mCallbackRecords) {
155 final RemoteConference conference = this;
156 final Callback callback = record.getCallback();
157 record.getHandler().post(new Runnable() {
158 @Override
159 public void run() {
160 callback.onDestroyed(conference);
161 }
162 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700163 }
164 }
165
Santos Cordonb804f8d2015-05-12 12:09:47 -0700166 /** @hide */
Andrew Lee011728f2015-04-23 15:47:06 -0700167 void setState(final int newState) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700168 if (newState != Connection.STATE_ACTIVE &&
169 newState != Connection.STATE_HOLDING &&
170 newState != Connection.STATE_DISCONNECTED) {
171 Log.w(this, "Unsupported state transition for Conference call.",
172 Connection.stateToString(newState));
173 return;
174 }
175
176 if (mState != newState) {
Andrew Lee011728f2015-04-23 15:47:06 -0700177 final int oldState = mState;
Ihab Awadb8e85c72014-08-23 20:34:57 -0700178 mState = newState;
Andrew Lee011728f2015-04-23 15:47:06 -0700179 for (CallbackRecord<Callback> record : mCallbackRecords) {
180 final RemoteConference conference = this;
181 final Callback callback = record.getCallback();
182 record.getHandler().post(new Runnable() {
183 @Override
184 public void run() {
185 callback.onStateChanged(conference, oldState, newState);
186 }
187 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700188 }
189 }
190 }
191
Santos Cordonb804f8d2015-05-12 12:09:47 -0700192 /** @hide */
Andrew Lee011728f2015-04-23 15:47:06 -0700193 void addConnection(final RemoteConnection connection) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700194 if (!mChildConnections.contains(connection)) {
195 mChildConnections.add(connection);
196 connection.setConference(this);
Andrew Lee011728f2015-04-23 15:47:06 -0700197 for (CallbackRecord<Callback> record : mCallbackRecords) {
198 final RemoteConference conference = this;
199 final Callback callback = record.getCallback();
200 record.getHandler().post(new Runnable() {
201 @Override
202 public void run() {
203 callback.onConnectionAdded(conference, connection);
204 }
205 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700206 }
207 }
208 }
209
Santos Cordonb804f8d2015-05-12 12:09:47 -0700210 /** @hide */
Andrew Lee011728f2015-04-23 15:47:06 -0700211 void removeConnection(final RemoteConnection connection) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700212 if (mChildConnections.contains(connection)) {
213 mChildConnections.remove(connection);
214 connection.setConference(null);
Andrew Lee011728f2015-04-23 15:47:06 -0700215 for (CallbackRecord<Callback> record : mCallbackRecords) {
216 final RemoteConference conference = this;
217 final Callback callback = record.getCallback();
218 record.getHandler().post(new Runnable() {
219 @Override
220 public void run() {
221 callback.onConnectionRemoved(conference, connection);
222 }
223 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700224 }
225 }
226 }
227
Santos Cordonb804f8d2015-05-12 12:09:47 -0700228 /** @hide */
Andrew Lee011728f2015-04-23 15:47:06 -0700229 void setConnectionCapabilities(final int connectionCapabilities) {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800230 if (mConnectionCapabilities != connectionCapabilities) {
231 mConnectionCapabilities = connectionCapabilities;
Andrew Lee011728f2015-04-23 15:47:06 -0700232 for (CallbackRecord<Callback> record : mCallbackRecords) {
233 final RemoteConference conference = this;
234 final Callback callback = record.getCallback();
235 record.getHandler().post(new Runnable() {
236 @Override
237 public void run() {
238 callback.onConnectionCapabilitiesChanged(
239 conference, mConnectionCapabilities);
240 }
241 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700242 }
243 }
244 }
245
Ihab Awad50e35062014-09-30 09:17:03 -0700246 /** @hide */
247 void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
248 mConferenceableConnections.clear();
249 mConferenceableConnections.addAll(conferenceableConnections);
Andrew Lee011728f2015-04-23 15:47:06 -0700250 for (CallbackRecord<Callback> record : mCallbackRecords) {
251 final RemoteConference conference = this;
252 final Callback callback = record.getCallback();
253 record.getHandler().post(new Runnable() {
254 @Override
255 public void run() {
256 callback.onConferenceableConnectionsChanged(
257 conference, mUnmodifiableConferenceableConnections);
258 }
259 });
Ihab Awad50e35062014-09-30 09:17:03 -0700260 }
261 }
262
Santos Cordonb804f8d2015-05-12 12:09:47 -0700263 /** @hide */
Andrew Lee011728f2015-04-23 15:47:06 -0700264 void setDisconnected(final DisconnectCause disconnectCause) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700265 if (mState != Connection.STATE_DISCONNECTED) {
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700266 mDisconnectCause = disconnectCause;
Ihab Awadb8e85c72014-08-23 20:34:57 -0700267 setState(Connection.STATE_DISCONNECTED);
Andrew Lee011728f2015-04-23 15:47:06 -0700268 for (CallbackRecord<Callback> record : mCallbackRecords) {
269 final RemoteConference conference = this;
270 final Callback callback = record.getCallback();
271 record.getHandler().post(new Runnable() {
272 @Override
273 public void run() {
274 callback.onDisconnected(conference, disconnectCause);
275 }
276 });
Ihab Awadb8e85c72014-08-23 20:34:57 -0700277 }
278 }
279 }
280
Santos Cordon6b7f9552015-05-27 17:21:45 -0700281 /** @hide */
282 void setExtras(final Bundle extras) {
283 mExtras = extras;
284 for (CallbackRecord<Callback> record : mCallbackRecords) {
285 final RemoteConference conference = this;
286 final Callback callback = record.getCallback();
287 record.getHandler().post(new Runnable() {
288 @Override
289 public void run() {
290 callback.onExtrasChanged(conference, extras);
291 }
292 });
293 }
294 }
295
Santos Cordonb804f8d2015-05-12 12:09:47 -0700296 /**
297 * Returns the list of {@link RemoteConnection}s contained in this conference.
298 *
299 * @return A list of child connections.
300 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700301 public final List<RemoteConnection> getConnections() {
302 return mUnmodifiableChildConnections;
303 }
304
Santos Cordonb804f8d2015-05-12 12:09:47 -0700305 /**
306 * Gets the state of the conference call. See {@link Connection} for valid values.
307 *
308 * @return A constant representing the state the conference call is currently in.
309 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700310 public final int getState() {
311 return mState;
312 }
313
Santos Cordonb804f8d2015-05-12 12:09:47 -0700314 /**
315 * Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class
316 * {@link Connection} for valid values.
317 *
318 * @return A bitmask of the capabilities of the conference call.
319 */
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800320 public final int getConnectionCapabilities() {
321 return mConnectionCapabilities;
Ihab Awadb8e85c72014-08-23 20:34:57 -0700322 }
323
Santos Cordonb804f8d2015-05-12 12:09:47 -0700324 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700325 * Obtain the extras associated with this {@code RemoteConnection}.
326 *
327 * @return The extras for this connection.
328 */
329 public final Bundle getExtras() {
330 return mExtras;
331 }
332
333 /**
Santos Cordonb804f8d2015-05-12 12:09:47 -0700334 * Disconnects the conference call as well as the child {@link RemoteConnection}s.
335 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700336 public void disconnect() {
337 try {
338 mConnectionService.disconnect(mId);
339 } catch (RemoteException e) {
340 }
341 }
342
Santos Cordonb804f8d2015-05-12 12:09:47 -0700343 /**
344 * Removes the specified {@link RemoteConnection} from the conference. This causes the
345 * {@link RemoteConnection} to become a standalone connection. This is a no-op if the
346 * {@link RemoteConnection} does not belong to this conference.
347 *
348 * @param connection The remote-connection to remove.
349 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700350 public void separate(RemoteConnection connection) {
351 if (mChildConnections.contains(connection)) {
352 try {
353 mConnectionService.splitFromConference(connection.getId());
354 } catch (RemoteException e) {
355 }
356 }
357 }
358
Santos Cordonb804f8d2015-05-12 12:09:47 -0700359 /**
360 * Merges all {@link RemoteConnection}s of this conference into a single call. This should be
361 * invoked only if the conference contains the capability
362 * {@link Connection#CAPABILITY_MERGE_CONFERENCE}, otherwise it is a no-op. The presence of said
363 * capability indicates that the connections of this conference, despite being part of the
364 * same conference object, are yet to have their audio streams merged; this is a common pattern
365 * for CDMA conference calls, but the capability is not used for GSM and SIP conference calls.
366 * Invoking this method will cause the unmerged child connections to merge their audio
367 * streams.
368 */
mike dooley95ea5762014-09-25 14:49:21 -0700369 public void merge() {
370 try {
371 mConnectionService.mergeConference(mId);
372 } catch (RemoteException e) {
373 }
374 }
375
Santos Cordonb804f8d2015-05-12 12:09:47 -0700376 /**
377 * Swaps the active audio stream between the conference's child {@link RemoteConnection}s.
378 * This should be invoked only if the conference contains the capability
379 * {@link Connection#CAPABILITY_SWAP_CONFERENCE}, otherwise it is a no-op. This is only used by
380 * {@link ConnectionService}s that create conferences for connections that do not yet have
381 * their audio streams merged; this is a common pattern for CDMA conference calls, but the
382 * capability is not used for GSM and SIP conference calls. Invoking this method will change the
383 * active audio stream to a different child connection.
384 */
mike dooley95ea5762014-09-25 14:49:21 -0700385 public void swap() {
386 try {
387 mConnectionService.swapConference(mId);
388 } catch (RemoteException e) {
389 }
390 }
391
Santos Cordonb804f8d2015-05-12 12:09:47 -0700392 /**
393 * Puts the conference on hold.
394 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700395 public void hold() {
396 try {
397 mConnectionService.hold(mId);
398 } catch (RemoteException e) {
399 }
400 }
401
Santos Cordonb804f8d2015-05-12 12:09:47 -0700402 /**
403 * Unholds the conference call.
404 */
Ihab Awadb8e85c72014-08-23 20:34:57 -0700405 public void unhold() {
406 try {
407 mConnectionService.unhold(mId);
408 } catch (RemoteException e) {
409 }
410 }
411
Santos Cordonb804f8d2015-05-12 12:09:47 -0700412 /**
413 * Returns the {@link DisconnectCause} for the conference if it is in the state
414 * {@link Connection#STATE_DISCONNECTED}. If the conference is not disconnected, this will
415 * return null.
416 *
417 * @return The disconnect cause.
418 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700419 public DisconnectCause getDisconnectCause() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700420 return mDisconnectCause;
421 }
422
Santos Cordonb804f8d2015-05-12 12:09:47 -0700423 /**
424 * Requests that the conference start playing the specified DTMF tone.
425 *
426 * @param digit The digit for which to play a DTMF tone.
427 */
Yorke Lee58bacc52014-09-16 10:43:06 -0700428 public void playDtmfTone(char digit) {
429 try {
430 mConnectionService.playDtmfTone(mId, digit);
431 } catch (RemoteException e) {
432 }
433 }
434
Santos Cordonb804f8d2015-05-12 12:09:47 -0700435 /**
436 * Stops the most recent request to play a DTMF tone.
437 *
438 * @see #playDtmfTone
439 */
Yorke Lee58bacc52014-09-16 10:43:06 -0700440 public void stopDtmfTone() {
441 try {
442 mConnectionService.stopDtmfTone(mId);
443 } catch (RemoteException e) {
444 }
445 }
446
Santos Cordonb804f8d2015-05-12 12:09:47 -0700447 /**
448 * Request to change the conference's audio routing to the specified state. The specified state
449 * can include audio routing (Bluetooth, Speaker, etc) and muting state.
450 *
451 * @see android.telecom.AudioState
Yorke Lee4af59352015-05-13 14:14:54 -0700452 * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead.
453 * @hide
Santos Cordonb804f8d2015-05-12 12:09:47 -0700454 */
Yorke Lee4af59352015-05-13 14:14:54 -0700455 @SystemApi
456 @Deprecated
Yorke Lee58bacc52014-09-16 10:43:06 -0700457 public void setAudioState(AudioState state) {
Yorke Lee4af59352015-05-13 14:14:54 -0700458 setCallAudioState(new CallAudioState(state));
459 }
460
461 /**
462 * Request to change the conference's audio routing to the specified state. The specified state
463 * can include audio routing (Bluetooth, Speaker, etc) and muting state.
464 */
465 public void setCallAudioState(CallAudioState state) {
Yorke Lee58bacc52014-09-16 10:43:06 -0700466 try {
Yorke Lee4af59352015-05-13 14:14:54 -0700467 mConnectionService.onCallAudioStateChanged(mId, state);
Yorke Lee58bacc52014-09-16 10:43:06 -0700468 } catch (RemoteException e) {
469 }
470 }
471
Yorke Lee4af59352015-05-13 14:14:54 -0700472
Santos Cordonb804f8d2015-05-12 12:09:47 -0700473 /**
474 * Returns a list of independent connections that can me merged with this conference.
475 *
476 * @return A list of conferenceable connections.
477 */
Ihab Awad50e35062014-09-30 09:17:03 -0700478 public List<RemoteConnection> getConferenceableConnections() {
479 return mUnmodifiableConferenceableConnections;
480 }
481
Santos Cordonb804f8d2015-05-12 12:09:47 -0700482 /**
483 * Register a callback through which to receive state updates for this conference.
484 *
485 * @param callback The callback to notify of state changes.
486 */
Andrew Lee100e2932014-09-08 15:34:24 -0700487 public final void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -0700488 registerCallback(callback, new Handler());
489 }
490
Santos Cordonb804f8d2015-05-12 12:09:47 -0700491 /**
492 * Registers a callback through which to receive state updates for this conference.
493 * Callbacks will be notified using the specified handler, if provided.
494 *
495 * @param callback The callback to notify of state changes.
496 * @param handler The handler on which to execute the callbacks.
497 */
Andrew Lee011728f2015-04-23 15:47:06 -0700498 public final void registerCallback(Callback callback, Handler handler) {
499 unregisterCallback(callback);
500 if (callback != null && handler != null) {
501 mCallbackRecords.add(new CallbackRecord(callback, handler));
502 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700503 }
504
Santos Cordonb804f8d2015-05-12 12:09:47 -0700505 /**
506 * Unregisters a previously registered callback.
507 *
508 * @see #registerCallback
509 *
510 * @param callback The callback to unregister.
511 */
Andrew Lee100e2932014-09-08 15:34:24 -0700512 public final void unregisterCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -0700513 if (callback != null) {
514 for (CallbackRecord<Callback> record : mCallbackRecords) {
515 if (record.getCallback() == callback) {
516 mCallbackRecords.remove(record);
517 break;
518 }
519 }
520 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700521 }
522}