Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 160c0416 authored by Ravi Paluri's avatar Ravi Paluri Committed by Linux Build Service Account
Browse files

IMS-VT: Handle power button interactions in a VT call

1. Introduce InCallUiStateNotifier class that listens to below events
   and notify whether UI is visible to the user or not using
   onUiShowing API
       a. InCallActivity's lifecycle events (onStop/onStart)
       b. Display state change events (DISPLAY_ON/DISPLAY_OFF)
2. Introduce InCallUiStateNotifierListener Interface that exposes
   onUiShowing API
3. Handle onUiShowing API to
       a. Turn ON/OFF camera
       b. Send Pause/Resume requests when multitasking is enabled
4. Ignore duplicate Pause/Resume requests

IMS_VT: Enable camera only when InCall UI is in foreground

- We don't need to enable camera when InCall UI is in
  background.
Change-Id: Ic95b4ab8d2e8e3a8ba0ea856a53bb320aa713e37

IMS-VT: Always update "mIsInBackground" flag

update "mIsInBackground" flag whenever there are indications
that UE moved to either background or foreground and never
ignore these indications
Change-Id: I9f127fa640b779175dda95ff44aa5e77dc645a42

Change-Id: If4da4fa9fa3a007d23d1bf9e9896e6f40d859900
CRs-Fixed: 881797
parent b8f6a6c1
Loading
Loading
Loading
Loading
+7 −6
Original line number Original line Diff line number Diff line
@@ -339,6 +339,7 @@ public class InCallPresenter implements CallList.Listener,
        mCallList.addListener(this);
        mCallList.addListener(this);


        InCallCsRedialHandler.getInstance().setUp(mContext);
        InCallCsRedialHandler.getInstance().setUp(mContext);
        InCallUiStateNotifier.getInstance().setUp(mContext);
        VideoPauseController.getInstance().setUp(this);
        VideoPauseController.getInstance().setUp(this);
        InCallVideoCallCallbackNotifier.getInstance().addSessionModificationListener(this);
        InCallVideoCallCallbackNotifier.getInstance().addSessionModificationListener(this);


@@ -371,8 +372,8 @@ public class InCallPresenter implements CallList.Listener,


        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        VideoPauseController.getInstance().tearDown();
        VideoPauseController.getInstance().tearDown();
        InCallUiStateNotifier.getInstance().tearDown();
        InCallVideoCallCallbackNotifier.getInstance().removeSessionModificationListener(this);
        InCallVideoCallCallbackNotifier.getInstance().removeSessionModificationListener(this);

        InCallMessageController.getInstance().tearDown();
        InCallMessageController.getInstance().tearDown();
        removeDetailsListener(CallSubstateNotifier.getInstance());
        removeDetailsListener(CallSubstateNotifier.getInstance());


