Commit 68022ff6 authored by Scott Nichols's avatar Scott Nichols Committed by Commit Bot

Working on first impl of persistent host settings.

+ adds a wrapper around defaults and makes this a singleton.
+ Creates a new settings object to save settings in.
+ Serializes the settings to and from defaults.

Change-Id: I8e4aaed4c38fd02ca8a71b410c6d441e17da72b6
Reviewed-on: https://chromium-review.googlesource.com/574888
Commit-Queue: Scott Nichols <nicholss@chromium.org>
Reviewed-by: default avatarYuwei Huang <yuweih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#487308}
parent d1136c8f
......@@ -27,28 +27,16 @@ source_set("ios_core") {
"client_gestures.mm",
"client_keyboard.h",
"client_keyboard.mm",
"host_preferences.h",
"host_preferences.mm",
"host_preferences_persistence.h",
"keychain_wrapper.h",
"keychain_wrapper.mm",
]
if (!is_chrome_branded) {
sources += [ "host_preferences_persistence_chromium.mm" ]
} else {
# TODO(nicholss): Until we have a private implementation of this, stub it
# with the chromium version. We still want the logic of is_chrome_branded
# but to get the release builds building we will just reuse the file.
sources += [ "host_preferences_persistence_chromium.mm" ]
}
public_deps = [
"//remoting/ios/domain",
"//remoting/ios/facade",
"//remoting/ios/session",
"//third_party/webrtc/rtc_base:rtc_base",
"//third_party/webrtc/modules/desktop_capture:primitives",
"//third_party/webrtc/rtc_base:rtc_base",
]
deps = [
......
......@@ -70,7 +70,9 @@ source_set("common_source_set") {
"//remoting/ios/app/resources:assets",
"//remoting/ios/app/settings",
"//remoting/ios/display",
"//remoting/ios/domain",
"//remoting/ios/mdc",
"//remoting/ios/persistence",
"//remoting/protocol",
"//ui/base",
"//ui/gfx",
......
......@@ -16,7 +16,10 @@
#import "remoting/ios/client_gestures.h"
#import "remoting/ios/client_keyboard.h"
#import "remoting/ios/display/eagl_view.h"
#import "remoting/ios/domain/host_info.h"
#import "remoting/ios/domain/host_settings.h"
#import "remoting/ios/mdc/MDCActionImageView.h"
#import "remoting/ios/persistence/remoting_preferences.h"
#import "remoting/ios/session/remoting_client.h"
#include "base/strings/sys_string_conversions.h"
......@@ -37,6 +40,7 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
ClientKeyboard* _clientKeyboard;
CGSize _keyboardSize;
BOOL _surfaceCreated;
HostSettings* _settings;
}
@end
......@@ -48,6 +52,8 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
_client = client;
_keyboardSize = CGSizeZero;
_surfaceCreated = NO;
_settings =
[[RemotingPreferences instance] settingsForHost:client.hostInfo.hostId];
}
return self;
}
......@@ -81,9 +87,7 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
[_floatingButton addSubview:_actionImageView];
[self.view addSubview:_floatingButton];
// TODO(yuweih): This should be loaded from and stored into user defaults.
_client.gestureInterpreter->SetInputMode(
remoting::GestureInterpreter::DIRECT_INPUT_MODE);
[self applyInputMode];
}
- (void)viewDidUnload {
......@@ -135,6 +139,9 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[RemotingPreferences instance] setSettings:_settings
forHost:_client.hostInfo.hostId];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
......@@ -242,15 +249,13 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
}
- (void)useDirectInputMode {
// TODO(nicholss): Store this as a preference.
_client.gestureInterpreter->SetInputMode(
remoting::GestureInterpreter::DIRECT_INPUT_MODE);
_settings.inputMode = ClientInputModeDirect;
[self applyInputMode];
}
- (void)useTrackpadInputMode {
// TODO(nicholss): Store this as a preference.
_client.gestureInterpreter->SetInputMode(
remoting::GestureInterpreter::TRACKPAD_INPUT_MODE);
_settings.inputMode = ClientInputModeTrackpad;
[self applyInputMode];
}
- (void)sendCtrAltDel {
......@@ -263,6 +268,19 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
#pragma mark - Private
- (void)applyInputMode {
switch (_settings.inputMode) {
case ClientInputModeTrackpad:
_client.gestureInterpreter->SetInputMode(
remoting::GestureInterpreter::TRACKPAD_INPUT_MODE);
break;
case ClientInputModeDirect: // Fall-through.
default:
_client.gestureInterpreter->SetInputMode(
remoting::GestureInterpreter::DIRECT_INPUT_MODE);
}
}
- (void)didTap:(id)sender {
// TODO(nicholss): The FAB is being used to launch an alert window with
// more options. This is not ideal but it gets us an easy way to make a
......@@ -298,10 +316,15 @@ static const CGFloat kKeyboardAnimationTime = 0.3;
? @"Trackpad Mode"
: @"Touch Mode";
void (^switchInputModeHandler)(UIAlertAction*) = ^(UIAlertAction*) {
_client.gestureInterpreter->SetInputMode(
currentInputMode == remoting::GestureInterpreter::DIRECT_INPUT_MODE
? remoting::GestureInterpreter::TRACKPAD_INPUT_MODE
: remoting::GestureInterpreter::DIRECT_INPUT_MODE);
switch (currentInputMode) {
case remoting::GestureInterpreter::DIRECT_INPUT_MODE:
[self useTrackpadInputMode];
break;
case remoting::GestureInterpreter::TRACKPAD_INPUT_MODE: // Fall-through.
default:
[self useDirectInputMode];
break;
}
[_actionImageView setActive:NO animated:YES];
};
[alert addAction:[UIAlertAction actionWithTitle:switchInputModeTitle
......
......@@ -12,6 +12,8 @@ source_set("domain") {
"client_session_details.mm",
"host_info.h",
"host_info.mm",
"host_settings.h",
"host_settings.mm",
"user_info.h",
"user_info.mm",
]
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_IOS_DOMAIN_HOST_SETTINGS_H_
#define REMOTING_IOS_DOMAIN_HOST_SETTINGS_H_
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, ClientInputMode) {
ClientInputModeUndefined,
ClientInputModeDirect,
ClientInputModeTrackpad,
};
// A detail record for a Remoting Settings.
@interface HostSettings : NSObject<NSCoding>
// Various properties of the Remoting Settings.
@property(nonatomic, copy) NSString* hostId;
@property(nonatomic) ClientInputMode inputMode;
@end
#endif // REMOTING_IOS_DOMAIN_HOST_SETTINGS_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "remoting/ios/domain/host_settings.h"
@implementation HostSettings
@synthesize hostId = _hostId;
@synthesize inputMode = _inputMode;
- (id)initWithCoder:(NSCoder*)coder {
self = [super init];
if (self) {
self.hostId = [coder decodeObjectForKey:@"hostId"];
NSNumber* mode = [coder decodeObjectForKey:@"inputMode"];
self.inputMode = (ClientInputMode)[mode intValue];
}
return self;
}
- (void)encodeWithCoder:(NSCoder*)coder {
[coder encodeObject:self.hostId forKey:@"hostId"];
NSNumber* mode = [NSNumber numberWithInt:self.inputMode];
[coder encodeObject:mode forKey:@"inputMode"];
}
- (NSString*)description {
return [NSString stringWithFormat:@"HostSettings: hostId=%@ inputMode=%d",
_hostId, (int)_inputMode];
}
@end
......@@ -25,6 +25,7 @@ source_set("facade") {
"//base",
"//remoting/base:authorization",
"//remoting/ios/domain",
"//remoting/ios/persistence",
]
configs += [ "//build/config/compiler:enable_arc" ]
......
......@@ -18,6 +18,7 @@
#import "remoting/ios/facade/ios_client_runtime_delegate.h"
#import "remoting/ios/facade/remoting_service.h"
#import "remoting/ios/keychain_wrapper.h"
#import "remoting/ios/persistence/remoting_preferences.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
......@@ -25,9 +26,6 @@
#include "remoting/base/oauth_token_getter.h"
#include "remoting/base/oauth_token_getter_impl.h"
static NSString* const kCRDAuthenticatedUserEmailKey =
@"kCRDAuthenticatedUserEmailKey";
const char kOauthRedirectUrl[] =
"https://chromoting-oauth.talkgadget."
"google.com/talkgadget/oauth/chrome-remote-desktop/dev";
......@@ -184,22 +182,19 @@ RemotingAuthenticationStatus oauthStatusToRemotingAuthenticationStatus(
#pragma mark - Persistence
- (void)storeUserInfo:(UserInfo*)user {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if (user) {
[defaults setObject:user.userEmail forKey:kCRDAuthenticatedUserEmailKey];
[RemotingPreferences instance].activeUserKey = user.userEmail;
// TODO(nicholss): Need to match the token with the email.
[_keychainWrapper setRefreshToken:user.refreshToken];
} else {
[defaults removeObjectForKey:kCRDAuthenticatedUserEmailKey];
[RemotingPreferences instance].activeUserKey = nil;
[_keychainWrapper resetKeychainItem];
}
[defaults synchronize];
}
- (UserInfo*)loadUserInfo {
UserInfo* user = [[UserInfo alloc] init];
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
user.userEmail = [defaults objectForKey:kCRDAuthenticatedUserEmailKey];
user.userEmail = [RemotingPreferences instance].activeUserKey;
// TODO(nicholss): Need to match the token with the email.
user.refreshToken = [_keychainWrapper refreshToken];
......
......@@ -38,13 +38,13 @@ extern NSString* const kUserInfo;
// singleton and should only be accessed via the |SharedInstance| method.
@interface RemotingService : NSObject
// Access to the singleton shared instance from this method.
+ (RemotingService*)instance;
// Start a request to fetch the host list. This will produce an notification on
// |kHostsDidUpdate| when a new host is ready.
- (void)requestHostListFetch;
// Access to the singleton shared instance from this property.
@property(nonatomic, readonly, class) RemotingService* instance;
// Returns the current host list.
@property(nonatomic, readonly) NSArray<HostInfo*>* hosts;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_IOS_HOST_PREFERENCES_H_
#define REMOTING_IOS_HOST_PREFERENCES_H_
#import <CoreData/CoreData.h>
// A HostPreferences contains details to negotiate and maintain a connection
// to a remote Chromoting host. This is an entity in a backing store.
@interface HostPreferences : NSObject<NSCoding>
// Properties supplied by the host server.
@property(nonatomic, copy) NSString* hostId;
@property(nonatomic, copy) NSString* pairId;
@property(nonatomic, copy) NSString* pairSecret;
// Commit this record using the Keychain for current identity.
- (void)saveToKeychain;
// Load a record from the Keychain for current identity.
// If a record does not exist, return a new record with a blank secret.
+ (HostPreferences*)hostForId:(NSString*)hostId;
@end
#endif // REMOTING_IOS_HOST_PREFERENCES_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "remoting/ios/host_preferences.h"
#import "base/logging.h"
#import "remoting/ios/host_preferences_persistence.h"
namespace {
static NSString* const kHostPreferencesDataKeyHostDictionary =
@"kHostPreferencesDataKeyHostDictionary";
static NSString* const kHostPreferencesHostIdKey = @"HostId";
static NSString* const kHostPreferencesPairIdKey = @"PairId";
static NSString* const kHostPreferencesPairSecretKey = @"PairSecret";
} // namespace
@interface HostPreferences ()
// Load the known hosts from the Keychain.
// If no data exists, return an empty dictionary
+ (NSMutableDictionary*)loadHosts;
@end
@implementation HostPreferences
@synthesize hostId = _hostId;
@synthesize pairId = _pairId;
@synthesize pairSecret = _pairSecret;
#pragma mark - Public
- (void)saveToKeychain {
NSMutableDictionary* hosts = [HostPreferences loadHosts];
[hosts setObject:self forKey:_hostId];
NSData* writeData = [NSKeyedArchiver archivedDataWithRootObject:hosts];
NSError* keychainError =
remoting::ios::WriteHostPreferencesToKeychain(writeData);
LOG_IF(ERROR, !keychainError) << "Could not write to keychain.";
}
+ (HostPreferences*)hostForId:(NSString*)hostId {
NSMutableDictionary* hosts = [HostPreferences loadHosts];
HostPreferences* host = hosts[hostId];
if (!host) {
host = [[HostPreferences alloc] init];
host.hostId = hostId;
host.pairId = @"";
host.pairSecret = @"";
}
return host;
}
#pragma mark - Private
+ (NSMutableDictionary*)loadHosts {
NSData* readData = remoting::ios::ReadHostPreferencesFromKeychain();
if (readData) {
return [NSKeyedUnarchiver unarchiveObjectWithData:readData];
} else {
return [[NSMutableDictionary alloc] init];
}
}
#pragma mark - NSCoding
- (instancetype)initWithCoder:(NSCoder*)coder {
self = [super init];
if (self) {
[self setHostId:[coder decodeObjectForKey:kHostPreferencesHostIdKey]];
[self setPairId:[coder decodeObjectForKey:kHostPreferencesPairIdKey]];
[self
setPairSecret:[coder decodeObjectForKey:kHostPreferencesPairSecretKey]];
}
return self;
}
- (void)encodeWithCoder:(NSCoder*)coder {
[coder encodeObject:_hostId forKey:kHostPreferencesHostIdKey];
[coder encodeObject:_pairId forKey:kHostPreferencesPairIdKey];
[coder encodeObject:_pairSecret forKey:kHostPreferencesPairSecretKey];
}
@end
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_IOS_HOST_PREFERENCES_PERSISTENCE_H_
#define REMOTING_IOS_HOST_PREFERENCES_PERSISTENCE_H_
#import <CoreData/CoreData.h>
// Methods used to store and recall Host Prefrences on the keychain.
// Used to cache data for quicker connection to previously fetched host data.
namespace remoting {
namespace ios {
NSError* WriteHostPreferencesToKeychain(NSData* data);
NSData* ReadHostPreferencesFromKeychain();
} // namespace ios
} // namespace remoting
#endif // REMOTING_IOS_HOST_PREFERENCES_PERSISTENCE_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "remoting/ios/host_preferences_persistence.h"
#import "base/logging.h"
namespace remoting {
namespace ios {
// TODO(nicholss): It might be useful to save |data| in a static variable,
// which is then returned from ReadHostPreferencesFromKeychain(). This would
// allow to test pairing, even though the pairing info is not persisted when
// the app is restarted.
NSError* WriteHostPreferencesToKeychain(NSData* data) {
NOTIMPLEMENTED();
return nil;
}
NSData* ReadHostPreferencesFromKeychain() {
NOTIMPLEMENTED();
return nil;
}
} // namespace ios
} // namespace remoting
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/chrome_build.gni")
import("//build/config/ios/rules.gni")
import("//remoting/build/config/remoting_build.gni")
source_set("persistence") {
sources = [
"remoting_preferences.h",
"remoting_preferences.mm",
]
deps = [
"//base",
"//remoting/ios/domain",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_IOS_PERSISTENCE_REMOTING_PREFERENCES_H_
#define REMOTING_IOS_PERSISTENCE_REMOTING_PREFERENCES_H_
#import <Foundation/Foundation.h>
@class HostSettings;
// |RemotingPreferences| is the centralized place to ask for information about
// defaults and prefrences.
@interface RemotingPreferences : NSObject
- (HostSettings*)settingsForHost:(NSString*)hostId;
- (void)setSettings:(HostSettings*)settings forHost:(NSString*)hostId;
// Access to the singleton shared instance from this property.
@property(nonatomic, readonly, class) RemotingPreferences* instance;
@property(nonatomic) NSString* activeUserKey;
@end
#endif // REMOTING_IOS_PERSISTENCE_REMOTING_PREFERENCES_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "remoting/ios/persistence/remoting_preferences.h"
#import "base/mac/bind_objc_block.h"
#import "remoting/ios/domain/host_info.h"
#import "remoting/ios/domain/host_settings.h"
#include "base/logging.h"
static NSString* const kActiveUserKey = @"kActiveUserKey";
static NSString* const kHostSettingsKey = @"kHostSettingsKey";
@interface RemotingPreferences () {
NSUserDefaults* _defaults;
}
@end
@implementation RemotingPreferences
// RemotingService is a singleton.
+ (RemotingPreferences*)instance {
static RemotingPreferences* sharedInstance = nil;
static dispatch_once_t guard;
dispatch_once(&guard, ^{
sharedInstance = [[RemotingPreferences alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_defaults = [NSUserDefaults standardUserDefaults];
}
return self;
}
#pragma mark - RemotingPreferences Implementation
- (HostSettings*)settingsForHost:(NSString*)hostId {
NSString* key =
[NSString stringWithFormat:@"%@-%@", kHostSettingsKey, hostId];
NSData* encodedSettings = [_defaults objectForKey:key];
HostSettings* settings =
[NSKeyedUnarchiver unarchiveObjectWithData:encodedSettings];
if (settings == nil) {
settings = [[HostSettings alloc] init];
settings.hostId = hostId;
[self setSettings:settings forHost:hostId];
}
return settings;
}
- (void)setSettings:(HostSettings*)settings forHost:(NSString*)hostId {
NSString* key =
[NSString stringWithFormat:@"%@-%@", kHostSettingsKey, hostId];
if (settings) {
NSData* encodedSettings =
[NSKeyedArchiver archivedDataWithRootObject:settings];
[_defaults setObject:encodedSettings forKey:key];
} else {
return [_defaults removeObjectForKey:key];
}
[_defaults synchronize];
}
#pragma mark - Properties
- (void)setActiveUserKey:(NSString*)activeUserKey {
if (activeUserKey) {
[_defaults setObject:activeUserKey forKey:kActiveUserKey];
} else {
[_defaults removeObjectForKey:kActiveUserKey];
}
[_defaults synchronize];
}
- (NSString*)activeUserKey {
return [_defaults objectForKey:kActiveUserKey];
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment