JLChen
2021-08-02 38f4fb064df09f344fc3237409c76a9fba2a8a9e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
 * Copyright (c) 2010-2020 Belledonne Communications SARL.
 *
 * This file is part of linphone-iphone
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
#import <AudioToolbox/AudioToolbox.h>
 
#import "LinphoneManager.h"
#import "PhoneMainView.h"
 
@implementation DialerView
 
#pragma mark - UICompositeViewDelegate Functions
 
static UICompositeViewDescription *compositeDescription = nil;
 
+ (UICompositeViewDescription *)compositeViewDescription {
    if (compositeDescription == nil) {
        compositeDescription = [[UICompositeViewDescription alloc] init:self.class
                                                              statusBar:StatusBarView.class
                                                                 tabBar:TabBarView.class
                                                               sideMenu:SideMenuView.class
                                                             fullscreen:false
                                                         isLeftFragment:YES
                                                           fragmentWith:nil];
        compositeDescription.darkBackground = true;
    }
    return compositeDescription;
}
 
- (UICompositeViewDescription *)compositeViewDescription {
    return self.class.compositeViewDescription;
}
 
#pragma mark - ViewController Functions
 
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
 
    _padView.hidden =
        !IPAD && UIInterfaceOrientationIsLandscape(PhoneMainView.instance.mainViewController.currentOrientation);
 
    // Set observer
    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(callUpdateEvent:)
                                               name:kLinphoneCallUpdate
                                             object:nil];
 
    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(coreUpdateEvent:)
                                               name:kLinphoneCoreUpdate
                                             object:nil];
 
    // Update on show
    LinphoneManager *mgr = LinphoneManager.instance;
    LinphoneCall *call = linphone_core_get_current_call(LC);
    LinphoneCallState state = (call != NULL) ? linphone_call_get_state(call) : 0;
    [self callUpdate:call state:state];
 
    if (IPAD) {
        BOOL videoEnabled = linphone_core_video_display_enabled(LC);
        BOOL previewPref = [mgr lpConfigBoolForKey:@"preview_preference"];
 
        if (videoEnabled && previewPref) {
            linphone_core_set_native_preview_window_id(LC, (__bridge void *)(_videoPreview));
 
            if (!linphone_core_video_preview_enabled(LC)) {
                linphone_core_enable_video_preview(LC, TRUE);
            }
 
            [_backgroundView setHidden:FALSE];
            [_videoCameraSwitch setHidden:FALSE];
        } else {
            linphone_core_set_native_preview_window_id(LC, NULL);
            linphone_core_enable_video_preview(LC, FALSE);
            [_backgroundView setHidden:TRUE];
            [_videoCameraSwitch setHidden:TRUE];
        }
    } else {
        linphone_core_enable_video_preview(LC, FALSE);
    }
    [_addressField setText:@""];
}
 
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [NSNotificationCenter.defaultCenter removeObserver:self];
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    [_zeroButton setDigit:'0'];
    [_oneButton setDigit:'1'];
    [_twoButton setDigit:'2'];
    [_threeButton setDigit:'3'];
    [_fourButton setDigit:'4'];
    [_fiveButton setDigit:'5'];
    [_sixButton setDigit:'6'];
    [_sevenButton setDigit:'7'];
    [_eightButton setDigit:'8'];
    [_nineButton setDigit:'9'];
    [_starButton setDigit:'*'];
    [_hashButton setDigit:'#'];
 
    [_addressField setAdjustsFontSizeToFitWidth:TRUE]; // Not put it in IB: issue with placeholder size
 
    UILongPressGestureRecognizer *backspaceLongGesture =
        [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onBackspaceLongClick:)];
    [_backspaceButton addGestureRecognizer:backspaceLongGesture];
 
    UILongPressGestureRecognizer *zeroLongGesture =
        [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onZeroLongClick:)];
    [_zeroButton addGestureRecognizer:zeroLongGesture];
 
    UILongPressGestureRecognizer *oneLongGesture =
        [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onOneLongClick:)];
    [_oneButton addGestureRecognizer:oneLongGesture];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                                                                    initWithTarget:self
                                                                                    action:@selector(dismissKeyboards)];
    
    [self.view addGestureRecognizer:tap];
 
    if (IPAD) {
        if (LinphoneManager.instance.frontCamId != nil) {
            // only show camera switch button if we have more than 1 camera
            [_videoCameraSwitch setHidden:FALSE];
        }
    }
}
 
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                                         duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    switch (toInterfaceOrientation) {
        case UIInterfaceOrientationPortrait:
            [_videoPreview setTransform:CGAffineTransformMakeRotation(0)];
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            [_videoPreview setTransform:CGAffineTransformMakeRotation(M_PI)];
            break;
        case UIInterfaceOrientationLandscapeLeft:
            [_videoPreview setTransform:CGAffineTransformMakeRotation(M_PI / 2)];
            break;
        case UIInterfaceOrientationLandscapeRight:
            [_videoPreview setTransform:CGAffineTransformMakeRotation(-M_PI / 2)];
            break;
        default:
            break;
    }
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0, 0);
    _videoPreview.frame = frame;
    _padView.hidden = !IPAD && UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
    if (linphone_core_get_calls_nb(LC)) {
        _backButton.hidden = FALSE;
        _addContactButton.hidden = TRUE;
    } else {
        _backButton.hidden = TRUE;
        _addContactButton.hidden = FALSE;
    }
}
 
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [LinphoneManager.instance shouldPresentLinkPopup];
}
 
