boolean displayInAppMessage(IInAppMessage inAppMessage, boolean isCarryOver) {
    // Note:  for mDisplayingInAppMessage to be accurate it requires this method does not exit
    // anywhere but the at the end
    // of this try/catch when we know whether we are successfully displaying the IAM or not.
    if (!mDisplayingInAppMessage.compareAndSet(false, true)) {
      AppboyLogger.d(
          TAG,
          "A in-app message is currently being displayed.  Adding in-app message back on the stack.");
      mInAppMessageStack.push(inAppMessage);
      return false;
    }

    try {
      if (mActivity == null) {
        mCarryoverInAppMessage = inAppMessage;
        throw new Exception(
            "No activity is currently registered to receive in-app messages. Registering in-app message as carry-over "
                + "in-app message. It will automatically be displayed when the next activity registers to receive in-app messages.");
      }
      if (!isCarryOver) {
        long inAppMessageExpirationTimestamp = inAppMessage.getExpirationTimestamp();
        if (inAppMessageExpirationTimestamp > 0) {
          long currentTimeMillis = System.currentTimeMillis();
          if (currentTimeMillis > inAppMessageExpirationTimestamp) {
            throw new Exception(
                String.format(
                    "In-app message is expired. Doing nothing. Expiration: $%d. Current time: %d",
                    inAppMessageExpirationTimestamp, currentTimeMillis));
          }
        } else {
          AppboyLogger.d(TAG, "Expiration timestamp not defined. Continuing.");
        }
      } else {
        AppboyLogger.d(TAG, "Not checking expiration status for carry-over in-app message.");
      }
      if (!verifyOrientationStatus(inAppMessage)) {
        throw new Exception(
            "Current orientation did not match specified orientation for in-app message. Doing nothing.");
      }
      IInAppMessageViewFactory inAppMessageViewFactory = getInAppMessageViewFactory(inAppMessage);
      if (inAppMessageViewFactory == null) {
        throw new Exception("ViewFactory from getInAppMessageViewFactory was null.");
      }
      final View inAppMessageView =
          inAppMessageViewFactory.createInAppMessageView(mActivity, inAppMessage);

      if (inAppMessageView == null) {
        throw new Exception(
            "The in-app message view returned from the IInAppMessageViewFactory was null. The in-app message will "
                + "not be displayed and will not be put back on the stack.");
      }

      if (inAppMessageView.getParent() != null) {
        throw new Exception(
            "The in-app message view returned from the IInAppMessageViewFactory already has a parent. This "
                + "is a sign that the view is being reused. The IInAppMessageViewFactory method createInAppMessageView"
                + "must return a new view without a parent. The in-app message will not be displayed and will not "
                + "be put back on the stack.");
      }

      Animation openingAnimation =
          getInAppMessageAnimationFactory().getOpeningAnimation(inAppMessage);
      Animation closingAnimation =
          getInAppMessageAnimationFactory().getClosingAnimation(inAppMessage);

      if (inAppMessageView instanceof IInAppMessageImmersiveView) {
        AppboyLogger.d(TAG, "Creating view wrapper for immersive in-app message.");
        IInAppMessageImmersiveView inAppMessageViewImmersive =
            (IInAppMessageImmersiveView) inAppMessageView;
        mInAppMessageViewWrapper =
            new InAppMessageViewWrapper(
                inAppMessageView,
                inAppMessage,
                mInAppMessageViewLifecycleListener,
                openingAnimation,
                closingAnimation,
                inAppMessageViewImmersive.getMessageClickableView(),
                inAppMessageViewImmersive.getMessageButtonViews(),
                inAppMessageViewImmersive.getMessageCloseButtonView());
      } else if (inAppMessageView instanceof IInAppMessageView) {
        AppboyLogger.d(TAG, "Creating view wrapper for base in-app message.");
        IInAppMessageView inAppMessageViewBase = (IInAppMessageView) inAppMessageView;
        mInAppMessageViewWrapper =
            new InAppMessageViewWrapper(
                inAppMessageView,
                inAppMessage,
                mInAppMessageViewLifecycleListener,
                openingAnimation,
                closingAnimation,
                inAppMessageViewBase.getMessageClickableView());
      } else {
        AppboyLogger.d(TAG, "Creating view wrapper for in-app message.");
        mInAppMessageViewWrapper =
            new InAppMessageViewWrapper(
                inAppMessageView,
                inAppMessage,
                mInAppMessageViewLifecycleListener,
                openingAnimation,
                closingAnimation,
                inAppMessageView);
      }
      mInAppMessageViewWrapper.open(mActivity);
      return true;
    } catch (Exception e) {
      AppboyLogger.e(TAG, "Could not display in-app message", e);
      resetAfterInAppMessageClose();
      return false;
    }
  }