public class RiotCallingPageObjects extends TestUtilities{
	private AndroidDriver<MobileElement> driver;
	public RiotCallingPageObjects(AppiumDriver<MobileElement> myDriver){
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		driver=(AndroidDriver<MobileElement>) myDriver;
		try {
			waitUntilDisplayed(driver,"im.vector.alpha:id/call_layout", true, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	@AndroidFindBy(id="im.vector.alpha:id/call_layout")
	public MobileElement mainCallLayout;
	/*
	 * TOP BAR
	 */
	@AndroidFindBy(id="im.vector.alpha:id/back_icon")
	public MobileElement menuBackButton;
	@AndroidFindBy(id="im.vector.alpha:id/incoming_call_title")
	public MobileElement incomingCallStatus;
	
	public void waitUntilCallTook() throws InterruptedException{
		waitUntilDisplayed(driver, "//*[@resource-id='im.vector.alpha:id/incoming_call_title' and text='Call connecting…']", false, 5);
	}
	/**
	 * Asserts true or false if the view is displayed.
	 * @param displayed
	 * @return 
	 * @throws InterruptedException
	 */
	public Boolean isDisplayed(Boolean displayed) throws InterruptedException{
		return waitUntilDisplayed(driver,"im.vector.alpha:id/call_layout", displayed, 5);
	}
	/*
	 * BOTTOM BAR : hang out button, microphone, etc
	 */
	@AndroidFindBy(id="im.vector.alpha:id/call_menu_buttons_layout_container")//im.vector.alpha:id/action_bar_header_room_members
	public MobileElement bottomBarLayout;
	@AndroidFindBy(id="im.vector.alpha:id/hang_up_button")
	public MobileElement hangUpButton;
	@AndroidFindBy(id="im.vector.alpha:id/mute_audio")
	public MobileElement muteAudioButton;
	@AndroidFindBy(id="im.vector.alpha:id/mute_local_camera")
	public MobileElement muteLocalCameraButton;
	@AndroidFindBy(id="im.vector.alpha:id/call_switch_camera_view")
	public MobileElement switchCameraButton;
	@AndroidFindBy(id="im.vector.alpha:id/room_chat_link")
	public MobileElement chatLinkButton;
} public class RiotIncomingCallPageObjects extends TestUtilities{
	private AndroidDriver<MobileElement> driver;
	public RiotIncomingCallPageObjects(AppiumDriver<MobileElement> myDriver){
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		driver=(AndroidDriver<MobileElement>) myDriver;
		try {
			waitUntilDisplayed(driver,"android:id/content", true, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * INCOMING CALL VIEW
	 */
	@AndroidFindBy(xpath="//android.widget.TextView[@resource-id='im.vector.alpha:id/room_name']/../android.widget.RelativeLayout")
	public MobileElement incomingCallContainer;
	@AndroidFindBy(id="im.vector.alpha:id/avatar_img")
	public MobileElement incomingCallAvatarImageView;
	@AndroidFindBy(id="im.vector.alpha:id/room_name")
	public MobileElement incomingCallerName;
	@AndroidFindBy(id="im.vector.alpha:id/incoming_call_title")
	public MobileElement incomingCallStatus;
	@AndroidFindBy(id="im.vector.alpha:id/button_incoming_call_accept")
	public MobileElement acceptCallButton;
	@AndroidFindBy(id="im.vector.alpha:id/button_incoming_call_ignore")
	public MobileElement ignoreCallButton;
	/**
	 * Check the incoming call view. Put isDisplayed at false to ckeck that is not displayed.</br>
	 * Check that the 2 buttons are displayed.
	 * @param isDisplayed
	 * @param callerName
	 * @param status
	 * @throws InterruptedException 
	 */
	public void checkIncomingCallView(Boolean isDisplayed, String callerName, String status) throws InterruptedException{
		String messagePendingViewPresent;
		if(isDisplayed){
			messagePendingViewPresent="Incoming call view isn't displayed";
		}else{
			messagePendingViewPresent="Incoming call view is displayed";
		}
		Assert.assertTrue(waitUntilDisplayed(driver, "//android.widget.TextView[@resource-id='im.vector.alpha:id/room_name']/../android.widget.RelativeLayout", isDisplayed, 5)==isDisplayed, messagePendingViewPresent);
		if(isDisplayed){
			Assert.assertEquals(incomingCallerName.getText(), callerName);
			Assert.assertEquals(incomingCallStatus.getText(), status);
			Assert.assertTrue(acceptCallButton.isEnabled(), "Accept button in incoming call container isn't enabled");
			Assert.assertTrue(ignoreCallButton.isEnabled(), "Ignore button in incoming call container isn't enabled");
			Assert.assertEquals(acceptCallButton.getText(), "ACCEPT");
			Assert.assertEquals(ignoreCallButton.getText(), "IGNORE");
			org.openqa.selenium.Dimension avatarIcon=incomingCallAvatarImageView.getSize();
		    Assert.assertTrue(avatarIcon.height!=0 && avatarIcon.width!=0, "avatar icon from incoming call view has null dimension");
		}
	}
} public class RiotRoomDetailsPageObjects extends TestUtilities{
	private AndroidDriver<MobileElement> driver;
	public RiotRoomDetailsPageObjects(AppiumDriver<MobileElement> myDriver) throws InterruptedException{
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		driver=(AndroidDriver<MobileElement>) myDriver;
		//ExplicitWait(driver,this.messagesListView);
		//if 'Riot permissions .... Allow Riot to access your contacts' pops up, close it.
		if(waitUntilDisplayed(driver, "//android.widget.TextView[@resource-id='android:id/alertTitle' and @text='Information']", true, 1)){
			driver.findElementById("android:id/button1").click();
		}
		
		try {
			waitUntilDisplayed(driver,"//android.widget.HorizontalScrollView", true, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * TOP : contains action bar and the 3 tabs (PEOPLE, FILES, SETTINGS)
	 */
	@AndroidFindBy(id="im.vector.alpha:id/action_bar")
	public MobileElement actionBarView;
	@AndroidFindBy(xpath="//android.widget.ImageButton[@content-desc='Navigate up']")
	public MobileElement menuBackButton;
	@AndroidFindBy(xpath="//android.view.View[@resource-id='im.vector.alpha:id/action_bar']/android.widget.TextView[@index='1']")
	public MobileElement roomDetailsTextView;
	
	@AndroidFindBy(xpath="//android.widget.TextView[@text='People']/../*")
	public MobileElement peopleTab;
	@AndroidFindBy(xpath="//android.widget.TextView[@text='Files']/../*")
	public MobileElement filesTab;
	@AndroidFindBy(xpath="//android.widget.TextView[@text='Settings']/../*")
	public MobileElement settingsTab;
	/*
	 * 				PEOPLE TAB
	 */
	/*
	 * FILTER BAR
	 */
	@AndroidFindBy(id="im.vector.alpha:id/search_value_edit_text")
	public MobileElement filterRoomMembersEditText;
	@AndroidFindBy(id="im.vector.alpha:id/clear_search_icon_image_view")
	public MobileElement clearFilteredBarButton;
	/*
	 * MEMBERS LIST
	 */
	
	//@AndroidFindBy(id="im.vector.alpha:id/filtered_list_cell")
	@AndroidFindBy(xpath="//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/room_details_members_exp_list_view']/android.widget.RelativeLayout/android.widget.RelativeLayout[@resource-id='im.vector.alpha:id/filtered_list_cell']/..")
	public List<MobileElement> membersList;
	@AndroidFindBy(xpath="//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/room_details_members_exp_list_view']/android.widget.RelativeLayout[@enabled='true']")
	public List<MobileElement> categoryList;
	@AndroidFindBy(id="im.vector.alpha:id/search_no_results_text_view")
	public MobileElement noResultTextView;
	
	/**
	 * ADD BUTTON
	 */
	@AndroidFindBy(id="im.vector.alpha:id/add_participants_create_view")
	public MobileElement addParticipantButton;
	
	public void addParticipant(String inviteeAddress) throws InterruptedException {
		addParticipantButton.click();
		RiotContactPickerPageObjects inviteMember = new RiotContactPickerPageObjects(driver);
		inviteMember.searchAndSelectMember(inviteeAddress);
		checkInviteConfirmationMsgBox(inviteeAddress);
		inputDialogOkButton.click();
		waitUntilDisplayed(driver, "//android.widget.ProgressBar", false, 10);
	}
	
	/**
	 * Return a member relativelayout using name of the member.
	 * @param memberName
	 * @return
	 */
	public MobileElement getMemberByName(String memberName){
		try {
			return driver.findElementByXPath("//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/room_details_members_exp_list_view']//android.widget.TextView[@resource-id='im.vector.alpha:id/filtered_list_name' and @text='"+memberName+"']/..");	
		} catch (Exception e) {
			System.out.println("No member found with name '"+memberName+"'");
			return null;
		}
		
	}
	
	/**
	 * Check texts of the invite confirmation msgbox.
	 * @throws InterruptedException 
	 */
	public void checkInviteConfirmationMsgBox(String memberAddress) throws InterruptedException{
		waitUntilDisplayed(driver, "im.vector.alpha:id/parentPanel", true, 5);
		Assert.assertEquals(inputDialogNameTextView.getText(), "Confirmation");
		Assert.assertTrue(inputDialogTextView.getText().matches("^Are you sure you want to invite (\\S+) to this chat\\?$"));
	}
	
	/**
	 * Wait until INVITED categorie is displayed.</br>
	 * Can be used to wait until an invitation is done.
	 * @throws InterruptedException
	 */
	public void waitUntilInvitedCategorieIsDisplayed(Boolean invitedCategorieDisplayed) throws InterruptedException{
		int maxToWait=30;
		int timeWaited=0;
		int size;
		if(invitedCategorieDisplayed){
			size=2;
		}else{
			size=1;
		}
		while (categoryList.size()!=size && timeWaited <=maxToWait) {
			Thread.sleep(500);
			timeWaited++;
		}
		if(timeWaited>=maxToWait){
			Assert.fail();
			System.out.println("INVITED categorie isn't displayed after "+maxToWait+"s.");
		}
	}
	
	/**
	 * From the room details people tab, enter a text on the filter room members edittext.
	 * @param filter
	 */
	public void filterOnRoomMembersList(String filter){
		filterRoomMembersEditText.setValue(filter);
	}
	
	/**
	 * Return the displayname from a filtered member from the people tab.
	 * @param member
	 * @return
	 */
	public String getDisplayNameOfMemberFromPeopleTab(MobileElement member){
		try {
			return member.findElementById("im.vector.alpha:id/filtered_list_name").getText();
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * Swipe to the left on a member item, then hit the "eject" button.</br>
	 * Wait until the progress bar is gone.
	 * @param memberItem
	 * @return 
	 * @throws InterruptedException 
	 */
	public void removeMemberWithSwipeOnItem(MobileElement memberItem) throws InterruptedException{
		int x = memberItem.getLocation().getX();
		int y= memberItem.getLocation().getY();
		int witdthX=memberItem.getSize().getWidth();
		int xFirst=x+witdthX-80;
		float xEndF=(float) (0.6*witdthX);
		int xEnd=(int)xEndF;
		//Swipe to the left on the item.
		driver.swipe(xFirst,y, xEnd,y,500);Thread.sleep(500);
		//Hit on eject button
		memberItem.findElementById("im.vector.alpha:id/filtered_list_delete_action").click();
		//hit on remove confirmation button from dialog alert
		waitUntilDisplayed(driver, "android:id/parentPanel", true, 10);
		Assert.assertEquals(inputAndroidDialogNameTextView.getText(), "Confirmation");
		inputDialogOkButton.click();
		waitUntilDisplayed(driver, "//android.widget.ProgressBar", false, 10);
	}
	
		
	/*
	 * 				FILES TAB
	 */
	@AndroidFindBy(xpath="//android.widget.ListView[@resource-id='im.vector.alpha:id/listView_messages']/android.widget.RelativeLayout")
	public List<MobileElement> attachedFilesList;
	
	/*
	 * 				SETTINGS TAB
	 */
	@AndroidFindBy(id="android:id/list")
	public MobileElement listItemSettings;
	
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView")
	public MobileElement roomNameListItem;
	
	public void changeRoomName(String roomName){
		listItemSettings.findElementByXPath("//*[@text='Room Name']").click();
		ExplicitWait(driver, inputDialogEditText);
		inputDialogEditText.sendKeys(roomName);
		inputDialogOkButton.click();
		ExplicitWait(driver, listItemSettings.findElementByXPath("//*[@text='Room Name']"));
	}
	/*
	 * ADVANCED SECTION
	 */
	@AndroidFindBy(xpath="//android.widget.TextView[contains(@text,'Enable encryption')]")
	public MobileElement enableEncryptionSwitch;
	/**
	 * Switch off encryption on a room. The switch need to be focused.
	 * </br> Assert that the dialog have a warning title.
	 * </br> Click on Yes Button.
	 */
	public void enableEncryption(){
		enableEncryptionSwitch.click();
		Assert.assertEquals(inputAndroidDialogNameTextView.getText(), "Warning!");
		inputDialogOkButton.click();
	}
	
	/*
	 * 		MISC
	 */
	/*
	 * INPUT DIALOG BOX
	 */
	@AndroidFindBy(id="im.vector.alpha:id/parentPanel")
	public MobileElement inputDialogMainLayout;
	@AndroidFindBy(id="im.vector.alpha:id/alertTitle")
	public MobileElement inputDialogNameTextView;
	@AndroidFindBy(id="android:id/alertTitle")
	public MobileElement inputAndroidDialogNameTextView;
	@AndroidFindBy(id="android:id/message")
	public MobileElement inputDialogTextView;
	@AndroidFindBy(id="android:id/edit")
	public MobileElement inputDialogEditText;
	@AndroidFindBy(id="android:id/button2")
	public MobileElement inputDialogCancelButton;
	@AndroidFindBy(id="android:id/button1")
	public MobileElement inputDialogOkButton;
} public class RiotRoomPageObjects extends TestUtilities{
	private AndroidDriver<MobileElement> driver;
	public RiotRoomPageObjects(AppiumDriver<MobileElement> myDriver) {
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		driver=(AndroidDriver<MobileElement>) myDriver;
		//ExplicitWait(driver,this.messagesListView);
		try {
			Assert.assertTrue(waitUntilDisplayed(driver,"im.vector.alpha:id/listView_messages", true, 10), "No room page present");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/*
	 * ACTION BAR
	 */
	@AndroidFindBy(id="im.vector.alpha:id/action_bar_header")//collapsed view. contains avatar, room name, topic and active members
	public MobileElement actionBarCollapsedLayout;
	@AndroidFindBy(id="im.vector.alpha:id/avatar_img")
	public MobileElement avatarImageView;
	@AndroidFindBy(id="im.vector.alpha:id/action_bar_header_room_title")
	public MobileElement roomNameTextViewCollapsed;
	@AndroidFindBy(id="im.vector.alpha:id/action_bar_header_room_members_settings_view")
	public MobileElement openRoomMemberSettingsButton;
	@AndroidFindBy(id="im.vector.alpha:id/action_bar_header_room_members_text_view")
	public MobileElement activeMembersTextView;
	@AndroidFindBy(id="im.vector.alpha:id/action_bar_header_room_members_invite_view")
	public MobileElement inviteMembersButton;

	
	@AndroidFindBy(id="im.vector.alpha:id/room_toolbar")//action bar : contains back, room name, topic,search, collapse and more options buttons.
	public MobileElement actionBarView;
	@AndroidFindBy(xpath="//android.widget.ImageButton[@content-desc='Navigate up']")
	public MobileElement menuBackButton;
	@AndroidFindBy(id="im.vector.alpha:id/room_action_bar_title")
	public MobileElement roomNameTextView;
	@AndroidFindBy(id="im.vector.alpha:id/room_action_bar_topic")
	public MobileElement roomTopicTextView;
	@AndroidFindBy(id="im.vector.alpha:id/open_chat_header_arrow")// ^ button
	public MobileElement collapseChatButton;
	@AndroidFindBy(id="im.vector.alpha:id/ic_action_search_in_room")
	public MobileElement searchInRoomButton;
	@AndroidFindBy(xpath="//android.view.View[@resource-id='im.vector.alpha:id/room_toolbar']//android.widget.ImageView[@content-desc='More options']")
	public MobileElement moreOptionsButton;

	public void addParticipantFromCollapsedActionBar(String inviteeAddress) throws InterruptedException{
		inviteMembersButton.click();
		RiotContactPickerPageObjects inviteMember = new RiotContactPickerPageObjects(driver);
		inviteMember.searchAndSelectMember(inviteeAddress);
		checkInviteConfirmationMsgBox(inviteeAddress);
		alertDialogButton2.click();
		waitUntilDisplayed(driver, "//android.widget.ProgressBar", false, 10);
	}
	
	/**
	 * Check texts of the invite confirmation msgbox.
	 * @throws InterruptedException 
	 */
	public void checkInviteConfirmationMsgBox(String memberAddress) throws InterruptedException{
		waitUntilDisplayed(driver, "im.vector.alpha:id/parentPanel", true, 5);
		Assert.assertEquals(inputDialogNameTextView.getText(), "Confirmation");
		Assert.assertTrue(inputDialogTextView.getText().matches("^Are you sure you want to invite (\\S+) to this chat\\?$"));
	}
	
	/*
	 * ROOM NAME DIALOG : opened after hit on room name from collapsed action bar.
	 */
	@AndroidFindBy(id="android:id/parentPanel")
	public MobileElement roomNameDialogLayout;//contains cancel and ok buttons, and room name
	@AndroidFindBy(id="im.vector.alpha:id/dialog_title")
	public MobileElement roomNameFromChangeDialogTextView;
	@AndroidFindBy(id="im.vector.alpha:id/dialog_edit_text")
	public MobileElement roomNameFromChangeDialogEditText;
	@AndroidFindBy(xpath="//android.widget.LinearLayout[@resource-id='android:id/buttonPanel']//android.widget.Button[@text='OK']")
	public MobileElement okFromChangeRoomNameButton;
	@AndroidFindBy(xpath="//android.widget.LinearLayout[@resource-id='android:id/buttonPanel']//android.widget.Button[@text='Cancel']")
	public MobileElement cancelFromChangeRoomNameButton;

	/**
	 * Change the room name. Action bar must be collapsed first.
	 * @param roomName
	 * @throws InterruptedException 
	 */
	public void changeRoomName(String roomName) throws InterruptedException {
		waitUntilDisplayed(driver, "im.vector.alpha:id/action_bar_header", true, 10);
		roomNameTextViewCollapsed.click();
		roomNameFromChangeDialogEditText.sendKeys(roomName);
		okFromChangeRoomNameButton.click();
		//ExplicitWait(driver, roomNameTextViewCollapsed);
		waitUntilDisplayed(driver, "im.vector.alpha:id/listView_spinner", false, 4);
		Assert.assertEquals(roomNameTextViewCollapsed.getText(), roomName, "Room name haven't be changed.");
	}

	/*
	 * ROOM MENU
	 */
	@AndroidFindBy(xpath="//android.widget.TextView[@resource-id='im.vector.alpha:id/title' and @text='Room Details']")
	public MobileElement roomDetailsMenuItem;
	@AndroidFindBy(xpath="//android.widget.TextView[@resource-id='im.vector.alpha:id/title' and @text='Leave']")
	public MobileElement leaveRoomMenuItem;

	public void leaveRoom(){
		moreOptionsButton.click();
		leaveRoomMenuItem.click();
		alertDialogButton2.click();
	}

	/*
	 * PREVIEW LAYOUT
	 */
	@AndroidFindBy(id="im.vector.alpha:id/room_preview_info_layout")//preview info layout : contains join room and cancel buttons
	public MobileElement previewRoomLayout;
	@AndroidFindBy(id="im.vector.alpha:id/room_preview_invitation_textview")//"You have been invited to join this room by USER"
	public MobileElement invitationMessageTextView;
	@AndroidFindBy(id="im.vector.alpha:id/button_join_room")
	public MobileElement joinRoomButton;
	@AndroidFindBy(id="im.vector.alpha:id/button_decline")
	public MobileElement cancelInvitationButton;

	/**
	 * Check the room preview layout after accepting an invitation.
	 * @throws InterruptedException 
	 */
	public void checkPreviewRoomLayout(String roomName) throws InterruptedException{
		ExplicitWait(driver,previewRoomLayout);
		//check invitation messsage
		Assert.assertTrue(invitationMessageTextView.getText().contains("You have been invited to join this room by "));
		//check buttons
		Assert.assertEquals(joinRoomButton.getText(), "Join Room");
		Assert.assertEquals(cancelInvitationButton.getText(), "Cancel");
		//check more options button is not here
		Assert.assertFalse(waitUntilDisplayed(driver,"//android.widget.TextView[@resource-id='im.vector.alpha:id/ic_action_search_in_room']/../android.widget.ImageView", false, 0));
		//check search button is not here
		Assert.assertFalse(waitUntilDisplayed(driver,"im.vector.alpha:id/ic_action_search_in_room", false, 0));
		//check back button is displayed
		Assert.assertTrue(menuBackButton.isDisplayed(),"Back button isn't displayed");
		//check collapse button is displayed
		Assert.assertTrue(collapseChatButton.isDisplayed(),"Collapse button isn't displayed");
		//room name is displayed
		Assert.assertEquals(roomNameTextViewCollapsed.getText(), roomName);
		//avatar isn't empty
		org.openqa.selenium.Dimension roomAvatar=avatarImageView.getSize();
		Assert.assertTrue(roomAvatar.height!=0 && roomAvatar.width!=0, "Riot logo has null dimension");
		//check that bottom bar isn't here
		//send bar
		Assert.assertFalse(waitUntilDisplayed(driver,"//android.widget.RelativeLayout[@resource-id='im.vector.alpha:id/room_bottom_layout']//android.widget.EditText[@resource-id='im.vector.alpha:id/editText_messageBox']", false, 0));
		Assert.assertFalse(waitUntilDisplayed(driver,"im.vector.alpha:id/room_send_layout", false, 0));
		Assert.assertFalse(waitUntilDisplayed(driver,"im.vector.alpha:id/room_start_call_layout", false, 0));
		Assert.assertFalse(waitUntilDisplayed(driver,"im.vector.alpha:id/room_end_call_layout", false, 0));
	}

	/**
	 * Check the room page layout. </br>
	 * TODO complete this function by inspirant of checkPreviewRoomLayout()  </br>
	 * @param roomName
	 * @throws InterruptedException 
	 */
	public void checkRoomLayout(String roomName) throws InterruptedException {
		//check that preview layout isn't displayed
		Assert.assertFalse(waitUntilDisplayed(driver,"im.vector.alpha:id/room_preview_info_layout", false, 3));
		//check action bar
		Assert.assertTrue(actionBarView.isDisplayed(), "Action bar isn't displayed");
		Assert.assertTrue(menuBackButton.isDisplayed(), "Menu back button isn't displayed");
		Assert.assertTrue(collapseChatButton.isDisplayed(), "Collapse chat button isn't displayed");
		Assert.assertTrue(searchInRoomButton.isDisplayed(), "Search in room button isn't displayed");
		Assert.assertTrue(moreOptionsButton.isDisplayed(), "More option button isn't displayed");
		//check that bottom bar is displayed
		Assert.assertTrue(messageZoneEditText.isDisplayed(), "Message zone edit text isn't displayed");
		Assert.assertTrue(sendMessageButton.isDisplayed(), "Send message button isn't displayed");
		Assert.assertTrue(startCallButton.isDisplayed(), "Start call button isn't displayed");
	}

	/**
	 * Return true or false if the room view is still displayed.</br>
	 * Can be useful to test that the room page is closed after quitting it.
	 * @param displayed
	 * @throws InterruptedException
	 */
	public void isDisplayed(Boolean displayed) throws InterruptedException{
		String messageFailed;
		if(displayed){
			messageFailed="Room page isn't displayed.";
		}else{
			messageFailed="Room page is displayed.";
		}
		Assert.assertEquals(waitUntilDisplayed(driver,"im.vector.alpha:id/listView_messages", displayed, 5),displayed, messageFailed);
	}

	/*
	 * PENDING CALL VIEW
	 */
	@AndroidFindBy(id="im.vector.alpha:id/room_pending_call_view")
	public MobileElement roomPendingCallLayout;
	@AndroidFindBy(id="im.vector.alpha:id/call_icon")
	public MobileElement callIconImageView;
	@AndroidFindBy(id="im.vector.alpha:id/pending_call_room_name_textview")
	public MobileElement calledRoomNameTextView;
	@AndroidFindBy(id="im.vector.alpha:id/pending_call_status_textview")
	public MobileElement callStatusTextView;

	public void checkPendingCallView(Boolean displayed,String status) throws InterruptedException{
		String messagePendingViewPresent;
		if(displayed){
			messagePendingViewPresent="Pending view isn't displayed";
		}else{
			messagePendingViewPresent="Pending view is displayed";
		}
		Assert.assertTrue(waitUntilDisplayed(driver, "im.vector.alpha:id/room_pending_call_view", displayed, 5)==displayed, messagePendingViewPresent);
		if(displayed){
			waitUntilDisplayed(driver, "im.vector.alpha:id/pending_call_status_textview", true, 5);
			Assert.assertEquals(callStatusTextView.getText(), status);
		}
	}

	/*
	 * MESSAGES
	 */
	/**
	 * Similar to messagesListView, but as a list and not just a MobileElement.
	 */
	@AndroidFindBy(xpath="//android.widget.ListView[@resource-id='im.vector.alpha:id/listView_messages']/android.widget.LinearLayout")//messages list. Contains messages, days separators
	public List<MobileElement> postsListLayout;

	public MobileElement getLastPost(){
		//return Iterables.getLast(this.postsListLayout);
		int sizeList=postsListLayout.size();
		if(sizeList>0){
			return postsListLayout.get(sizeList-1);
		}else{
			Assert.fail("Not a single post layout found in the room.");
			return null;
		}
		
	}

	/**
	 * Return a post by his index.
	 */
	public MobileElement getPostByIndex(int indexPost){
		return postsListLayout.get(indexPost);
	}

	/**
	 * TODO use xpath instead of id because of https://github.com/appium/appium/issues/6269 issue
	 * @param postLinearLayout
	 * @return
	 */
	public MobileElement getUserAvatarByPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElementById("im.vector.alpha:id/avatar_img");
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * TODO use xpath instead of id because of https://github.com/appium/appium/issues/6269 issue
	 * @param postLinearLayout
	 * @return
	 */
	public MobileElement getSenderNameByPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElementById("im.vector.alpha:id/messagesAdapter_sender");
		} catch (Exception e) {
			return null;
		}
	}
	/**TODO use xpath instead of id because of https://github.com/appium/appium/issues/6269 issue </br>
	 * Get the imageview attached from a linearLayout object message (first children of the listView_messages). </br> Return null if not found.
	 * @param message
	 * @return
	 */
	public MobileElement getAttachedImageByPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElement(By.id("im.vector.alpha:id/messagesAdapter_image"));
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * TODO use xpath instead of id because of https://github.com/appium/appium/issues/6269 issue </br>
	 * Return the timestamp, example : 15:12. </br> Return null if not found.
	 * @param postLinearLayout
	 * @return
	 */
	public MobileElement getTimeStampByPost(MobileElement postLinearLayout){	
		try {
			//			return postLinearLayout.findElement(By.id("im.vector.alpha:id/messagesAdapter_timestamp"));
			return postLinearLayout.findElement(By.xpath("//android.widget.TextView[@resource-id='im.vector.alpha:id/messagesAdapter_timestamp']"));
		} catch (Exception e) {
			return null;
		}
	}
	public MobileElement getContextMenuByPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElementById("im.vector.alpha:id/messagesAdapter_action_image");
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * TODO use xpath instead of id because of https://github.com/appium/appium/issues/6269 issue
	 * Get the textView from a post. </br> Return null if not found.
	 * @param message
	 * @return
	 */
	public MobileElement getTextViewFromPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElement(By.id("im.vector.alpha:id/messagesAdapter_body"));
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * Get the media upload failed icon on an attached image from a post. </br> Return null if not found.
	 * @param message
	 * @return
	 */
	public MobileElement getMediaUploadFailIconFromPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElement(By.id("im.vector.alpha:id/media_upload_failed"));
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Get the progress bar displayed when a photo or video is uploaded.</br> Return null if not found.
	 * @param message
	 * @return
	 */
	public MobileElement getProgressionBarFromPost(MobileElement postLinearLayout){
		try {
			//return postLinearLayout.findElement(By.xpath("//android.widget.ProgressBar[@resource-id='im.vector.alpha:id/media_progress_view']"));
			return postLinearLayout.findElement(By.id("im.vector.alpha:id/media_progress_view"));
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Get the "X" imageview to stop the upload of a photo or video.</br> Return null if not found.
	 * @param postLinearLayout
	 * @return
	 */
	public MobileElement getCancelMediaProgressFromPost(MobileElement postLinearLayout){
		try {
			return postLinearLayout.findElement(By.xpath("//android.widget.ProgressBar[@resource-id='im.vector.alpha:id/media_progress_view']"));
		} catch (Exception e) {
			return null;
		}
	}

	/*
	 * NOTIFICATION AREA
	 */
	@AndroidFindBy(id="im.vector.alpha:id/room_notifications_area")
	public MobileElement roomNotificationArea;
	@AndroidFindBy(id="im.vector.alpha:id/room_notification_icon")
	public MobileElement notificationIcon;
	@AndroidFindBy(id="im.vector.alpha:id/room_notification_message")
	public MobileElement notificationMessage;

	/**
	 * Click on "Resend All" link on the messages not sent due to unknown devices messages, on the notification area.
	 */
	public void clickOnResendAllLinkFromNotificationArea(){
		notificationMessage.getSize().getWidth();notificationMessage.getCenter();
		int xLink=notificationMessage.getCenter().getX()+10;
		int yLink=notificationMessage.getLocation().getY()+(notificationMessage.getSize().getHeight()/4)*3;
		driver.tap(1, xLink, yLink, 10);
	}
	//MobileElement lastMessage=(MobileElement) getDriver().findElementByXPath("//android.widget.ListView[@resource-id='im.vector.alpha:id/listView_messages']/android.widget.LinearLayout[last()]");

	/*
	 * BOTTOM BAR : send edittext, attachment button, callbutton
	 */
	//@AndroidFindBy(xpath="//android.widget.RelativeLayout[@resource-id='im.vector.alpha:id/room_bottom_layout']//android.widget.EditText[@resource-id='im.vector.alpha:id/editText_messageBox']")
	@AndroidFindBy(id="im.vector.alpha:id/editText_messageBox")
	public MobileElement messageZoneEditText;
	@AndroidFindBy(id="im.vector.alpha:id/room_send_layout")
	public MobileElement sendMessageButton;
	@AndroidFindBy(id="im.vector.alpha:id/room_start_call_layout")//start a call button
	public MobileElement startCallButton;
	@AndroidFindBy(id="im.vector.alpha:id/room_end_call_layout")//end a call button
	public MobileElement endCallButton;

	/*
	 * CONTEXT MENU ON MESSAGE
	 */
	@AndroidFindBy(className="android.widget.ListView")//list items menu
	public MobileElement menuListItems;
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView[@text='Quote']/../..")//quote item
	public MobileElement quoteItemFromMenu;

	/*
	 * POPING MENU: CALL MENU (voice call, video call), or ATTACHMENT MENU (send files, take photo)
	 */
	@AndroidFindBy(id="im.vector.alpha:id/listView_icon_and_text")//call menu with voice and videos buttons
	public MobileElement callMenuList;
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView[@text='Voice Call']/..")//call menu with voice and videos buttons
	public MobileElement voiceCallFromMenuButton;
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView[@text='Video Call']/..")//video menu with voice and videos buttons
	public MobileElement videoCallFromMenuButton;
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView[@text='Send files']/..")//send files menu with send files and take photo buttons
	public MobileElement sendFilesFromMenuButton;
	@AndroidFindBy(xpath="//android.widget.ListView//android.widget.TextView[@text='Take photo or video']/..")//take photo menu with send files and take photo buttons
	public MobileElement takePhotoFromMenuButton;

	/*
	 * ALERT DIALOG
	 */
	/**
	 * Cancel Button.
	 */
	@AndroidFindBy(id="android:id/button2")
	public MobileElement alertDialogButton1;
	/**
	 * Leave Button.
	 */
	@AndroidFindBy(id="android:id/button1")
	public MobileElement alertDialogButton2;
	@AndroidFindBy(id="im.vector.alpha:id/parentPanel")
	public MobileElement inputDialogMainLayout;
	@AndroidFindBy(id="im.vector.alpha:id/alertTitle")
	public MobileElement inputDialogNameTextView;
	@AndroidFindBy(id="android:id/message")
	public MobileElement inputDialogTextView;

	/*
	 * Functions
	 */
	/**
	 * Type and send a message.
	 * @param message
	 */
	public void sendAMessage(String message){
		ExplicitWait(driver, messageZoneEditText);
		messageZoneEditText.sendKeys(message);//messageZoneEditText.setValue(message); //<-- doesn't work on this edittext
		sendMessageButton.click();
		System.out.println("Message "+message+" sent in the room.");
	}

	/**
	 * Wait for a new post to arrive in the room.
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InterruptedException
	 */
	public void waitForReceivingNewMessage(int maxSecondsToWait) throws InstantiationException, IllegalAccessException, InterruptedException{
		int sizeAtBegining=postsListLayout.size();
		float secondsWaited=0;
		while (postsListLayout.size()==sizeAtBegining && secondsWaited<maxSecondsToWait) {
			Thread.sleep(500);secondsWaited=(float) (secondsWaited+0.5);
		}
	}

	/**
	 * Wait for the posts lists to be not empty.
	 * @throws InterruptedException
	 */
	public void waitForPostsToBeDisplayed() throws InterruptedException{
		int maxSecondsToWait=10;
		float secondsWaited=0;
		while (postsListLayout.size()==0 && secondsWaited<maxSecondsToWait) {
			Thread.sleep(500);secondsWaited=(float) (secondsWaited+0.5);
		}
	}

	/**
	 * Wait until progress bar in the post is still displayed.
	 * @param postLinearLayout
	 * @param maxToWait
	 * @throws InterruptedException
	 */
	public Boolean waitAndCheckForMediaToBeUploaded(MobileElement postLinearLayout, int maxToWait) throws InterruptedException {
		float secondsWaited=0;Boolean uploaded=false;
		while (getProgressionBarFromPost(postLinearLayout)!=null && secondsWaited<maxToWait) {
			Thread.sleep(500);secondsWaited=(float) (secondsWaited+0.5);
		}
		if(getProgressionBarFromPost(postLinearLayout)==null){
			uploaded=true;
			System.out.println("Media uploaded after "+secondsWaited+" s.");
		}
		return uploaded;
	}
	
	/**
	 * Check that a photo is present in a post by checking his dimension.
	 * @param post
	 */
	public void checkThatPhotoIsPresentInPost(MobileElement post){
		org.openqa.selenium.Dimension takenPhoto=this.getAttachedImageByPost(post).getSize();
	    Assert.assertTrue(takenPhoto.height!=0 && takenPhoto.width!=0, "The unsent photo has null dimension");
	}

	/**
	 * From a room, take a photo and attach it to the messages.
	 * @param photoSize : choose between Original, Large, Medium, Small.
	 * @throws InterruptedException 
	 */
	public void attachPhotoFromCamera(String photoSize) throws InterruptedException{
		sendMessageButton.click(); //(this button id is for both attachment files and send message buttons)
		takePhotoFromMenuButton.click();
		RiotCameraPageObjects cameraPreview = new RiotCameraPageObjects(driver);
		cameraPreview.triggerCameraButton.click();//take a photo
		waitUntilDisplayed(driver,"im.vector.alpha:id/medias_picker_preview_layout", true, 5);
		cameraPreview.confirmPickingPictureButton.click();
		ExplicitWaitToBeVisible(driver,cameraPreview.sendAsMenuLayout);
		cameraPreview.getItemFromSendAsMenu(photoSize).click();
		//wait until the progress layout on the room page is gone. Don't mix up with the progress bar in the post showing the upload of the media.
		waitUntilDisplayed(driver, "im.vector.alpha:id/medias_processing_progress", false, 10);
	}

	/**
	 * Start a voice call from the room page.
	 * @throws InterruptedException 
	 */
	public void startVoiceCall() throws InterruptedException {
		waitForPostsToBeDisplayed();
		startCallButton.click();
		voiceCallFromMenuButton.click();
	}

	public void startVideoCall() throws InterruptedException{
		waitForPostsToBeDisplayed();
		startCallButton.click();
		videoCallFromMenuButton.click();
	}
	
	/*
	 * Encryption
	 */
	/**
	 * Close the warning alert about the beta state of encryption when user enters the first time in a room.
	 * @throws InterruptedException
	 */
	public void closeWarningAlertAboutBetaStateOfE2e() throws InterruptedException{
		if(waitUntilDisplayed(driver, "im.vector.alpha:id/parentPanel", true, 1)){
			alertDialogButton2.click();
		}
	}
} public class RiotUnknownDevicesPageObjects extends TestUtilities {
	private AndroidDriver<MobileElement> driver;
	public RiotUnknownDevicesPageObjects(AppiumDriver<MobileElement> myDriver) throws InterruptedException{
		driver=(AndroidDriver<MobileElement>) myDriver;
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		try {
			waitUntilDisplayed((AndroidDriver<MobileElement>) driver,"android:id/parentPanel", true, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * ALERT TITLE
	 */
	@AndroidFindBy(id="android:id/alertTitle")
	public MobileElement alertTitleTextView;
	
	/*
	 * ALERT BODY
	 */
	@AndroidFindBy(id="im.vector.alpha:id/unknown_devices_list_view")
	public MobileElement alertBodyListView;
	/**
	 * Text view containing the main message.
	 */
	@AndroidFindBy(xpath="//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/unknown_devices_list_view']//android.widget.TextView")
	public MobileElement alertBodyMessageTextView;
	
	/**
	 * List of the collapsable items containing the unknown devices of a user.
	 */
	@AndroidFindBy(xpath="//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/unknown_devices_list_view']/android.widget.RelativeLayout/android.widget.RelativeLayout/android.widget.TextView[@resource-id='im.vector.alpha:id/heading']/../")
	public List<MobileElement> userNameSectionCollapsableList;
	
	/**
	 * List of unknown devices items. An item contains the device name, the device id and the two buttons: verify/unverify, blacklist/unblacklist.
	 */
	@AndroidFindBy(xpath="//android.widget.ExpandableListView[@resource-id='im.vector.alpha:id/unknown_devices_list_view']//android.widget.TextView[@resource-id='im.vector.alpha:id/device_name']/..")
	public List<MobileElement> unknownDevicesItemsList;
	
	/*
	 * ALERT BOTTOM
	 */
	@AndroidFindBy(id="android:id/buttonPanel")
	public MobileElement buttonPanel;
	
	@AndroidFindBy(id="android:id/button1")
	public MobileElement sendAnywayButton;
	@AndroidFindBy(id="android:id/button3")
	public MobileElement okButton;
	
	public void checkUnknownDevicesModal(){
		Assert.assertEquals(alertTitleTextView.getText(), "Room contains unknown devices", "Modal title is wrong.");
		Assert.assertEquals(alertBodyMessageTextView.getText(), "This room contains unknown devices which have not been verified.\nThis means there is no guarantee that the devices belong to the users they claim to.\nWe recommend you go through the verification process for each device before continuing, but you can resend the message without verifying if you prefer.\n\nUnknown devices:", "Modal main message is wrong.");
		Assert.assertTrue(unknownDevicesItemsList.size()>=1, "There is less than 1 device to verify");
		Assert.assertEquals(sendAnywayButton.getText(), "Send Anyway");
		Assert.assertEquals(okButton.getText(), "OK");
	}
	
	/**
	 * Return the device name of an item at indexDevice.
	 * @param indexDevice
	 * @return
	 */
	public String getDeviceNameByIndex(int indexDevice){
		if(indexDevice<unknownDevicesItemsList.size()){
			return unknownDevicesItemsList.get(indexDevice).findElementById("im.vector.alpha:id/device_name").getText();
		}else{
			System.out.println("There is not device item at index "+indexDevice);
			return null;
		}
	}
	
	/**
	 * Return the device id of an item at indexDevice.
	 * @param indexDevice
	 * @return
	 */
	public String getDeviceIDByIndex(int indexDevice){
		if(indexDevice<unknownDevicesItemsList.size()){
			return unknownDevicesItemsList.get(indexDevice).findElementById("im.vector.alpha:id/device_id").getText();
		}else{
			System.out.println("There is not device item at index "+indexDevice);
			return null;
		}
	}
	
	
	/**
	 * Hit the verify button of a device by his index position.
	 * @param indexDevice
	 */
	public MobileElement getVerifyDeviceButton(int indexDevice){
		if(indexDevice<unknownDevicesItemsList.size()){
			return unknownDevicesItemsList.get(indexDevice).findElementById("im.vector.alpha:id/button_verify");
		}else{
			System.out.println("There is not device item at index "+indexDevice);
			return null;
		}
	}
} public class RiotVerifyDevicePageObjects extends TestUtilities{
	private AndroidDriver<MobileElement> driver;
	public RiotVerifyDevicePageObjects(AppiumDriver<MobileElement> myDriver) throws InterruptedException{
		driver=(AndroidDriver<MobileElement>) myDriver;
		PageFactory.initElements(new AppiumFieldDecorator(myDriver), this);
		try {
			waitUntilDisplayed((AndroidDriver<MobileElement>) driver,"im.vector.alpha:id/parentPanel", true, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/*
	 * ALERT TITLE
	 */
	@AndroidFindBy(id="im.vector.alpha:id/alertTitle")
	public MobileElement alertTitleTextView;

	/*
	 * ALERT BODY
	 */
	@AndroidFindBy(xpath="//android.widget.ScrollView/android.widget.LinearLayout/android.widget.TextView[1]")
	public MobileElement alertBodyMessageTextView1;

	@AndroidFindBy(id="im.vector.alpha:id/encrypted_device_info_device_name")
	public MobileElement alertDeviceNameTextView;
	@AndroidFindBy(id="im.vector.alpha:id/encrypted_device_info_device_id")
	public MobileElement alertDeviceIdTextView;
	@AndroidFindBy(id="im.vector.alpha:id/encrypted_device_info_device_key")
	public MobileElement alertDeviceKeyTextView;

	@AndroidFindBy(xpath="//android.widget.ScrollView/android.widget.LinearLayout/android.widget.TextView[8]")
	public MobileElement alertBodyMessageTextView2;

	/*
	 * ALERT BOTTOM
	 */
	@AndroidFindBy(id="android:id/button1")
	public MobileElement alertVerifyButton;
	@AndroidFindBy(id="android:id/button2")
	public MobileElement alertCancelButton;

	/**
	 * Verify the alert title, messages and the device name, id and key.</br>
	 * Put these parameters as null if you don't want to test it.
	 * @param deviceName
	 * @param deviceId
	 * @param deviceKey
	 */
	public void checkVerifyDeviceAlert(String deviceName, String deviceId, String deviceKey){
		Assert.assertEquals(alertTitleTextView.getText(), "Verify device");
		Assert.assertEquals(alertBodyMessageTextView1.getText(), "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:");
		Assert.assertEquals(alertBodyMessageTextView2.getText(), "If it matches, press the verify button below. If it doesnt, then someone else is intercepting this device and you probably want to press the block button instead.\nIn future this verification process will be more sophisticated.");
		Assert.assertEquals(alertVerifyButton.getText(), "I verify that the keys match");
		Assert.assertEquals(alertCancelButton.getText(), "Cancel");
		
		if(deviceName!=null){
			Assert.assertEquals(alertDeviceNameTextView.getText(), deviceName, "Device name in the 'Verify device' alert isn't the one expected.");
		}else{
			Assert.assertNotNull(alertDeviceNameTextView.getText());
		}
		if(deviceId!=null){
			Assert.assertEquals(alertDeviceIdTextView.getText(), deviceId, "Device id in the 'Verify device' alert isn't the one expected.");
		}else{
			Assert.assertNotNull(alertDeviceIdTextView.getText());
		}
		if(deviceKey!=null){
			Assert.assertEquals(alertDeviceKeyTextView.getText(), deviceKey, "Device key in the 'Verify device' alert isn't the one expected.");
		}else{
			Assert.assertNotNull(alertDeviceKeyTextView.getText());
		}
	}
} public class RiotHomePageTabObjects extends RiotTabPageObjects{

	public RiotHomePageTabObjects(AppiumDriver<MobileElement> myDriver) throws InterruptedException {
		super(myDriver);
		super.roomsList=this.roomsList;
		PageFactory.initElements(new AppiumFieldDecorator(driver), this);
		Assert.assertTrue(waitUntilDisplayed((AndroidDriver<MobileElement>) driver,"im.vector.alpha:id/fragment_container", true, 10),"HomePage tab isn't open.");
	}

	/*
	 * INVITES
	 */
	/*
	 * 		Favourites Section.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/invitations_section")
	public MobileElement invitesSectionLayout;
	
	/*
	 * ROOMS.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/circular_room_view")
	public List<WebElement> roomsList;
	/**
	 * Contains only the header of the section. His direct parent contains the section and the rooms.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/section_header")
	public List<WebElement> roomsHeader;
	
	/**
	 * Swipe on the left on a room section.
	 */
	public void leftSwipeOnRoomSection(MobileElement roomSection){
		int xStart, y;
		xStart=roomSection.getLocation().getX()+roomSection.getSize().width-10;
		y=roomSection.getLocation().getY()+roomSection.getSize().getHeight()/2;
		driver.swipe(xStart, y, 0, y, 300);
		//new TouchAction(driver).press(xStart, y).waitAction(500).moveTo(0, 0).perform();
	}
	
	/**
	 * Swipe on section until the room is found then returns it.
	 * @param roomSection
	 * @param roomName
	 * @param swipeNumberMax
	 * @return room
	 */
	public MobileElement swipeSectionUntilRoomDisplayed(MobileElement roomSection, String roomName, int swipeNumberMax){
		int nbSwipeDone=0;
		MobileElement room;
		while (null==(room=getRoomFromSectionByName(roomSection,roomName)) && nbSwipeDone<swipeNumberMax) {
			leftSwipeOnRoomSection(roomSection);
			nbSwipeDone++;
		}
		if(null==room)
			System.out.println("Room "+roomName+ " not found after "+nbSwipeDone+" swipes on his section.");
		return room;
	}
	
	/**
	 * Hit a section using his name. Can be use to focus on the related rooms or collapse a section.
	 * @param sectionName
	 */
	public void hitSectionHeader(String sectionName){
		try {
			driver.findElementByXPath("//android.widget.RelativeLayout/android.widget.TextView[contains(@text,'"+sectionName+"')]").click();
		} catch (Exception e) {
			Assert.fail("No section found with name: "+sectionName);
		}
	}
	
	/**
	 * Return a room as a MobileElement. </br>
	 * Return null if not found.
	 * @param myRoomName
	 * @return
	 */
	public MobileElement getRoomByName(String myRoomName){
		try {
			return (MobileElement) driver.findElementByXPath("//android.support.v7.widget.RecyclerView//android.widget.TextView[@text='"+myRoomName+"']/..");	
			//return roomsListView.findElementByName(myRoomName);
		} catch (Exception e) {
			System.out.println("No room found with name "+myRoomName);
			return null;
		}
	}
	
	/**
	 * Search and returns a room from a section (Favourites, people, rooms, low priority).
	 * @param section
	 * @param myRoomName
	 * @return
	 */
	public MobileElement getRoomFromSectionByName(MobileElement section,String myRoomName){
		try {
			return section.findElementByXPath("//android.widget.RelativeLayout[@resource-id='im.vector.alpha:id/circular_room_view']/android.widget.TextView[@text='"+myRoomName+"']");
		} catch (Exception e) {
			System.out.println("No room found with name "+myRoomName+ " in this section.");
			return null;
		}
	}
	
	/**
	 * Only for HOME PAGE. </br>
	 * Check that room is in a room category (favorites, people, rooms, etc). </br>
	 * TODO maybe scroll to the end of the list to check the room ?
	 * @param roomNameTest
	 * @param category : can be : Favourites, People, Rooms, Low priority
	 */
	public Boolean checkRoomInCategory(String roomNameTest, MobileElement roomSection, int nbSwipeTrials) {
		System.out.println("Looking for room "+roomNameTest+" in the category "+roomSection);
		return null!=swipeSectionUntilRoomDisplayed(roomSection, roomNameTest,nbSwipeTrials);
	}
	
	/**
	 * Click on the context menu on a room, then choose one of the item : Notifications, Favourite, De-prioritize, Direct Chat, Leave Conversation
	 * @param roomName
	 * @param item
	 * @throws InterruptedException 
	 */
	public void clickOnContextMenuOnRoom(String roomName, String item) throws InterruptedException{
		//open contxt menu on a room item
		MobileElement roomItem=getRoomByName(roomName);
		if(null!=roomItem){
			TouchAction longPressAction = new TouchAction(driver);
			longPressAction.longPress(roomItem, 500).perform();
			//hit the item on the options
			driver.findElementByXPath("//android.widget.ListView//android.widget.TextView[@text='"+item+"']/../..").click();
			Assert.assertFalse(waitUntilDisplayed(driver,"//android.widget.ListView[count(android.widget.LinearLayout)=4]", false, 0), "Option windows isn't closed");	
		}else{
			System.out.println("No room found with name "+roomName+", impossible to click on item "+item+" on context menu.");
		}
	}
	
	/*
	 * 		Favourites Section.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/favourites_section")
	public MobileElement favouritesSectionLayout;
	
	/*
	 * 		People Section.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/direct_chats_section")
	public MobileElement directChatSectionLayout;
	
	/*
	 * 		Rooms Section.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/rooms_section")
	public MobileElement roomsSectionLayout;
	/*
	 * 		Low Priority Section.
	 */
	@AndroidFindBy(id="im.vector.alpha:id/low_priority_section")
	public MobileElement lowPrioritySectionLayout;
} public class Constant {
	public static final String FILE_TESTDATA = "testdata1.xlsx";
	/*
	 * APPIUM SERVERS
	 */
	public static final String SERVER1_ADDRESS="0.0.0.0";
	public static final String SERVER2_ADDRESS="127.0.0.1";
	public static final String APPIUM_COMMON_PORT="4723";
	public static final String WEBDRIVERAGENT_PORT="8080";
	public static final String SERVER1_HTTP_ADDRESS="http://"+SERVER1_ADDRESS+":"+APPIUM_COMMON_PORT+"/wd/hub";
	public static final String SERVER2_HTTP_ADDRESS="http://"+SERVER2_ADDRESS+":"+APPIUM_COMMON_PORT+"/wd/hub";

	public static final String getServer1HttpAddress() throws FileNotFoundException, YamlException{
		if("2"==ReadConfigFile.getInstance().getConfMap().get("starting_server_mode"))
			return AppiumServerStartAndStopService.service_url1;
		else
			return SERVER1_HTTP_ADDRESS;
	}

	public static final String getServer2HttpAddress() throws FileNotFoundException, YamlException{
		if("2"==ReadConfigFile.getInstance().getConfMap().get("starting_server_mode"))
			return AppiumServerStartAndStopService.service_url2;
		else
			return SERVER2_HTTP_ADDRESS;
	}

	/*
	 * CONF
	 */
	public static final String CONFIG_FILE = "src/test/java/config/config.yaml";
	public static final String DEVICES_CONFIG_FILE ="src/test/java/config/devices.yaml";

	/*
	 * RIOT
	 */
	public static final String APPLICATION_NAME = "RIOT";
	/*
	 * 			iOS-specific
	 */
	public static final String APP_BUNDLE_ID = "im.vector.app";
	public static final String PATH_TO_IOS_IPA="/buildipa/riot-ios/out/Vector.ipa";
	/*
	 * 			Android-specific
	 */
	public static final String PACKAGE_APP_NAME = "im.vector.alpha";
	public static final String APPLICATION_LOGIN_ACTIVITY="im.vector.activity.LoginActivity";
	public static final String PATH_TO_ANDROID_APK="/buildapk/riot-android/out/Vector.apk";


	/*
	 * NODE JS AND APPIUM
	 */
	public static final String PATH_TO_NODE_DIRECTORY="/usr/local/bin/node";
	public static final String PATH_TO_APPIUM_JAVASCRIPT="/usr/local/lib/node_modules/appium/build/lib/main.js";
	/*
	 * MISC 
	 */
	public static final String PATH_TESTDATA = "src//test//resources//testDatas//";
	public static final String DEFAULT_USERNAME="riotuser2";
	public static final String DEFAULT_USERPWD="riotuser";
	public static final String DEFAULT_USERADRESS="@riotuser2:matrix.org";
	public static final String DEFAULT_MATRIX_SERVER_URL="https://matrix.org";
	public static final String DEFAULT_MATRIX_SERVER="matrix.org";
	public static final String DEFAULT_IDENTITY_SERVER_URL="https://vector.im";

	/*
	 * E2E ENCRYPTION
	 */
	public static final String ENCRYPTION_TURNEDON_EVENT="turned on end-to-end encryption";
	public static final String ENCRYPTION_UNKNOWN_SESSION_ID_MSG="** Unable to decrypt: The sender's device has not sent us the keys for this message. **";
} public abstract class RiotParentTest extends TestUtilities {
	public static AppiumFactory appiumFactory=AppiumFactory.getInstance();

	@BeforeGroups(groups="1driver_android")
	public void setUp1AndroidDriver() throws Exception{
		//Start appium server 1 if necessary.
		startAppiumServer1();

		//Create android driver 1 if necessary
		//if(appiumFactory.getAndroidDriver1()==null || appiumFactory.getAndroidDriver1()!=null && appiumFactory.getAndroidDriver1().getSessionId()==null){
		if(appiumFactory.getAndroidDriver1()==null || appiumFactory.getAndroidDriver1().getSessionId()==null){
			Map<String, String> androidDevice1=ReadConfigFile.getInstance().getDevicesMap().get("androiddevice1");
			DesiredCapabilities capabilities = new DesiredCapabilities();
			capabilities.setCapability(MobileCapabilityType.UDID,androidDevice1.get(MobileCapabilityType.UDID));
			capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,androidDevice1.get(MobileCapabilityType.DEVICE_NAME));
			capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME,androidDevice1.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, androidDevice1.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities.setCapability("appPackage", Constant.PACKAGE_APP_NAME);
			capabilities.setCapability("appActivity", Constant.APPLICATION_LOGIN_ACTIVITY);
			capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
			capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);
			capabilities.setCapability(MobileCapabilityType.FULL_RESET, false);
			//Set android driver 1
			appiumFactory.setAndroidDriver1(new URL(Constant.getServer1HttpAddress()), capabilities);
			System.out.println("Application "+Constant.PACKAGE_APP_NAME+" started on device "+capabilities.getCapability(MobileCapabilityType.DEVICE_NAME) +" with AppiumDriver 1.");	
		}
	}

	/**
	 * @throws Exception
	 */
	@BeforeGroups(groups="2drivers_android")
	public void setUp2AndroidDrivers() throws Exception{
		//Start the two appium's servers if necessary.
		start2AppiumServers();

		Map<String, String> androidDevice1=ReadConfigFile.getInstance().getDevicesMap().get("androiddevice1");
		Map<String, String> androidDevice2=ReadConfigFile.getInstance().getDevicesMap().get("androiddevice2");

		//Create android driver 1 if necessary
		if(appiumFactory.getAndroidDriver1()==null || appiumFactory.getAndroidDriver1().getSessionId()==null){
			DesiredCapabilities capabilities1 = new DesiredCapabilities();
			capabilities1.setCapability(MobileCapabilityType.UDID,androidDevice1.get(MobileCapabilityType.UDID));
			capabilities1.setCapability(MobileCapabilityType.DEVICE_NAME,androidDevice1.get(MobileCapabilityType.DEVICE_NAME));
			capabilities1.setCapability(MobileCapabilityType.PLATFORM_NAME,androidDevice1.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities1.setCapability(MobileCapabilityType.PLATFORM_VERSION, androidDevice1.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities1.setCapability("appPackage", Constant.PACKAGE_APP_NAME);
			capabilities1.setCapability("appActivity", Constant.APPLICATION_LOGIN_ACTIVITY);
			capabilities1.setCapability(MobileCapabilityType.NO_RESET, true);
			capabilities1.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, "1200");
			capabilities1.setCapability(MobileCapabilityType.FULL_RESET, false);

			appiumFactory.setAndroidDriver1(new URL(Constant.getServer1HttpAddress()), capabilities1);
			System.out.println("Application "+Constant.APPLICATION_NAME+" started on ANDROID device "+capabilities1.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 1.");	
		}

		if(appiumFactory.getAndroidDriver2()==null || appiumFactory.getAndroidDriver2().getSessionId()==null){
			DesiredCapabilities capabilities2 = new DesiredCapabilities();
			capabilities2.setCapability(MobileCapabilityType.UDID,androidDevice2.get(MobileCapabilityType.UDID));
			capabilities2.setCapability(MobileCapabilityType.DEVICE_NAME,androidDevice2.get(MobileCapabilityType.DEVICE_NAME));
			capabilities2.setCapability(MobileCapabilityType.PLATFORM_NAME,androidDevice2.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities2.setCapability(MobileCapabilityType.PLATFORM_VERSION, androidDevice2.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities2.setCapability("appPackage", Constant.PACKAGE_APP_NAME);
			capabilities2.setCapability("appActivity", Constant.APPLICATION_LOGIN_ACTIVITY);
			capabilities2.setCapability(MobileCapabilityType.NO_RESET, true);
			capabilities2.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, "1200");
			capabilities2.setCapability(MobileCapabilityType.FULL_RESET, false);
			appiumFactory.setAndroidDriver2(new URL(Constant.getServer2HttpAddress()), capabilities2);
			System.out.println("Application "+Constant.APPLICATION_NAME+" started on ANDROID device "+capabilities2.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 2.");
		}
	}

	//	@AfterGroups(groups="1driver_android")
	//	public void tearDownAndroidDriver1() throws Exception{
	//		appiumFactory.getAndroidDriver1().quit();
	//		System.out.println("Android DRIVER 1 quitted on ANDROID device "+ReadConfigFile.getInstance().getDevicesMap().get("androiddevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//		System.out.println("session id driver 1 after quitting :"+appiumFactory.getAndroidDriver1().getSessionId());
	//		//Stop appium server1.
	//		stopAppiumServer1();
	//	}
	//
	//	@AfterGroups(groups={"2drivers_android"}, alwaysRun=true)
	//	public void tearDown2AndroidDrivers() throws Exception{
	//		appiumFactory.getAndroidDriver1().quit();
	//		System.out.println("Android DRIVER 1 quitted on ANDROID device "+ReadConfigFile.getInstance().getDevicesMap().get("androiddevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//		appiumFactory.getAndroidDriver2().quit();
	//		System.out.println("Android DRIVER 2 quitted on ANDROID device "+ReadConfigFile.getInstance().getDevicesMap().get("androiddevice2").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//		System.out.println("session id driver 1 after quitting :"+appiumFactory.getAndroidDriver1().getSessionId());
	//		System.out.println("session id driver 2 after quitting :"+appiumFactory.getAndroidDriver2().getSessionId());
	//		//Stop the two appium's servers.
	//		stop2AppiumServers();
	//	}

	@AfterGroups(groups={"2drivers_android","1driver_android","1driver_ios","2drivers_ios"})
	public void tearDownAllDrivers() throws Exception{
		if(null!=appiumFactory.getAndroidDriver1()){
			appiumFactory.getAndroidDriver1().quit();
			System.out.println("Android DRIVER 1 quitted on ANDROID device "+ReadConfigFile.getInstance().getDevicesMap().get("androiddevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");	
		}
		if(null!=appiumFactory.getAndroidDriver2()){
			appiumFactory.getAndroidDriver2().quit();
			System.out.println("Android DRIVER 2 quitted on ANDROID device "+ReadConfigFile.getInstance().getDevicesMap().get("androiddevice2").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");	
		}
		if(null!=appiumFactory.getiOsDriver1()){
			appiumFactory.getiOsDriver1().quit();
			System.out.println("Ios DRIVER 1 quitted on iOS device "+ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");	
		}
		if(null!=appiumFactory.getiOsDriver2()){
			appiumFactory.getiOsDriver2().quit();
			System.out.println("Ios DRIVER 2 quitted on iOS device "+ReadConfigFile.getInstance().getDevicesMap().get("iosdevice2").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");	
		}
		//Stop the two appium's servers.
		stop2AppiumServers();
	}

	@BeforeGroups(groups="1driver_ios")
	public void setUp1IosDriver() throws Exception{
		//Start appium server 1 if necessary.
		startAppiumServer1();

		//Create ios driver 1 if necessary
		if(appiumFactory.getiOsDriver1()==null || appiumFactory.getiOsDriver1().getSessionId()==null){
			Map<String, String> iosDevice1=ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1");
			DesiredCapabilities capabilities = new DesiredCapabilities();
			capabilities.setCapability(MobileCapabilityType.UDID, iosDevice1.get(MobileCapabilityType.UDID));
			capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,iosDevice1.get(MobileCapabilityType.DEVICE_NAME));
			capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME,iosDevice1.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, iosDevice1.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities.setCapability(IOSMobileCapabilityType.BUNDLE_ID, "im.vector.app");
			capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME,iosDevice1.get(MobileCapabilityType.AUTOMATION_NAME));
			capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
			capabilities.setCapability(MobileCapabilityType.FULL_RESET, false);
			capabilities.setCapability("xcodeOrgId", ReadConfigFile.getInstance().getConfMap().get("development_team"));
			capabilities.setCapability("xcodeSigningId", ReadConfigFile.getInstance().getConfMap().get("code_sign_identity"));
			//capabilities.setCapability("xcodeConfigFile", "/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/Configurations/ProjectSettings.xcconfig");
			//capabilities.setCapability("keychainPath","/Users/matrix/Library/Keychains/appiumKeychain.keychain");
			//capabilities.setCapability("keychainPassword","appium6754");
			capabilities.setCapability("autoDismissAlerts", false);
			capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);

			appiumFactory.setiOSDriver1(new URL(Constant.getServer1HttpAddress()), capabilities);
			System.out.println("Application "+Constant.APPLICATION_NAME+" started on IOS device "+capabilities.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 1.");
		}
	}

	@BeforeGroups(groups="1driver_ios_install")
	public void setUp1IosDriverForInstallation() throws Exception{
		//Start appium server 1 if necessary.
		startAppiumServer1();
		Map<String, String> iosDevice1=ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1");

		DesiredCapabilities capabilities = new DesiredCapabilities();
		capabilities.setCapability(MobileCapabilityType.UDID, iosDevice1.get(MobileCapabilityType.UDID));
		capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,iosDevice1.get(MobileCapabilityType.DEVICE_NAME));
		capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME,iosDevice1.get(MobileCapabilityType.PLATFORM_NAME));
		capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, iosDevice1.get(MobileCapabilityType.PLATFORM_VERSION));
		capabilities.setCapability(MobileCapabilityType.APP, System.getProperty("user.dir")+Constant.PATH_TO_IOS_IPA);
		//capabilities.setCapability("bundleId", "im.vector.app");
		//XCUITest is used because Appium Ios driver doesn't support xcode version 8.0
		capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME,iosDevice1.get(MobileCapabilityType.AUTOMATION_NAME));
		capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
		capabilities.setCapability(MobileCapabilityType.FULL_RESET, false);
		capabilities.setCapability("xcodeOrgId", ReadConfigFile.getInstance().getConfMap().get("development_team"));
		capabilities.setCapability("xcodeSigningId", ReadConfigFile.getInstance().getConfMap().get("code_sign_identity"));
		capabilities.setCapability(IOSMobileCapabilityType.AUTO_DISMISS_ALERTS, false);
		capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);
		//		capabilities.setCapability("autoWebview", true);

		AppiumFactory appiumFactory=AppiumFactory.getInstance();
		appiumFactory.setiOSDriver1(new URL(Constant.getServer1HttpAddress()), capabilities);
		System.out.println("Application "+Constant.APPLICATION_NAME+" started on IOS device "+capabilities.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 1.");
	}

	@BeforeGroups(groups="2drivers_ios")
	public void setUp2IosDriver() throws Exception{
		//Start the two appium's servers if necessary.
		Boolean iosDriver1NeedToStart=false;
		start2AppiumServers();

		//Create ios driver 1 if necessary
		if(appiumFactory.getiOsDriver1()==null || appiumFactory.getiOsDriver1().getSessionId()==null){
			iosDriver1NeedToStart=true;
			Map<String, String> iosDevice1=ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1");
			DesiredCapabilities capabilities1 = new DesiredCapabilities();
			capabilities1.setCapability(MobileCapabilityType.UDID, iosDevice1.get(MobileCapabilityType.UDID));
			capabilities1.setCapability(MobileCapabilityType.DEVICE_NAME,iosDevice1.get(MobileCapabilityType.DEVICE_NAME));
			capabilities1.setCapability(MobileCapabilityType.PLATFORM_NAME,iosDevice1.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities1.setCapability(MobileCapabilityType.PLATFORM_VERSION, iosDevice1.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities1.setCapability(IOSMobileCapabilityType.BUNDLE_ID, "im.vector.app");
			//capabilities.setCapability(MobileCapabilityType.APP,"/Users/matrix/Documents/apps/ipa/Vector-d5ce6ff019a3e6b06a20bcc849ab57074e31e773-build1399.ipa");
			//XCUITest is used because Appium Ios driver doesn't support xcode version 8.0
			capabilities1.setCapability(MobileCapabilityType.AUTOMATION_NAME,iosDevice1.get(MobileCapabilityType.AUTOMATION_NAME));
			capabilities1.setCapability(MobileCapabilityType.NO_RESET, true);
			capabilities1.setCapability(MobileCapabilityType.FULL_RESET, false);
			capabilities1.setCapability("xcodeOrgId", ReadConfigFile.getInstance().getConfMap().get("development_team"));
			capabilities1.setCapability("xcodeSigningId", ReadConfigFile.getInstance().getConfMap().get("code_sign_identity"));
			capabilities1.setCapability(IOSMobileCapabilityType.AUTO_DISMISS_ALERTS, false);
			capabilities1.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);

			appiumFactory.setiOSDriver1(new URL(Constant.getServer1HttpAddress()), capabilities1);
			System.out.println("Application "+Constant.APPLICATION_NAME+" started on IOS device "+capabilities1.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 1.");
		}

		//Create ios driver 2 if necessary
		if(appiumFactory.getiOsDriver2()==null || appiumFactory.getiOsDriver2().getSessionId()==null){
			DesiredCapabilities capabilities2 = new DesiredCapabilities();
			Map<String, String> iosDevice2=ReadConfigFile.getInstance().getDevicesMap().get("iosdevice2");
			capabilities2.setCapability(MobileCapabilityType.UDID, iosDevice2.get(MobileCapabilityType.UDID));
			capabilities2.setCapability(MobileCapabilityType.DEVICE_NAME,iosDevice2.get(MobileCapabilityType.DEVICE_NAME));
			capabilities2.setCapability(MobileCapabilityType.PLATFORM_NAME,iosDevice2.get(MobileCapabilityType.PLATFORM_NAME));
			capabilities2.setCapability(MobileCapabilityType.PLATFORM_VERSION, iosDevice2.get(MobileCapabilityType.PLATFORM_VERSION));
			capabilities2.setCapability(IOSMobileCapabilityType.BUNDLE_ID, "im.vector.app");//app
			//capabilities.setCapability(MobileCapabilityType.APP,"/Users/matrix/Documents/apps/ipa/Vector-d5ce6ff019a3e6b06a20bcc849ab57074e31e773-build1399.ipa");
			//XCUITest is used because Appium Ios driver doesn't support xcode version 8.0
			capabilities2.setCapability(MobileCapabilityType.AUTOMATION_NAME,iosDevice2.get(MobileCapabilityType.AUTOMATION_NAME));
			capabilities2.setCapability("realDeviceLogger", "/usr/local/lib/node_modules/deviceconsole/deviceconsole");
			capabilities2.setCapability(MobileCapabilityType.NO_RESET, true);
			//capabilities2.setCapability(MobileCapabilityType.FULL_RESET, false);
			capabilities2.setCapability("xcodeOrgId", ReadConfigFile.getInstance().getConfMap().get("development_team"));
			capabilities2.setCapability("xcodeSigningId", ReadConfigFile.getInstance().getConfMap().get("code_sign_identity"));
			capabilities2.setCapability("autoDismissAlerts", false);
			capabilities2.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1200);
			
			if(!iosDriver1NeedToStart){
				Thread.sleep(5000);
				int timeWaited=0;
				int maxToWait=6;
				while (!AppiumServerStartAndStopService.service2.isRunning()&&timeWaited<maxToWait) {
					timeWaited++;
					Thread.sleep(1000);
				}
				System.out.println(timeWaited);
			}
			appiumFactory.setiOSDriver2(new URL(Constant.getServer2HttpAddress()), capabilities2);
			System.out.println("Application "+Constant.APPLICATION_NAME+" started on IOS device "+capabilities2.getCapability(MobileCapabilityType.DEVICE_NAME) +" with DRIVER 2.");
		}		
	}

	//	@AfterGroups(groups="1driver_ios")
	//	public void tearDownIosDriver1() throws Exception{
	//		appiumFactory.getiOsDriver1().quit();
	//		System.out.println("Ios DRIVER 1 quitted on IOS device "+ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//
	//		//Stop appium server1.
	//		stopAppiumServer1();
	//	}
	//
	//	@AfterGroups(groups={"2drivers_ios"}, alwaysRun=true)
	//	public void tearDown2IosDrivers() throws Exception{
	//		appiumFactory.getiOsDriver1().quit();
	//		System.out.println("Ios DRIVER 1 quitted on IOS device "+ReadConfigFile.getInstance().getDevicesMap().get("iosdevice1").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//		appiumFactory.getiOsDriver2().quit();
	//		System.out.println("Ios DRIVER 2 quitted on IOS device "+ReadConfigFile.getInstance().getDevicesMap().get("iosdevice2").get("deviceName") +", closing application "+Constant.APPLICATION_NAME+".");
	//
	//		//Stop the two appium's servers.
	//		stop2AppiumServers();
	//	}


	/**
	 * According to the chosen starting mode, start the first appium server if needed.
	 * @throws Exception 
	 */
	protected void startAppiumServer1() throws Exception{
		switch (ReadConfigFile.getInstance().getConfMap().get("starting_server_mode")) {
		case "1":
			AppiumServerStartAndStopCmdLine.startAppiumServer1IfNecessary();
			break;
		case "2":
			AppiumServerStartAndStopService.startAppiumServer1IfNecessary();
			break;
		default:
			break;
		}
	}
	/**
	 * According to the chosen starting mode, start the two appiums servers if needed.
	 * @throws Exception 
	 */
	protected void start2AppiumServers() throws Exception{
		switch (ReadConfigFile.getInstance().getConfMap().get("starting_server_mode")) {
		case "1":
			AppiumServerStartAndStopCmdLine.startAppiumServer1IfNecessary();
			AppiumServerStartAndStopCmdLine.startAppiumServer2IfNecessary();
			break;
		case "2":
			AppiumServerStartAndStopService.startAppiumServer1IfNecessary();
			AppiumServerStartAndStopService.startAppiumServer2IfNecessary();
			break;
		default:
			break;
		}
	}
	/**
	 * According to the chosen starting mode, stop the first appium.
	 * @throws Exception 
	 */
	@SuppressWarnings("unused")
	private void stopAppiumServer1() throws Exception{
		switch (ReadConfigFile.getInstance().getConfMap().get("starting_server_mode")) {
		case "1":
			AppiumServerStartAndStopCmdLine.stopAppiumServer1();
			break;
		case "2":
			AppiumServerStartAndStopService.appiumServer1Stop();
			break;
		default:
			break;
		}
	}
	/**
	 * According to the chosen starting mode, stop the two appiums servers.
	 * @throws Exception 
	 */
	private void stop2AppiumServers() throws Exception{
		switch (ReadConfigFile.getInstance().getConfMap().get("starting_server_mode")) {
		case "1":
			AppiumServerStartAndStopCmdLine.stopAppiumServer1();
			AppiumServerStartAndStopCmdLine.stopAppiumServer2();
			break;
		case "2":
			AppiumServerStartAndStopService.appiumServer1Stop();
			AppiumServerStartAndStopService.appiumServer2Stop();
			break;
		default:
			break;
		}
	}

} public class ScreenshotUtility implements ITestListener {
	public static AppiumFactory appiumFactory=AppiumFactory.getInstance();
	
	public void onTestStart(ITestResult result) {

	}

	public void onTestSuccess(ITestResult result) {
		if(appiumFactory.getCurrentDriver()!=null)captureScreenShot(result, "pass");
	}

	public void onTestFailure(ITestResult result) {
		if(appiumFactory.getCurrentDriver()!=null)captureScreenShot(result, "fail");
	}

	public void onTestSkipped(ITestResult result) {

	}

	public void onTestFailedButWithinSuccessPercentage(ITestResult result) {

	}

	public void onStart(ITestContext context) {

	}

	public void onFinish(ITestContext context) {

	}
	// Function to capture screenshot.
	public void captureScreenShot(ITestResult result, String status) {
		//choice of output screenshot according to the sut
		String os="";
		if(appiumFactory.getCurrentDriver() instanceof AndroidDriver<?>){
			os="android";
		}else{
			os="ios";
		}
		System.out.println("Screenshot taken on "+os);
		String destDir = "";
		String passfailMethod = result.getMethod().getRealClass().getSimpleName() + "." + result.getMethod().getMethodName();
		// To capture screenshot.
		File scrFile = ((TakesScreenshot) appiumFactory.getCurrentDriver()).getScreenshotAs(OutputType.FILE);
		DateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy__hh_mm_ssaa");

		// If status = fail then set folder name "screenshots/Failures"
		if (status.equalsIgnoreCase("fail")) {
			destDir = "screenshots_"+os+"/Failures";
		}
		// If status = pass then set folder name "screenshots/Success"
		else if (status.equalsIgnoreCase("pass")) {
			destDir = "screenshots_"+os+"/Success";
		}

		// To create folder to store screenshots
		new File(destDir).mkdirs();
		// Set file name with combination of test class name + date time.
		String destFile = passfailMethod + " - " + dateFormat.format(new Date()) + ".png";

		try {
			// Store file at destination folder location
			FileUtils.copyFile(scrFile, new File(destDir + "/" + destFile));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import com.esotericsoftware.yamlbeans.YamlException;
import pom_android.RiotCallingPageObjects;
import pom_android.RiotIncomingCallPageObjects;
import pom_android.RiotRoomDetailsPageObjects;
import pom_android.RiotRoomPageObjects;
import pom_android.RiotUnknownDevicesPageObjects;
import pom_android.RiotVerifyDevicePageObjects;
import pom_android.main_tabs.RiotHomePageTabObjects;
import utility.Constant;
import utility.RiotParentTest;
import utility.ScreenshotUtility;
package mobilestests_android;





@Listeners({ ScreenshotUtility.class })
public class RiotE2eEncryptionTests extends RiotParentTest{
	private String roomWithEncryption="auto test encryption";
	private String oneToOneRoomWithEncryption="1:1e2e_automated tests";
	private String encrypted_msg_1="msg sent in encrypted room";
	private String encrypted_msg_2="this msg will be decrypted";
	private String participant1DisplayName="riotuser9";
	private String participant2DisplayName="riotuser10";	

	/**
	 * 1. Open room roomWithEncryption.</br>
	 * 2. Send a photo</br>
	 * Check that the photo is correctly uploaded. 
	 * @throws InterruptedException 
	 */
	@Test(groups={"1driver_android","1checkuser"},  priority=4, description="upload a photo in encrypted room")
	public void sendPhotoInEncryptedRoom() throws InterruptedException{
		//1. Create room with Device 1 and enable encryption.
		RiotHomePageTabObjects homePage1=new RiotHomePageTabObjects(appiumFactory.getAndroidDriver1());
		homePage1.getRoomByName(oneToOneRoomWithEncryption).click();
		RiotRoomPageObjects roomPage1=new RiotRoomPageObjects(appiumFactory.getAndroidDriver1());
		roomPage1.closeWarningAlertAboutBetaStateOfE2e();
		// 2. Send a photo
		roomPage1.attachPhotoFromCamera("Small");
		RiotUnknownDevicesPageObjects unknownDevicesModal1 = new RiotUnknownDevicesPageObjects(appiumFactory.getAndroidDriver1());
		unknownDevicesModal1.okButton.click();
		//verifies that it's displayed in the message list
		Assert.assertTrue(roomPage1.waitAndCheckForMediaToBeUploaded(roomPage1.getLastPost(), 10), "Media wasn't uploaded after "+10+"s in encrypted room.");
		org.openqa.selenium.Dimension takenPhoto=roomPage1.getAttachedImageByPost(roomPage1.getLastPost()).getSize();
		Assert.assertTrue(takenPhoto.height!=0 && takenPhoto.width!=0, "The unsent photo has null dimension");
		//come back in rooms list
		roomPage1.menuBackButton.click();
	}

	/**
	 * 1. Open room roomWithEncryption with Device 1.</br>
	 * 2. Open room roomWithEncryption with Device 2.</br>
	 * 3. Start a VOICE call with Device 2.</br>
	 * Check that an incoming layout is displayed on device 1.</br>
	 * 4. Accept call with device 1.</br>
	 * 5. Hang-out after a few seconds.</br>
	 * Check that calling layout is closed on both devices.</br>
	 * 6. Start a VIDEO call with Device 2.</br>
	 * Check that an incoming layout is displayed on device 1.</br>
	 * 7. Accept call with device 1.</br>
	 * 8. Hang-out after a few seconds.</br>
	 * Check that calling layout is closed on both devices.
	 * @throws InterruptedException 
	 */
	@Test(groups={"2drivers_android","2checkusers"}, priority=5,description="start a voice call in encrypted room")
	public void startVoiceAndVideoCallInEncryptedRoom() throws InterruptedException{
		RiotHomePageTabObjects homePage1=new RiotHomePageTabObjects(appiumFactory.getAndroidDriver1());
		RiotHomePageTabObjects homePage2=new RiotHomePageTabObjects(appiumFactory.getAndroidDriver2());

		//1. Open room roomWithEncryption with Device 1.
		homePage1.getRoomByName(oneToOneRoomWithEncryption);
		RiotRoomPageObjects newRoomDevice1 = new RiotRoomPageObjects(appiumFactory.getAndroidDriver1());
		newRoomDevice1.closeWarningAlertAboutBetaStateOfE2e();
		
		//2. Open room roomWithEncryption with Device 2.
		homePage2.getRoomByName(oneToOneRoomWithEncryption);
		RiotRoomPageObjects newRoomDevice2 = new RiotRoomPageObjects(appiumFactory.getAndroidDriver2());
		newRoomDevice2.closeWarningAlertAboutBetaStateOfE2e();

		//3. Start a voice call with Device 2.
		newRoomDevice2.startVoiceCall();
		RiotCallingPageObjects callingViewDevice2= new RiotCallingPageObjects(appiumFactory.getAndroidDriver2());
		callingViewDevice2.isDisplayed(true);
		//Check that an incoming layout is displayed on device 1.
		RiotIncomingCallPageObjects incomingCallDevice1= new RiotIncomingCallPageObjects(appiumFactory.getAndroidDriver1());
		incomingCallDevice1.checkIncomingCallView(true, participant2DisplayName, "Incoming Call");

		//4. Accept call with device 1.
		incomingCallDevice1.acceptCallButton.click();
		//check that call layout is diplayed on device 1
		RiotCallingPageObjects callingViewDevice1= new RiotCallingPageObjects(appiumFactory.getAndroidDriver1());
		callingViewDevice1.isDisplayed(true);

		//5. Hang-out after a few seconds.
		callingViewDevice1.hangUpButton.click();
		//Check that calling layout is closed on both devices.
		callingViewDevice1.isDisplayed(false);
		callingViewDevice2.isDisplayed(false);
		//check end call events on messages
		Assert.assertEquals(newRoomDevice1.getTextViewFromPost(newRoomDevice1.getLastPost()).getText(),participant1DisplayName+" ended the call.");
		Assert.assertEquals(newRoomDevice2.getTextViewFromPost(newRoomDevice2.getLastPost()).getText(),participant1DisplayName+" ended the call.");

		//6. Start a video call with Device 2.
		newRoomDevice2.startVideoCall();
		callingViewDevice2= new RiotCallingPageObjects(appiumFactory.getAndroidDriver2());
		callingViewDevice2.isDisplayed(true);
		//Check that an incoming layout is displayed on device 1.
		incomingCallDevice1= new RiotIncomingCallPageObjects(appiumFactory.getAndroidDriver1());
		incomingCallDevice1.checkIncomingCallView(true, participant2DisplayName, "Incoming Call");

		//7. Accept call with device 1.
		incomingCallDevice1.acceptCallButton.click();
		callingViewDevice2.waitUntilCallTook();
		//check that call layout is diplayed on device 1
		callingViewDevice1= new RiotCallingPageObjects(appiumFactory.getAndroidDriver1());
		callingViewDevice1.isDisplayed(true);

		//8. Hang-out after a few seconds.
		callingViewDevice1.mainCallLayout.click();//display the controls if they had fade out.
		callingViewDevice1.hangUpButton.click();
		//Check that calling layout is closed on both devices.
		callingViewDevice1.isDisplayed(false);
		callingViewDevice2.isDisplayed(false);
		//check end call events on messages
		Assert.assertEquals(newRoomDevice1.getTextViewFromPost(newRoomDevice1.getLastPost()).getText(),participant1DisplayName+" ended the call.");
		Assert.assertEquals(newRoomDevice2.getTextViewFromPost(newRoomDevice2.getLastPost()).getText(),participant1DisplayName+" ended the call.");
		
		//come back in rooms list
		newRoomDevice1.menuBackButton.click();
		newRoomDevice2.menuBackButton.click();
	}

	/**
	 * 1. Create room with Device 1 and enable encryption.</br>
	 * Check that the last event in the room is about turning e2e encryption</br>
	 * 2. Sent a message.</br>
	 * 3. Send invitation to user on Device 2 and device 2 accepts.</br>
	 * Check that user on Device 2 can't read the msg sent by Device 1 before he joined.</br>
	 * 4. Send a message with device 2</br>
	 * Check that user on device 1 can decrypt and read the message.</br>
	 * @throws InterruptedException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	@Test(groups={"2drivers_android","2checkusers"}, priority=6)
	public void tryReadEncryptedMessageSentAfterJoining() throws InterruptedException, InstantiationException, IllegalAccessException{
		//1. Create room with Device 1 and enable encryption.
		RiotHomePageTabObjects homePage1=new RiotHomePageTabObjects(appiumFactory.getAndroidDriver1());
		RiotRoomPageObjects newRoomDevice1=homePage1.createRoom();
		//Open room details
		newRoomDevice1.moreOptionsButton.click();
		newRoomDevice1.roomDetailsMenuItem.click();
		RiotRoomDetailsPageObjects newRoomDetailsDevice1 = new RiotRoomDetailsPageObjects(appiumFactory.getAndroidDriver1());
		newRoomDetailsDevice1.settingsTab.click();
		//changing room name
		newRoomDetailsDevice1.changeRoomName(roomWithEncryption);
		scrollToBottom(appiumFactory.getAndroidDriver1());
		//enables encryption
		newRoomDetailsDevice1.enableEncryption();
		//come back on the room page
		ExplicitWait(appiumFactory.getAndroidDriver1(), newRoomDetailsDevice1.menuBackButton);
		newRoomDetailsDevice1.menuBackButton.click();
		//Check that the last event in the room is about turning e2e encryption
		System.out.println(newRoomDevice1.getTextViewFromPost(newRoomDevice1.getLastPost()).getText());
		waitUntilDisplayed(appiumFactory.getAndroidDriver1(), "//android.widget.TextView[contains(@text,'"+ utility.Constant.ENCRYPTION_TURNEDON_EVENT +"')]", true, 5);