• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 android.telecom;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SdkConstant;
22 import android.app.Service;
23 import android.content.Intent;
24 import android.net.Uri;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.RemoteException;
30 
31 import com.android.internal.os.SomeArgs;
32 import com.android.internal.telecom.ICallRedirectionAdapter;
33 import com.android.internal.telecom.ICallRedirectionService;
34 
35 /**
36  * This service can be implemented to interact between Telecom and its implementor
37  * for making outgoing call with optional redirection/cancellation purposes.
38  *
39  * <p>
40  * Below is an example manifest registration for a {@code CallRedirectionService}.
41  * {@code
42  * <service android:name="your.package.YourCallRedirectionServiceImplementation"
43  *          android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
44  *      <intent-filter>
45  *          <action android:name="android.telecom.CallRedirectionService"/>
46  *      </intent-filter>
47  * </service>
48  * }
49  */
50 public abstract class CallRedirectionService extends Service {
51     /**
52      * The {@link Intent} that must be declared as handled by the service.
53      */
54     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
55     public static final String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
56 
57     /**
58      * An adapter to inform Telecom the response from the implementor of the Call
59      * Redirection service
60      */
61     private ICallRedirectionAdapter mCallRedirectionAdapter;
62 
63     /**
64      * Telecom calls this method once upon binding to a {@link CallRedirectionService} to inform
65      * it of a new outgoing call which is being placed. Telecom does not request to redirect
66      * emergency calls and does not request to redirect calls with gateway information.
67      *
68      * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
69      * the implemented {@link CallRedirectionService} set by users.
70      *
71      * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
72      * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
73      * from here. Calls to these methods are assumed by the Telecom framework to be the response
74      * for the phone call for which {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} was
75      * invoked by Telecom. The Telecom framework will only invoke
76      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} once each time it binds to a
77      * {@link CallRedirectionService}.
78      *
79      * @param handle the phone number dialed by the user, represented in E.164 format if possible
80      * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
81      * @param allowInteractiveResponse a boolean to tell if the implemented
82      *                                 {@link CallRedirectionService} should allow interactive
83      *                                 responses with users. Will be {@code false} if, for example
84      *                                 the device is in car mode and the user would not be able to
85      *                                 interact with their device.
86      */
onPlaceCall(@onNull Uri handle, @NonNull PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse)87     public abstract void onPlaceCall(@NonNull Uri handle,
88                                      @NonNull PhoneAccountHandle initialPhoneAccount,
89                                      boolean allowInteractiveResponse);
90 
91     /**
92      * The implemented {@link CallRedirectionService} calls this method to response a request
93      * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
94      * no changes are required to the outgoing call, and that the call should be placed as-is.
95      *
96      * <p>This can only be called from implemented
97      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
98      * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
99      *
100      */
placeCallUnmodified()101     public final void placeCallUnmodified() {
102         try {
103             mCallRedirectionAdapter.placeCallUnmodified();
104         } catch (RemoteException e) {
105             e.rethrowAsRuntimeException();
106         }
107     }
108 
109     /**
110      * The implemented {@link CallRedirectionService} calls this method to response a request
111      * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
112      * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
113      * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
114      * replies Telecom a handle for an emergency number.
115      *
116      * <p>This can only be called from implemented
117      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
118      * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
119      *
120      * @param gatewayUri the gateway uri for call redirection.
121      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
122      * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
123      *                     if the confirmFirst is true, and if the redirection request of this
124      *                     response was sent with a true flag of allowInteractiveResponse via
125      *                     {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
126      */
redirectCall(@onNull Uri gatewayUri, @NonNull PhoneAccountHandle targetPhoneAccount, boolean confirmFirst)127     public final void redirectCall(@NonNull Uri gatewayUri,
128                                    @NonNull PhoneAccountHandle targetPhoneAccount,
129                                    boolean confirmFirst) {
130         try {
131             mCallRedirectionAdapter.redirectCall(gatewayUri, targetPhoneAccount, confirmFirst);
132         } catch (RemoteException e) {
133             e.rethrowAsRuntimeException();
134         }
135     }
136 
137     /**
138      * The implemented {@link CallRedirectionService} calls this method to response a request
139      * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
140      * an outgoing call should be canceled entirely.
141      *
142      * <p>This can only be called from implemented
143      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
144      * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
145      *
146      */
cancelCall()147     public final void cancelCall() {
148         try {
149             mCallRedirectionAdapter.cancelCall();
150         } catch (RemoteException e) {
151             e.rethrowAsRuntimeException();
152         }
153     }
154 
155     /**
156      * A handler message to process the attempt to place call with redirection service from Telecom
157      */
158     private static final int MSG_PLACE_CALL = 1;
159 
160     /**
161      * A handler to process the attempt to place call with redirection service from Telecom
162      */
163     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
164         @Override
165         public void handleMessage(Message msg) {
166             switch (msg.what) {
167                 case MSG_PLACE_CALL:
168                     SomeArgs args = (SomeArgs) msg.obj;
169                     try {
170                         mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
171                         onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
172                                 (boolean) args.arg4);
173                     } finally {
174                         args.recycle();
175                     }
176                     break;
177             }
178         }
179     };
180 
181     private final class CallRedirectionBinder extends ICallRedirectionService.Stub {
182 
183         /**
184          * Telecom calls this method to inform the CallRedirectionService of a new outgoing call
185          * which is about to be placed.
186          * @param handle the phone number dialed by the user
187          * @param initialPhoneAccount the URI of the number the user dialed
188          * @param allowInteractiveResponse a boolean to tell if the implemented
189          *                                 {@link CallRedirectionService} should allow interactive
190          *                                 responses with users.
191          */
192         @Override
placeCall(@onNull ICallRedirectionAdapter adapter, @NonNull Uri handle, @NonNull PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse)193         public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
194                               @NonNull PhoneAccountHandle initialPhoneAccount,
195                               boolean allowInteractiveResponse) {
196             SomeArgs args = SomeArgs.obtain();
197             args.arg1 = adapter;
198             args.arg2 = handle;
199             args.arg3 = initialPhoneAccount;
200             args.arg4 = allowInteractiveResponse;
201             mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
202         }
203     }
204 
205     @Override
onBind(@onNull Intent intent)206     public final @Nullable IBinder onBind(@NonNull Intent intent) {
207         return new CallRedirectionBinder();
208     }
209 
210     @Override
onUnbind(@onNull Intent intent)211     public final boolean onUnbind(@NonNull Intent intent) {
212         return false;
213     }
214 }
215