Skip to content

Commit

Permalink
Further refactor Telecom and add tests
Browse files Browse the repository at this point in the history
Complete refactoring Telecom to remove singletons from the core code.

Introduce a unit test that simulates a full outgoing phone call from
start to hangup.

Change-Id: I8b09cac6eb9b6aeeb0aeba5d8ae032b4c303c08d
  • Loading branch information
ihabawad committed Mar 16, 2015
1 parent 6fc9603 commit 8de7691
Show file tree
Hide file tree
Showing 31 changed files with 1,659 additions and 491 deletions.
2 changes: 1 addition & 1 deletion Android.mk
Expand Up @@ -12,7 +12,7 @@ LOCAL_PACKAGE_NAME := Telecom
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true

LOCAL_PROGUARD_FLAGS := $(proguard.flags)
LOCAL_PROGUARD_FLAG_FILES := proguard.flags

# Workaround for "local variable type mismatch" error.
LOCAL_DX_FLAGS += --no-locals
Expand Down
8 changes: 6 additions & 2 deletions proguard.flags
@@ -1,4 +1,8 @@
-verbose

# Keep @VisibleForTesting elements
-keep @com.android.internal.annotations.VisibleForTesting class *
-keep class com.android.server.telecom.TelecomSystem {
*;
}
-keep class com.android.server.telecom.Log {
*;
}
30 changes: 15 additions & 15 deletions src/com/android/server/telecom/Call.java
Expand Up @@ -94,7 +94,7 @@ interface Listener {
boolean onCanceledViaNewOutgoingCallBroadcast(Call call);
}

