summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorSteve Kondik <shade@chemlab.org>2014-06-06 22:35:15 -0700
committerSteve Kondik <shade@chemlab.org>2014-06-06 22:35:15 -0700
commit1485c5a54e6d70ff35639b28a942067e6143025e (patch)
tree68b7efb95e65a878db57ea73a8e117c79c1550d0 /src/com/android
parentac6448f77dcf38b517190df45307349863e998d1 (diff)
parent97e4c867a288c975e5425aabb0c5c0df583ffbbf (diff)
downloadandroid_packages_apps_InCallUI-1485c5a54e6d70ff35639b28a942067e6143025e.tar.gz
android_packages_apps_InCallUI-1485c5a54e6d70ff35639b28a942067e6143025e.tar.bz2
android_packages_apps_InCallUI-1485c5a54e6d70ff35639b28a942067e6143025e.zip
Merge branch 'qcril' of git://github.com/CyanogenMod/android_packages_apps_InCallUI into cm-11.0
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/incallui/CallCardFragment.java22
-rw-r--r--src/com/android/incallui/CallCardPresenter.java37
-rw-r--r--src/com/android/incallui/CallCommandClient.java39
-rw-r--r--src/com/android/incallui/CallHandlerService.java12
-rw-r--r--src/com/android/incallui/CallList.java4
-rw-r--r--src/com/android/incallui/CallUtils.java24
-rw-r--r--src/com/android/incallui/CameraHandler.java6
-rw-r--r--src/com/android/incallui/ImsCamera.java26
-rw-r--r--src/com/android/incallui/InCallActivity.java95
-rw-r--r--src/com/android/incallui/InCallPresenter.java18
-rw-r--r--src/com/android/incallui/MSimAnswerPresenter.java7
-rw-r--r--src/com/android/incallui/MediaHandler.java16
-rw-r--r--src/com/android/incallui/StatusBarNotifier.java16
-rw-r--r--src/com/android/incallui/VideoCallManager.java11
-rw-r--r--src/com/android/incallui/VideoCallPanel.java53
-rw-r--r--src/com/android/incallui/VideoPauseController.java244
16 files changed, 595 insertions, 35 deletions
diff --git a/src/com/android/incallui/CallCardFragment.java b/src/com/android/incallui/CallCardFragment.java
index 02faa24e..bd4bdc06 100644
--- a/src/com/android/incallui/CallCardFragment.java
+++ b/src/com/android/incallui/CallCardFragment.java
@@ -150,6 +150,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
@Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mVideoCallPanel!=null) {
+ mVideoCallPanel.onDestroy();
+ mVideoCallPanel = null;
+ }
+ }
+
+ @Override
public void setVisible(boolean on) {
if (on) {
getView().setVisibility(View.VISIBLE);
@@ -242,6 +252,17 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
}
+ if (MSimTelephonyManager.getDefault().isMultiSimEnabled() &&
+ !(MSimTelephonyManager.getDefault().getMultiSimConfiguration()
+ == MSimTelephonyManager.MultiSimVariants.DSDA)) {
+ String[] sub = {"SUB 1", "SUB 2", "SUB 3"};
+ int subscription = getPresenter().getActiveSubscription();
+
+ if (subscription != -1) {
+ showSubscriptionInfo(sub[subscription]);
+ }
+ }
+
if (! isVideo) {
setDrawableToImageView(mPhoto, photo);
}
@@ -605,7 +626,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
private void updateVideoCallState(int callState, int callType) {
log(" - Videocall.state: " + callState);
- // Null check
if (mVideoCallPanel == null) {
loge("VideocallPanel is null");
return;
diff --git a/src/com/android/incallui/CallCardPresenter.java b/src/com/android/incallui/CallCardPresenter.java
index 5697aaca..0708a020 100644
--- a/src/com/android/incallui/CallCardPresenter.java
+++ b/src/com/android/incallui/CallCardPresenter.java
@@ -39,6 +39,7 @@ import com.android.incallui.InCallPresenter.IncomingCallListener;
import com.android.services.telephony.common.AudioMode;
import com.android.services.telephony.common.Call;
import com.android.services.telephony.common.Call.Capabilities;
+import com.android.services.telephony.common.CallDetails;
import com.android.services.telephony.common.CallIdentification;
import com.google.common.base.Preconditions;
import com.android.incallui.CallUtils;
@@ -158,8 +159,22 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
final boolean primaryChanged = !areCallsSame(mPrimary, primary);
final boolean primaryForwardedChanged = isForwarded(mPrimary) != isForwarded(primary);
final boolean secondaryChanged = !areCallsSame(mSecondary, secondary);
- mSecondary = secondary;
- mPrimary = primary;
+
+ if (primary != null && secondary != null &&
+ primary.getCallDetails().getCallDomain() != secondary.getCallDetails()
+ .getCallDomain() && areCallsSameOnDifferentDomains(primary, secondary)) {
+ Log.d(this, "SRVCC scenario primary and secondary are same call Primary " +
+ mPrimary + " Secondary " + mSecondary);
+ mSecondary = null;
+ if (primary.getCallDetails().getCallDomain() == CallDetails.CALL_DOMAIN_PS) {
+ mPrimary = secondary; //primary overwritten with CS
+ } else {
+ mPrimary = primary; //primary retains CS
+ }
+ } else {
+ mSecondary = secondary;
+ mPrimary = primary;
+ }
if (primaryChanged && mPrimary != null) {
// primary call has changed
@@ -253,6 +268,24 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
call1.getCallDetails().isMpty() == call2.getCallDetails().isMpty();
}
+ private boolean areCallsSameOnDifferentDomains(Call call1, Call call2) {
+ if (call1 == null || call2 == null) {
+ return false;
+ }
+ boolean callsSame = false;
+ if (call1.getCallDetails().isMpty() && call2.getCallDetails().isMpty()) { //MPTY SRVCC
+ //Currently more than one conference call each on a different domain
+ //If we hit here it means SRVCC scenario for a conference call
+ callsSame = true;
+ Log.d (this, "areCallsSameOnDifferentDomains for Mpty SRVCC call");
+ } else if (call1.getNumber() != null && call1.getNumber().equals(call2.getNumber())) {
+ //Normal SRVCC
+ callsSame = true;
+ Log.d (this, "areCallsSameOnDifferentDomains for SRVCC call");
+ }
+ return callsSame;
+ }
+
private void maybeStartSearch(Call call, boolean isPrimary) {
// no need to start search for conference calls which show generic info.
if (call != null && !call.isConferenceCall()) {
diff --git a/src/com/android/incallui/CallCommandClient.java b/src/com/android/incallui/CallCommandClient.java
index 3102c3e5..f55c9d8d 100644
--- a/src/com/android/incallui/CallCommandClient.java
+++ b/src/com/android/incallui/CallCommandClient.java
@@ -17,6 +17,7 @@
package com.android.incallui;
import android.os.RemoteException;
+import android.os.SystemProperties;
import com.android.internal.telephony.MSimConstants;
@@ -252,13 +253,47 @@ public class CallCommandClient {
return;
}
try {
- Log.v(this, "acceptCall() " );
- mCommandService.answerCallWithCallType(callId,callType);
+ /*
+ * To test call deflection this property has to be set with the
+ * number to which the call should be deflected. If this property is
+ * set to a number, on pressing the UI answer button, call deflect
+ * request will be sent. This is done to provide hooks to test call
+ * deflection through the UI answer button. For commercialization UI
+ * should be customized to call this API through the Call deflect UI
+ * button By default this property is not set and Answer button will
+ * work as expected
+ * Example:
+ * To deflect call to number 12345
+ * adb shell setprop persist.radio.deflect.number 12345
+ *
+ * Toggle above property and to invoke answerCallWithCallType
+ * adb shell setprop persist.radio.deflect.number ""
+ */
+ String deflectcall = SystemProperties.get("persist.radio.deflect.number");
+ if (deflectcall != null && !deflectcall.isEmpty()) {
+ mCommandService.deflectCall(callId, deflectcall);
+ } else {
+ Log.v(this, "acceptCall() ");
+ mCommandService.answerCallWithCallType(callId, callType);
+ }
} catch (RemoteException e) {
Log.e(this, "Error on acceptCall().", e);
}
}
+ public void deflectCall(int callId, String number) {
+ if (mCommandService == null) {
+ Log.e(this, "Cannot deflectCall(); CallCommandService == null");
+ return;
+ }
+ try{
+ Log.v(this, "deflectCall() ");
+ mCommandService.deflectCall(callId, number);
+ } catch (RemoteException e) {
+ Log.e(this, "Error on deflectCall().", e);
+ }
+ }
+
public void modifyCallInitiate(int callId, int callType) {
if (mCommandService == null) {
Log.e(this, "Cannot modifyCall(); CallCommandService == null");
diff --git a/src/com/android/incallui/CallHandlerService.java b/src/com/android/incallui/CallHandlerService.java
index 7a206317..f404b490 100644
--- a/src/com/android/incallui/CallHandlerService.java
+++ b/src/com/android/incallui/CallHandlerService.java
@@ -50,8 +50,9 @@ public class CallHandlerService extends Service {
private static final int ON_DESTROY = 10;
private static final int ON_ACTIVE_SUB_CHANGE = 11;
private static final int ON_UNSOL_CALLMODIFY = 12;
+ private static final int ON_SUPP_SERVICE_FAIL = 13;
- private static final int LARGEST_MSG_ID = ON_ACTIVE_SUB_CHANGE;
+ private static final int LARGEST_MSG_ID = ON_SUPP_SERVICE_FAIL;
private CallList mCallList;
@@ -204,6 +205,11 @@ public class CallHandlerService extends Service {
mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_ACTIVE_SUB_CHANGE, activeSub));
}
+ @Override
+ public void onSuppServiceFailed(int service) {
+ mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_SUPP_SERVICE_FAIL, service));
+ }
+
};
private void doStart(ICallCommandService service) {
@@ -344,6 +350,10 @@ public class CallHandlerService extends Service {
Log.i(TAG, "ON_ACTIVE_SUB_CHANGE: " + msg.obj);
mCallList.onActiveSubChanged((Integer) msg.obj);
break;
+ case ON_SUPP_SERVICE_FAIL:
+ Log.i(TAG, "ON_SUPP_SERVICE_FAIL: ");
+ mInCallPresenter.onSuppServiceFailed((Integer) msg.obj);
+ break;
default:
break;
diff --git a/src/com/android/incallui/CallList.java b/src/com/android/incallui/CallList.java
index 9b942ed1..6a3c8521 100644
--- a/src/com/android/incallui/CallList.java
+++ b/src/com/android/incallui/CallList.java
@@ -109,6 +109,10 @@ public class CallList {
public void onIncoming(Call call, List<String> textMessages) {
Log.d(this, "onIncoming - " + call);
+ // ensure the ringing call is active subscription, since phone state
+ // changed is notified before new incoming call ringing, and the event
+ // will switch active sub to a wrong sub(which is not ringing)
+ CallCommandClient.getInstance().setActiveSubscription(call.getSubscription());
updateActiveSuscription();
updateCallInMap(call);
diff --git a/src/com/android/incallui/CallUtils.java b/src/com/android/incallui/CallUtils.java
index 9fb488fd..0f0a9bb0 100644
--- a/src/com/android/incallui/CallUtils.java
+++ b/src/com/android/incallui/CallUtils.java
@@ -37,7 +37,10 @@ public class CallUtils {
public static boolean isVideoCall(int callType) {
return callType == CallDetails.CALL_TYPE_VT ||
callType == CallDetails.CALL_TYPE_VT_TX ||
- callType == CallDetails.CALL_TYPE_VT_RX;
+ callType == CallDetails.CALL_TYPE_VT_RX ||
+ callType == CallDetails.CALL_TYPE_VT_NODIR ||
+ callType == CallDetails.CALL_TYPE_VT_PAUSE ||
+ callType == CallDetails.CALL_TYPE_VT_RESUME;
}
public static int getCallType(Call call) {
@@ -99,8 +102,7 @@ public class CallUtils {
if (call == null) return false;
Preconditions.checkNotNull(call.getCallDetails());
final int callType = call.getCallDetails().getCallType();
- final boolean isImsVideoCall = isVideoCall(call) ||
- (callType == CallDetails.CALL_TYPE_VT_NODIR);
+ final boolean isImsVideoCall = isVideoCall(call);
final boolean isImsVoiceCall = (callType == CallDetails.CALL_TYPE_VOICE
&& call.getCallDetails().getCallDomain() == CallDetails.CALL_DOMAIN_PS);
return isImsVideoCall || isImsVoiceCall;
@@ -116,4 +118,20 @@ public class CallUtils {
|| isImsCall(callList.getDisconnectedCall());
}
+ public static boolean isVideoPaused(Call call) {
+ return call!=null && call.getCallDetails().getCallType() == CallDetails.CALL_TYPE_VT_PAUSE;
+ }
+
+ public static boolean areCallsSame(Call call1, Call call2) {
+ if (call1 == null && call2 == null) {
+ return true;
+ } else if (call1 == null || call2 == null) {
+ return false;
+ }
+ return (call1.getCallId() == call2.getCallId());
+ }
+
+ public static boolean canVideoPause(Call call) {
+ return isVideoCall(call) && call.getState() == Call.State.ACTIVE;
+ }
}
diff --git a/src/com/android/incallui/CameraHandler.java b/src/com/android/incallui/CameraHandler.java
index 7c0a063e..b8414c1e 100644
--- a/src/com/android/incallui/CameraHandler.java
+++ b/src/com/android/incallui/CameraHandler.java
@@ -58,6 +58,7 @@ public class CameraHandler {
private CameraInfo[] mInfo;
private CameraState mCameraState = CameraState.CAMERA_CLOSED;
private Context mContext;
+ private String mPackageName;
// Use a singleton.
private static CameraHandler mInstance;
@@ -94,7 +95,10 @@ public class CameraHandler {
private CameraHandler(Context context) {
mContext = context;
mNumberOfCameras = android.hardware.Camera.getNumberOfCameras();
+ mPackageName = context.getPackageName();
+
log("Number of cameras supported is: " + mNumberOfCameras);
+ log("Package name: " + mPackageName);
mInfo = new CameraInfo[mNumberOfCameras];
for (int i = 0; i < mNumberOfCameras; i++) {
mInfo[i] = new CameraInfo();
@@ -151,7 +155,7 @@ public class CameraHandler {
if (mCameraDevice == null) {
try {
if (DBG) log("opening camera " + cameraId);
- mCameraDevice = ImsCamera.open(cameraId);
+ mCameraDevice = ImsCamera.open(cameraId, mPackageName);
mCameraId = cameraId;
} catch (Exception e) {
loge("fail to connect Camera" + e);
diff --git a/src/com/android/incallui/ImsCamera.java b/src/com/android/incallui/ImsCamera.java
index de8d9ee3..603f6734 100644
--- a/src/com/android/incallui/ImsCamera.java
+++ b/src/com/android/incallui/ImsCamera.java
@@ -47,8 +47,11 @@ public class ImsCamera {
System.loadLibrary("imscamera_jni");
}
+ // @deprecated Use overloaded variant and explicitly pass the package name.
public static native short native_open(int cameraId);
+ public static native short native_open(int cameraId, String packageName);
+
public native short native_release();
public native short native_startPreview();
@@ -73,15 +76,28 @@ public class ImsCamera {
public native short native_setPreviewFpsRange(short fps);
+ // @deprecated Use overloaded variant and explicitly pass the package name.
public static ImsCamera open(int cameraId) throws Exception {
Log.d(TAG, "open cameraId=" + cameraId);
- short error = native_open(cameraId);
- if (error != IMS_CAMERA_OPERATION_SUCCESS) {
- Log.e(TAG, "open cameraId=" + cameraId + " failed with error=" + error);
- throw new Exception();
- } else {
+ return openImpl(cameraId, null);
+ }
+
+ public static ImsCamera open(int cameraId, String packageName) throws Exception {
+ Log.d(TAG, "open cameraId=" + cameraId);
+ if (packageName == null) throw new IllegalArgumentException();
+ return openImpl(cameraId, packageName);
+ }
+
+ private static ImsCamera openImpl(int cameraId, String packageName) throws Exception {
+ final short error =
+ packageName == null ? native_open(cameraId) : native_open(cameraId, packageName);
+ if (error == IMS_CAMERA_OPERATION_SUCCESS) {
return new ImsCamera();
}
+
+ Log.e(TAG, "open cameraId=" + cameraId + " packageName=" + packageName
+ + " failed with error=" + error);
+ throw new Exception("Failed to open ImsCamera");
}
public short release() {
diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java
index 8e80c9ff..043bec09 100644
--- a/src/com/android/incallui/InCallActivity.java
+++ b/src/com/android/incallui/InCallActivity.java
@@ -67,6 +67,11 @@ public class InCallActivity extends Activity {
/** Use to pass 'showDialpad' from {@link #onNewIntent} to {@link #onResume} */
private boolean mShowDialpadRequested;
+ // This enum maps to Phone.SuppService defined in telephony
+ private enum SuppService {
+ UNKNOWN, SWITCH, SEPARATE, TRANSFER, CONFERENCE, REJECT, HANGUP;
+ }
+
@Override
protected void onCreate(Bundle icicle) {
Log.d(this, "onCreate()... this = " + this);
@@ -612,11 +617,12 @@ public class InCallActivity extends Activity {
return super.dispatchPopulateAccessibilityEvent(event);
}
- public void maybeShowErrorDialogOnDisconnect(Call.DisconnectCause cause) {
- Log.d(this, "maybeShowErrorDialogOnDisconnect");
+ public void maybeShowErrorDialogOnDisconnect(Call call) {
+ Log.d(this, "maybeShowErrorDialogOnDisconnect: Call=" + call);
- if (!isFinishing()) {
- final int resId = getResIdForDisconnectCause(cause);
+ if (!isFinishing() && call != null) {
+ final int resId = getResIdForDisconnectCause(call.getDisconnectCause(),
+ call.getSuppServNotification());
if (resId != INVALID_RES_ID) {
showErrorDialog(resId);
}
@@ -637,6 +643,62 @@ public class InCallActivity extends Activity {
}
/**
+ * Handle a failure notification for a supplementary service
+ * (i.e. conference, switch, separate, transfer, etc.).
+ */
+ void onSuppServiceFailed(int service) {
+ Log.d(this, "onSuppServiceFailed: " + service);
+ SuppService result = SuppService.values()[service];
+ int errorMessageResId;
+
+ switch (result) {
+ case SWITCH:
+ // Attempt to switch foreground and background/incoming calls failed
+ // ("Failed to switch calls")
+ errorMessageResId = R.string.incall_error_supp_service_switch;
+ break;
+
+ case SEPARATE:
+ // Attempt to separate a call from a conference call
+ // failed ("Failed to separate out call")
+ errorMessageResId = R.string.incall_error_supp_service_separate;
+ break;
+
+ case TRANSFER:
+ // Attempt to connect foreground and background calls to
+ // each other (and hanging up user's line) failed ("Call
+ // transfer failed")
+ errorMessageResId = R.string.incall_error_supp_service_transfer;
+ break;
+
+ case CONFERENCE:
+ // Attempt to add a call to conference call failed
+ // ("Conference call failed")
+ errorMessageResId = R.string.incall_error_supp_service_conference;
+ break;
+
+ case REJECT:
+ // Attempt to reject an incoming call failed
+ // ("Call rejection failed")
+ errorMessageResId = R.string.incall_error_supp_service_reject;
+ break;
+
+ case HANGUP:
+ // Attempt to release a call failed ("Failed to release call(s)")
+ errorMessageResId = R.string.incall_error_supp_service_hangup;
+ break;
+
+ case UNKNOWN:
+ default:
+ // Attempt to use a service we don't recognize or support
+ // ("Unsupported service" or "Selected service failed")
+ errorMessageResId = R.string.incall_error_supp_service_unknown;
+ break;
+ }
+ showErrorDialog(errorMessageResId);
+ }
+
+ /**
* Utility function to bring up a generic "error" dialog.
*/
private void showErrorDialog(int resId) {
@@ -663,11 +725,30 @@ public class InCallActivity extends Activity {
mDialog.show();
}
- private int getResIdForDisconnectCause(Call.DisconnectCause cause) {
+ private int getResIdForDisconnectCause(Call.DisconnectCause cause,
+ Call.SsNotification notification) {
int resId = INVALID_RES_ID;
- if (cause == Call.DisconnectCause.CALL_BARRED) {
- resId = R.string.callFailed_cb_enabled;
+ if (cause == Call.DisconnectCause.INCOMING_MISSED) {
+ // If the network sends SVC Notification then this dialog will be displayed
+ // in case of B when the incoming call at B is not answered and gets forwarded
+ // to C
+ if (notification != null && notification.notificationType == 1 &&
+ notification.code ==
+ Call.SsNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED) {
+ resId = R.string.callUnanswered_forwarded;
+ }
+ } else if (cause == Call.DisconnectCause.CALL_BARRED) {
+ // When call is disconnected with this code then it can either be barring from
+ // MO side or MT side.
+ // In MT case, if network sends SVC Notification then this dialog will be
+ // displayed when A is calling B & incoming is barred on B.
+ if (notification != null && notification.notificationType == 0 &&
+ notification.code == Call.SsNotification.MO_CODE_INCOMING_CALLS_BARRED) {
+ resId = R.string.callFailed_incoming_cb_enabled;
+ } else {
+ resId = R.string.callFailed_cb_enabled;
+ }
} else if (cause == Call.DisconnectCause.FDN_BLOCKED) {
resId = R.string.callFailed_fdn_only;
} else if (cause == Call.DisconnectCause.CS_RESTRICTED) {
diff --git a/src/com/android/incallui/InCallPresenter.java b/src/com/android/incallui/InCallPresenter.java
index ff1b963f..92f2cb5d 100644
--- a/src/com/android/incallui/InCallPresenter.java
+++ b/src/com/android/incallui/InCallPresenter.java
@@ -64,6 +64,7 @@ public class InCallPresenter implements CallList.Listener {
private ProximitySensor mProximitySensor;
private boolean mServiceConnected = false;
private static String LOG_TAG = "InCallPresenter";
+ VideoCallManager mVideoCallManager;
/**
* This table is for deciding whether consent is
@@ -146,8 +147,10 @@ public class InCallPresenter implements CallList.Listener {
// will kick off an update and the whole process can start.
mCallList.addListener(this);
- // Initialize VideoCallManager. Instantiates the singleton.
- VideoCallManager.getInstance(mContext);
+ mVideoCallManager = VideoCallManager.getInstance(mContext);
+ final VideoPauseController videoPause = mVideoCallManager.getVideoPauseController();
+ addListener(videoPause);
+ addIncomingCallListener(videoPause);
Log.d(this, "Finished InCallPresenter.setUp");
}
@@ -356,7 +359,6 @@ public class InCallPresenter implements CallList.Listener {
== MSimTelephonyManager.MultiSimVariants.DSDA && (mInCallActivity != null)) {
mInCallActivity.updateDsdaTab();
}
-
if (isActivityStarted()) {
final boolean hasCall = callList.getActiveOrBackgroundCall() != null ||
callList.getOutgoingCall() != null;
@@ -530,6 +532,8 @@ public class InCallPresenter implements CallList.Listener {
if (showing) {
mIsActivityPreviouslyStarted = true;
}
+
+ mVideoCallManager.getVideoPauseController().onUiShowing(showing);
}
/**
@@ -650,7 +654,7 @@ public class InCallPresenter implements CallList.Listener {
private void maybeShowErrorDialogOnDisconnect(Call call) {
// For newly disconnected calls, we may want to show a dialog on specific error conditions
if (isActivityStarted() && call.getState() == Call.State.DISCONNECTED) {
- mInCallActivity.maybeShowErrorDialogOnDisconnect(call.getDisconnectCause());
+ mInCallActivity.maybeShowErrorDialogOnDisconnect(call);
}
}
@@ -863,6 +867,12 @@ public class InCallPresenter implements CallList.Listener {
}
}
+ public void onSuppServiceFailed(int service) {
+ if (mInCallActivity != null) {
+ mInCallActivity.onSuppServiceFailed(service);
+ }
+ }
+
/**
* Private constructor. Must use getInstance() to get this singleton.
*/
diff --git a/src/com/android/incallui/MSimAnswerPresenter.java b/src/com/android/incallui/MSimAnswerPresenter.java
index 375b05de..f813e65a 100644
--- a/src/com/android/incallui/MSimAnswerPresenter.java
+++ b/src/com/android/incallui/MSimAnswerPresenter.java
@@ -121,7 +121,12 @@ public class MSimAnswerPresenter extends Presenter<MSimAnswerPresenter.AnswerUi>
// Stop listening for updates.
CallList.getInstance().removeCallUpdateListener(mCallId[subscription], this);
- getUi().showAnswerUi(false);
+ final Call incall = CallList.getInstance().getIncomingCall();
+ if (incall != null) {
+ getUi().showAnswerUi(true);
+ } else {
+ getUi().showAnswerUi(false);
+ }
// mCallId will hold the state of the call. We don't clear the mCall variable here as
// it may be useful for sending text messages after phone disconnects.
diff --git a/src/com/android/incallui/MediaHandler.java b/src/com/android/incallui/MediaHandler.java
index 95acd7b9..dbf35562 100644
--- a/src/com/android/incallui/MediaHandler.java
+++ b/src/com/android/incallui/MediaHandler.java
@@ -49,6 +49,9 @@ public class MediaHandler extends Handler {
public static final int DPL_INIT_FAILURE = -1;
public static final int DPL_INIT_MULTIPLE = -2;
+ public static final int PLAYER_STATE_STARTED = 0;
+ public static final int PLAYER_STATE_STOPPED = 1;
+
private static final String TAG = "VideoCall_MediaHandler";
private static SurfaceTexture mSurface;
@@ -73,6 +76,8 @@ public class MediaHandler extends Handler {
//Following values are from the IMS VT API documentation
public static final int PARAM_READY_EVT = 1;
public static final int START_READY_EVT = 2;
+ public static final int PLAYER_START_EVENT = 3;
+ public static final int PLAYER_STOP_EVENT = 4;
public static final int DISPLAY_MODE_EVT = 5;
public static final int PEER_RESOLUTION_CHANGE_EVT = 6;
@@ -122,6 +127,7 @@ public class MediaHandler extends Handler {
void onDisplayModeEvent();
void onStartReadyEvent();
void onPeerResolutionChangeEvent();
+ void onPlayerStateChanged(int state);
}
static {
@@ -293,6 +299,16 @@ public class MediaHandler extends Handler {
mMediaEventListener.onDisplayModeEvent();
}
break;
+ case PLAYER_START_EVENT:
+ if (mMediaEventListener != null) {
+ mMediaEventListener.onPlayerStateChanged(PLAYER_STATE_STARTED);
+ }
+ break;
+ case PLAYER_STOP_EVENT:
+ if (mMediaEventListener != null) {
+ mMediaEventListener.onPlayerStateChanged(PLAYER_STATE_STOPPED);
+ }
+ break;
default:
Log.e(TAG, "Received unknown event id=" + eventId);
}
diff --git a/src/com/android/incallui/StatusBarNotifier.java b/src/com/android/incallui/StatusBarNotifier.java
index 98442671..19595b82 100644
--- a/src/com/android/incallui/StatusBarNotifier.java
+++ b/src/com/android/incallui/StatusBarNotifier.java
@@ -451,10 +451,22 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
// different calls. So if both lines are in use, display info
// from the foreground call. And if there's a ringing call,
// display that regardless of the state of the other calls.
+ int resId;
+ int voicePrivacy = call.getCapabilities() & Call.Capabilities.VOICE_PRIVACY;
if (call.getState() == Call.State.ONHOLD) {
- return R.drawable.stat_sys_phone_call_on_hold;
+ if (voicePrivacy != 0) {
+ resId = R.drawable.stat_sys_vp_phone_call_on_hold;
+ } else {
+ resId = R.drawable.stat_sys_phone_call_on_hold;
+ }
+ } else {
+ if (voicePrivacy != 0) {
+ resId = R.drawable.stat_sys_vp_phone_call;
+ } else {
+ resId = R.drawable.stat_sys_phone_call;
+ }
}
- return R.drawable.stat_sys_phone_call;
+ return resId;
}
/**
diff --git a/src/com/android/incallui/VideoCallManager.java b/src/com/android/incallui/VideoCallManager.java
index f9bd0461..6c2cfd5f 100644
--- a/src/com/android/incallui/VideoCallManager.java
+++ b/src/com/android/incallui/VideoCallManager.java
@@ -52,6 +52,8 @@ public class VideoCallManager {
private CameraHandler mCameraHandler;
private MediaHandler mMediaHandler;
private CvoHandler mCvoHandler;
+ private final VideoPauseController mVideoPauseController;
+
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -90,6 +92,7 @@ public class VideoCallManager {
mCvoHandler = new CvoHandler(context);
mMediaHandler.registerForCvoModeRequestChanged(mHandler, CVO_MODE_REQUEST_CHANGED, null);
mCvoHandler.registerForCvoInfoChange(mHandler, CVO_INFO_CHANGED, null);
+ mVideoPauseController = new VideoPauseController(context, CallCommandClient.getInstance());
}
private void notifyCvoClient(int orientation) {
@@ -336,11 +339,15 @@ public class VideoCallManager {
return aspectRatio;
}
- private void log(String msg) {
+ private static void log(String msg) {
Log.d(TAG, msg);
}
- private void loge(String msg) {
+ private static void loge(String msg) {
Log.e(TAG, msg);
}
+
+ public VideoPauseController getVideoPauseController() {
+ return mVideoPauseController;
+ }
}
diff --git a/src/com/android/incallui/VideoCallPanel.java b/src/com/android/incallui/VideoCallPanel.java
index 1f71c0f3..f0b8816c 100644
--- a/src/com/android/incallui/VideoCallPanel.java
+++ b/src/com/android/incallui/VideoCallPanel.java
@@ -65,6 +65,7 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
// "Video Call" UI elements and state
private ViewGroup mVideoCallPanel;
private ZoomControlBar mZoomControl;
+
private TextureView mFarEndView;
private TextureView mCameraPreview;
private SurfaceTexture mCameraSurface;
@@ -127,6 +128,17 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
}
@Override
+ public void onPlayerStateChanged(int state) {
+ if (state == MediaHandler.PLAYER_STATE_STARTED) {
+ log("PLAYER_STARTED");
+ } else if (state == MediaHandler.PLAYER_STATE_STOPPED) {
+ log("PLAYER_STOPPED");
+ } else {
+ log("UNKOWN_STATE");
+ }
+ }
+
+ @Override
public void onDisplayModeEvent() {
// NO-OP
}
@@ -216,6 +228,14 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
// Set media event listener
mVideoCallManager.setMediaEventListener(new MediaEventListener());
mVideoCallManager.setCvoEventListener(new CvoListener());
+
+ releaseCachedSurfaces();
+ }
+
+ // The function must be called from the parent's onDestroy function.
+ public void onDestroy() {
+ log("onDestroy...");
+ releaseCachedSurfaces();
}
public void setCameraNeeded(boolean mCameraNeeded) {
@@ -306,7 +326,7 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
public boolean isCameraInitNeeded() {
if (DBG) {
- log("isCameraInitNeeded mCameraNeeded=" + mCameraNeeded + " mCameraSurface= "
+ log("isCameraInitNeeded mCameraNeeded=" + mCameraNeeded + " CameraSurface= "
+ mCameraSurface + " camera state = "
+ mVideoCallManager.getCameraState());
}
@@ -365,13 +385,25 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
if (surface.equals(mCameraPreview.getSurfaceTexture())) {
if (DBG) log("Camera surface texture created");
+
mCameraSurface = surface;
+
+ // Initialize Camera as needed.
if (isCameraInitNeeded()) {
initializeCamera();
}
} else if (surface.equals(mFarEndView.getSurfaceTexture())) {
+
+ // Use cached surface texture.
if (DBG) log("Video surface texture created");
- mFarEndSurface = surface;
+ if (mFarEndSurface==null) {
+ log("Caching video surface texture.");
+ mFarEndSurface = surface;
+ } else {
+ log("Resetting video surface texture.");
+ mFarEndView.setSurfaceTexture(mFarEndSurface);
+ }
+
mVideoCallManager.setFarEndSurface(mFarEndSurface);
}
}
@@ -383,10 +415,10 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
stopRecordingAndPreview();
closeCamera();
mCameraSurface = null;
+ return true;
} else if (surface.equals(mFarEndView.getSurfaceTexture())) {
if (DBG) log("FarEndView surface texture destroyed");
- mFarEndSurface = null;
- mVideoCallManager.setFarEndSurface(null);
+ return false;
}
return true;
}
@@ -637,6 +669,19 @@ public class VideoCallPanel extends RelativeLayout implements TextureView.Surfac
}
}
+ // Releases surface texture if it's not null.
+ private void release(SurfaceTexture s) {
+ if (s == null) return;
+ log("VideoCall: Releasing surface texture, " + s);
+ s.release();
+ }
+
+ private void releaseCachedSurfaces() {
+ release(mFarEndSurface);
+ mFarEndSurface = null;
+ mVideoCallManager.setFarEndSurface(mFarEndSurface);
+ }
+
public void startOrientationListener(boolean start) {
mVideoCallManager.startOrientationListener(start);
}
diff --git a/src/com/android/incallui/VideoPauseController.java b/src/com/android/incallui/VideoPauseController.java
new file mode 100644
index 00000000..3c4e5ba1
--- /dev/null
+++ b/src/com/android/incallui/VideoPauseController.java
@@ -0,0 +1,244 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.incallui;
+
+import android.content.Context;
+import android.widget.Toast;
+
+import com.android.incallui.InCallPresenter.InCallState;
+import com.android.incallui.InCallPresenter.InCallStateListener;
+import com.android.incallui.InCallPresenter.IncomingCallListener;
+import com.android.internal.util.Preconditions;
+import com.android.services.telephony.common.Call;
+import com.android.services.telephony.common.CallDetails;
+
+/**
+ * The class is responsible for generating video pause/resume request.
+ */
+class VideoPauseController implements InCallStateListener, IncomingCallListener {
+ private static final String TAG = "VideoCallPauseController";
+
+ private CallCommandClient mCallCommandClient;
+ private Context mContext;
+
+ private Call mCurrCall = null; // call visible to the user, if any.
+ private boolean mIsInBackground = false; // True if UI is not visible, false otherwise.
+
+ public VideoPauseController(Context context, CallCommandClient callCommandClient) {
+ mCallCommandClient = Preconditions.checkNotNull(callCommandClient);
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * The function gets called when call state changes.
+ * @param state Phone state.
+ * @param callList List of current call.
+ */
+ @Override
+ public void onStateChange(InCallState state, CallList callList) {
+ log("onStateChange, state=" + state);
+
+ Call call = null;
+ if (state == InCallState.INCOMING) {
+ call = callList.getIncomingCall();
+ } else if (state == InCallState.OUTGOING) {
+ call = callList.getOutgoingCall();
+ } else {
+ call = callList.getActiveCall();
+ }
+
+ // Check if we should display a toast message.
+ displayToast(call);
+
+ boolean hasPrimaryCallChanged = !CallUtils.areCallsSame(call, mCurrCall);
+ boolean canVideoPause = CallUtils.canVideoPause(call);
+ log("onStateChange, hasPrimaryCallChanged=" + hasPrimaryCallChanged);
+ log("onStateChange, canVideoPause=" + canVideoPause);
+ log("onStateChange, IsInBackground=" + mIsInBackground);
+ log("onStateChange, New call = " + call);
+
+ // Send pause request if outgoing request becomes active while UI is in
+ // background.
+ if (!hasPrimaryCallChanged && isOutgoing(mCurrCall) && canVideoPause && mIsInBackground) {
+ sendRequest(call, false);
+ }
+
+ // Send pause request if VoLTE call becomes active while UI is in
+ // background.
+ if (!hasPrimaryCallChanged && !CallUtils.isVideoCall(mCurrCall) && canVideoPause
+ && mIsInBackground) {
+ sendRequest(call, false);
+ }
+
+ // Send resume request for the active call, if user rejects incoming
+ // call
+ // and UI is in foreground.
+ if (hasPrimaryCallChanged && isIncomming(mCurrCall) && canVideoPause && !mIsInBackground) {
+ sendRequest(call, true);
+ }
+
+ // Send resume request for the active call, if user ends outgoing call
+ // and UI is in foreground.
+ if (hasPrimaryCallChanged && isOutgoing(mCurrCall) && canVideoPause && !mIsInBackground) {
+ sendRequest(call, true);
+ }
+
+ // Send pause request for the active call, if the holding call ends
+ // while UI is in background
+ if (hasPrimaryCallChanged && isHolding(mCurrCall) && canVideoPause && mIsInBackground) {
+ sendRequest(call, false);
+ }
+
+ mCurrCall = call;
+ }
+
+ /**
+ * The function gets called when InCallUI receives a new incoming call.
+ */
+ @Override
+ public void onIncomingCall(InCallState state, Call call) {
+ log("onIncomingCall, call=" + call);
+
+ if (CallUtils.areCallsSame(call, mCurrCall)) {
+ return;
+ }
+
+ // Pause current video call, if there is an incoming call.
+ if (CallUtils.canVideoPause(mCurrCall)) {
+ sendRequest(mCurrCall, false);
+ }
+ mCurrCall = call;
+ }
+
+ /**
+ * Called when UI goes in/out of the foreground.
+ * @param showing true if UI is in the foreground, false otherwise.
+ */
+ public void onUiShowing(boolean showing) {
+ if (showing) {
+ onResume();
+ } else {
+ onPause();
+ }
+ }
+
+ /**
+ * Sends Pause/Resume request.
+ * @param call Call to be paused/resumed.
+ * @param resume If true resume request will be sent, otherwise pause request.
+ */
+ private void sendRequest(Call call, boolean resume) {
+ if (resume) {
+ log("sending resume request, call=" + call);
+ mCallCommandClient.modifyCallInitiate(call.getCallId(),
+ CallDetails.CALL_TYPE_VT_RESUME);
+ } else {
+ log("sending pause request, call=" + call);
+ mCallCommandClient.modifyCallInitiate(call.getCallId(),
+ CallDetails.CALL_TYPE_VT_PAUSE);
+ }
+ }
+
+ /**
+ * Returns true if call is in incoming/waiting state, false otherwise.
+ */
+ private boolean isIncomming(Call call) {
+ return call!=null && call.getState() == Call.State.CALL_WAITING;
+ }
+
+ /**
+ * Returns true if the call is outgoing, false otherwise
+ */
+ private boolean isOutgoing(Call call) {
+ return call!=null && (call.getState() == Call.State.DIALING || call.getState() == Call.State.REDIALING);
+ }
+
+ /**
+ * Returns true if the call is on hold, false otherwise
+ */
+ private boolean isHolding(Call call) {
+ return call!=null && call.getState() == Call.State.ONHOLD;
+ }
+
+ /**
+ * Called when UI becomes visible. This will send resume request for current video call, if any.
+ */
+ private void onResume() {
+ log("onResume");
+
+ mIsInBackground = false;
+ if (CallUtils.canVideoPause(mCurrCall)) {
+ sendRequest(mCurrCall, true);
+ } else {
+ log("onResume. Ignoring...");
+ }
+ }
+
+ /**
+ * Called when UI becomes invisible. This will send pause request for current video call, if any.
+ */
+ private void onPause() {
+ log("onPause");
+
+ mIsInBackground = true;
+ if (CallUtils.canVideoPause(mCurrCall)) {
+ sendRequest(mCurrCall, false);
+ } else {
+ log("onPause, Ignoring...");
+ }
+ }
+
+ /**
+ * Displays toast message if video call has been paused/resumed.
+ */
+ private void displayToast(Call newCall) {
+ if (!CallUtils.isVideoCall(newCall)) {
+ log("displayToast Not a video call, ignoring... call " + newCall);
+ return;
+ }
+ boolean primaryChanged = !CallUtils.areCallsSame(mCurrCall, newCall);
+ boolean videoPauseStateChanged = CallUtils.isVideoPaused(mCurrCall) != CallUtils
+ .isVideoPaused(newCall);
+ final String msg = CallUtils.isVideoPaused(newCall) ? "Video Paused" : "Video Resumed";
+ if ((primaryChanged && CallUtils.isVideoPaused(newCall))
+ || (!primaryChanged && videoPauseStateChanged)) {
+ log("Call " + newCall.getCallId() + " has been " + msg);
+ Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
+ private static void loge(String msg) {
+ Log.e(TAG, msg);
+ }
+
+}