diff options
author | Steve Kondik <shade@chemlab.org> | 2014-06-06 22:35:15 -0700 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2014-06-06 22:35:15 -0700 |
commit | 1485c5a54e6d70ff35639b28a942067e6143025e (patch) | |
tree | 68b7efb95e65a878db57ea73a8e117c79c1550d0 /src | |
parent | ac6448f77dcf38b517190df45307349863e998d1 (diff) | |
parent | 97e4c867a288c975e5425aabb0c5c0df583ffbbf (diff) | |
download | packages_apps_InCallUI-1485c5a54e6d70ff35639b28a942067e6143025e.tar.gz packages_apps_InCallUI-1485c5a54e6d70ff35639b28a942067e6143025e.tar.bz2 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')
-rw-r--r-- | src/com/android/incallui/CallCardFragment.java | 22 | ||||
-rw-r--r-- | src/com/android/incallui/CallCardPresenter.java | 37 | ||||
-rw-r--r-- | src/com/android/incallui/CallCommandClient.java | 39 | ||||
-rw-r--r-- | src/com/android/incallui/CallHandlerService.java | 12 | ||||
-rw-r--r-- | src/com/android/incallui/CallList.java | 4 | ||||
-rw-r--r-- | src/com/android/incallui/CallUtils.java | 24 | ||||
-rw-r--r-- | src/com/android/incallui/CameraHandler.java | 6 | ||||
-rw-r--r-- | src/com/android/incallui/ImsCamera.java | 26 | ||||
-rw-r--r-- | src/com/android/incallui/InCallActivity.java | 95 | ||||
-rw-r--r-- | src/com/android/incallui/InCallPresenter.java | 18 | ||||
-rw-r--r-- | src/com/android/incallui/MSimAnswerPresenter.java | 7 | ||||
-rw-r--r-- | src/com/android/incallui/MediaHandler.java | 16 | ||||
-rw-r--r-- | src/com/android/incallui/StatusBarNotifier.java | 16 | ||||
-rw-r--r-- | src/com/android/incallui/VideoCallManager.java | 11 | ||||
-rw-r--r-- | src/com/android/incallui/VideoCallPanel.java | 53 | ||||
-rw-r--r-- | src/com/android/incallui/VideoPauseController.java | 244 |
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); + } + +} |