blob: 581cd7ee6d50bbda697021b3279131848aaada20 [file] [log] [blame]
/*
* Copyright (C) 2022 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 android.telecom;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import androidx.annotation.Nullable;
import com.android.internal.telecom.ICallStreamingService;
import com.android.internal.telecom.IStreamingCallAdapter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This service is implemented by an app that wishes to provide functionality for a general call
* streaming sender for voip calls.
* <p>
* Below is an example manifest registration for a {@code CallStreamingService}.
* <pre>
* {@code
* <service android:name=".EgCallStreamingService"
* android:permission="android.permission.BIND_CALL_STREAMING_SERVICE" >
* ...
* <intent-filter>
* <action android:name="android.telecom.CallStreamingService" />
* </intent-filter>
* </service>
* }
* </pre>
*
* @hide
*/
@SystemApi
public abstract class CallStreamingService extends Service {
/**
* The {@link android.content.Intent} that must be declared as handled by the service.
*/
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE = "android.telecom.CallStreamingService";
private static final int MSG_SET_STREAMING_CALL_ADAPTER = 1;
private static final int MSG_CALL_STREAMING_STARTED = 2;
private static final int MSG_CALL_STREAMING_STOPPED = 3;
private static final int MSG_CALL_STREAMING_STATE_CHANGED = 4;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (mStreamingCallAdapter == null && msg.what != MSG_SET_STREAMING_CALL_ADAPTER) {
Log.i(this, "handleMessage: null adapter!");
return;
}
switch (msg.what) {
case MSG_SET_STREAMING_CALL_ADAPTER:
if (msg.obj != null) {
Log.i(this, "MSG_SET_STREAMING_CALL_ADAPTER");
mStreamingCallAdapter = new StreamingCallAdapter(
(IStreamingCallAdapter) msg.obj);
}
break;
case MSG_CALL_STREAMING_STARTED:
Log.i(this, "MSG_CALL_STREAMING_STARTED");
mCall = (StreamingCall) msg.obj;
mCall.setAdapter(mStreamingCallAdapter);
CallStreamingService.this.onCallStreamingStarted(mCall);
break;
case MSG_CALL_STREAMING_STOPPED:
Log.i(this, "MSG_CALL_STREAMING_STOPPED");
mCall = null;
mStreamingCallAdapter = null;
CallStreamingService.this.onCallStreamingStopped();
break;
case MSG_CALL_STREAMING_STATE_CHANGED:
int state = (int) msg.obj;
if (mStreamingCallAdapter != null) {
mCall.requestStreamingState(state);
CallStreamingService.this.onCallStreamingStateChanged(state);
}
break;
default:
break;
}
}
};
@Nullable
@Override
public IBinder onBind(@NonNull Intent intent) {
Log.i(this, "onBind");
return new CallStreamingServiceBinder();
}
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class CallStreamingServiceBinder extends ICallStreamingService.Stub {
@Override
public void setStreamingCallAdapter(IStreamingCallAdapter streamingCallAdapter)
throws RemoteException {
Log.i(this, "setCallStreamingAdapter");
mHandler.obtainMessage(MSG_SET_STREAMING_CALL_ADAPTER, streamingCallAdapter)
.sendToTarget();
}
@Override
public void onCallStreamingStarted(StreamingCall call) throws RemoteException {
Log.i(this, "onCallStreamingStarted");
mHandler.obtainMessage(MSG_CALL_STREAMING_STARTED, call).sendToTarget();
}
@Override
public void onCallStreamingStopped() throws RemoteException {
mHandler.obtainMessage(MSG_CALL_STREAMING_STOPPED).sendToTarget();
}
@Override
public void onCallStreamingStateChanged(int state) throws RemoteException {
mHandler.obtainMessage(MSG_CALL_STREAMING_STATE_CHANGED, state).sendToTarget();
}
}
/**
* Call streaming request reject reason used with
* {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
* call streaming request due to unknown reason.
*/
public static final int STREAMING_FAILED_UNKNOWN = 0;
/**
* Call streaming request reject reason used with
* {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
* call streaming request because there's an ongoing streaming call on this device.
*/
public static final int STREAMING_FAILED_ALREADY_STREAMING = 1;
/**
* Call streaming request reject reason used with
* {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
* call streaming request because telecom can't find existing general streaming sender on this
* device.
*/
public static final int STREAMING_FAILED_NO_SENDER = 2;
/**
* Call streaming request reject reason used with
* {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
* call streaming request because telecom can't bind to the general streaming sender app.
*/
public static final int STREAMING_FAILED_SENDER_BINDING_ERROR = 3;
private StreamingCallAdapter mStreamingCallAdapter;
private StreamingCall mCall;
/**
* @hide
*/
@IntDef(prefix = {"STREAMING_FAILED"},
value = {
STREAMING_FAILED_UNKNOWN,
STREAMING_FAILED_ALREADY_STREAMING,
STREAMING_FAILED_NO_SENDER,
STREAMING_FAILED_SENDER_BINDING_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface StreamingFailedReason {
}
;
/**
* Called when a {@code StreamingCall} has been added to this call streaming session. The call
* streaming sender should start to intercept the device audio using audio records and audio
* tracks from Audio frameworks.
*
* @param call a newly added {@code StreamingCall}.
*/
public void onCallStreamingStarted(@NonNull StreamingCall call) {
}
/**
* Called when a current {@code StreamingCall} has been removed from this call streaming
* session. The call streaming sender should notify the streaming receiver that the call is
* stopped streaming and stop the device audio interception.
*/
public void onCallStreamingStopped() {
}
/**
* Called when the streaming state of current {@code StreamingCall} changed. General streaming
* sender usually get notified of the holding/unholding from the original owner voip app of the
* call.
*/
public void onCallStreamingStateChanged(@StreamingCall.StreamingCallState int state) {
}
}