diff --git a/akka-bbb-apps/src/main/resources/application.conf b/akka-bbb-apps/src/main/resources/application.conf
index 826aa0ec080f07aec5e533450f583ceae2a19886..c77900571b3c2ebf2aba7339ede3c79cd2d5a7a3 100755
--- a/akka-bbb-apps/src/main/resources/application.conf
+++ b/akka-bbb-apps/src/main/resources/application.conf
@@ -90,4 +90,9 @@ voiceConf {
 
 recording {
   chapterBreakLengthInMinutes = 180
+}
+
+inactivityAudit {
+  timer = 120
+  responseDuration = 5
 }
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
index e047984436b90e0bd2719adf0f5acd611c38c289..0d9346271334f352849ccf68a4e5f39ff0c96134 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
@@ -21,8 +21,8 @@ trait SystemConfiguration {
   lazy val red5DeskShareIP = Try(config.getString("red5.deskshareip")).getOrElse("127.0.0.1")
   lazy val red5DeskShareApp = Try(config.getString("red5.deskshareapp")).getOrElse("")
 
-  lazy val inactivityDeadline = Try(config.getInt("inactivity.deadline")).getOrElse(2 * 3600) // 2 hours
-  lazy val inactivityTimeLeft = Try(config.getInt("inactivity.timeLeft")).getOrElse(5 * 60) // 5 minutes
+  lazy val userInactivityAuditTimer = Try(config.getInt("inactivityAudit.timer")).getOrElse(120) // 2 hours
+  lazy val userInactivityAuditResponseDuration = Try(config.getInt("inactivityAudit.responseDuration")).getOrElse(5) // 5 minutes
 
   lazy val expireLastUserLeft = Try(config.getInt("expire.lastUserLeft")).getOrElse(60) // 1 minute
   lazy val expireNeverJoined = Try(config.getInt("expire.neverJoined")).getOrElse(5 * 60) // 5 minutes
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserInactivityAuditResponseMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserInactivityAuditResponseMsgHdlr.scala
new file mode 100755
index 0000000000000000000000000000000000000000..d97f2a83985b15a0dfa4ed02043ffa9b4e8f52fb
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserInactivityAuditResponseMsgHdlr.scala
@@ -0,0 +1,17 @@
+package org.bigbluebutton.core.apps.users
+
+import org.bigbluebutton.common2.msgs.UserInactivityAuditResponseMsg
+import org.bigbluebutton.core.models.Users2x
+import org.bigbluebutton.core.running.MeetingActor
+
+trait UserInactivityAuditResponseMsgHdlr {
+  this: MeetingActor =>
+
+  def handleUserInactivityAuditResponseMsg(msg: UserInactivityAuditResponseMsg): Unit = {
+    for {
+      user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
+    } yield {
+      Users2x.updateInactivityResponse(liveMeeting.users2x, user)
+    }
+  }
+}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala
index a67d2c3876c2b3e8777b8303ab968d734da84497..ff12fe2043ab5725d6b6efbf4f5718754065d980 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.models
 
 import com.softwaremill.quicklens._
+import org.bigbluebutton.core.util.TimeUtil
 
 object Users2x {
   def findWithIntId(users: Users2x, intId: String): Option[UserState] = {
@@ -26,6 +27,12 @@ object Users2x {
     users.toVector.filter(u => !u.presenter)
   }
 
+  def updateInactivityResponse(users: Users2x, u: UserState): UserState = {
+    val newUserState = modify(u)(_.inactivityResponseOn).setTo(TimeUtil.timeNowInMs())
+    users.save(newUserState)
+    newUserState
+  }
+
   def changeRole(users: Users2x, u: UserState, newRole: String): UserState = {
     val newUserState = modify(u)(_.role).setTo(newRole).modify(_.roleChangedOn).setTo(System.currentTimeMillis())
     users.save(newUserState)
@@ -204,7 +211,9 @@ case class OldPresenter(userId: String, changedPresenterOn: Long)
 
 case class UserState(intId: String, extId: String, name: String, role: String,
                      guest: Boolean, authed: Boolean, guestStatus: String, emoji: String, locked: Boolean,
-                     presenter: Boolean, avatar: String, roleChangedOn: Long = System.currentTimeMillis())
+                     presenter: Boolean, avatar: String,
+                     roleChangedOn:        Long = System.currentTimeMillis(),
+                     inactivityResponseOn: Long = TimeUtil.timeNowInMs())
 
 case class UserIdAndName(id: String, name: String)
 
@@ -232,4 +241,5 @@ object EjectReasonCode {
   val EJECT_USER = "user_requested_eject_reason"
   val SYSTEM_EJECT_USER = "system_requested_eject_reason"
   val VALIDATE_TOKEN = "validate_token_failed_eject_reason"
+  val USER_INACTIVITY = "user_inactivity_eject_reason"
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
index 24ddce2377e59b932825a2844521c93a7e39933f..e1645e8b00b1a84e13ea7a5683d5aba2a8c5c3ce 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
@@ -94,6 +94,8 @@ class ReceivedJsonMsgHandlerActor(
         routeGenericMsg[RemoveUserFromPresenterGroupCmdMsg](envelope, jsonNode)
       case GetPresenterGroupReqMsg.NAME =>
         routeGenericMsg[GetPresenterGroupReqMsg](envelope, jsonNode)
+      case UserInactivityAuditResponseMsg.NAME =>
+        routeGenericMsg[UserInactivityAuditResponseMsg](envelope, jsonNode)
 
       // Poll
       case StartCustomPollReqMsg.NAME =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
index bd686d3636ad4c2cbe0d4c8fbf4369f7e147c65f..00a97f8517b88aa6c68ff20d2f23fc85d066bcf0 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
@@ -4,6 +4,7 @@ import java.io.{ PrintWriter, StringWriter }
 
 import akka.actor._
 import akka.actor.SupervisorStrategy.Resume
+import org.bigbluebutton.SystemConfiguration
 import org.bigbluebutton.core.apps.groupchats.{ GroupChatApp, GroupChatHdlrs }
 import org.bigbluebutton.core.apps.presentationpod._
 import org.bigbluebutton.core.apps.users._
@@ -34,7 +35,7 @@ import scala.concurrent.duration._
 import org.bigbluebutton.core.apps.layout.LayoutApp2x
 import org.bigbluebutton.core.apps.meeting.{ SyncGetMeetingInfoRespMsgHdlr, ValidateConnAuthTokenSysMsgHdlr }
 import org.bigbluebutton.core.apps.users.ChangeLockSettingsInMeetingCmdMsgHdlr
-import org.bigbluebutton.core2.message.senders.MsgBuilder
+import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
 import org.bigbluebutton.core2.testdata.FakeTestData
 
 object MeetingActor {
@@ -54,6 +55,7 @@ class MeetingActor(
   val liveMeeting: LiveMeeting
 )
     extends BaseMeetingActor
+    with SystemConfiguration
     with GuestsApp
     with LayoutApp2x
     with VoiceApp2x
@@ -78,7 +80,8 @@ class MeetingActor(
     with ChangeLockSettingsInMeetingCmdMsgHdlr
     with SyncGetMeetingInfoRespMsgHdlr
     with ClientToServerLatencyTracerMsgHdlr
-    with ValidateConnAuthTokenSysMsgHdlr {
+    with ValidateConnAuthTokenSysMsgHdlr
+    with UserInactivityAuditResponseMsgHdlr {
 
   override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
     case e: Exception => {
@@ -165,11 +168,11 @@ class MeetingActor(
   // Set webcamsOnlyForModerator property in case we didn't after meeting creation
   MeetingStatus2x.setWebcamsOnlyForModerator(liveMeeting.status, liveMeeting.props.usersProp.webcamsOnlyForModerator)
 
-  /*******************************************************************/
+  /** *****************************************************************/
   // Helper to create fake users for testing (ralam jan 5, 2018)
   //object FakeTestData extends FakeTestData
   //FakeTestData.createFakeUsers(liveMeeting)
-  /*******************************************************************/
+  /** *****************************************************************/
 
   def receive = {
     //=============================
@@ -347,6 +350,8 @@ class MeetingActor(
 
       case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
 
+      case m: UserInactivityAuditResponseMsg => handleUserInactivityAuditResponseMsg(m)
+
       case _ => log.warning("***** Cannot handle " + msg.envelope.name)
     }
   }
@@ -409,6 +414,8 @@ class MeetingActor(
 
     sendRttTraceTest()
     setRecordingChapterBreak()
+
+    processUserInactivityAudit()
   }
 
   var lastRecBreakSentOn = expiryTracker.startedOnInMs
@@ -502,7 +509,49 @@ class MeetingActor(
         "system", MeetingStatus2x.isRecording(liveMeeting.status)
       )
       outGW.send(event)
+    }
+  }
+
+  var lastUserInactivitySentOn = TimeUtil.timeNowInMs()
+  var checkInactiveUsers = false
+
+  def processUserInactivityAudit(): Unit = {
+    val now = TimeUtil.timeNowInMs()
+    val auditTimerMs = TimeUtil.minutesToMillis(userInactivityAuditTimer)
+    if (now - lastUserInactivitySentOn > auditTimerMs) {
+      lastUserInactivitySentOn = now
+      checkInactiveUsers = true
+      val event = buildUserInactivityAuditMsg(liveMeeting.props.meetingProp.intId)
+      outGW.send(event)
+    }
 
+    val auditResponseMs = TimeUtil.minutesToMillis(userInactivityAuditResponseDuration)
+    if (checkInactiveUsers && now - lastUserInactivitySentOn > auditResponseMs) {
+      checkInactiveUsers = false
+      checkForInactiveUsers()
     }
   }
+
+  def checkForInactiveUsers(): Unit = {
+    val auditResponseMs = TimeUtil.minutesToMillis(userInactivityAuditResponseDuration)
+    val users = Users2x.findAll(liveMeeting.users2x)
+    users foreach { u =>
+      val respondedOntIme = lastUserInactivitySentOn < u.inactivityResponseOn && (lastUserInactivitySentOn + auditResponseMs) > u.inactivityResponseOn
+      if (!respondedOntIme) {
+        UsersApp.ejectUserFromMeeting(outGW, liveMeeting, u.intId, SystemUser.ID, "User inactive for too long.", EjectReasonCode.USER_INACTIVITY)
+        Sender.sendDisconnectClientSysMsg(liveMeeting.props.meetingProp.intId, u.intId, SystemUser.ID, EjectReasonCode.USER_INACTIVITY, outGW)
+      }
+    }
+  }
+
+  def buildUserInactivityAuditMsg(meetingId: String): BbbCommonEnvCoreMsg = {
+    val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "system")
+    val envelope = BbbCoreEnvelope(UserInactivityAuditMsg.NAME, routing)
+    val body = UserInactivityAuditMsgBody(meetingId, TimeUtil.minutesToSeconds(userInactivityAuditResponseDuration))
+    val header = BbbClientMsgHeader(UserInactivityAuditMsg.NAME, meetingId, "system")
+    val event = UserInactivityAuditMsg(header, body)
+
+    BbbCommonEnvCoreMsg(envelope, event)
+  }
+
 }
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/AllowedMessageNames.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/AllowedMessageNames.scala
index 6b322b5b34aca966b5a0fb93196f0a39a57754ff..07dac9fb098eefcc6d4600e8986b9d8d9712f6eb 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/AllowedMessageNames.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/AllowedMessageNames.scala
@@ -34,6 +34,7 @@ object AllowedMessageNames {
       GetGuestPolicyReqMsg.NAME,
       SetGuestPolicyCmdMsg.NAME,
       GuestsWaitingApprovedMsg.NAME,
+      UserInactivityAuditResponseMsg.NAME,
 
       // Webcams
       GetWebcamsOnlyForModeratorReqMsg.NAME,
diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala
index 00fdc483958f309d3860de29fa4edbdad80aed47..3abf0819f0f8efd36f4a8d4e6bd57b7c5ea8da01 100755
--- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala
+++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala
@@ -358,3 +358,12 @@ case class GetPresenterGroupReqMsgBody(requesterId: String)
 object GetPresenterGroupRespMsg { val NAME = "GetPresenterGroupRespMsg" }
 case class GetPresenterGroupRespMsg(header: BbbClientMsgHeader, body: GetPresenterGroupRespMsgBody) extends StandardMsg
 case class GetPresenterGroupRespMsgBody(presenterGroup: Vector[String], requesterId: String)
+
+
+object UserInactivityAuditMsg { val NAME = "UserInactivityAuditMsg" }
+case class UserInactivityAuditMsg(header: BbbClientMsgHeader, body: UserInactivityAuditMsgBody) extends StandardMsg
+case class UserInactivityAuditMsgBody(meetingId: String, responseDuration: Long)
+
+object UserInactivityAuditResponseMsg { val NAME = "UserInactivityAuditResponseMsg" }
+case class UserInactivityAuditResponseMsg(header: BbbClientMsgHeader, body: UserInactivityAuditResponseMsgBody) extends StandardMsg
+case class UserInactivityAuditResponseMsgBody(userId: String)
diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties
index b2f2698e37c54fd5fb18cb6c3c2421516c3db387..0651c28fd2b9b8aaedfe16a28fc3062a57c3e390 100755
--- a/bigbluebutton-client/locale/en_US/bbbResources.properties
+++ b/bigbluebutton-client/locale/en_US/bbbResources.properties
@@ -94,6 +94,9 @@ bbb.inactivityWarning.title = No activity detected
 bbb.inactivityWarning.message = This meeting seems to be inactive. Automatically shutting it down...
 bbb.shuttingDown.message = This meeting is being closed due to inactivity
 bbb.inactivityWarning.cancel = Cancel
+bbb.userInactivityAudit.title = User activity check
+bbb.userInactivityAudit.message = Check if user is still in meeting
+bbb.userInactive.message = User is not in meeting. Ejecting.
 bbb.mainToolbar.helpBtn = Help
 bbb.mainToolbar.logoutBtn = Logout
 bbb.mainToolbar.logoutBtn.toolTip = Log Out
@@ -551,6 +554,7 @@ bbb.logout.breakoutRoomClose = Your browser window will be closed
 bbb.logout.duplicateUserEjectReason = Duplicate user trying to join meeting.
 bbb.logout.permissionEjectReason = Ejected due to permission violation.
 bbb.logout.validateTokenFailedEjectReason = Failed to validate authorization token.
+bbb.logout.userInactivityEjectReason = User inactive for too long.
 bbb.logout.ejectedFromMeeting = You have been removed from the meeting.
 bbb.logout.refresh.message = If this logout was unexpected click the button below to reconnect.
 bbb.logout.refresh.label = Reconnect
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
index 13d252a0b76db72af80a872c424ff7aa3f0a3893..f2bb00e2faa570917b0f944ae03a5923b1da38f8 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
@@ -69,6 +69,9 @@ package org.bigbluebutton.main.events {
 
 		public static const CANCEL_RECONNECTION_EVENT:String = "CANCEL_RECONNECTION_EVENT";
 		public static const WEBRTC_MONITOR_UPDATE_EVENT:String = "WEBRTC_MONITOR_UPDATE_EVENT";
+		
+		public static const USER_INACTIVITY_AUDIT_EVENT:String = "user_inactivity_audit_event";
+		public static const USER_INACTIVITY_AUDIT_RESPONSE_EVENT:String = "user_inactivity_audit_response_event";
 
 		public var message:String;
 		public var payload:Object = new Object();
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
index 6b5b4e4e622178cc58cfad7f049d69b9297af593..970ac101fa15c831c0b5e9fbd4c203f0fcf4239d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
@@ -188,6 +188,10 @@ package org.bigbluebutton.main.model.users
 			sender.activityResponse();
 		}
 		
+		public function userInactivityAuditResponse():void {
+			sender.userInactivityAuditResponse();
+		}
+		
 		private function queryForRecordingStatus():void {
 			sender.queryForRecordingStatus();
 		}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
index 27312f91a2e91a1df6066f104040a6d6e1ca2a8d..c5d3aea7f4c1363cca1d0c10c825f6e21a3600f6 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
@@ -126,6 +126,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 							message = ResourceUtil.getInstance().getString('bbb.logout.ejectedFromMeeting');
 						} else if (reasonCode == "validate_token_failed_eject_reason") {
 							message = ResourceUtil.getInstance().getString('bbb.logout.validateTokenFailedEjectReason');
+						} else if (reasonCode == "user_inactivity_eject_reason") {
+							message = ResourceUtil.getInstance().getString('bbb.logout.userInactivityEjectReason');
 						}
 						break;
 					case ConnectionFailedEvent.USER_LOGGED_OUT:
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
index b85a5cb8575f1c33139f2a4d23ab2977e586cd48..9eb9657ba7081c0e549e7cfc652446b62d6a2997 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
@@ -60,6 +60,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<mate:Listener type="{ShortcutEvent.OPEN_SHORTCUT_WIN}" method="openShortcutHelpWindow" />
 		<mate:Listener type="{BBBEvent.OPEN_WEBCAM_PREVIEW}" method="openVideoPreviewWindow" />
 		<mate:Listener type="{BBBEvent.INACTIVITY_WARNING_EVENT}" method="handleInactivityWarningEvent" />
+		<mate:Listener type="{BBBEvent.USER_INACTIVITY_AUDIT_EVENT}" method="handleUserInactivityAuditEvent" />
 		<mate:Listener type="{LockControlEvent.OPEN_LOCK_SETTINGS}" method="openLockSettingsWindow" />
 		<mate:Listener type="{BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL}" method="openBreakoutRoomsWindow" />
 		
@@ -131,7 +132,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.model.options.LanguageOptions;
 			import org.bigbluebutton.main.model.options.LayoutOptions;
 			import org.bigbluebutton.main.model.users.events.ConferenceCreatedEvent;
-			import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
 			import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent;
 			import org.bigbluebutton.modules.phone.events.FlashMicSettingsEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCCallEvent;
@@ -496,6 +496,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	   			mdiCanvas.addChild(e.component);
 	   		}
 	   		
+			private function handleUserInactivityAuditEvent(e:BBBEvent):void {
+				var inactivityWarning:UserInactivityAuditWindow = PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, 
+					UserInactivityAuditWindow, true) as UserInactivityAuditWindow;
+				inactivityWarning.duration = e.payload.duration;
+			}
+			
 			private function handleInactivityWarningEvent(e:BBBEvent):void {
 				var inactivityWarning:InactivityWarningWindow = PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, InactivityWarningWindow, true) as InactivityWarningWindow;
 				inactivityWarning.duration = e.payload.duration;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/UserInactivityAuditWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/UserInactivityAuditWindow.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..54ee5745f205e442581c5b9c865394759dc4b7c7
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/UserInactivityAuditWindow.mxml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<mx:Panel xmlns:mx="library://ns.adobe.com/flex/mx"
+		xmlns:fx="http://ns.adobe.com/mxml/2009"
+		xmlns:mate="http://mate.asfusion.com/"
+		verticalScrollPolicy="off"
+		horizontalScrollPolicy="off"
+		horizontalAlign="center"
+		width="500"
+		height="120"
+		styleName="inactivityWarningTextStyle"
+		title="{ResourceUtil.getInstance().getString('bbb.userInactivityAudit.title')}"
+		creationComplete="onCreationComplete()">
+
+	<fx:Script>
+	<![CDATA[
+		import com.asfusion.mate.events.Dispatcher;
+		
+		import mx.managers.PopUpManager;
+		
+		import org.as3commons.logging.api.ILogger;
+		import org.as3commons.logging.api.getClassLogger;
+		import org.bigbluebutton.main.events.BBBEvent;
+		import org.bigbluebutton.util.i18n.ResourceUtil;
+
+		private static const LOGGER:ILogger = getClassLogger(InactivityWarningWindow);
+
+		public var duration:Number = 0;
+		private var tickTimer:Timer;
+
+		[Bindable]
+		private var cancelButtonLabel:String = ResourceUtil.getInstance().getString('bbb.inactivityWarning.cancel');
+
+		private function onCreationComplete():void {
+			tickTimer = new Timer(1000, 0);
+			tickTimer.addEventListener(TimerEvent.TIMER, tick);
+
+			cancelButton.width = cancelButton.measureText(genCancelButtonLabel(duration)).width
+					+ cancelButton.getStyle("paddingRight")
+					+ cancelButton.getStyle("paddingLeft")
+					+ 8; // 8 is magic number
+
+			tickTimer.start();
+			cancelButton.label = ResourceUtil.getInstance().getString('bbb.inactivityWarning.cancel');
+			cancelButton.visible = true;
+		}
+
+		private function tick(e:TimerEvent):void {
+			if (duration > 0) {
+				warningMessage.text = genCancelButtonLabel(duration);
+				duration--;
+			} else {
+				tickTimer.stop();
+				cancelButton.visible = false;
+				cancelButton.includeInLayout = false;
+				warningMessage.text = ResourceUtil.getInstance().getString('bbb.userInactive.message');
+				PopUpManager.removePopUp(this);
+			}
+		}
+
+		private function genCancelButtonLabel(timeLeft:Number):String {
+			return ResourceUtil.getInstance().getString('bbb.userInactivityAudit.message') + " (" + timeLeft.toString() + ")";
+		}
+
+		private function cancelButtonClicked():void {
+			var dispatcher:Dispatcher = new Dispatcher();
+			var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.USER_INACTIVITY_AUDIT_RESPONSE_EVENT);
+			dispatcher.dispatchEvent(bbbEvent);
+			tickTimer.stop();
+			PopUpManager.removePopUp(this);
+		}
+	]]>
+	</fx:Script>
+	<mx:VBox width="100%" height="100%"  paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" horizontalAlign="center" verticalAlign="middle">
+		<mx:Text id="warningMessage" selectable="false" text="{ResourceUtil.getInstance().getString('bbb.userInactivityAudit.message')}" styleName="inactivityWarningTextStyle"/>
+		<mx:Button id="cancelButton" click="cancelButtonClicked()" visible="false" styleName="inactivityWarningWindowCancelButtonStyle"/>
+	</mx:VBox>
+</mx:Panel>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
index b7a4122612374e81793f1d5c5eef35676b29228c..e2a5f5d6b110babd1cf2bda5c81460f07c32f3a7 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
@@ -113,6 +113,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	  <EventHandlers type="{BBBEvent.ACTIVITY_RESPONSE_EVENT}">
 	    <MethodInvoker generator="{UserService}" method="activityResponse" />
 	  </EventHandlers>
+		
+		<EventHandlers type="{BBBEvent.USER_INACTIVITY_AUDIT_RESPONSE_EVENT}">
+			<MethodInvoker generator="{UserService}" method="userInactivityAuditResponse" />
+		</EventHandlers>
 
     <EventHandlers type="{TokenValidEvent.TOKEN_VALID_EVENT}" >
       <MethodInvoker generator="{UserService}" method="tokenValidEventHandler" arguments="{event}" />
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
index 3a9ef1465cc7402fae11d0843bbec8abd72acdf5..8297b2091d9fd9978e85323f18d6f04d998d6bf3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
@@ -205,9 +205,21 @@ package org.bigbluebutton.modules.users.services
         case "GetGuestsWaitingApprovalRespMsg":
           handleGetGuestsWaitingApprovalRespMsg(message);
           break;
+				case "UserInactivityAuditMsg":
+					handleUserInactivityAuditMsg(message);
+					break;
       }
     }
     
+		private function handleUserInactivityAuditMsg(msg: Object):void {
+			var header: Object = msg.header as Object;
+			var body: Object = msg.body as Object;
+			
+			var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.USER_INACTIVITY_AUDIT_EVENT);    
+			bbbEvent.payload.duration = body.responseDuration as Number;
+			globalDispatcher.dispatchEvent(bbbEvent);
+		}
+		
     private function handleUserJoinedVoiceConfToClientEvtMsg(msg: Object): void {
       var header: Object = msg.header as Object;
       var body: Object = msg.body as Object;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
index 4e5d030a454b57070659dbce154232df6ed5ec53..4a4d50226ecd273a0ad1c8150949b489275faa6c 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
@@ -321,6 +321,27 @@ package org.bigbluebutton.modules.users.services
         JSON.stringify(message)
       ); //_netConnection.call
     }
+		
+		public function userInactivityAuditResponse():void {
+			var message:Object = {
+				header: {name: "UserInactivityAuditResponseMsg", meetingId: UsersUtil.getInternalMeetingID(), 
+					userId: UsersUtil.getMyUserID()},
+				body: {userId: UsersUtil.getMyUserID()}
+			};
+			
+			var _nc:ConnectionManager = BBB.initConnectionManager();
+			_nc.sendMessage2x(
+				function(result:String):void { // On successful result
+				},
+				function(status:String):void { // status - On error occurred
+					var logData:Object = UsersUtil.initLogData();
+					logData.tags = ["apps"];
+					logData.message = "Error occured activity response.";
+					LOGGER.info(JSON.stringify(logData));
+				},
+				JSON.stringify(message)
+			); //_netConnection.call
+		}
 
     public function changeRecordingStatus(userID:String, recording:Boolean):void {
       var message:Object = {
diff --git a/clients/flash/air-client/src/css/hdpi.css b/clients/flash/air-client/src/css/hdpi.css
index 00d3df54134a071e4199082cf32a3a319654bd62..bcb7e8ae9cf860b0b8e3f40db9754338e100ec4f 100755
--- a/clients/flash/air-client/src/css/hdpi.css
+++ b/clients/flash/air-client/src/css/hdpi.css
@@ -73,7 +73,7 @@
         padding: 22.50;
     }
 
-    main|ExitView, main|DisconnectView {
+    main|ExitView, main|DisconnectView, main|UserInactivityView {
         gap: 22.50;
         padding: 22.50;
     }
diff --git a/clients/flash/air-client/src/css/ldpi.css b/clients/flash/air-client/src/css/ldpi.css
index 215ed93a288476636ea7aef722ed3d4b9f9407d7..2ac80b9964b2b448e76e85f9c2f0329e8c680bd7 100755
--- a/clients/flash/air-client/src/css/ldpi.css
+++ b/clients/flash/air-client/src/css/ldpi.css
@@ -73,7 +73,7 @@
         padding: 11.250;
     }
 
-    main|ExitView, main|DisconnectView {
+    main|ExitView, main|DisconnectView, main|UserInactivityView {
         gap: 11.250;
         padding: 11.250;
     }
diff --git a/clients/flash/air-client/src/css/mdpi.css b/clients/flash/air-client/src/css/mdpi.css
index a67a638ffe55b00004f17651753e7932a67275a2..aad476eca3eaf85b256b88817060bb3f4c6cccdd 100755
--- a/clients/flash/air-client/src/css/mdpi.css
+++ b/clients/flash/air-client/src/css/mdpi.css
@@ -73,7 +73,7 @@
         padding: 15.0;
     }
 
-    main|ExitView, main|DisconnectView {
+    main|ExitView, main|DisconnectView, main|UserInactivityView {
         gap: 15.0;
         padding: 15.0;
     }
diff --git a/clients/flash/air-client/src/css/xhdpi.css b/clients/flash/air-client/src/css/xhdpi.css
index 432547ca997e2f364836a97371daa0d3c59f10a4..c7c384c956b1be8bd58526a8748f98b6f0bb4c11 100755
--- a/clients/flash/air-client/src/css/xhdpi.css
+++ b/clients/flash/air-client/src/css/xhdpi.css
@@ -61,7 +61,7 @@
 		padding: 30;
 	}
 	
-	main|ExitView, main|DisconnectView {
+	main|ExitView, main|DisconnectView, main|UserInactivityView {
 		gap     : 30;
 		padding : 30;
 	}
diff --git a/clients/flash/air-client/src/css/xxhdpi.css b/clients/flash/air-client/src/css/xxhdpi.css
index 200a30d00df45c242c8e95286e972d0525a9eab4..a3261e654fba8b20a9664fe7c8e6a48a932c7c04 100755
--- a/clients/flash/air-client/src/css/xxhdpi.css
+++ b/clients/flash/air-client/src/css/xxhdpi.css
@@ -73,7 +73,7 @@
         padding: 45.0;
     }
 
-    main|ExitView, main|DisconnectView {
+    main|ExitView, main|DisconnectView, main|UserInactivityView {
         gap: 45.0;
         padding: 45.0;
     }
diff --git a/clients/flash/air-client/src/css/xxxhdpi.css b/clients/flash/air-client/src/css/xxxhdpi.css
index 24cf693ebcbd5018273ac19f146efc2f4344ea37..24d5b4896e5a972244765b8987b34c2bc2143278 100755
--- a/clients/flash/air-client/src/css/xxxhdpi.css
+++ b/clients/flash/air-client/src/css/xxxhdpi.css
@@ -73,7 +73,7 @@
         padding: 60;
     }
 
-    main|ExitView, main|DisconnectView {
+    main|ExitView, main|DisconnectView, main|UserInactivityView {
         gap: 60;
         padding: 60;
     }
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/AppConfig.as b/clients/flash/air-client/src/org/bigbluebutton/air/AppConfig.as
index 77a37a4149caedc05b1a1f39a70ee11cd33610b0..fee65edab4d6324ba150bad974f043309b586644 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/AppConfig.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/AppConfig.as
@@ -20,6 +20,10 @@ package org.bigbluebutton.air {
 	import org.bigbluebutton.air.main.commands.KickUserSignal;
 	import org.bigbluebutton.air.main.commands.LockUserCommand;
 	import org.bigbluebutton.air.main.commands.LockUserSignal;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerCommand;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerResponseCommand;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerResponseSignal;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerSignal;
 	import org.bigbluebutton.air.main.commands.PresenterCommand;
 	import org.bigbluebutton.air.main.commands.PresenterSignal;
 	import org.bigbluebutton.air.main.models.ConferenceParameters;
@@ -55,7 +59,7 @@ package org.bigbluebutton.air {
 	
 	import robotlegs.bender.extensions.signalCommandMap.api.ISignalCommandMap;
 	import robotlegs.bender.framework.api.IConfig;
-	import robotlegs.bender.framework.api.IInjector;
+	import robotlegs.bender.framework.api.IInjector;
 	
 	public class AppConfig implements IConfig {
 		
@@ -96,6 +100,8 @@ package org.bigbluebutton.air {
 			signalCommandMap.map(LockUserSignal).toCommand(LockUserCommand);
 			signalCommandMap.map(ChangeUserRoleSignal).toCommand(ChangeUserRoleCommand);
 			signalCommandMap.map(KickUserSignal).toCommand(KickUserCommand);
+			signalCommandMap.map(UserInactivityTimerSignal).toCommand(UserInactivityTimerCommand);
+			signalCommandMap.map(UserInactivityTimerResponseSignal).toCommand(UserInactivityTimerResponseCommand);
 		}
 	}
 }
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/common/PageEnum.as b/clients/flash/air-client/src/org/bigbluebutton/air/common/PageEnum.as
index 4aebce66290b93bb7b19d92aef8dd17c7c310ebb..cf2ba625d5c79d202d56105d5e12f218e3523db8 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/common/PageEnum.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/common/PageEnum.as
@@ -5,6 +5,7 @@ package org.bigbluebutton.air.common {
 	import org.bigbluebutton.air.chat.views.ChatRoomView;
 	import org.bigbluebutton.air.main.views.DisconnectView;
 	import org.bigbluebutton.air.main.views.ExitView;
+	import org.bigbluebutton.air.main.views.UserInactivityView;
 	import org.bigbluebutton.air.main.views.MainView;
 	import org.bigbluebutton.air.participants.views.ParticipantsView;
 	import org.bigbluebutton.air.settings.views.SettingsView;
@@ -14,7 +15,7 @@ package org.bigbluebutton.air.common {
 	import org.bigbluebutton.air.settings.views.lock.LockSettingsView;
 	import org.bigbluebutton.air.user.views.UserDetailsView;
 	import org.bigbluebutton.air.voice.views.EchoTestView;
-	import org.bigbluebutton.air.voice.views.JoinAudioView;
+	import org.bigbluebutton.air.voice.views.JoinAudioView;
 	
 	public class PageEnum {
 		public static const MAIN:String = "main";
@@ -49,6 +50,8 @@ package org.bigbluebutton.air.common {
 		
 		public static const APPLICATION_SETTINGS:String = "ApplicationSettings";
 		
+		public static const INACTIVITY_VIEW:String = "UserInactivityView";
+		
 		/**
 		 * Especials
 		 */
@@ -74,6 +77,7 @@ package org.bigbluebutton.air.common {
 				dic[DISCONNECT] = DisconnectView;
 				//		dic[DESKSHARE] = DeskshareView;
 				dic[EXIT] = ExitView;
+				dic[INACTIVITY_VIEW] = UserInactivityView;
 				dicInitiated = true;
 			}
 		}
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/MainConfig.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/MainConfig.as
index df6e1d56112e8065d9cbf330cc0823c5a4fefe0d..64261f1910dce99890b7df390a50d7c319d126c4 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/main/MainConfig.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/MainConfig.as
@@ -24,6 +24,8 @@ package org.bigbluebutton.air.main {
 	import org.bigbluebutton.air.main.views.PagesNavigatorViewMediator;
 	import org.bigbluebutton.air.main.views.TopToolbarBase;
 	import org.bigbluebutton.air.main.views.TopToolbarMediator;
+	import org.bigbluebutton.air.main.views.UserInactivityView;
+	import org.bigbluebutton.air.main.views.UserInactivityViewMediator;
 	
 	import robotlegs.bender.extensions.matching.TypeMatcher;
 	import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
@@ -62,6 +64,7 @@ package org.bigbluebutton.air.main {
 			mediatorMap.map(ExitView).toMediator(ExitViewMediator);
 			mediatorMap.map(DisconnectView).toMediator(DisconnectViewMediator);
 			mediatorMap.map(MainView).toMediator(MainViewMediator);
+			mediatorMap.map(UserInactivityView).toMediator(UserInactivityViewMediator);
 		}
 		
 		/**
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerCommand.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerCommand.as
new file mode 100755
index 0000000000000000000000000000000000000000..71ccee1c971403f1b132de357345c6c95067bee2
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerCommand.as
@@ -0,0 +1,21 @@
+package org.bigbluebutton.air.main.commands
+{
+	import org.bigbluebutton.air.common.PageEnum;
+	import org.bigbluebutton.air.main.models.IUISession;
+	
+	import robotlegs.bender.bundles.mvcs.Command;
+	
+	public class UserInactivityTimerCommand extends Command
+	{
+		[Inject]
+		public var uiSession:IUISession
+		
+		[Inject]
+		public var responseDuration: Number
+		
+		override public function execute():void {
+			trace("RECEIVED INACTIVITY TIMER MESSAGE responseDuration=" + responseDuration);
+			uiSession.pushPage(PageEnum.INACTIVITY_VIEW);
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseCommand.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseCommand.as
new file mode 100755
index 0000000000000000000000000000000000000000..80933e69bd4bb12e0c64a8fbd8be24d5ffc5c632
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseCommand.as
@@ -0,0 +1,28 @@
+package org.bigbluebutton.air.main.commands
+{
+	import org.bigbluebutton.air.main.models.IUISession;
+	import org.bigbluebutton.air.user.services.IUsersService;
+	
+	import robotlegs.bender.bundles.mvcs.Command;
+	
+	public class UserInactivityTimerResponseCommand extends Command
+	{
+		
+		[Inject]
+		public var userService:IUsersService;
+		
+		[Inject]
+		public var uiSession:IUISession
+		
+		public function UserInactivityTimerResponseCommand()
+		{
+			super();
+		}
+		
+		override public function execute():void {
+			uiSession.popPage();
+			
+			userService.userInactivityAuditResponse();
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseSignal.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseSignal.as
new file mode 100755
index 0000000000000000000000000000000000000000..e62c3d592fea4ff89706d1e721d2b8819f758627
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerResponseSignal.as
@@ -0,0 +1,12 @@
+package org.bigbluebutton.air.main.commands
+{
+	import org.osflash.signals.Signal;
+	
+	public class UserInactivityTimerResponseSignal extends Signal
+	{
+		public function UserInactivityTimerResponseSignal()
+		{
+			super();
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerSignal.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerSignal.as
new file mode 100755
index 0000000000000000000000000000000000000000..b7fed3947d4f966cf738948c1f365aed689534f0
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/commands/UserInactivityTimerSignal.as
@@ -0,0 +1,12 @@
+package org.bigbluebutton.air.main.commands
+{
+	import org.osflash.signals.Signal;
+	
+	public class UserInactivityTimerSignal extends Signal
+	{
+		public function UserInactivityTimerSignal()
+		{
+			super(Number);
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/LoadingScreenMediator.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/LoadingScreenMediator.as
index 91195cbb365290f51f6a57c1858a9faf912553c0..cf2de0bb5b068a3d957c2f111257d5f7d50ea611 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/LoadingScreenMediator.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/LoadingScreenMediator.as
@@ -44,7 +44,7 @@ package org.bigbluebutton.air.main.views {
 				joinRoom(url);
 			}
 		}
-		
+				
 		private function onInvokeEvent(invocation:InvokeEvent):void {
 			if (invocation.arguments.length > 0 && !Capabilities.isDebugger) {
 				var url:String = invocation.arguments[0].toString();			
@@ -60,7 +60,6 @@ package org.bigbluebutton.air.main.views {
 					FlexGlobals.topLevelApplication.mainshell.visible = false;
 					uiSession.popPage();
 					uiSession.pushPage(PageEnum.MAIN);
-					
 					joinRoom(url);
 				}
 			} else {
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/PagesNavigatorViewMediator.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/PagesNavigatorViewMediator.as
index 37380a38371ac19c0bbbf0254962285b9f64dcec..78f044984dc79d3c4a4a34722ba023394a1f332c 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/PagesNavigatorViewMediator.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/PagesNavigatorViewMediator.as
@@ -82,6 +82,7 @@ package org.bigbluebutton.air.main.views {
 			} else if (pageRemoved) {
 				view.popView(transition);
 			} else if (pageName != null && pageName != "") {
+				trace("SWITCHING PAGE to " + pageName);
 				view.pushView(PageEnum.getClassfromName(pageName), null, null, transition);
 			}
 		}
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityView.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityView.as
new file mode 100755
index 0000000000000000000000000000000000000000..b2a84f2bea996ba4d83994407bc38de62fa72da1
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityView.as
@@ -0,0 +1,40 @@
+package org.bigbluebutton.air.main.views
+{
+	import spark.components.Button;
+	import spark.components.Label;
+	import spark.layouts.VerticalLayout;
+	
+	import org.bigbluebutton.air.common.views.NoTabView;
+
+	public class UserInactivityView extends NoTabView
+	{
+		public var okButton:Button;
+		
+		public function UserInactivityView()
+		{
+			super();
+			
+			var l:VerticalLayout = new VerticalLayout();
+			l.horizontalAlign = "center";
+			layout = l;
+			
+			var messageText:Label = new Label();
+			messageText.percentWidth = 90;
+			messageText.text = "Inactivity Timer";
+			messageText.setStyle("textAlign", "center");
+			messageText.styleName = "disconnectMessage";
+			addElement(messageText);
+			
+			okButton = new Button();
+			okButton.percentWidth = 90;
+			okButton.label = "Ok";
+			addElement(okButton);
+		}
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+			this.layout["gap"] = getStyle("gap");
+			this.layout["padding"] = getStyle("padding");
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityViewMediator.as b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityViewMediator.as
new file mode 100755
index 0000000000000000000000000000000000000000..22583c0386c49a77c5fee691a6cce6b3595d3251
--- /dev/null
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/main/views/UserInactivityViewMediator.as
@@ -0,0 +1,31 @@
+package org.bigbluebutton.air.main.views
+{
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerResponseSignal;
+	
+	import robotlegs.bender.bundles.mvcs.Mediator;
+
+	public class UserInactivityViewMediator extends Mediator
+	{
+		[Inject]
+		public var view:UserInactivityView;
+		
+		[Inject]
+		public var userInactivityTimerResponseSignal:UserInactivityTimerResponseSignal;
+		
+		override public function initialize():void {
+			view.okButton.visible = true;
+			view.okButton.addEventListener(MouseEvent.CLICK, okButtonClicked);
+		}
+		
+		override public function destroy():void {
+			view.okButton.removeEventListener(MouseEvent.CLICK, okButtonClicked);
+		}
+		
+		private function okButtonClicked(event:Event):void {
+			userInactivityTimerResponseSignal.dispatch();
+		}
+	}
+}
\ No newline at end of file
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/IUsersService.as b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/IUsersService.as
index 7d587769b0fb258314353432285feec79fb22dfb..ef0ad6b666432fb4f5a576254c8ae4c4e44ccd91 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/IUsersService.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/IUsersService.as
@@ -23,5 +23,6 @@ package org.bigbluebutton.air.user.services {
 		function validateToken():void;
 		function joinMeeting():void;
 		function changeRole(userId:String, role:String):void;
+		function userInactivityAuditResponse():void;
 	}
 }
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageReceiver.as b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageReceiver.as
index 971ad4b0d1d03ca3f0ac6e35137e04bf9a43f170..b1a2fd537c1d1a3e2bfe962cf0f3f29c86eb6e28 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageReceiver.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageReceiver.as
@@ -4,6 +4,7 @@ package org.bigbluebutton.air.user.services {
 	import org.bigbluebutton.air.chat.models.IChatMessagesSession;
 	import org.bigbluebutton.air.common.models.IMessageListener;
 	import org.bigbluebutton.air.main.commands.DisconnectUserSignal;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerSignal;
 	import org.bigbluebutton.air.main.models.IConferenceParameters;
 	import org.bigbluebutton.air.main.models.IMeetingData;
 	import org.bigbluebutton.air.main.models.IUserSession;
@@ -27,6 +28,8 @@ package org.bigbluebutton.air.user.services {
 		
 		public var disconnectUserSignal:DisconnectUserSignal;
 		
+		public var meetingInactivityTimerSignal:UserInactivityTimerSignal;
+		
 		public function UsersMessageReceiver() {
 		}
 		
@@ -94,11 +97,19 @@ package org.bigbluebutton.air.user.services {
 				case "UserRoleChangedEvtMsg":
 					handleUserRoleChangedEvtMsg(message);
 					break;
+				case "UserInactivityAuditMsg":
+					handleUserInactivityAuditMsg(message);
+					break;
 				default:
 					break;
 			}
 		}
 		
+		private function handleUserInactivityAuditMsg(m:Object):void {
+			trace("handleInactivityWarning: " + ObjectUtil.toString(m));
+			meetingInactivityTimerSignal.dispatch(m.body.responseDuration as Number);
+		}
+				
 		private function handleMeetingMuted(m:Object):void {
 			var msg:Object = JSON.parse(m.msg);
 			trace("handleMeetingMuted: " + ObjectUtil.toString(msg));
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageSender.as b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageSender.as
index c7092034265144a6d9ddfabbfd727cf66e8ef2b6..20f059643ffa6a26045f853d0e6dcc7b766e5b76 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageSender.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersMessageSender.as
@@ -231,5 +231,15 @@ package org.bigbluebutton.air.user.services {
 			
 			userSession.mainConnection.sendMessage2x(defaultSuccessResponse, defaultFailureResponse, message);
 		}
+		
+		public function userInactivityAuditResponse():void {
+			var message:Object = {
+				header: {name: "UserInactivityAuditResponseMsg", meetingId: conferenceParameters.meetingID, 
+					userId: conferenceParameters.internalUserID},
+				body: {userId: conferenceParameters.internalUserID}
+			};
+			
+			userSession.mainConnection.sendMessage2x(defaultSuccessResponse, defaultFailureResponse, message);
+		}
 	}
 }
diff --git a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersService.as b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersService.as
index 922e5490ccdef58b40623f4319fec4963a62d671..eb2e3340b7d1166e6c41fafa7435038005317c07 100755
--- a/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersService.as
+++ b/clients/flash/air-client/src/org/bigbluebutton/air/user/services/UsersService.as
@@ -2,6 +2,7 @@ package org.bigbluebutton.air.user.services {
 	
 	import org.bigbluebutton.air.chat.models.IChatMessagesSession;
 	import org.bigbluebutton.air.main.commands.DisconnectUserSignal;
+	import org.bigbluebutton.air.main.commands.UserInactivityTimerSignal;
 	import org.bigbluebutton.air.main.models.IConferenceParameters;
 	import org.bigbluebutton.air.main.models.IMeetingData;
 	import org.bigbluebutton.air.main.models.IUserSession;
@@ -24,6 +25,9 @@ package org.bigbluebutton.air.user.services {
 		[Inject]
 		public var disconnectUserSignal:DisconnectUserSignal;
 		
+		[Inject]
+		public var meetingInactivityTimerSignal:UserInactivityTimerSignal;
+		
 		public var usersMessageSender:UsersMessageSender;
 		
 		public var usersMessageReceiver:UsersMessageReceiver;
@@ -39,6 +43,7 @@ package org.bigbluebutton.air.user.services {
 			usersMessageReceiver.chatMessagesSession = chatMessagesSession;
 			usersMessageReceiver.conferenceParameters = conferenceParameters;
 			usersMessageReceiver.disconnectUserSignal = disconnectUserSignal;
+			usersMessageReceiver.meetingInactivityTimerSignal = meetingInactivityTimerSignal;
 			usersMessageSender.userSession = userSession;
 			usersMessageSender.conferenceParameters = conferenceParameters;
 			userSession.mainConnection.addMessageListener(usersMessageReceiver);
@@ -138,5 +143,8 @@ package org.bigbluebutton.air.user.services {
 			usersMessageSender.changeRole(userId, role);
 		}
 	
+		public function userInactivityAuditResponse():void {
+			usersMessageSender.userInactivityAuditResponse();
+		}
 	}
 }