abstract static class ListenerBase implements Listener {
public abstract static class ListenerBase implements Listener {
@Override
public void onSuccessfulOutgoingCall(Call call, int callState) {}
@Override
Expand Down Expand Up @@ -327,7 +327,7 @@ public void run() {
* one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
* @param isIncoming True if this is an incoming call.
*/
Call(
public Call(
Context context,
CallsManager callsManager,
ConnectionServiceRepository repository,
Expand Down Expand Up @@ -384,11 +384,11 @@ public void run() {
mConnectTimeMillis = connectTimeMillis;
}

void addListener(Listener listener) {
public void addListener(Listener listener) {
mListeners.add(listener);
}

void removeListener(Listener listener) {
public void removeListener(Listener listener) {
if (listener != null) {
mListeners.remove(listener);
}
Expand Down Expand Up @@ -445,7 +445,7 @@ private boolean shouldContinueProcessingAfterDisconnect() {
* misbehave and they do this very often. The result is that we do not enforce state transitions
* and instead keep the code resilient to unexpected state changes.
*/
void setState(int newState) {
public void setState(int newState) {
if (mState != newState) {
Log.v(this, "setState %s -> %s", mState, newState);

Expand Down Expand Up @@ -491,7 +491,7 @@ boolean isConference() {
return mIsConference;
}

Uri getHandle() {
public Uri getHandle() {
return mHandle;
}

Expand All @@ -504,7 +504,7 @@ void setHandle(Uri handle) {
setHandle(handle, TelecomManager.PRESENTATION_ALLOWED);
}

void setHandle(Uri handle, int presentation) {
public void setHandle(Uri handle, int presentation) {
if (!Objects.equals(handle, mHandle) || presentation != mHandlePresentation) {
mHandlePresentation = presentation;
if (mHandlePresentation == TelecomManager.PRESENTATION_RESTRICTED ||
Expand Down Expand Up @@ -548,29 +548,29 @@ void setCallerDisplayName(String callerDisplayName, int presentation) {
}
}

String getName() {
public String getName() {
return mCallerInfo == null ? null : mCallerInfo.name;
}

Bitmap getPhotoIcon() {
public Bitmap getPhotoIcon() {
return mCallerInfo == null ? null : mCallerInfo.cachedPhotoIcon;
}

Drawable getPhoto() {
public Drawable getPhoto() {
return mCallerInfo == null ? null : mCallerInfo.cachedPhoto;
}

/**
* @param disconnectCause The reason for the disconnection, represented by
* {@link android.telecom.DisconnectCause}.
*/
void setDisconnectCause(DisconnectCause disconnectCause) {
public void setDisconnectCause(DisconnectCause disconnectCause) {
// TODO: Consider combining this method with a setDisconnected() method that is totally
// separate from setState.
mDisconnectCause = disconnectCause;
}

DisconnectCause getDisconnectCause() {
public DisconnectCause getDisconnectCause() {
return mDisconnectCause;
}

Expand Down Expand Up @@ -655,11 +655,11 @@ long getAgeMillis() {
* @return The time when this call object was created and added to the set of pending outgoing
* calls.
*/
long getCreationTimeMillis() {
public long getCreationTimeMillis() {
return mCreationTimeMillis;
}

void setCreationTimeMillis(long time) {
public void setCreationTimeMillis(long time) {
mCreationTimeMillis = time;
}

Expand Down Expand Up @@ -1321,7 +1321,7 @@ private void maybeLoadCannedSmsResponses() {
if (mIsIncoming && isRespondViaSmsCapable() && !mCannedSmsResponsesLoadingStarted) {
Log.d(this, "maybeLoadCannedSmsResponses: starting task to load messages");
mCannedSmsResponsesLoadingStarted = true;
TelecomSystem.getInstance().getRespondViaSmsManager().loadCannedTextMessages(
mCallsManager.getRespondViaSmsManager().loadCannedTextMessages(
new Response<Void, List<String>>() {
@Override
public void onResult(Void request, List<String>... result) {
Expand Down
26 changes: 16 additions & 10 deletions src/com/android/server/telecom/CallAudioManager.java
Expand Up @@ -37,6 +37,7 @@ final class CallAudioManager extends CallsManagerListenerBase
private final AudioManager mAudioManager;
private final BluetoothManager mBluetoothManager;
private final WiredHeadsetManager mWiredHeadsetManager;
private final CallsManager mCallsManager;

private AudioState mAudioState;
private int mAudioFocusStreamType;
Expand All @@ -45,12 +46,17 @@ final class CallAudioManager extends CallsManagerListenerBase
private boolean mWasSpeakerOn;
private int mMostRecentlyUsedMode = AudioManager.MODE_IN_CALL;

CallAudioManager(Context context, StatusBarNotifier statusBarNotifier,
WiredHeadsetManager wiredHeadsetManager) {
CallAudioManager(
Context context,
StatusBarNotifier statusBarNotifier,
WiredHeadsetManager wiredHeadsetManager,
CallsManager callsManager) {
mStatusBarNotifier = statusBarNotifier;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mBluetoothManager = new BluetoothManager(context, this);
mWiredHeadsetManager = wiredHeadsetManager;
mCallsManager = callsManager;

mWiredHeadsetManager.addListener(this);

saveAudioState(getInitialAudioState(null));
Expand Down Expand Up @@ -78,7 +84,7 @@ public void onCallAdded(Call call) {
public void onCallRemoved(Call call) {
// If we didn't already have focus, there's nothing to do.
if (hasFocus()) {
if (TelecomSystem.getInstance().getCallsManager().getCalls().isEmpty()) {
if (mCallsManager.getCalls().isEmpty()) {
Log.v(this, "all calls removed, reseting system audio to default state");
setInitialAudioState(null, false /* force */);
mWasSpeakerOn = false;
Expand All @@ -99,7 +105,7 @@ public void onIncomingCallAnswered(Call call) {
// We do two things:
// (1) If this is the first call, then we can to turn on bluetooth if available.
// (2) Unmute the audio for the new incoming call.
boolean isOnlyCall = TelecomSystem.getInstance().getCallsManager().getCalls().size() == 1;
boolean isOnlyCall = mCallsManager.getCalls().size() == 1;
if (isOnlyCall && mBluetoothManager.isBluetoothAvailable()) {
mBluetoothManager.connectBluetoothAudio();
route = AudioState.ROUTE_BLUETOOTH;
Expand Down Expand Up @@ -175,7 +181,7 @@ void mute(boolean shouldMute) {
Log.v(this, "mute, shouldMute: %b", shouldMute);

// Don't mute if there are any emergency calls.
if (TelecomSystem.getInstance().getCallsManager().hasEmergencyCall()) {
if (mCallsManager.hasEmergencyCall()) {
shouldMute = false;
Log.v(this, "ignoring mute for emergency call");
}
Expand Down Expand Up @@ -325,7 +331,7 @@ private void setSystemAudioState(
}

if (!oldAudioState.equals(mAudioState)) {
TelecomSystem.getInstance().getCallsManager()
mCallsManager
.onAudioStateChanged(oldAudioState, mAudioState);
updateAudioForForegroundCall();
}
Expand Down Expand Up @@ -360,7 +366,7 @@ private void updateAudioStreamAndMode() {
requestAudioFocusAndSetMode(AudioManager.STREAM_RING, AudioManager.MODE_RINGTONE);
} else {
Call foregroundCall = getForegroundCall();
Call waitingForAccountSelectionCall = TelecomSystem.getInstance().getCallsManager()
Call waitingForAccountSelectionCall = mCallsManager
.getFirstCallWithState(CallState.PRE_DIAL_WAIT);
if (foregroundCall != null && waitingForAccountSelectionCall == null) {
// In the case where there is a call that is waiting for account selection,
Expand Down Expand Up @@ -504,7 +510,7 @@ private void setInitialAudioState(Call call, boolean force) {
}

private void updateAudioForForegroundCall() {
Call call = TelecomSystem.getInstance().getCallsManager().getForegroundCall();
Call call = mCallsManager.getForegroundCall();
if (call != null && call.getConnectionService() != null) {
call.getConnectionService().onAudioStateChanged(call, mAudioState);
}
Expand All @@ -514,7 +520,7 @@ private void updateAudioForForegroundCall() {
* Returns the current foreground call in order to properly set the audio mode.
*/
private Call getForegroundCall() {
Call call = TelecomSystem.getInstance().getCallsManager().getForegroundCall();
Call call = mCallsManager.getForegroundCall();

// We ignore any foreground call that is in the ringing state because we deal with ringing
// calls exclusively through the mIsRinging variable set by {@link Ringer}.
Expand All @@ -526,7 +532,7 @@ private Call getForegroundCall() {
}

private boolean hasRingingForegroundCall() {
Call call = TelecomSystem.getInstance().getCallsManager().getForegroundCall();
Call call = mCallsManager.getForegroundCall();
return call != null && call.getState() == CallState.RINGING;
}

Expand Down
39 changes: 28 additions & 11 deletions src/com/android/server/telecom/CallsManager.java
Expand Up @@ -106,6 +106,7 @@ void onConnectionServiceChanged(
private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
private final InCallController mInCallController;
private final CallAudioManager mCallAudioManager;
private RespondViaSmsManager mRespondViaSmsManager;
private final Ringer mRinger;
private final InCallWakeLockController mInCallWakeLockController;
// For this set initial table size to 16 because we add 13 listeners in
Expand Down Expand Up @@ -139,27 +140,32 @@ void onConnectionServiceChanged(
/**
* Initializes the required Telecom components.
*/
CallsManager(Context context, MissedCallNotifier missedCallNotifier,
CallsManager(
Context context,
MissedCallNotifier missedCallNotifier,
PhoneAccountRegistrar phoneAccountRegistrar,
RespondViaSmsManager respondViaSmsManager) {
HeadsetMediaButtonFactory headsetMediaButtonFactory,
ProximitySensorManagerFactory proximitySensorManagerFactory,
InCallWakeLockControllerFactory inCallWakeLockControllerFactory) {
mContext = context;
mPhoneAccountRegistrar = phoneAccountRegistrar;
mMissedCallNotifier = missedCallNotifier;
StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
mWiredHeadsetManager = new WiredHeadsetManager(context);
mCallAudioManager = new CallAudioManager(context, statusBarNotifier, mWiredHeadsetManager);
mCallAudioManager = new CallAudioManager(
context, statusBarNotifier, mWiredHeadsetManager, this);
InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(mCallAudioManager);
mRinger = new Ringer(mCallAudioManager, this, playerFactory, context);
mHeadsetMediaButton = new HeadsetMediaButton(context, this);
mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this);
mTtyManager = new TtyManager(context, mWiredHeadsetManager);
mProximitySensorManager = new ProximitySensorManager(context);
mPhoneStateBroadcaster = new PhoneStateBroadcaster();
mProximitySensorManager = proximitySensorManagerFactory.create(context, this);
mPhoneStateBroadcaster = new PhoneStateBroadcaster(this);
mCallLogManager = new CallLogManager(context);
mInCallController = new InCallController(context);
mInCallController = new InCallController(context, this);
mDtmfLocalTonePlayer = new DtmfLocalTonePlayer(context);
mConnectionServiceRepository = new ConnectionServiceRepository(mPhoneAccountRegistrar,
context);
mInCallWakeLockController = new InCallWakeLockController(context, this);
mConnectionServiceRepository =
new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, this);
mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this);

mListeners.add(statusBarNotifier);
mListeners.add(mCallLogManager);
Expand All @@ -172,10 +178,21 @@ void onConnectionServiceChanged(
mListeners.add(missedCallNotifier);
mListeners.add(mDtmfLocalTonePlayer);
mListeners.add(mHeadsetMediaButton);
mListeners.add(respondViaSmsManager);
mListeners.add(mProximitySensorManager);
}

public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) {
if (mRespondViaSmsManager != null) {
mListeners.remove(mRespondViaSmsManager);
}
mRespondViaSmsManager = respondViaSmsManager;
mListeners.add(respondViaSmsManager);
}

public RespondViaSmsManager getRespondViaSmsManager() {
return mRespondViaSmsManager;
}

@Override
public void onSuccessfulOutgoingCall(Call call, int callState) {
Log.v(this, "onSuccessfulOutgoingCall, %s", call);
Expand Down
Expand Up @@ -21,7 +21,7 @@
/**
* Provides a default implementation for listeners of CallsManager.
*/
class CallsManagerListenerBase implements CallsManager.CallsManagerListener {
public class CallsManagerListenerBase implements CallsManager.CallsManagerListener {
@Override
public void onCallAdded(Call call) {
}
Expand Down
Expand Up @@ -33,6 +33,7 @@ final class ConnectionServiceRepository {
new HashMap<>();
private final PhoneAccountRegistrar mPhoneAccountRegistrar;
private final Context mContext;
private final CallsManager mCallsManager;

private final ServiceBinder.Listener<ConnectionServiceWrapper> mUnbindListener =
new ServiceBinder.Listener<ConnectionServiceWrapper>() {
Expand All @@ -42,9 +43,13 @@ public void onUnbind(ConnectionServiceWrapper service) {
}
};

ConnectionServiceRepository(PhoneAccountRegistrar phoneAccountRegistrar, Context context) {
ConnectionServiceRepository(
PhoneAccountRegistrar phoneAccountRegistrar,
Context context,
CallsManager callsManager) {
mPhoneAccountRegistrar = phoneAccountRegistrar;
mContext = context;
mCallsManager = callsManager;
}

ConnectionServiceWrapper getService(ComponentName componentName, UserHandle userHandle) {
Expand All @@ -55,6 +60,7 @@ ConnectionServiceWrapper getService(ComponentName componentName, UserHandle user
componentName,
this,
mPhoneAccountRegistrar,
mCallsManager,
mContext,
userHandle);
service.addListener(mUnbindListener);
Expand Down

0 comments on commit 8de7691

Please sign in to comment.