Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2017 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 
     17 package com.android.dialer.simulator.impl;
     18 
     19 import android.content.Context;
     20 import android.os.Bundle;
     21 import android.support.annotation.NonNull;
     22 import android.telecom.Connection;
     23 import android.telecom.DisconnectCause;
     24 import com.android.dialer.common.Assert;
     25 import com.android.dialer.common.LogUtil;
     26 import com.android.dialer.common.concurrent.ThreadUtil;
     27 import com.android.dialer.simulator.Simulator;
     28 import com.android.dialer.simulator.Simulator.Event;
     29 import com.android.dialer.simulator.SimulatorComponent;
     30 import com.android.dialer.simulator.SimulatorConnectionsBank;
     31 import java.util.ArrayList;
     32 import java.util.Locale;
     33 
     34 /** Creates a conference with a given number of participants. */
     35 final class SimulatorConferenceCreator
     36     implements SimulatorConnectionService.Listener,
     37         SimulatorConnection.Listener,
     38         SimulatorConference.Listener {
     39   private static final String EXTRA_CALL_COUNT = "call_count";
     40   private static final String RECONNECT = "reconnect";
     41   @NonNull private final Context context;
     42 
     43   private final SimulatorConnectionsBank simulatorConnectionsBank;
     44 
     45   private boolean onNewIncomingConnectionEnabled = false;
     46 
     47   @Simulator.ConferenceType private final int conferenceType;
     48 
     49   public SimulatorConferenceCreator(
     50       @NonNull Context context, @Simulator.ConferenceType int conferenceType) {
     51     this.context = Assert.isNotNull(context);
     52     this.conferenceType = conferenceType;
     53     simulatorConnectionsBank = SimulatorComponent.get(context).getSimulatorConnectionsBank();
     54   }
     55 
     56   void start(int callCount) {
     57     onNewIncomingConnectionEnabled = true;
     58     SimulatorConnectionService.addListener(this);
     59     if (conferenceType == Simulator.CONFERENCE_TYPE_VOLTE) {
     60       addNextCall(callCount, true);
     61     } else if (conferenceType == Simulator.CONFERENCE_TYPE_GSM) {
     62       addNextCall(callCount, false);
     63     }
     64   }
     65   /**
     66    * Add a call in a process of making a conference.
     67    *
     68    * @param callCount the remaining number of calls to make
     69    * @param reconnect whether all connections should reconnect once (connections are reconnected
     70    *     once in making VoLTE conference)
     71    */
     72   private void addNextCall(int callCount, boolean reconnect) {
     73     LogUtil.i("SimulatorConferenceCreator.addNextIncomingCall", "callCount: " + callCount);
     74     if (callCount <= 0) {
     75       LogUtil.i("SimulatorConferenceCreator.addNextCall", "done adding calls");
     76       if (reconnect) {
     77         simulatorConnectionsBank.disconnectAllConnections();
     78         addNextCall(simulatorConnectionsBank.getConnectionTags().size(), false);
     79       } else {
     80         simulatorConnectionsBank.mergeAllConnections(conferenceType, context);
     81         SimulatorConnectionService.removeListener(this);
     82       }
     83       return;
     84     }
     85     String callerId = String.format(Locale.US, "+1-650-234%04d", callCount);
     86     Bundle extras = new Bundle();
     87     extras.putInt(EXTRA_CALL_COUNT, callCount - 1);
     88     extras.putBoolean(RECONNECT, reconnect);
     89     addConferenceCall(callerId, extras);
     90   }
     91 
     92   private void addConferenceCall(String number, Bundle extras) {
     93     switch (conferenceType) {
     94       case Simulator.CONFERENCE_TYPE_VOLTE:
     95         extras.putBoolean(Simulator.IS_VOLTE, true);
     96         break;
     97       default:
     98         break;
     99     }
    100     SimulatorSimCallManager.addNewIncomingCall(
    101         context, number, SimulatorSimCallManager.CALL_TYPE_VOICE, extras);
    102   }
    103 
    104   @Override
    105   public void onNewIncomingConnection(@NonNull SimulatorConnection connection) {
    106     if (!onNewIncomingConnectionEnabled) {
    107       return;
    108     }
    109     if (!simulatorConnectionsBank.isSimulatorConnection(connection)) {
    110       LogUtil.i("SimulatorConferenceCreator.onNewOutgoingConnection", "unknown connection");
    111       return;
    112     }
    113     LogUtil.i("SimulatorConferenceCreator.onNewOutgoingConnection", "connection created");
    114     connection.addListener(this);
    115     // Once the connection is active, go ahead and conference it and add the next call.
    116     ThreadUtil.postDelayedOnUiThread(
    117         () -> {
    118           connection.setActive();
    119           addNextCall(getCallCount(connection), shouldReconnect(connection));
    120         },
    121         1000);
    122   }
    123 
    124   @Override
    125   public void onNewOutgoingConnection(@NonNull SimulatorConnection connection) {}
    126 
    127   /**
    128    * This is called when the user clicks the merge button. We create the initial conference
    129    * automatically but with this method we can let the user split and merge calls as desired.
    130    */
    131   @Override
    132   public void onConference(
    133       @NonNull SimulatorConnection connection1, @NonNull SimulatorConnection connection2) {
    134     LogUtil.enterBlock("SimulatorConferenceCreator.onConference");
    135     if (!simulatorConnectionsBank.isSimulatorConnection(connection1)
    136         || !simulatorConnectionsBank.isSimulatorConnection(connection2)) {
    137       LogUtil.i("SimulatorConferenceCreator.onConference", "unknown connections, ignoring");
    138       return;
    139     }
    140 
    141     if (connection1.getConference() != null) {
    142       connection1.getConference().addConnection(connection2);
    143     } else if (connection2.getConference() != null) {
    144       connection2.getConference().addConnection(connection1);
    145     } else {
    146       SimulatorConference conference =
    147           SimulatorConference.newGsmConference(
    148               SimulatorSimCallManager.getSystemPhoneAccountHandle(context));
    149       conference.addConnection(connection1);
    150       conference.addConnection(connection2);
    151       conference.addListener(this);
    152       SimulatorConnectionService.getInstance().addConference(conference);
    153     }
    154   }
    155 
    156   private static int getCallCount(@NonNull Connection connection) {
    157     return connection.getExtras().getInt(EXTRA_CALL_COUNT);
    158   }
    159 
    160   private static boolean shouldReconnect(@NonNull Connection connection) {
    161     return connection.getExtras().getBoolean(RECONNECT);
    162   }
    163 
    164   @Override
    165   public void onEvent(@NonNull SimulatorConnection connection, @NonNull Event event) {
    166     switch (event.type) {
    167       case Event.NONE:
    168         throw Assert.createIllegalStateFailException();
    169       case Event.HOLD:
    170         connection.setOnHold();
    171         break;
    172       case Event.UNHOLD:
    173         connection.setActive();
    174         break;
    175       case Event.DISCONNECT:
    176         connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
    177         break;
    178       default:
    179         LogUtil.i(
    180             "SimulatorConferenceCreator.onEvent", "unexpected conference event: " + event.type);
    181         break;
    182     }
    183   }
    184 
    185   @Override
    186   public void onEvent(@NonNull SimulatorConference conference, @NonNull Event event) {
    187     switch (event.type) {
    188       case Event.MERGE:
    189         int capabilities = conference.getConnectionCapabilities();
    190         capabilities |= Connection.CAPABILITY_SWAP_CONFERENCE;
    191         conference.setConnectionCapabilities(capabilities);
    192         break;
    193       case Event.SEPARATE:
    194         SimulatorConnection connectionToRemove =
    195             SimulatorSimCallManager.findConnectionByTag(event.data1);
    196         conference.removeConnection(connectionToRemove);
    197         break;
    198       case Event.DISCONNECT:
    199         for (Connection connection : new ArrayList<>(conference.getConnections())) {
    200           connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
    201         }
    202         conference.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
    203         break;
    204       default:
    205         LogUtil.i(
    206             "SimulatorConferenceCreator.onEvent", "unexpected conference event: " + event.type);
    207         break;
    208     }
    209   }
    210 }
    211