@@ -1089,7 +1090,7 @@ public class InCallPresenter implements CallList.Listener,
    /*package*/
    /*package*/
    void onActivityStarted() {
    void onActivityStarted() {
        Log.d(this, "onActivityStarted");
        Log.d(this, "onActivityStarted");
        notifyVideoPauseController(true);
        notifyInCallUiStateNotifier(true);
        if (mStatusBarNotifier != null) {
        if (mStatusBarNotifier != null) {
            mStatusBarNotifier.updateCallStatusBar(mCallList);
            mStatusBarNotifier.updateCallStatusBar(mCallList);
        }
        }
@@ -1098,17 +1099,17 @@ public class InCallPresenter implements CallList.Listener,
    /*package*/
    /*package*/
    void onActivityStopped() {
    void onActivityStopped() {
        Log.d(this, "onActivityStopped");
        Log.d(this, "onActivityStopped");
        notifyVideoPauseController(false);
        notifyInCallUiStateNotifier(false);
        if (mStatusBarNotifier != null ) {
        if (mStatusBarNotifier != null ) {
            mStatusBarNotifier.updateCallStatusBar(mCallList);
            mStatusBarNotifier.updateCallStatusBar(mCallList);
        }
        }
    }
    }


    private void notifyVideoPauseController(boolean showing) {
    private void notifyInCallUiStateNotifier(boolean showing) {
        Log.d(this, "notifyVideoPauseController: mIsChangingConfigurations=" +
        Log.d(this, "notifyInCallUiStateNotifier: mIsChangingConfigurations=" +
                mIsChangingConfigurations);
                mIsChangingConfigurations);
        if (!mIsChangingConfigurations) {
        if (!mIsChangingConfigurations) {
            VideoPauseController.getInstance().onUiShowing(showing);
            InCallUiStateNotifier.getInstance().onUiShowing(showing);
        }
        }
    }
    }


+229 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2015, 2016, 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.hardware.display.DisplayManager;
import android.view.Display;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;

import com.google.common.base.Preconditions;

/**
 * This class listens to below events and notifes whether InCallUI is visible to the user or not.
 * a. InCallActivity's lifecycle events (onStop/onStart)
 * b. Display state change events (DISPLAY_ON/DISPLAY_OFF)
 */
public class InCallUiStateNotifier implements DisplayManager.DisplayListener {

    private List<InCallUiStateNotifierListener> mInCallUiStateNotifierListeners =
            new CopyOnWriteArrayList<>();
    private static InCallUiStateNotifier sInCallUiStateNotifier;
    private DisplayManager mDisplayManager;
    private Context mContext;

    /**
     * Tracks whether the application is in the background. {@code True} if the application is in
     * the background, {@code false} otherwise.
     */
    private boolean mIsInBackground;

    /**
     * Tracks whether display is ON/OFF. {@code True} if display is ON, {@code false} otherwise.
     */
    private boolean mIsDisplayOn;

    /**
     * Handles set up of the {@class InCallUiStateNotifier}. Instantiates the context needed by
     * the class and adds a listener to listen to display state changes.
     */
    public void setUp(Context context) {
        mContext = context;
        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
        mDisplayManager.registerDisplayListener(this, null);
        mIsDisplayOn = isDisplayOn(
                mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState());
        Log.d(this, "setUp mIsDisplayOn: " + mIsDisplayOn);
    }

    /**
     * Private constructor. Must use getInstance() to get this singleton.
     */
    private InCallUiStateNotifier() {
    }

    /**
     * This method returns a singleton instance of {@class InCallUiStateNotifier}
     */
    public static synchronized InCallUiStateNotifier getInstance() {
        if (sInCallUiStateNotifier == null) {
            sInCallUiStateNotifier = new InCallUiStateNotifier();
        }
        return sInCallUiStateNotifier;
    }

   /**
     * Adds a new {@link InCallUiStateNotifierListener}.
     *
     * @param listener The listener.
     */
    public void addListener(InCallUiStateNotifierListener listener) {
        Preconditions.checkNotNull(listener);
        mInCallUiStateNotifierListeners.add(listener);
    }

    /**
     * Remove a {@link InCallUiStateNotifierListener}.
     *
     * @param listener The listener.
     */
    public void removeListener(InCallUiStateNotifierListener listener) {
        if (listener != null) {
            mInCallUiStateNotifierListeners.remove(listener);
        } else {
            Log.e(this, "Can't remove null listener");
        }
    }

    /**
     * Notfies when visibility of InCallUI is changed. For eg.
     * when UE moves in/out of the foreground, display either turns ON/OFF
     * @param showing true if InCallUI is visible, false  otherwise.
     */
    private void notifyOnUiShowing(boolean showing) {
        Preconditions.checkNotNull(mInCallUiStateNotifierListeners);
        for (InCallUiStateNotifierListener listener : mInCallUiStateNotifierListeners) {
            listener.onUiShowing(showing);
        }
    }

    /**
     * Handles tear down of the {@class InCallUiStateNotifier}. Sets the context to null and
     * unregisters it's display listener.
     */
    public void tearDown() {
        mDisplayManager.unregisterDisplayListener(this);
        mDisplayManager = null;
        mContext = null;
        mInCallUiStateNotifierListeners.clear();
    }

    /**
      * checks to see whether InCallUI experience is visible to the user or not.
      * returns true if InCallUI experience is visible to the user else false.
      */
    private boolean isUiShowing() {
        /* Not in background and display is ON does mean that InCallUI is visible/showing.
        Return true in such cases else false */
        return  !mIsInBackground && mIsDisplayOn;
    }

    /**
     * Checks whether the display is ON.
     *
     * @param displayState The display's current state.
     */
    public static boolean isDisplayOn(int displayState) {
        return displayState == Display.STATE_ON ||
                displayState == Display.STATE_DOZE ||
                displayState == Display.STATE_DOZE_SUSPEND;
    }

    /**
     * Called when UE goes in/out of the foreground.
     * @param showing true if UE is in the foreground, false otherwise.
     */
    public void onUiShowing(boolean showing) {

        //Check UI's old state before updating corresponding state variable(s)
        final boolean wasShowing = isUiShowing();

        mIsInBackground = !showing;

        //Check UI's new state after updating corresponding state variable(s)
        final boolean isShowing = isUiShowing();

        Log.d(this, "onUiShowing wasShowing: " + wasShowing + " isShowing: " + isShowing);
        //notify if there is a change in UI state
        if (wasShowing != isShowing) {
            notifyOnUiShowing(showing);
        }
    }

    /**
     * This method overrides onDisplayRemoved method of {@interface DisplayManager.DisplayListener}
     * Added for completeness. No implementation yet.
     */
    @Override
    public void onDisplayRemoved(int displayId) {
    }

    /**
     * This method overrides onDisplayAdded method of {@interface DisplayManager.DisplayListener}
     * Added for completeness. No implementation yet.
     */
    @Override
    public void onDisplayAdded(int displayId) {
    }

    /**
     * This method overrides onDisplayAdded method of {@interface DisplayManager.DisplayListener}
     * The method gets invoked whenever the properties of a logical display have changed.
     */
    @Override
    public void onDisplayChanged(int displayId) {
        final int displayState = mDisplayManager.getDisplay(displayId).getState();
        Log.d(this, "onDisplayChanged displayState: " + displayState +
                " displayId: " + displayId);

        /* Ignore display changed indications if they are received for displays
         * other than default display
         */
        if (displayId != Display.DEFAULT_DISPLAY) {
            Log.w(this, "onDisplayChanged Ignoring...");
            return;
        }

        //Check UI's old state before updating corresponding state variable(s)
        final boolean wasShowing = isUiShowing();

        mIsDisplayOn = isDisplayOn(displayState);

        //Check UI's new state after updating corresponding state variable(s)
        final boolean isShowing = isUiShowing();

        Log.d(this, "onDisplayChanged wasShowing: " + wasShowing + " isShowing: " + isShowing);
        //notify if there is a change in UI state
        if (wasShowing != isShowing) {
            notifyOnUiShowing(mIsDisplayOn);
        }
    }
}
+38 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2015, 2016, 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;

/**
 * Listener interface for any class that wants to be notified when
 * visibilitiy of InCallUI is changed. For eg. when UE moves in/out of the foreground,
 * display either turns ON/OFF
 */
public interface InCallUiStateNotifierListener {
    public void onUiShowing(boolean showing);
}
+46 −6
Original line number Original line Diff line number Diff line
@@ -68,7 +68,7 @@ import java.util.Objects;
public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements
public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements
        IncomingCallListener, InCallOrientationListener, InCallStateListener,
        IncomingCallListener, InCallOrientationListener, InCallStateListener,
        InCallDetailsListener, SurfaceChangeListener, VideoEventListener,
        InCallDetailsListener, SurfaceChangeListener, VideoEventListener,
        InCallPresenter.InCallEventListener {
        InCallPresenter.InCallEventListener, InCallUiStateNotifierListener {
    public static final String TAG = "VideoCallPresenter";
    public static final String TAG = "VideoCallPresenter";


    public static final boolean DEBUG = false;
    public static final boolean DEBUG = false;
@@ -190,6 +190,10 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
     */
     */
    private int mAutoFullscreenTimeoutMillis = 0;
    private int mAutoFullscreenTimeoutMillis = 0;


    /**
     *Caches information about whether InCall UI is in the background or foreground
     */
    private boolean mIsInBackground;
    /**
    /**
     * Determines if the countdown is currently running to automatically enter full screen video
     * Determines if the countdown is currently running to automatically enter full screen video
     * mode.
     * mode.
@@ -240,6 +244,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
        // Register for surface and video events from {@link InCallVideoCallListener}s.
        // Register for surface and video events from {@link InCallVideoCallListener}s.
        InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this);
        InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this);
        InCallVideoCallCallbackNotifier.getInstance().addVideoEventListener(this);
        InCallVideoCallCallbackNotifier.getInstance().addVideoEventListener(this);
        InCallUiStateNotifier.getInstance().addListener(this);
        mCurrentVideoState = VideoProfile.STATE_AUDIO_ONLY;
        mCurrentVideoState = VideoProfile.STATE_AUDIO_ONLY;
        mCurrentCallState = Call.State.INVALID;
        mCurrentCallState = Call.State.INVALID;


@@ -270,6 +275,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi


        InCallVideoCallCallbackNotifier.getInstance().removeSurfaceChangeListener(this);
        InCallVideoCallCallbackNotifier.getInstance().removeSurfaceChangeListener(this);
        InCallVideoCallCallbackNotifier.getInstance().removeVideoEventListener(this);
        InCallVideoCallCallbackNotifier.getInstance().removeVideoEventListener(this);
        InCallUiStateNotifier.getInstance().removeListener(this);
    }
    }


    /**
    /**
@@ -295,8 +301,8 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
            if (mPreviewSurfaceState == PreviewSurfaceState.CAPABILITIES_RECEIVED) {
            if (mPreviewSurfaceState == PreviewSurfaceState.CAPABILITIES_RECEIVED) {
                mPreviewSurfaceState = PreviewSurfaceState.SURFACE_SET;
                mPreviewSurfaceState = PreviewSurfaceState.SURFACE_SET;
                mVideoCall.setPreviewSurface(ui.getPreviewVideoSurface());
                mVideoCall.setPreviewSurface(ui.getPreviewVideoSurface());
            } else if (mPreviewSurfaceState == PreviewSurfaceState.NONE && isCameraRequired()){
            } else {
                enableCamera(mVideoCall, true);
                maybeEnableCamera();
            }
            }
        } else if (surface == VideoCallFragment.SURFACE_DISPLAY) {
        } else if (surface == VideoCallFragment.SURFACE_DISPLAY) {
            mVideoCall.setDisplaySurface(ui.getDisplayVideoSurface());
            mVideoCall.setDisplaySurface(ui.getDisplayVideoSurface());
@@ -670,9 +676,9 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
        }
        }
    }
    }


    private static boolean isCameraRequired(int videoState) {
    private boolean isCameraRequired(int videoState) {
        return VideoProfile.isBidirectional(videoState) ||
        return ((VideoProfile.isBidirectional(videoState) ||
                VideoProfile.isTransmissionEnabled(videoState);
                VideoProfile.isTransmissionEnabled(videoState)) && !mIsInBackground);
    }
    }


    private boolean isCameraRequired() {
    private boolean isCameraRequired() {
@@ -826,6 +832,40 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
        return VideoProfile.isTransmissionEnabled(videoState);
        return VideoProfile.isTransmissionEnabled(videoState);
    }
    }


    /**
     * Opens camera if the camera has not yet been set on the {@link VideoCall}; negotiation has
     * not yet started and if camera is required
     */
    private void maybeEnableCamera() {
        if (mPreviewSurfaceState == PreviewSurfaceState.NONE && isCameraRequired()) {
            enableCamera(mVideoCall, true);
        }
    }

    /**
     * This method gets invoked when visibility of InCallUI is changed. For eg.
     * when UE moves in/out of the foreground, display either turns ON/OFF
     * @param showing true if InCallUI is visible, false  otherwise.
     */
    @Override
    public void onUiShowing(boolean showing) {
        Log.d(this, "onUiShowing, showing = " + showing + " mPrimaryCall = " + mPrimaryCall +
                " mPreviewSurfaceState = " + mPreviewSurfaceState);

        mIsInBackground = !showing;

        if (mPrimaryCall == null || !VideoUtils.isActiveVideoCall(mPrimaryCall)) {
            Log.w(this, "onUiShowing, received for non-active video call");
            return;
        }

        if (showing) {
            maybeEnableCamera();
        } else if (mPreviewSurfaceState != PreviewSurfaceState.NONE) {
            enableCamera(mVideoCall, false);
        }
    }

    /**
    /**
     * Handles peer video pause state changes.
     * Handles peer video pause state changes.
     *
     *
+20 −4
Original line number Original line Diff line number Diff line
@@ -29,8 +29,9 @@ import android.telecom.VideoProfile;
 * This class is responsible for generating video pause/resume requests when the InCall UI is sent
 * This class is responsible for generating video pause/resume requests when the InCall UI is sent
 * to the background and subsequently brought back to the foreground.
 * to the background and subsequently brought back to the foreground.
 */
 */
class VideoPauseController implements InCallStateListener, IncomingCallListener {
class VideoPauseController implements InCallStateListener, IncomingCallListener,
    private static final String TAG = "VideoPauseController";
        InCallUiStateNotifierListener {
    private static final String TAG = "VideoPauseController:";


    /**
    /**
     * Keeps track of the current active/foreground call.
     * Keeps track of the current active/foreground call.
@@ -106,6 +107,7 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener
        mInCallPresenter = Preconditions.checkNotNull(inCallPresenter);
        mInCallPresenter = Preconditions.checkNotNull(inCallPresenter);
        mInCallPresenter.addListener(this);
        mInCallPresenter.addListener(this);
        mInCallPresenter.addIncomingCallListener(this);
        mInCallPresenter.addIncomingCallListener(this);
        InCallUiStateNotifier.getInstance().addListener(this);
    }
    }


    /**
    /**
@@ -114,6 +116,7 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener
     */
     */
    public void tearDown() {
    public void tearDown() {
        log("tearDown...");
        log("tearDown...");
        InCallUiStateNotifier.getInstance().removeListener(this);
        mInCallPresenter.removeListener(this);
        mInCallPresenter.removeListener(this);
        mInCallPresenter.removeIncomingCallListener(this);
        mInCallPresenter.removeIncomingCallListener(this);
        clear();
        clear();
@@ -242,10 +245,13 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener
    }
    }


    /**
    /**
     * Called when UI goes in/out of the foreground.
     * This method gets invoked when visibility of InCallUI is changed. For eg.
     * @param showing true if UI is in the foreground, false otherwise.
     * when UE moves in/out of the foreground, display either turns ON/OFF
     * @param showing true if InCallUI is visible, false  otherwise.
     */
     */
    @Override
    public void onUiShowing(boolean showing) {
    public void onUiShowing(boolean showing) {
        log("onUiShowing, showing = " + showing);
        // Only send pause/unpause requests if we are in the INCALL state.
        // Only send pause/unpause requests if we are in the INCALL state.
        if (mInCallPresenter == null) {
        if (mInCallPresenter == null) {
            return;
            return;
@@ -266,6 +272,11 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener
    private void onResume(boolean isInCall) {
    private void onResume(boolean isInCall) {
        log("onResume");
        log("onResume");


        if (!mIsInBackground) {
            log("onResume, Ignoring... already resumed");
            return;
        }

        mIsInBackground = false;
        mIsInBackground = false;
        if (canVideoPause(mPrimaryCallContext) && isInCall) {
        if (canVideoPause(mPrimaryCallContext) && isInCall) {
            sendRequest(mPrimaryCallContext.getCall(), true);
            sendRequest(mPrimaryCallContext.getCall(), true);
@@ -282,6 +293,11 @@ class VideoPauseController implements InCallStateListener, IncomingCallListener
    private void onPause(boolean isInCall) {
    private void onPause(boolean isInCall) {
        log("onPause");
        log("onPause");


        if (mIsInBackground) {
            log("onPause, Ignoring... already paused");
            return;
        }

        mIsInBackground = true;
        mIsInBackground = true;
        if (canVideoPause(mPrimaryCallContext) && isInCall) {
        if (canVideoPause(mPrimaryCallContext) && isInCall) {
            sendRequest(mPrimaryCallContext.getCall(), false);
            sendRequest(mPrimaryCallContext.getCall(), false);