Chat: fix message state icon by reworking file transfer a bit and add simultanous uploads/downloads tests

This commit is contained in:
Gautier Pelloux-Prayer 2015-06-23 17:33:06 +02:00
parent 5991aef599
commit 9d000cdfb9
8 changed files with 133 additions and 68 deletions

View file

@ -41,8 +41,6 @@
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[TUNinePatchCache flushCache]; // Clear cache
// [self clearMessageList];
// chatRoom = NULL;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
@ -70,7 +68,7 @@
linphone_chat_room_get_peer_address(chatRoom) &&
linphone_chat_message_is_outgoing(ftd.message)) {
LOGI(@"Appending transient upload message %p", ftd.message);
self->messageList = ms_list_append(self->messageList, ftd.message);
self->messageList = ms_list_append(self->messageList, linphone_chat_message_ref(ftd.message));
}
}
}

View file

@ -549,7 +549,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{
FileTransferDelegate * fileTransfer = [[FileTransferDelegate alloc] init];
[[[LinphoneManager instance] fileTransferDelegates] addObject:fileTransfer];
[fileTransfer upload:image withURL:url forChatRoom:chatRoom];
[tableController addChatEntry:linphone_chat_message_ref(fileTransfer.message)];
[tableController scrollToBottom:true];

View file

@ -86,22 +86,44 @@ static UIFont *CELL_FONT = nil;
- (void)dealloc {
[self disconnectFromFileDelegate];
if (self->chat) {
linphone_chat_message_unref(self->chat);
linphone_chat_message_set_user_data(self->chat, NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(self->chat), NULL);
self->chat = NULL;
}
}
#pragma mark -
- (void)setChatMessage:(LinphoneChatMessage *)message {
if (message != self->chat) {
if (self->chat) {
linphone_chat_message_unref(self->chat);
linphone_chat_message_set_user_data(self->chat, NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(self->chat), NULL);
}
self->chat = message;
messageImageView.image = nil;
[self disconnectFromFileDelegate];
for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) {
if (message &&
linphone_chat_message_get_storage_id(aftd.message) == linphone_chat_message_get_storage_id(message)) {
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message,
linphone_chat_message_get_user_data(message));
[self connectToFileDelegate:aftd];
break;
if (self->chat) {
linphone_chat_message_ref(self->chat);
linphone_chat_message_set_user_data(self->chat, (void *)CFBridgingRetain(self));
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(self->chat),
message_status);
const LinphoneContent *c = linphone_chat_message_get_file_transfer_information(message);
if (c) {
const char *name = linphone_content_get_name(c);
for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) {
if (linphone_chat_message_get_file_transfer_information(aftd.message) &&
strcmp(name, linphone_content_get_name(
linphone_chat_message_get_file_transfer_information(aftd.message))) == 0) {
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message, aftd);
[self connectToFileDelegate:aftd];
break;
}
}
}
}
[self update];
@ -353,7 +375,6 @@ static UIFont *CELL_FONT = nil;
- (IBAction)onDownloadClick:(id)event {
if (ftd.message == nil) {
ftd = [[FileTransferDelegate alloc] init];
[[[LinphoneManager instance] fileTransferDelegates] addObject:ftd];
[self connectToFileDelegate:ftd];
[ftd download:chat];
_cancelButton.hidden = NO;
@ -423,6 +444,11 @@ static UIFont *CELL_FONT = nil;
}
}
}
#pragma mark - State changed handler
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
UIChatRoomCell *thiz = (__bridge UIChatRoomCell *)linphone_chat_message_get_user_data(msg);
[thiz update];
}
#pragma mark - LinphoneFileTransfer Notifications Handling

View file