#pragma mark - Event Functions
 
- (void)callUpdateEvent:(NSNotification *)notif {
    LinphoneCall *call = [[notif.userInfo objectForKey:@"call"] pointerValue];
    LinphoneCallState state = [[notif.userInfo objectForKey:@"state"] intValue];
    [self callUpdate:call state:state];
}
 
- (void)coreUpdateEvent:(NSNotification *)notif {
    @try {
        if (IPAD) {
            if (linphone_core_video_display_enabled(LC) && linphone_core_video_preview_enabled(LC)) {
                linphone_core_set_native_preview_window_id(LC, (__bridge void *)(_videoPreview));
                [_backgroundView setHidden:FALSE];
                [_videoCameraSwitch setHidden:FALSE];
            } else {
                linphone_core_set_native_preview_window_id(LC, NULL);
                [_backgroundView setHidden:TRUE];
                [_videoCameraSwitch setHidden:TRUE];
            }
        }
    } @catch (NSException *exception) {
        if ([exception.name isEqualToString:@"LinphoneCoreException"]) {
            LOGE(@"Core already destroyed");
            return;
        }
        LOGE(@"Uncaught exception : %@", exception.description);
        abort();
    }
}
 
#pragma mark - Debug Functions
- (void)presentMailViewWithTitle:(NSString *)subject forRecipients:(NSArray *)recipients attachLogs:(BOOL)attachLogs {
    if ([MFMailComposeViewController canSendMail]) {
        MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
        if (controller) {
            controller.mailComposeDelegate = self;
            [controller setSubject:subject];
            [controller setToRecipients:recipients];
 
            if (attachLogs) {
                char *filepath = linphone_core_compress_log_collection();
                if (filepath == NULL) {
                    LOGE(@"Cannot sent logs: file is NULL");
                    return;
                }
 
                NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
                NSString *filename = [appName stringByAppendingString:@".gz"];
                NSString *mimeType = @"text/plain";
 
                if ([filename hasSuffix:@".gz"]) {
                    mimeType = @"application/gzip";
                    filename = [appName stringByAppendingString:@".gz"];
                } else {
                    LOGE(@"Unknown extension type: %@, cancelling email", filename);
                    return;
                }
                [controller setMessageBody:NSLocalizedString(@"Application logs", nil) isHTML:NO];
                [controller addAttachmentData:[NSData dataWithContentsOfFile:[NSString stringWithUTF8String:filepath]]
                                     mimeType:mimeType
                                     fileName:filename];
 
                ms_free(filepath);
            }
            self.modalPresentationStyle = UIModalPresentationPageSheet;
            [self.view.window.rootViewController presentViewController:controller
                                                              animated:TRUE
                                                            completion:^{
                                                            }];
        }
 
    } else {
        UIAlertController *errView = [UIAlertController alertControllerWithTitle:subject
                                                                         message:NSLocalizedString(@"Error: no mail account configured",
                                                                                                   nil)
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
                                                                style:UIAlertActionStyleDefault
                                                              handler:^(UIAlertAction * action) {}];
        
        [errView addAction:defaultAction];
        [self presentViewController:errView animated:YES completion:nil];
    }
}
 
