blob: 028b6e49e34e446b6192601a09dced24971c1369 [file] [log] [blame]
/*
* Copyright (C) 2013 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.telecomm;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import com.android.internal.os.SomeArgs;
import com.android.internal.telecomm.IInCallAdapter;
import com.android.internal.telecomm.IInCallService;
/**
* This service is implemented by any app that wishes to provide the user-interface for managing
* phone calls. Telecomm binds to this service while there exists a live (active or incoming)
* call, and uses it to notify the in-call app of any live and and recently disconnected calls.
*
* TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
*/
public abstract class InCallService {
private static final int MSG_SET_IN_CALL_ADAPTER = 1;
private static final int MSG_ADD_CALL = 2;
private static final int MSG_UPDATE_CALL = 3;
private static final int MSG_SET_POST_DIAL = 4;
private static final int MSG_SET_POST_DIAL_WAIT = 5;
private static final int MSG_ON_AUDIO_STATE_CHANGED = 6;
private static final int MSG_BRING_TO_FOREGROUND = 7;
/** 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) {
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
onPhoneCreated(mPhone);
break;
case MSG_ADD_CALL:
mPhone.internalAddCall((InCallCall) msg.obj);
break;
case MSG_UPDATE_CALL:
mPhone.internalUpdateCall((InCallCall) msg.obj);
break;
case MSG_SET_POST_DIAL: {
SomeArgs args = (SomeArgs) msg.obj;
try {
String callId = (String) args.arg1;
String remaining = (String) args.arg2;
mPhone.internalSetPostDial(callId, remaining);
} finally {
args.recycle();
}
break;
}
case MSG_SET_POST_DIAL_WAIT: {
SomeArgs args = (SomeArgs) msg.obj;
try {
String callId = (String) args.arg1;
String remaining = (String) args.arg2;
mPhone.internalSetPostDialWait(callId, remaining);
} finally {
args.recycle();
}
break;
}
case MSG_ON_AUDIO_STATE_CHANGED:
mPhone.internalAudioStateChanged((CallAudioState) msg.obj);
break;
case MSG_BRING_TO_FOREGROUND:
mPhone.internalBringToForeground(msg.arg1 == 1);
break;
default:
break;
}
}
};
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
/** {@inheritDoc} */
@Override
public void setInCallAdapter(IInCallAdapter inCallAdapter) {
mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void addCall(InCallCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void updateCall(InCallCall call) {
mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
}
@Override
public void setPostDial(String callId, String remaining) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = remaining;
mHandler.obtainMessage(MSG_SET_POST_DIAL, args).sendToTarget();
}
@Override
public void setPostDialWait(String callId, String remaining) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = remaining;
mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, args).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void onAudioStateChanged(CallAudioState audioState) {
mHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, audioState).sendToTarget();
}
/** {@inheritDoc} */
@Override
public void bringToForeground(boolean showDialpad) {
mHandler.obtainMessage(MSG_BRING_TO_FOREGROUND, showDialpad ? 1 : 0, 0).sendToTarget();
}
}
private Phone mPhone;
protected InCallService() {}
public final IBinder getBinder() {
return new InCallServiceBinder();
}
/**
* Obtain the {@code Phone} associated with this {@code InCallService}.
*
* @return The {@code Phone} object associated with this {@code InCallService}, or {@code null}
* if the {@code InCallService} is not in a state where it has an associated {@code Phone}.
*/
public Phone getPhone() {
return mPhone;
}
/**
* Invoked when the {@code Phone} has been created. This is a signal to the in-call experience
* to start displaying in-call information to the user. Each instance of {@code InCallService}
* will have only one {@code Phone}, and this method will be called exactly once in the
* lifetime of the {@code InCallService}.
*
* @param phone The {@code Phone} object associated with this {@code InCallService}.
*/
public void onPhoneCreated(Phone phone) { }
/**
* Invoked when a {@code Phone} has been destroyed. This is a signal to the in-call experience
* to stop displaying in-call information to the user. This method will be called exactly once
* in the lifetime of the {@code InCallService}, and it will always be called after a previous
* call to {@link #onPhoneCreated(Phone)}.
*
* @param phone The {@code Phone} object associated with this {@code InCallService}.
*/
public void onPhoneDestroyed(Phone phone) { }
}