@ -19,9 +19,18 @@
}
}
+ (FileTransferDelegate *)messageDelegate:(LinphoneChatMessage *)message {
for (FileTransferDelegate *ftd in [[LinphoneManager instance] fileTransferDelegates]) {
if (ftd.message == message) {
return ftd;
}
}
return nil;
}
static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, const LinphoneContent *content,
const LinphoneBuffer *buffer) {
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message);
FileTransferDelegate *thiz = [FileTransferDelegate messageDelegate:message];
size_t size = linphone_buffer_get_size(buffer);
if (!thiz.data) {
@ -35,7 +44,7 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con
// we're finished, save the image and update the message
UIImage *image = [UIImage imageWithData:thiz.data];
CFBridgingRetain(thiz);
[[[LinphoneManager instance] fileTransferDelegates] removeObject:thiz];
[[LinphoneManager instance]
@ -59,6 +68,7 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con
forKey:@"localimage"
inMessage:message];
}
linphone_chat_message_unref(thiz.message);
thiz.message = NULL;
[[NSNotificationCenter defaultCenter]
postNotificationName:kLinphoneFileTransferRecvUpdate
@ -88,7 +98,7 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con
static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent *content,
size_t offset, size_t size) {
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message);
FileTransferDelegate *thiz = [FileTransferDelegate messageDelegate:message];
size_t total = thiz.data.length;
if (thiz.data) {
size_t remaining = total - offset;
@ -97,16 +107,26 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m
@"state" : @(linphone_chat_message_get_state(message)),
@"progress" : @(offset * 1.f / total),
}];
LOGD(@"Transfer of %s (%d bytes): already sent %ld, remaining %ld", linphone_content_get_name(content), total,
offset, remaining);
LOGD(@"Transfer of %s (%d bytes): already sent %ld (%f%%), remaining %ld", linphone_content_get_name(content),
total, offset, offset * 100.f / total, remaining);
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneFileTransferSendUpdate
object:thiz
userInfo:dict];
LinphoneBuffer *buffer = NULL;
@try {
return linphone_buffer_new_from_data([thiz.data subdataWithRange:NSMakeRange(offset, size)].bytes, size);
buffer = linphone_buffer_new_from_data([thiz.data subdataWithRange:NSMakeRange(offset, size)].bytes, size);
} @catch (NSException *exception) {
LOGE(@"Exception: %@", exception);
}
// this is the last time we will be notified, so destroy ourselve
if (remaining <= size) {
linphone_chat_message_unref(thiz.message);
thiz.message = NULL;
[thiz stopAndDestroy];
}
return buffer;
} else {
LOGE(@"Transfer of %s (%d bytes): %d Error - no upload data in progress!", linphone_content_get_name(content),
total, offset);
@ -115,28 +135,9 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m
return NULL;
}
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(msg);
NSString *notification =
linphone_chat_message_is_outgoing(msg) ? kLinphoneFileTransferSendUpdate : kLinphoneFileTransferRecvUpdate;
const char *text = (linphone_chat_message_get_file_transfer_information(msg) != NULL)
? "photo transfer"
: linphone_chat_message_get_text(msg);
LOGI(@"Delivery status for [%s] is [%s]", text, linphone_chat_message_state_to_string(state));
NSDictionary *dict = @{ @"state" : @(state), @"progress" : @0.f };
if (state == LinphoneChatMessageStateFileTransferDone || state == LinphoneChatMessageStateFileTransferError) {
thiz.message = NULL;
}
[[NSNotificationCenter defaultCenter] postNotificationName:notification object:thiz userInfo:dict];
if (linphone_chat_message_is_outgoing(msg)) {
[thiz stopAndDestroy];
}
}
- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom {
[[[LinphoneManager instance] fileTransferDelegates] addObject:self];
LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom));
_data = [NSMutableData dataWithData:UIImageJPEGRepresentation(image, 1.0)];
linphone_content_set_type(content, "image");
@ -146,38 +147,36 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
[NSDate timeIntervalSinceReferenceDate]] UTF8String]);
linphone_content_set_size(content, [_data length]);
CFTypeRef myself = (__bridge CFTypeRef)self;
_message = linphone_chat_room_create_file_transfer_message(chatRoom, content);
linphone_chat_message_ref(_message);
linphone_chat_message_set_user_data(_message, (void *)CFRetain(myself));
linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message),
linphone_iphone_file_transfer_send);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status);
if (url) {
// internal url is saved in the appdata for display and later save
[LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:_message];
}
LOGI(@"%p Uploading content in %p", self, _message);
linphone_chat_room_send_chat_message(chatRoom, _message);
}
- (BOOL)download:(LinphoneChatMessage *)message {
[[[LinphoneManager instance] fileTransferDelegates] addObject:self];
_message = message;
// we need to keep a ref on the message to continue downloading even if user quit a chatroom which destroy all chat
// messages
linphone_chat_message_ref(_message);
const char *url = linphone_chat_message_get_external_body_url(_message);
LOGI(@"Content to download: %s", url);
LOGI(@"%p Downloading content in %p from %s", self, message, url);
if (url == nil)
return FALSE;
linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self));
linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message),
linphone_iphone_file_transfer_recv);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status);
linphone_chat_message_download_file(_message);
@ -187,18 +186,17 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
- (void)stopAndDestroy {
[[[LinphoneManager instance] fileTransferDelegates] removeObject:self];
if (_message != NULL) {
linphone_chat_message_set_user_data(_message, NULL);
LOGI(@"%p Cancelling transferm from %p", self, _message);
linphone_chat_message_cbs_set_file_transfer_progress_indication(linphone_chat_message_get_callbacks(_message),
NULL);
linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), NULL);
linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message), NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), NULL);
linphone_chat_message_cancel_file_transfer(_message);
linphone_chat_message_unref(_message);
}
_message = nil;
_data = nil;
LOGI(@"%p Destroying", self);
}
- (void)cancel {

View file

@ -35,6 +35,7 @@
if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) {
[self goBackFromChat];
}
ASSERT_EQ([LinphoneManager instance].fileTransferDelegates.count, 0)
}
#pragma mark - tools
@ -163,11 +164,11 @@
return tv;
}
- (void)uploadImage {
NSString *user = @"testios";
[self startChatWith:user];
- (void)uploadImageWithQuality:(NSString *)quality {
UITableView *tv = [self findTableView:@"Chat list"];
long messagesCount = [tv numberOfRowsInSection:0];
long delegatesCount = [[[LinphoneManager instance] fileTransferDelegates] count];
[tester tapViewWithAccessibilityLabel:@"Send picture"];
[tester tapViewWithAccessibilityLabel:@"Photo library"];
// if popup "Linphone would access your photo" pops up, click OK.
@ -177,32 +178,33 @@
#endif
}
[tester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:1];
// select another photo if already uploading one
[tester choosePhotoInAlbum:@"Camera Roll" atRow:1 + delegatesCount column:1];
// wait for the quality popup to show up
[tester waitForTimeInterval:1];
UIAccessibilityElement *element =
[[UIApplication sharedApplication] accessibilityElementMatchingBlock:^BOOL(UIAccessibilityElement *element) {
return [element.accessibilityLabel containsString:@"Minimum ("];
return [element.accessibilityLabel containsString:quality];
}];
[tester tapViewWithAccessibilityLabel:element.accessibilityLabel];
UITableView *tv = [self findTableView:@"Chat list"];
ASSERT_EQ([tv numberOfRowsInSection:0], 1);
ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 1);
ASSERT_EQ([tv numberOfRowsInSection:0], messagesCount + 1);
ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], delegatesCount + 1);
}
- (void)testUploadImage {
NSString *user = @"testios";
NSString *myself = @"testios";
[self startChatWith:myself];
ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0);
[self uploadImage];
[self uploadImageWithQuality:@"Minimum"];
ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 1);
[self goBackFromChat];
// if we go back to the same chatroom, the message should be still there
[self startChatWith:user];
[self startChatWith:myself];
UITableView *tv = [self findTableView:@"Chat list"];
ASSERT_EQ([tv numberOfRowsInSection:0], 1);
@ -219,7 +221,9 @@
}
- (void)testCancelUploadImage {
[self uploadImage];
NSString *myself = @"testios";
[self startChatWith:myself];
[self uploadImageWithQuality:@"Minimum"];
[tester tapViewWithAccessibilityLabel:@"Cancel transfer"];
if ([[[LinphoneManager instance] fileTransferDelegates] count] != 0) {
[[UIApplication sharedApplication] writeScreenshotForLine:__LINE__ inFile:@__FILE__ description:nil error:NULL];
@ -228,8 +232,29 @@
ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0);
}
- (void)test3UploadsSimultanously {
NSString *myself = @"testios";
[self startChatWith:myself];
// use Maximum quality to be sure that first transfer is not terminated when the third begins
[self uploadImageWithQuality:@"Maximum"];
[self uploadImageWithQuality:@"Maximum"];
[self uploadImageWithQuality:@"Minimum"];
UITableView *tv = [self findTableView:@"Chat list"];
ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 3);
// wait for ALL uploads to terminate...
for (int i = 0; i < 45; i++) {
[tester waitForTimeInterval:1.f];
if ([tv numberOfRowsInSection:0] == 6)
break;
}
ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0);
ASSERT_EQ([tv numberOfRowsInSection:0], 6);
}
- (void)downloadImage {
[self uploadImage];
NSString *myself = @"testios";
[self startChatWith:myself];
[self uploadImageWithQuality:@"Minimum"];
// wait for the upload to terminate...
for (int i = 0; i < 15; i++) {
[tester waitForTimeInterval:1.f];
@ -242,6 +267,26 @@
ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 1);
}
- (void)test3DownloadsSimultanously {
[self startChatWith:[self me]];
[self uploadImageWithQuality:@"Maximum"];
[self uploadImageWithQuality:@"Average"];
[self uploadImageWithQuality:@"Minimum"];
UITableView *tv = [self findTableView:@"Chat list"];
// wait for ALL uploads to terminate...
for (int i = 0; i < 45; i++) {
[tester waitForTimeInterval:1.f];
if ([tv numberOfRowsInSection:0] == 6)
break;
}
ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0);
for (int i = 0; i < 3; i++) {
[tester waitForViewWithAccessibilityLabel:@"Download"];
[tester tapViewWithAccessibilityLabel:@"Download"];
[tester waitForTimeInterval:.5f]; // just wait a few secs to start download
}
}
- (void)testDownloadImage {
[self downloadImage];
[tester waitForAbsenceOfViewWithAccessibilityLabel:@"Cancel transfer"];

View file

@ -1,4 +1,4 @@
#!/bin/bash -x
#!/bin/bash
# Install underscore-cli for hacking
if ! which underscore &> /dev/null; then

5
main.m
View file

@ -36,7 +36,6 @@ int main(int argc, char *argv[]) {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
#endif
@autoreleasepool {
int retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([LinphoneAppDelegate class]));
return retVal;
}
return UIApplicationMain(argc, argv, nil, NSStringFromClass([LinphoneAppDelegate class]));
}
}

@ -1 +1 @@
Subproject commit 2f795533d68784ae58abd6a43b24281d33c5730d
Subproject commit cfd87c55acee96699ce8306a3734b477fee3a00a