- (BOOL)displayDebugPopup:(NSString *)address {
    LinphoneManager *mgr = LinphoneManager.instance;
    NSString *debugAddress = [mgr lpConfigStringForKey:@"debug_popup_magic" withDefault:@""];
    if (![debugAddress isEqualToString:@""] && [address isEqualToString:debugAddress]) {
        UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Debug", nil)
                                                                         message:NSLocalizedString(@"Choose an action", nil)
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
                                                                style:UIAlertActionStyleDefault
                                                              handler:^(UIAlertAction * action) {}];
        
        [errView addAction:defaultAction];
 
        int debugLevel = [LinphoneManager.instance lpConfigIntForKey:@"debugenable_preference"];
        BOOL debugEnabled = (debugLevel >= ORTP_DEBUG && debugLevel < ORTP_ERROR);
 
        if (debugEnabled) {
            UIAlertAction* continueAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Send logs", nil)
                                                                     style:UIAlertActionStyleDefault
                                                                   handler:^(UIAlertAction * action) {
                                                                       NSString *appName =
                                                                       [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
                                                                       NSString *logsAddress = [mgr lpConfigStringForKey:@"debug_popup_email" withDefault:@""];
                                                                       [self presentMailViewWithTitle:appName forRecipients:@[ logsAddress ] attachLogs:true];
                                                                   }];
            [errView addAction:continueAction];
        }
        NSString *actionLog =
            (debugEnabled ? NSLocalizedString(@"Disable logs", nil) : NSLocalizedString(@"Enable logs", nil));
        
        UIAlertAction* logAction = [UIAlertAction actionWithTitle:actionLog
                                                            style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
                                                                   int newDebugLevel = debugEnabled ? 0 : ORTP_DEBUG;
                                                                   [LinphoneManager.instance lpConfigSetInt:newDebugLevel forKey:@"debugenable_preference"];
                                                                   [Log enableLogs:newDebugLevel];
                                                               }];
        [errView addAction:logAction];
        
        UIAlertAction* remAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Remove account(s) and self destruct", nil)
                                                            style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
                                                              linphone_core_clear_accounts([LinphoneManager getLc]);
                                                              linphone_core_clear_all_auth_info([LinphoneManager getLc]);
                                                              @try {
                                                                  [LinphoneManager.instance destroyLinphoneCore];
                                                              } @catch (NSException *e) {
                                                                  LOGW(@"Exception while destroying linphone core: %@", e);
                                                              } @finally {
                                                                  if ([NSFileManager.defaultManager
                                                                       isDeletableFileAtPath:[LinphoneManager preferenceFile:@"linphonerc"]] == YES) {
                                                                      [NSFileManager.defaultManager
                                                                       removeItemAtPath:[LinphoneManager preferenceFile:@"linphonerc"]
                                                                       error:nil];
                                                                  }
#ifdef DEBUG
                                                                  [LinphoneManager instanceRelease];
#endif
                                                              }
                                                              [UIApplication sharedApplication].keyWindow.rootViewController = nil;
                                                              // make the application crash to be sure that user restart it properly
                                                              LOGF(@"Self-destructing in 3..2..1..0!");
                                                          }];
        [errView addAction:remAction];
        
        [self presentViewController:errView animated:YES completion:nil];
        return true;
    }
    return false;
}
 
#pragma mark -
 
- (void)callUpdate:(LinphoneCall *)call state:(LinphoneCallState)state {
    BOOL callInProgress = (linphone_core_get_calls_nb(LC) > 0);
    _addContactButton.hidden = callInProgress;
    _backButton.hidden = !callInProgress;
    [_callButton updateIcon];
}
 
- (void)setAddress:(NSString *)address {
    [_addressField setText:address];
}
 
#pragma mark - UITextFieldDelegate Functions
 
- (BOOL)textField:(UITextField *)textField
    shouldChangeCharactersInRange:(NSRange)range
                replacementString:(NSString *)string {
    //[textField performSelector:@selector() withObject:nil afterDelay:0];
    return YES;
}
 
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (textField == _addressField) {
        [_addressField resignFirstResponder];
    }
    if (textField.text.length > 0) {
        LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:textField.text];
        [LinphoneManager.instance call:addr];
        if (addr)
            linphone_address_destroy(addr);
    }
    return YES;
}
 
#pragma mark - MFComposeMailDelegate
 
- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error {
    [controller dismissViewControllerAnimated:TRUE completion:nil];
    [self.navigationController setNavigationBarHidden:TRUE animated:FALSE];
}
 
#pragma mark - Action Functions
 
- (IBAction)onAddContactClick:(id)event {
    [ContactSelection setSelectionMode:ContactSelectionModeEdit];
    [ContactSelection setAddAddress:[_addressField text]];
    [ContactSelection setSipFilter:nil];
    [ContactSelection setNameOrEmailFilter:nil];
    [ContactSelection enableEmailFilter:FALSE];
    [PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
}
 
- (IBAction)onBackClick:(id)event {
    [PhoneMainView.instance popToView:CallView.compositeViewDescription];
}
 
- (IBAction)onAddressChange:(id)sender {
    if ([self displayDebugPopup:_addressField.text]) {
        _addressField.text = @"";
    }
    _addContactButton.enabled = _backspaceButton.enabled = ([[_addressField text] length] > 0);
    if ([_addressField.text length] == 0) {
        [self.view endEditing:YES];
    }
}
 
- (IBAction)onBackspaceClick:(id)sender {
    if ([_addressField.text length] > 0) {
        [_addressField setText:[_addressField.text substringToIndex:[_addressField.text length] - 1]];
    }
}
 
- (void)onBackspaceLongClick:(id)sender {
    [_addressField setText:@""];
}
 
- (void)onZeroLongClick:(id)sender {
    // replace last character with a '+'
    NSString *newAddress =
        [[_addressField.text substringToIndex:[_addressField.text length] - 1] stringByAppendingString:@"+"];
    [_addressField setText:newAddress];
    linphone_core_stop_dtmf(LC);
}
 
- (void)onOneLongClick:(id)sender {
    LinphoneManager *lm = LinphoneManager.instance;
    NSString *voiceMail = [lm lpConfigStringForKey:@"voice_mail_uri"];
    LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:voiceMail];
    if (addr) {
        linphone_address_set_display_name(addr, NSLocalizedString(@"Voice mail", nil).UTF8String);
        [lm call:addr];
        linphone_address_destroy(addr);
    } else {
        LOGE(@"Cannot call voice mail because URI not set or invalid!");
    }
    linphone_core_stop_dtmf(LC);
}
 
- (void)dismissKeyboards {
    [self.addressField resignFirstResponder];
}
@end