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
17package com.android.dialer.simulator.impl;
18
19import android.net.Uri;
20import android.os.Bundle;
21import android.support.annotation.NonNull;
22import android.telecom.Connection;
23import android.telecom.ConnectionRequest;
24import android.telecom.ConnectionService;
25import android.telecom.PhoneAccount;
26import android.telecom.PhoneAccountHandle;
27import android.telecom.TelecomManager;
28import android.telephony.TelephonyManager;
29import android.widget.Toast;
30import com.android.dialer.common.Assert;
31import com.android.dialer.common.LogUtil;
32import com.android.dialer.common.concurrent.ThreadUtil;
33import com.android.dialer.simulator.Simulator;
34import com.android.dialer.simulator.SimulatorComponent;
35import com.android.dialer.simulator.SimulatorConnectionsBank;
36import java.util.ArrayList;
37import java.util.List;
38
39/** Simple connection provider to create phone calls. This is useful for emulators. */
40public class SimulatorConnectionService extends ConnectionService {
41  private static final List<Listener> listeners = new ArrayList<>();
42  private static SimulatorConnectionService instance;
43  private SimulatorConnectionsBank simulatorConnectionsBank;
44
45  public static SimulatorConnectionService getInstance() {
46    return instance;
47  }
48
49  public static void addListener(@NonNull Listener listener) {
50    listeners.add(Assert.isNotNull(listener));
51  }
52
53  public static void removeListener(@NonNull Listener listener) {
54    listeners.remove(Assert.isNotNull(listener));
55  }
56
57  @Override
58  public void onCreate() {
59    super.onCreate();
60    instance = this;
61    simulatorConnectionsBank = SimulatorComponent.get(this).getSimulatorConnectionsBank();
62  }
63
64  @Override
65  public void onDestroy() {
66    LogUtil.enterBlock("SimulatorConnectionService.onDestroy");
67    instance = null;
68    simulatorConnectionsBank = null;
69    super.onDestroy();
70  }
71
72  @Override
73  public Connection onCreateOutgoingConnection(
74      PhoneAccountHandle phoneAccount, ConnectionRequest request) {
75    LogUtil.enterBlock("SimulatorConnectionService.onCreateOutgoingConnection");
76    if (!SimulatorComponent.get(this).getSimulator().isSimulatorMode()
77        && !SimulatorSimCallManager.isSimulatorConnectionRequest(request)) {
78      LogUtil.i(
79          "SimulatorConnectionService.onCreateOutgoingConnection",
80          "outgoing call not from simulator, unregistering");
81      Toast.makeText(this, "Unregistering simulator, making a real phone call", Toast.LENGTH_LONG)
82          .show();
83      SimulatorSimCallManager.unregister(this);
84      return null;
85    }
86    SimulatorConnection connection = new SimulatorConnection(this, request);
87    if (SimulatorSimCallManager.isSimulatorConnectionRequest(request)) {
88      simulatorConnectionsBank.add(connection);
89      connection.setAddress(
90          request.getAddress(),
91          request
92              .getExtras()
93              .getInt(Simulator.PRESENTATION_CHOICE, TelecomManager.PRESENTATION_ALLOWED));
94      connection.setDialing();
95      ThreadUtil.postOnUiThread(
96          () ->
97              SimulatorComponent.get(instance)
98                  .getSimulatorConnectionsBank()
99                  .updateConferenceableConnections());
100      for (Listener listener : listeners) {
101        listener.onNewOutgoingConnection(connection);
102      }
103    } else {
104      connection.setAddress(request.getAddress(), 1);
105      Bundle extras = connection.getExtras();
106      extras.putString("connection_tag", "SimulatorMode");
107      connection.putExtras(extras);
108      simulatorConnectionsBank.add(connection);
109      connection.addListener(new NonSimulatorConnectionListener());
110      connection.setDialing();
111      ThreadUtil.postOnUiThread(connection::setActive);
112    }
113    return connection;
114  }
115
116  @Override
117  public Connection onCreateIncomingConnection(
118      PhoneAccountHandle phoneAccount, ConnectionRequest request) {
119    LogUtil.enterBlock("SimulatorConnectionService.onCreateIncomingConnection");
120    if (!SimulatorSimCallManager.isSimulatorConnectionRequest(request)) {
121      LogUtil.i(
122          "SimulatorConnectionService.onCreateIncomingConnection",
123          "incoming call not from simulator, unregistering");
124      Toast.makeText(this, "Unregistering simulator, got a real incoming call", Toast.LENGTH_LONG)
125          .show();
126      SimulatorSimCallManager.unregister(this);
127      return null;
128    }
129    SimulatorConnection connection = new SimulatorConnection(this, request);
130    connection.setAddress(
131        getPhoneNumber(request),
132        request
133            .getExtras()
134            .getInt(Simulator.PRESENTATION_CHOICE, TelecomManager.PRESENTATION_ALLOWED));
135    connection.setRinging();
136    simulatorConnectionsBank.add(connection);
137    ThreadUtil.postOnUiThread(
138        () ->
139            SimulatorComponent.get(instance)
140                .getSimulatorConnectionsBank()
141                .updateConferenceableConnections());
142    for (Listener listener : listeners) {
143      listener.onNewIncomingConnection(connection);
144    }
145    return connection;
146  }
147
148  @Override
149  public void onConference(Connection connection1, Connection connection2) {
150    LogUtil.i(
151        "SimulatorConnectionService.onConference",
152        "connection1: "
153            + SimulatorSimCallManager.getConnectionTag(connection1)
154            + ", connection2: "
155            + SimulatorSimCallManager.getConnectionTag(connection2));
156    for (Listener listener : listeners) {
157      listener.onConference((SimulatorConnection) connection1, (SimulatorConnection) connection2);
158    }
159  }
160
161  /** Callback used to notify listeners when a new connection has been added. */
162  public interface Listener {
163    void onNewOutgoingConnection(@NonNull SimulatorConnection connection);
164
165    void onNewIncomingConnection(@NonNull SimulatorConnection connection);
166
167    void onConference(
168        @NonNull SimulatorConnection connection1, @NonNull SimulatorConnection connection2);
169  }
170
171  private static Uri getPhoneNumber(ConnectionRequest request) {
172    String phoneNumber = request.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
173    return Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null);
174  }
175}
176