3 * Copyright (c) 2021 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #import "MultiAdminViewController.h"
20 #import "CHIPUIViewUtils.h"
21 #import "DefaultsUtils.h"
22 #import "DeviceSelector.h"
24 static NSString * const DEFAULT_TIMEOUT = @"900";
25 static NSString * const DEFAULT_DISCRIMINATOR = @"3840";
27 @interface MultiAdminViewController ()
29 @property (strong, nonatomic) UISwitch * openPairingOnAllDevices;
30 @property (strong, nonatomic) UISwitch * useOnboardingTokenSwitch;
31 @property (strong, nonatomic) UITextField * discriminatorField;
32 @property (strong, nonatomic) UITextField * timeoutField;
33 @property (strong, nonatomic) UIButton * openPairingWindowButton;
35 @property (nonatomic, strong) UILabel * resultLabel;
36 @property (nonatomic, strong) UIStackView * stackView;
38 @property (nonatomic, strong) DeviceSelector * deviceSelector;
41 @implementation MultiAdminViewController
43 // MARK: UIViewController methods
48 [self setupUIElements];
50 // listen for taps to dismiss the keyboard
51 UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
52 [self.view addGestureRecognizer:tap];
55 - (void)dismissKeyboard
57 [self.discriminatorField resignFirstResponder];
58 [self.timeoutField resignFirstResponder];
59 [self.deviceSelector resignFirstResponder];
64 - (void)setupUIElements
66 self.view.backgroundColor = UIColor.whiteColor;
69 UILabel * titleLabel = [CHIPUIViewUtils addTitle:@"Open Pairing Window" toView:self.view];
72 UIStackView * stackView = [UIStackView new];
73 stackView.axis = UILayoutConstraintAxisVertical;
74 stackView.distribution = UIStackViewDistributionFill;
75 stackView.alignment = UIStackViewAlignmentLeading;
76 stackView.spacing = 30;
77 [self.view addSubview:stackView];
79 stackView.translatesAutoresizingMaskIntoConstraints = false;
80 [stackView.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:40].active = YES;
81 [stackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES;
82 [stackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES;
84 // Open pairing on all devices
85 UILabel * pairAllDevices = [UILabel new];
86 pairAllDevices.text = @"Enable pairing on all devices";
87 _openPairingOnAllDevices = [UISwitch new];
88 [_openPairingOnAllDevices setOn:YES];
89 UIView * openPairingOnAllDevicesView = [CHIPUIViewUtils viewWithLabel:pairAllDevices toggle:_openPairingOnAllDevices];
90 [_openPairingOnAllDevices addTarget:self action:@selector(pairAllDevicesButton:) forControlEvents:UIControlEventTouchUpInside];
91 [stackView addArrangedSubview:openPairingOnAllDevicesView];
92 openPairingOnAllDevicesView.translatesAutoresizingMaskIntoConstraints = false;
93 [openPairingOnAllDevicesView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
95 // Device List and selector
96 _deviceSelector = [DeviceSelector new];
97 [_deviceSelector setEnabled:NO];
99 UILabel * deviceIDLabel = [UILabel new];
100 deviceIDLabel.text = @"Device ID:";
101 UIView * deviceIDView = [CHIPUIViewUtils viewWithLabel:deviceIDLabel textField:_deviceSelector];
102 [stackView addArrangedSubview:deviceIDView];
104 deviceIDView.translatesAutoresizingMaskIntoConstraints = false;
105 [deviceIDView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = true;
107 // Open Pairing Window
108 UILabel * useOnboardingToken = [UILabel new];
109 useOnboardingToken.text = @"Use Onboarding Token";
110 _useOnboardingTokenSwitch = [UISwitch new];
111 [_useOnboardingTokenSwitch setOn:YES];
112 UIView * useOnboardingTokenView = [CHIPUIViewUtils viewWithLabel:useOnboardingToken toggle:_useOnboardingTokenSwitch];
113 [_useOnboardingTokenSwitch addTarget:self action:@selector(overrideControls:) forControlEvents:UIControlEventTouchUpInside];
114 [stackView addArrangedSubview:useOnboardingTokenView];
115 useOnboardingTokenView.translatesAutoresizingMaskIntoConstraints = false;
116 [useOnboardingTokenView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
119 _discriminatorField = [UITextField new];
120 _discriminatorField.keyboardType = UIKeyboardTypeNumberPad;
121 _discriminatorField.placeholder = DEFAULT_DISCRIMINATOR;
122 UILabel * discriminatorLabel = [UILabel new];
123 [discriminatorLabel setText:@"Discriminator"];
124 UIView * discriminatorView = [CHIPUIViewUtils viewWithLabel:discriminatorLabel textField:_discriminatorField];
125 [stackView addArrangedSubview:discriminatorView];
127 discriminatorView.translatesAutoresizingMaskIntoConstraints = false;
128 [discriminatorView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
131 _timeoutField = [UITextField new];
132 _timeoutField.keyboardType = UIKeyboardTypeNumberPad;
133 _timeoutField.placeholder = DEFAULT_TIMEOUT;
134 UILabel * timeoutLabel = [UILabel new];
135 [timeoutLabel setText:@"Timeout after (seconds)"];
136 UIView * timeoutView = [CHIPUIViewUtils viewWithLabel:timeoutLabel textField:_timeoutField];
137 [stackView addArrangedSubview:timeoutView];
139 timeoutView.translatesAutoresizingMaskIntoConstraints = false;
140 [timeoutView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
142 // Open Pairing Window button
143 _openPairingWindowButton = [UIButton new];
144 [_openPairingWindowButton setTitle:@"Open Pairing Window" forState:UIControlStateNormal];
145 [_openPairingWindowButton addTarget:self action:@selector(openPairingWindow:) forControlEvents:UIControlEventTouchUpInside];
146 _openPairingWindowButton.backgroundColor = UIColor.systemBlueColor;
147 _openPairingWindowButton.titleLabel.font = [UIFont systemFontOfSize:17];
148 _openPairingWindowButton.titleLabel.textColor = [UIColor whiteColor];
149 _openPairingWindowButton.layer.cornerRadius = 5;
150 _openPairingWindowButton.clipsToBounds = YES;
151 [stackView addArrangedSubview:_openPairingWindowButton];
153 _openPairingWindowButton.translatesAutoresizingMaskIntoConstraints = false;
154 [_openPairingWindowButton.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
157 _resultLabel = [UILabel new];
158 _resultLabel.hidden = YES;
159 _resultLabel.font = [UIFont systemFontOfSize:17];
160 _resultLabel.textColor = UIColor.systemBlueColor;
161 _resultLabel.lineBreakMode = NSLineBreakByWordWrapping;
162 _resultLabel.numberOfLines = 0;
163 [stackView addArrangedSubview:_resultLabel];
165 _resultLabel.translatesAutoresizingMaskIntoConstraints = false;
166 [_resultLabel.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;
167 _resultLabel.adjustsFontSizeToFitWidth = YES;
170 - (void)updateResult:(NSString *)result
172 _resultLabel.hidden = NO;
173 _resultLabel.text = result;
176 // MARK: UIButton actions
178 - (IBAction)pairAllDevicesButton:(id)sender
180 if ([_openPairingOnAllDevices isOn]) {
181 [_deviceSelector setEnabled:NO];
183 [_deviceSelector setEnabled:YES];
187 - (IBAction)overrideControls:(id)sender
189 if ([_useOnboardingTokenSwitch isOn]) {
190 _discriminatorField.placeholder = DEFAULT_DISCRIMINATOR;
191 _timeoutField.placeholder = DEFAULT_TIMEOUT;
192 [_discriminatorField setEnabled:YES];
194 _discriminatorField.text = @"";
195 _discriminatorField.placeholder = @"Original discriminator";
196 [_discriminatorField setEnabled:NO];
200 - (IBAction)openPairingWindow:(id)sender
202 uint32_t setupPIN = arc4random();
203 [_deviceSelector forSelectedDevices:^(uint64_t deviceId) {
204 CHIPDevice * chipDevice = CHIPGetPairedDeviceWithID(deviceId);
206 if (chipDevice != nil && [chipDevice isActive]) {
207 NSString * timeoutStr = [self.timeoutField text];
208 if (timeoutStr.length == 0) {
209 timeoutStr = [self.timeoutField placeholder];
211 int timeout = [timeoutStr intValue];
215 if ([self.useOnboardingTokenSwitch isOn]) {
216 NSString * discriminatorStr = [self.discriminatorField text];
217 if (discriminatorStr.length == 0) {
218 discriminatorStr = [self.discriminatorField placeholder];
220 NSInteger discriminator = [discriminatorStr intValue];
222 output = [chipDevice openPairingWindowWithPIN:timeout discriminator:discriminator setupPIN:setupPIN error:&error];
225 NSString * result = [@"Use Manual Code: " stringByAppendingString:output];
226 [self updateResult:result];
228 [self updateResult:@"Failed in opening the pairing window"];
231 BOOL didSend = [chipDevice openPairingWindow:timeout error:&error];
233 [self updateResult:@"Scan the QR code on the device"];
235 NSString * errorString = [@"Error: " stringByAppendingString:error.localizedDescription];
236 [self updateResult:errorString];
240 [self updateResult:@"Controller not connected"];