162 lines
5.6 KiB
C#
162 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Bit.Core.Models.Domain;
|
|
using Bit.Core.Services;
|
|
using Bit.iOS.Core.Utilities;
|
|
using Foundation;
|
|
using Newtonsoft.Json;
|
|
using ObjCRuntime;
|
|
|
|
namespace WatchConnectivity
|
|
{
|
|
public sealed class WCSessionManager : WCSessionDelegate
|
|
{
|
|
// Setup is converted from https://www.natashatherobot.com/watchconnectivity-say-hello-to-wcsession/
|
|
// with some extra bits
|
|
private static readonly WCSessionManager sharedManager = new WCSessionManager();
|
|
private static WCSession session = WCSession.IsSupported ? WCSession.DefaultSession : null;
|
|
|
|
public event WCSessionReceiveDataHandler OnApplicationContextUpdated;
|
|
public event WCSessionReceiveDataHandler OnMessagedReceived;
|
|
public delegate void WCSessionReceiveDataHandler(WCSession session, Dictionary<string, object> data);
|
|
|
|
WCSessionUserInfoTransfer _transf;
|
|
|
|
private WCSession validSession
|
|
{
|
|
get
|
|
{
|
|
Debug.WriteLine($"Paired status:{(session.Paired ? '✓' : '✗')}\n");
|
|
Debug.WriteLine($"Watch App Installed status:{(session.WatchAppInstalled ? '✓' : '✗')}\n");
|
|
return (session.Paired && session.WatchAppInstalled) ? session : null;
|
|
}
|
|
}
|
|
|
|
private WCSession validReachableSession
|
|
{
|
|
get
|
|
{
|
|
return session.Reachable ? validSession : null;
|
|
}
|
|
}
|
|
|
|
public bool IsValidSession => validSession != null;
|
|
|
|
public bool IsSessionReachable => session.Reachable;
|
|
|
|
public bool IsSessionActivated => validSession?.ActivationState == WCSessionActivationState.Activated;
|
|
|
|
private WCSessionManager() : base() { }
|
|
|
|
public static WCSessionManager SharedManager
|
|
{
|
|
get
|
|
{
|
|
return sharedManager;
|
|
}
|
|
}
|
|
|
|
public void StartSession()
|
|
{
|
|
if (session != null)
|
|
{
|
|
session.Delegate = this;
|
|
session.ActivateSession();
|
|
Debug.WriteLine($"Started Watch Connectivity Session");
|
|
}
|
|
}
|
|
|
|
public override void SessionReachabilityDidChange(WCSession session)
|
|
{
|
|
Debug.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')}");
|
|
}
|
|
|
|
public void SendBackgroundHighPriorityMessage(NSDictionary<NSString, NSObject> applicationContext)
|
|
{
|
|
// Application context doesnt need the watch to be reachable, it will be received when opened
|
|
if (validSession is null || validSession.ActivationState != WCSessionActivationState.Activated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var sendSuccessfully = validSession.UpdateApplicationContext(applicationContext, out var error);
|
|
if (sendSuccessfully)
|
|
{
|
|
Debug.WriteLine($"Sent App Context \nPayLoad: {applicationContext.ToString()} \n");
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine($"Error Updating Application Context: {error.LocalizedDescription}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
}
|
|
}
|
|
|
|
public void SendBackgroundFifoHighPriorityMessage(Dictionary<string, object> message)
|
|
{
|
|
if(validSession is null || validSession.ActivationState != WCSessionActivationState.Activated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_transf?.Cancel();
|
|
|
|
Debug.WriteLine("Started transferring user info");
|
|
|
|
_transf = session.TransferUserInfo(message.ToNSDictionary());
|
|
|
|
Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
while (_transf.Transferring)
|
|
{
|
|
await Task.Delay(1000);
|
|
}
|
|
Debug.WriteLine("Finished transferring user info");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
}
|
|
});
|
|
}
|
|
|
|
public override void DidReceiveApplicationContext(WCSession session, NSDictionary<NSString, NSObject> applicationContext)
|
|
{
|
|
Debug.WriteLine($"Receiving Message");
|
|
if (OnApplicationContextUpdated != null)
|
|
{
|
|
var keys = applicationContext.Keys.Select(k => k.ToString()).ToArray();
|
|
var values = applicationContext.Values.Select(v => JsonConvert.DeserializeObject(v.ToString())).ToArray();
|
|
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
|
|
.ToDictionary(x => x.Key, x => x.Value);
|
|
|
|
OnApplicationContextUpdated(session, dictionary);
|
|
}
|
|
}
|
|
|
|
public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message)
|
|
{
|
|
Debug.WriteLine($"Receiving Message");
|
|
|
|
OnMessagedReceived?.Invoke(session, message.ToDictionary());
|
|
}
|
|
|
|
public override void DidReceiveMessage(WCSession session, NSDictionary<NSString, NSObject> message, WCSessionReplyHandler replyHandler)
|
|
{
|
|
Debug.WriteLine($"Receiving Message");
|
|
|
|
OnMessagedReceived?.Invoke(session, message.ToDictionary());
|
|
}
|
|
}
|
|
}
|