diff options
Diffstat (limited to 'java/com/android/dialer/simulator')
9 files changed, 297 insertions, 73 deletions
diff --git a/java/com/android/dialer/simulator/Simulator.java b/java/com/android/dialer/simulator/Simulator.java index 2094b420e..d75d10e82 100644 --- a/java/com/android/dialer/simulator/Simulator.java +++ b/java/com/android/dialer/simulator/Simulator.java @@ -42,6 +42,19 @@ public interface Simulator { static final int CONFERENCE_TYPE_GSM = 1; static final int CONFERENCE_TYPE_VOLTE = 2; + /** The types of connection service listener events */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ON_NEW_OUTGOING_CONNECTION, + ON_NEW_INCOMING_CONNECTION, + ON_CONFERENCE, + }) + @interface ConnectionServiceEventType {} + + static final int ON_NEW_OUTGOING_CONNECTION = 1; + static final int ON_NEW_INCOMING_CONNECTION = 2; + static final int ON_CONFERENCE = 3; + /** Information about a connection event. */ public static class Event { /** The type of connection event. */ diff --git a/java/com/android/dialer/simulator/SimulatorComponent.java b/java/com/android/dialer/simulator/SimulatorComponent.java index f14496b80..dee188281 100644 --- a/java/com/android/dialer/simulator/SimulatorComponent.java +++ b/java/com/android/dialer/simulator/SimulatorComponent.java @@ -26,6 +26,8 @@ public abstract class SimulatorComponent { public abstract Simulator getSimulator(); + public abstract SimulatorConnectionsBank getSimulatorConnectionsBank(); + public static SimulatorComponent get(Context context) { return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) .simulatorComponent(); diff --git a/java/com/android/dialer/simulator/SimulatorConnectionsBank.java b/java/com/android/dialer/simulator/SimulatorConnectionsBank.java new file mode 100644 index 000000000..23c00424f --- /dev/null +++ b/java/com/android/dialer/simulator/SimulatorConnectionsBank.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.simulator; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.telecom.Connection; +import com.android.dialer.simulator.Simulator.ConferenceType; +import java.util.List; + +/** + * Used to create a shared connections bank which contains methods to manipulate connections. This + * is used mainly for conference calling. + */ +public interface SimulatorConnectionsBank { + + /** Add a connection into bank. */ + void add(Connection connection); + + /** Remove a connection from bank. */ + void remove(Connection connection); + + /** Merge all existing connections created by simulator into a conference. */ + void mergeAllConnections(@ConferenceType int conferenceType, Context context); + + /** Set all connections created by simulator to disconnected. */ + void disconnectAllConnections(); + + /** + * Update conferenceable connections for all connections in bank (usually after adding a new + * connection). Before calling this method, make sure all connections are returned by + * ConnectionService. + */ + void updateConferenceableConnections(); + + /** Determine whether a connection is created by simulator. */ + boolean isSimulatorConnection(@NonNull Connection connection); + + /** Get all connections tags from bank. */ + List<String> getConnectionTags(); +} diff --git a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java index d0249938a..36c19956a 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java @@ -19,8 +19,6 @@ package com.android.dialer.simulator.impl; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.telecom.Conferenceable; import android.telecom.Connection; import android.telecom.DisconnectCause; import com.android.dialer.common.Assert; @@ -28,8 +26,9 @@ import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.simulator.Simulator; import com.android.dialer.simulator.Simulator.Event; +import com.android.dialer.simulator.SimulatorComponent; +import com.android.dialer.simulator.SimulatorConnectionsBank; import java.util.ArrayList; -import java.util.List; import java.util.Locale; /** Creates a conference with a given number of participants. */ @@ -38,32 +37,59 @@ final class SimulatorConferenceCreator SimulatorConnection.Listener, SimulatorConference.Listener { private static final String EXTRA_CALL_COUNT = "call_count"; - + private static final String RECONNECT = "reconnect"; @NonNull private final Context context; - @NonNull private final List<String> connectionTags = new ArrayList<>(); + + private final SimulatorConnectionsBank simulatorConnectionsBank; + + private boolean onNewIncomingConnectionEnabled = false; + @Simulator.ConferenceType private final int conferenceType; public SimulatorConferenceCreator( @NonNull Context context, @Simulator.ConferenceType int conferenceType) { this.context = Assert.isNotNull(context); this.conferenceType = conferenceType; + simulatorConnectionsBank = SimulatorComponent.get(context).getSimulatorConnectionsBank(); } void start(int callCount) { + onNewIncomingConnectionEnabled = true; SimulatorConnectionService.addListener(this); - addNextCall(callCount); + if (conferenceType == Simulator.CONFERENCE_TYPE_VOLTE) { + addNextCall(callCount, true); + } else if (conferenceType == Simulator.CONFERENCE_TYPE_GSM) { + addNextCall(callCount, false); + } } - - private void addNextCall(int callCount) { + /** + * Add a call in a process of making a conference. + * + * @param callCount the remaining number of calls to make + * @param reconnect whether all connections should reconnect once (connections are reconnected + * once in making VoLTE conference) + */ + private void addNextCall(int callCount, boolean reconnect) { LogUtil.i("SimulatorConferenceCreator.addNextIncomingCall", "callCount: " + callCount); if (callCount <= 0) { LogUtil.i("SimulatorConferenceCreator.addNextCall", "done adding calls"); + if (reconnect) { + simulatorConnectionsBank.disconnectAllConnections(); + addNextCall(simulatorConnectionsBank.getConnectionTags().size(), false); + } else { + simulatorConnectionsBank.mergeAllConnections(conferenceType, context); + SimulatorConnectionService.removeListener(this); + } return; } - String callerId = String.format(Locale.US, "+1-650-234%04d", callCount); Bundle extras = new Bundle(); extras.putInt(EXTRA_CALL_COUNT, callCount - 1); + extras.putBoolean(RECONNECT, reconnect); + addConferenceCall(callerId, extras); + } + + private void addConferenceCall(String number, Bundle extras) { switch (conferenceType) { case Simulator.CONFERENCE_TYPE_VOLTE: extras.putBoolean("ISVOLTE", true); @@ -71,35 +97,25 @@ final class SimulatorConferenceCreator default: break; } - connectionTags.add( - SimulatorSimCallManager.addNewIncomingCall(context, callerId, false /* isVideo */, extras)); + SimulatorSimCallManager.addNewIncomingCall(context, number, false /* isVideo */, extras); } @Override public void onNewIncomingConnection(@NonNull SimulatorConnection connection) { - if (!isMyConnection(connection)) { + if (!onNewIncomingConnectionEnabled) { + return; + } + if (!simulatorConnectionsBank.isSimulatorConnection(connection)) { LogUtil.i("SimulatorConferenceCreator.onNewOutgoingConnection", "unknown connection"); return; } - LogUtil.i("SimulatorConferenceCreator.onNewOutgoingConnection", "connection created"); connection.addListener(this); - // Once the connection is active, go ahead and conference it and add the next call. ThreadUtil.postDelayedOnUiThread( () -> { - SimulatorConference conference = findCurrentConference(); - if (conference == null) { - conference = - SimulatorConference.newGsmConference( - SimulatorSimCallManager.getSystemPhoneAccountHandle(context)); - conference.addListener(this); - SimulatorConnectionService.getInstance().addConference(conference); - } - updateConferenceableConnections(); connection.setActive(); - conference.addConnection(connection); - addNextCall(getCallCount(connection)); + addNextCall(getCallCount(connection), shouldReconnect(connection)); }, 1000); } @@ -115,7 +131,8 @@ final class SimulatorConferenceCreator public void onConference( @NonNull SimulatorConnection connection1, @NonNull SimulatorConnection connection2) { LogUtil.enterBlock("SimulatorConferenceCreator.onConference"); - if (!isMyConnection(connection1) || !isMyConnection(connection2)) { + if (!simulatorConnectionsBank.isSimulatorConnection(connection1) + || !simulatorConnectionsBank.isSimulatorConnection(connection2)) { LogUtil.i("SimulatorConferenceCreator.onConference", "unknown connections, ignoring"); return; } @@ -125,7 +142,6 @@ final class SimulatorConferenceCreator } else if (connection2.getConference() != null) { connection2.getConference().addConnection(connection1); } else { - Assert.checkArgument(conferenceType == Simulator.CONFERENCE_TYPE_GSM); SimulatorConference conference = SimulatorConference.newGsmConference( SimulatorSimCallManager.getSystemPhoneAccountHandle(context)); @@ -136,54 +152,14 @@ final class SimulatorConferenceCreator } } - private boolean isMyConnection(@NonNull Connection connection) { - for (String connectionTag : connectionTags) { - if (connection.getExtras().getBoolean(connectionTag)) { - return true; - } - } - return false; - } - - private void updateConferenceableConnections() { - LogUtil.enterBlock("SimulatorConferenceCreator.updateConferenceableConnections"); - for (String connectionTag : connectionTags) { - SimulatorConnection connection = SimulatorSimCallManager.findConnectionByTag(connectionTag); - List<Conferenceable> conferenceables = getMyConferenceables(); - conferenceables.remove(connection); - conferenceables.remove(connection.getConference()); - connection.setConferenceables(conferenceables); - } - } - - private List<Conferenceable> getMyConferenceables() { - List<Conferenceable> conferenceables = new ArrayList<>(); - for (String connectionTag : connectionTags) { - SimulatorConnection connection = SimulatorSimCallManager.findConnectionByTag(connectionTag); - conferenceables.add(connection); - if (connection.getConference() != null - && !conferenceables.contains(connection.getConference())) { - conferenceables.add(connection.getConference()); - } - } - return conferenceables; - } - - @Nullable - private SimulatorConference findCurrentConference() { - for (String connectionTag : connectionTags) { - SimulatorConnection connection = SimulatorSimCallManager.findConnectionByTag(connectionTag); - if (connection.getConference() != null) { - return (SimulatorConference) connection.getConference(); - } - } - return null; - } - private static int getCallCount(@NonNull Connection connection) { return connection.getExtras().getInt(EXTRA_CALL_COUNT); } + private static boolean shouldReconnect(@NonNull Connection connection) { + return connection.getExtras().getBoolean(RECONNECT); + } + @Override public void onEvent(@NonNull SimulatorConnection connection, @NonNull Event event) { switch (event.type) { @@ -222,6 +198,7 @@ final class SimulatorConferenceCreator for (Connection connection : new ArrayList<>(conference.getConnections())) { connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); } + conference.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); break; default: LogUtil.i( diff --git a/java/com/android/dialer/simulator/impl/SimulatorConnection.java b/java/com/android/dialer/simulator/impl/SimulatorConnection.java index 168f5db98..2a24d8f37 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConnection.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConnection.java @@ -24,6 +24,8 @@ import android.telecom.VideoProfile; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.simulator.Simulator.Event; +import com.android.dialer.simulator.SimulatorComponent; +import com.android.dialer.simulator.SimulatorConnectionsBank; import java.util.ArrayList; import java.util.List; @@ -31,6 +33,7 @@ import java.util.List; public final class SimulatorConnection extends Connection { private final List<Listener> listeners = new ArrayList<>(); private final List<Event> events = new ArrayList<>(); + private final SimulatorConnectionsBank simulatorConnectionsBank; private int currentState = STATE_NEW; SimulatorConnection(@NonNull Context context, @NonNull ConnectionRequest request) { @@ -47,6 +50,7 @@ public final class SimulatorConnection extends Connection { setConnectionCapabilities(getConnectionCapabilities() | CAPABILITY_SEPARATE_FROM_CONFERENCE); } setVideoProvider(new SimulatorVideoProvider(context, this)); + simulatorConnectionsBank = SimulatorComponent.get(context).getSimulatorConnectionsBank(); } public void addListener(@NonNull Listener listener) { @@ -71,6 +75,7 @@ public final class SimulatorConnection extends Connection { @Override public void onReject() { LogUtil.enterBlock("SimulatorConnection.onReject"); + simulatorConnectionsBank.remove(this); onEvent(new Event(Event.REJECT)); } @@ -89,6 +94,7 @@ public final class SimulatorConnection extends Connection { @Override public void onDisconnect() { LogUtil.enterBlock("SimulatorConnection.onDisconnect"); + simulatorConnectionsBank.remove(this); onEvent(new Event(Event.DISCONNECT)); } diff --git a/java/com/android/dialer/simulator/impl/SimulatorConnectionService.java b/java/com/android/dialer/simulator/impl/SimulatorConnectionService.java index 465890cf0..e6bf99f3a 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConnectionService.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConnectionService.java @@ -28,6 +28,9 @@ import android.telephony.TelephonyManager; import android.widget.Toast; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.simulator.SimulatorComponent; +import com.android.dialer.simulator.SimulatorConnectionsBank; import java.util.ArrayList; import java.util.List; @@ -35,6 +38,7 @@ import java.util.List; public class SimulatorConnectionService extends ConnectionService { private static final List<Listener> listeners = new ArrayList<>(); private static SimulatorConnectionService instance; + private SimulatorConnectionsBank simulatorConnectionsBank; public static SimulatorConnectionService getInstance() { return instance; @@ -52,12 +56,14 @@ public class SimulatorConnectionService extends ConnectionService { public void onCreate() { super.onCreate(); instance = this; + simulatorConnectionsBank = SimulatorComponent.get(this).getSimulatorConnectionsBank(); } @Override public void onDestroy() { LogUtil.enterBlock("SimulatorConnectionService.onDestroy"); instance = null; + simulatorConnectionsBank = null; super.onDestroy(); } @@ -78,7 +84,12 @@ public class SimulatorConnectionService extends ConnectionService { SimulatorConnection connection = new SimulatorConnection(this, request); connection.setDialing(); connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED); - + simulatorConnectionsBank.add(connection); + ThreadUtil.postOnUiThread( + () -> + SimulatorComponent.get(instance) + .getSimulatorConnectionsBank() + .updateConferenceableConnections()); for (Listener listener : listeners) { listener.onNewOutgoingConnection(connection); } @@ -102,7 +113,12 @@ public class SimulatorConnectionService extends ConnectionService { SimulatorConnection connection = new SimulatorConnection(this, request); connection.setRinging(); connection.setAddress(getPhoneNumber(request), TelecomManager.PRESENTATION_ALLOWED); - + simulatorConnectionsBank.add(connection); + ThreadUtil.postOnUiThread( + () -> + SimulatorComponent.get(instance) + .getSimulatorConnectionsBank() + .updateConferenceableConnections()); for (Listener listener : listeners) { listener.onNewIncomingConnection(connection); } diff --git a/java/com/android/dialer/simulator/impl/SimulatorConnectionsBankImpl.java b/java/com/android/dialer/simulator/impl/SimulatorConnectionsBankImpl.java new file mode 100644 index 000000000..75f144fde --- /dev/null +++ b/java/com/android/dialer/simulator/impl/SimulatorConnectionsBankImpl.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.simulator.impl; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.telecom.Conferenceable; +import android.telecom.Connection; +import android.telecom.DisconnectCause; +import com.android.dialer.common.LogUtil; +import com.android.dialer.simulator.Simulator; +import com.android.dialer.simulator.Simulator.ConferenceType; +import com.android.dialer.simulator.Simulator.Event; +import com.android.dialer.simulator.SimulatorConnectionsBank; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.inject.Inject; + +/** Wraps a list of connection tags and common methods around the connection tags list. */ +public class SimulatorConnectionsBankImpl + implements SimulatorConnectionsBank, SimulatorConference.Listener { + private final List<String> connectionTags = new ArrayList<>(); + + @Inject + public SimulatorConnectionsBankImpl() {} + + @Override + public List<String> getConnectionTags() { + return connectionTags; + } + + @Override + public void add(Connection connection) { + connectionTags.add(SimulatorSimCallManager.getConnectionTag(connection)); + } + + @Override + public void remove(Connection connection) { + connectionTags.remove(SimulatorSimCallManager.getConnectionTag(connection)); + } + + @Override + public void mergeAllConnections(@ConferenceType int conferenceType, Context context) { + SimulatorConference simulatorConference = null; + if (conferenceType == Simulator.CONFERENCE_TYPE_GSM) { + simulatorConference = + SimulatorConference.newGsmConference( + SimulatorSimCallManager.getSystemPhoneAccountHandle(context)); + } else if (conferenceType == Simulator.CONFERENCE_TYPE_VOLTE) { + simulatorConference = + SimulatorConference.newVoLteConference( + SimulatorSimCallManager.getSystemPhoneAccountHandle(context)); + } + Collection<Connection> connections = + SimulatorConnectionService.getInstance().getAllConnections(); + for (Connection connection : connections) { + simulatorConference.addConnection(connection); + } + simulatorConference.addListener(this); + SimulatorConnectionService.getInstance().addConference(simulatorConference); + } + + @Override + public void disconnectAllConnections() { + Collection<Connection> connections = + SimulatorConnectionService.getInstance().getAllConnections(); + for (Connection connection : connections) { + connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); + } + } + + @Override + public void updateConferenceableConnections() { + LogUtil.enterBlock("SimulatorConferenceCreator.updateConferenceableConnections"); + for (String connectionTag : connectionTags) { + SimulatorConnection connection = SimulatorSimCallManager.findConnectionByTag(connectionTag); + List<Conferenceable> conferenceables = getSimulatorConferenceables(); + conferenceables.remove(connection); + conferenceables.remove(connection.getConference()); + connection.setConferenceables(conferenceables); + } + } + + private List<Conferenceable> getSimulatorConferenceables() { + List<Conferenceable> conferenceables = new ArrayList<>(); + for (String connectionTag : connectionTags) { + SimulatorConnection connection = SimulatorSimCallManager.findConnectionByTag(connectionTag); + conferenceables.add(connection); + if (connection.getConference() != null + && !conferenceables.contains(connection.getConference())) { + conferenceables.add(connection.getConference()); + } + } + return conferenceables; + } + + @Override + public boolean isSimulatorConnection(@NonNull Connection connection) { + for (String connectionTag : connectionTags) { + if (connection.getExtras().getBoolean(connectionTag)) { + return true; + } + } + return false; + } + + @Override + public void onEvent(@NonNull SimulatorConference conference, @NonNull Event event) { + switch (event.type) { + case Event.MERGE: + int capabilities = conference.getConnectionCapabilities(); + capabilities |= Connection.CAPABILITY_SWAP_CONFERENCE; + conference.setConnectionCapabilities(capabilities); + break; + case Event.SEPARATE: + SimulatorConnection connectionToRemove = + SimulatorSimCallManager.findConnectionByTag(event.data1); + conference.removeConnection(connectionToRemove); + break; + case Event.DISCONNECT: + for (Connection connection : new ArrayList<>(conference.getConnections())) { + connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); + } + conference.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); + break; + default: + LogUtil.i( + "SimulatorConferenceCreator.onEvent", "unexpected conference event: " + event.type); + break; + } + } +} diff --git a/java/com/android/dialer/simulator/impl/SimulatorModule.java b/java/com/android/dialer/simulator/impl/SimulatorModule.java index c0cca271b..2bc72c956 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorModule.java +++ b/java/com/android/dialer/simulator/impl/SimulatorModule.java @@ -17,6 +17,7 @@ package com.android.dialer.simulator.impl; import com.android.dialer.simulator.Simulator; +import com.android.dialer.simulator.SimulatorConnectionsBank; import dagger.Binds; import dagger.Module; import javax.inject.Singleton; @@ -27,4 +28,9 @@ public abstract class SimulatorModule { @Binds @Singleton public abstract Simulator bindsSimulator(SimulatorImpl simulator); + + @Binds + @Singleton + public abstract SimulatorConnectionsBank bindsSimulatorConnectionsBank( + SimulatorConnectionsBankImpl simulatorConnectionsBank); } diff --git a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java index d2eba6b03..451896b73 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java @@ -52,6 +52,8 @@ final class SimulatorVoiceCall private SimulatorVoiceCall(@NonNull Context context) { this.context = Assert.isNotNull(context); SimulatorConnectionService.addListener(this); + SimulatorConnectionService.addListener( + new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM)); } private void addNewIncomingCall(boolean isSpam) { |