/**
  * For in-app messages that have a preferred orientation, locks the screen orientation and returns
  * true if the screen is currently in the preferred orientation. If the screen is not currently in
  * the preferred orientation, returns false.
  *
  * <p>Always returns true for tablets, regardless of current orientation.
  *
  * <p>Always returns true if the in-app message doesn't have a preferred orientation.
  *
  * @param inAppMessage
  * @return
  */
 boolean verifyOrientationStatus(IInAppMessage inAppMessage) {
   if (ViewUtils.isRunningOnTablet(mActivity)) {
     AppboyLogger.d(TAG, "Running on tablet. In-app message can be displayed in any orientation.");
     return true;
   }
   Orientation preferredOrientation = inAppMessage.getOrientation();
   if (preferredOrientation == null) {
     AppboyLogger.d(
         TAG, "No orientation specified. In-app message can be displayed in any orientation.");
     return true;
   }
   if (preferredOrientation == Orientation.ANY) {
     AppboyLogger.d(
         TAG, "Any orientation specified. In-app message can be displayed in any orientation.");
     return true;
   }
   int currentScreenOrientation = mActivity.getResources().getConfiguration().orientation;
   if (currentOrientationIsValid(currentScreenOrientation, preferredOrientation)) {
     if (mOriginalOrientation == null) {
       AppboyLogger.d(TAG, "Requesting orientation lock.");
       mOriginalOrientation = mActivity.getRequestedOrientation();
       mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
     }
     return true;
   }
   return false;
 }
 /**
  * Hides any currently displaying in-app message.
  *
  * @deprecated Use {@link #hideCurrentlyDisplayingInAppMessage(boolean)}
  * @param animate whether to animate the message out of view. Note that in-app message animation
  *     is configurable on the in-app message model itself and should be configured there instead.
  * @param dismissed whether the message was dismissed by the user. If dismissed is true,
  *     IInAppMessageViewLifecycleListener.onDismissed() will be called on the current
  *     IInAppMessageViewLifecycleListener.
  */
 @Deprecated
 public void hideCurrentInAppMessage(boolean animate, boolean dismissed) {
   IInAppMessageViewWrapper inAppMessageWrapperView = mInAppMessageViewWrapper;
   if (inAppMessageWrapperView != null) {
     IInAppMessage inAppMessage = inAppMessageWrapperView.getInAppMessage();
     if (inAppMessage != null) {
       inAppMessage.setAnimateOut(animate);
     }
     hideCurrentlyDisplayingInAppMessage(dismissed);
   }
 }
  /**
   * Registers the in-app message manager, which will listen to and display incoming in-app
   * messages. The current Activity is required in order to properly inflate and display the in-app
   * message view.
   *
   * <p>Important note: Every Activity must call registerInAppMessageManager in the onResume
   * lifecycle method, otherwise in-app messages may be lost!
   *
   * @param activity The current Activity.
   */
  public void registerInAppMessageManager(Activity activity) {
    AppboyLogger.d(TAG, "registerInAppMessageManager called");
    // We need the current Activity so that we can inflate or programmatically create the in-app
    // message
    // View for each Activity. We cannot share the View because doing so would create a memory leak.
    mActivity = activity;
    if (mActivity != null && mApplicationContext == null) {
      // Note, because the IAMManager is a singleton and doesn't have any dependencies passed in,
      // we cache the application context here because it's not available (as it normally would be
      // from Appboy initialization).
      mApplicationContext = mActivity.getApplicationContext();
    }

    // We have a special check to see if the host app switched to a different Activity (or recreated
    // the same Activity during an orientation change) so that we can redisplay the in-app message.
    if (mCarryoverInAppMessage != null) {
      AppboyLogger.d(TAG, "Requesting display of carryover in-app message.");
      mCarryoverInAppMessage.setAnimateIn(false);
      displayInAppMessage(mCarryoverInAppMessage, true);
      mCarryoverInAppMessage = null;
    } else if (mUnRegisteredInAppMessage != null) {
      AppboyLogger.d(TAG, "Adding previously unregistered in-app message.");
      addInAppMessage(mUnRegisteredInAppMessage);
      mUnRegisteredInAppMessage = null;
    }

    ensureSubscribedToInAppMessageEvents(mApplicationContext);
  }
  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;
    }
  }