TelephonyConnectionService.java revision 6a6e769af983b973a67cff3e8926597525835aa9
1/*
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
17package com.android.services.telephony;
18
19import android.net.Uri;
20import android.text.TextUtils;
21
22import com.android.internal.telephony.CallStateException;
23import com.android.internal.telephony.Phone;
24import com.android.services.telecomm.Connection;
25import com.android.services.telecomm.ConnectionRequest;
26import com.android.services.telecomm.ConnectionService;
27import com.android.services.telecomm.Response;
28import com.android.services.telecomm.Subscription;
29
30import com.google.android.collect.Sets;
31
32import java.util.Set;
33
34/**
35 * The parent class for telephony-based call services. Subclasses provide the specific phone (GSM,
36 * CDMA, etc...) to use.
37 */
38public abstract class TelephonyConnectionService extends ConnectionService {
39    private static final Set<com.android.internal.telephony.Connection> sKnownConnections
40            = Sets.newHashSet();
41
42    /** {@inheritDoc} */
43    @Override
44    public void onFindSubscriptions(
45            Uri handle,
46            Response<Uri, Subscription> response) {
47        try {
48            responseResult(handle, response, canCall(handle) ? new Subscription() : null);
49        } catch (Exception e) {
50            responseError(handle, response, "onFindSubscriptions error: " + e.toString());
51        }
52    }
53
54    /**
55     * Initiates the underlying Telephony call, then creates a {@link TelephonyConnection}
56     * by calling
57     * {@link #createTelephonyConnection(ConnectionRequest,
58     *         com.android.internal.telephony.Connection)}
59     * at the appropriate time. Should be called by the subclass.
60     */
61    protected void startCallWithPhone(
62            Phone phone,
63            ConnectionRequest request,
64            Response<ConnectionRequest, Connection> response) {
65        Log.d(this, "startCallWithPhone: %s.", request);
66
67        if (phone == null) {
68            responseError(request, response, "Phone is null");
69            return;
70        }
71
72        if (request.getHandle() == null) {
73            responseError(request, response, "Handle is null");
74            return;
75        }
76
77        String number = request.getHandle().getSchemeSpecificPart();
78        if (TextUtils.isEmpty(number)) {
79            responseError(request, response, "Unable to parse number");
80            return;
81        }
82
83        com.android.internal.telephony.Connection connection;
84        try {
85            connection = phone.dial(number);
86        } catch (CallStateException e) {
87            Log.e(this, e, "Call to Phone.dial failed with exception");
88            responseError(request, response, e.getMessage());
89            return;
90        }
91
92        if (connection == null) {
93            responseError(request, response, "Call to phone.dial failed");
94            return;
95        }
96
97        try {
98            responseResult(request, response, createTelephonyConnection(request, connection));
99        } catch (Exception e) {
100            Log.e(this, e, "Call to createConnection failed with exception");
101            responseError(request, response, e.getMessage());
102        }
103    }
104
105    protected <REQUEST, RESULT> void responseError(
106            REQUEST request,
107            Response<REQUEST, RESULT> response,
108            String reason) {
109        Log.d(this, "responseError %s: %s", request, reason);
110        response.onError(request, reason);
111    }
112
113    protected void responseResult(
114            Uri request,
115            Response<Uri, Subscription> response,
116            Subscription result) {
117        Log.d(this, "responseResult %s -> %s", request, result);
118        response.onResult(request, result);
119    }
120
121    protected void responseResult(
122            ConnectionRequest request,
123            Response<ConnectionRequest, Connection> response,
124            Connection result) {
125        Log.d(this, "responseResult %s -> %s", request, result);
126        response.onResult(request, result);
127    }
128
129    protected final TelephonyConnection createTelephonyConnection(
130            ConnectionRequest request,
131            final com.android.internal.telephony.Connection connection) {
132        final TelephonyConnection telephonyConnection =
133                onCreateTelephonyConnection(request, connection);
134        sKnownConnections.add(connection);
135        telephonyConnection.addConnectionListener(new Connection.ListenerBase() {
136            @Override
137            public void onDestroyed(Connection c) {
138                telephonyConnection.removeConnectionListener(this);
139                sKnownConnections.remove(connection);
140            }
141        });
142        return telephonyConnection;
143    }
144
145    protected static boolean isConnectionKnown(
146            com.android.internal.telephony.Connection connection) {
147        return sKnownConnections.contains(connection);
148    }
149
150    /**
151     * Determine whether this {@link TelephonyConnectionService} can place a call
152     * to the supplied handle (phone number).
153     *
154     * @param handle The proposed handle.
155     * @return {@code true} if the handle can be called.
156     */
157    protected abstract boolean canCall(Uri handle);
158
159    /**
160     * Create a Telephony-specific {@link Connection} object.
161     *
162     * @param request A request for creating a {@link Connection}.
163     * @param connection An underlying Telephony {@link com.android.internal.telephony.Connection}
164     *         to use.
165     * @return A new {@link TelephonyConnection}.
166     */
167    protected abstract TelephonyConnection onCreateTelephonyConnection(
168            ConnectionRequest request,
169            com.android.internal.telephony.Connection connection);
170}
171