bool?IsWifiDirectGroupOwner(AndroidDevice device) // Is this guy the group owner of a Wifi Direct Group? { try { // Example response: // p2p0: ip 192.168.49.1 mask 255.255.255.0 flags [up broadcast running multicast] CommandResultReceiver rcvr = new CommandResultReceiver(); AdbHelper.Instance.ExecuteRemoteCommand(AndroidDebugBridge.AdbServerSocketAddress, "ifconfig p2p0", device.SerialNumbers[0], rcvr); string regex = $"p2p0: ip ({Device.RegExIpAddr}) mask {Device.RegExIpAddr} flags \\[([a-zA-Z ]*)\\]"; Match match = Regex.Match(rcvr.Result, regex, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline); if (match.Success && match.Groups[1].Value == AndroidDevice.WifiDirectIPAddress.ToString()) { string[] splits = match.Groups[2].Value.ToLowerInvariant().Split(' '); if (splits.Contains("up")) { return(true); } } } catch (Exception) { return(null); } return(false); }
public AndroidDevice DisconnectedCopy() { AndroidDevice result = (AndroidDevice)this.MemberwiseClone(); result.database = null; return(result); }
void ReconnectToLastTCPIPDevice() // Attempt to reconnect to the TCPIP device we last saw { lock (this.deviceConnectionLock) { if (this.lastTPCIPConnected != null) { string ipAddress = this.lastTPCIPConnected.IPAddressLastConnected ?? this.lastTPCIPConnected.WlanIpAddress; int portNumber = adbdPort; this.tracer.Trace($" reconnecting to {this.lastTPCIPConnected.UserIdentifier}:{this.lastTPCIPConnected.USBSerialNumber} on {ipAddress}"); if (AdbHelper.Instance.Connect(AndroidDebugBridge.AdbServerSocketAddress, ipAddress, portNumber)) { // Ok, we connected. But is it the same guy? We'll have to check later. We // snarf away a copy of the device so we'll be able to compare it's current // state to what we find later; if we didn't copy, then this state could be // tarnished by the 'update to latest connected devices' step. NotifyReconnected(Resources.NotifyReconnected, this.lastTPCIPConnected.UserIdentifier, ipAddress); this.reconnectionToVerify = this.lastTPCIPConnected.DisconnectedCopy(); this.lastTPCIPConnected.IPAddressLastConnected = ipAddress; } else { NotifyReconnected(Resources.NotifyReconnectedFail, this.lastTPCIPConnected.UserIdentifier, ipAddress); this.lastTPCIPConnected.IPAddressLastConnected = null; } } } }
void RememberLastTCPIPDevice(AndroidDevice device, string ipAddress) { lock (this.deviceConnectionLock) { device.IPAddressLastConnected = ipAddress; this.lastTPCIPConnected = device; UpdateTrayStatus(); } }
void ForgetLastTCPIPDevice() { lock (this.deviceConnectionLock) { if (this.lastTPCIPConnected != null) { this.lastTPCIPConnected = null; UpdateTrayStatus(); } } }
bool SendTcpipCommandAndConnect(AndroidDevice device, string ipAddress) { bool result = false; bool tcpipIssuedOk = true; try { // Restart the device listening on a port of interest. We don't know if he got there, // as we get no response from the command issued. this.tracer.Trace($" restarting {device.USBSerialNumber} adbd in TCPIP at {ipAddress}"); AdbHelper.Instance.TcpIp(AndroidDebugBridge.AdbServerSocketAddress, device.USBSerialNumber, adbdPort); } catch (Exception) { this.tracer.Trace($" restart of {device.USBSerialNumber} adbd failed"); tcpipIssuedOk = false; } if (tcpipIssuedOk) { // Give it a chance to restart. The actual time used here is a total guess, but // it does seem to work. Mostly (?). Thread.Sleep(1000); // Connect to the TCPIP version of that device this.tracer.Trace($" connecting to restarted {ipAddress} device"); if (AdbHelper.Instance.Connect(AndroidDebugBridge.AdbServerSocketAddress, ipAddress, adbdPort)) { NotifyConnected(device, ipAddress); // Remember to whom we last connected for later ADB Server restarts RememberLastTCPIPDevice(device, ipAddress); result = true; } } if (!result) { this.tracer.Trace($" failed to connect to {ipAddress}:{adbdPort}"); NotifyDisconnected(device, ipAddress); device.IPAddressLastConnected = null; } return(result); }
//----------------------------------------------------------------------------------------- // Operations //----------------------------------------------------------------------------------------- public AndroidDevice FromUSBSerialNumber(string usbSerialNumber) { if (string.IsNullOrEmpty(usbSerialNumber)) { throw new System.ArgumentException($"'{nameof(usbSerialNumber)}' cannot be null or empty"); } AndroidDevice result; if (!this.mpUsbToDevice.TryGetValue(usbSerialNumber, out result)) { result = new AndroidDevice(this) { USBSerialNumber = usbSerialNumber }; this.mpUsbToDevice[usbSerialNumber] = result; } return(result); }
public void UpdateFromDevicesConnectedToAdbServer(List <Device> devices) { foreach (AndroidDevice ad in this.mpUsbToDevice.Values) { ad.IsConnected = false; ad.IsTCPIPOnLine = false; ad.AdbEndpoints = new List <IPEndPoint>(); ad.SerialNumbers = new List <string>(); } foreach (Device device in devices) { if (!string.IsNullOrEmpty(device.USBSerialNumber)) { AndroidDevice ad = FromUSBSerialNumber(device.USBSerialNumber); ad.IsConnected = true; ad.WifiDirectName = device.WifiDirectName; ad.WlanIpAddress = device.WlanIpAddress; ad.WlanIsRunning = device.WlanIsRunning; ad.SerialNumbers.Add(device.SerialNumber); if (device.SerialNumberIsTCPIP) { string[] pieces = device.SerialNumber.Split(':'); ad.AdbEndpoints.Add(new IPEndPoint(IPAddress.Parse(pieces[0]), int.Parse(pieces[1]))); ad.IsTCPIPOnLine = device.IsOnline; } } else { // We're hitting this occasionally, but we don't exactly know why. It seems like // the Win32 notifications might be racing with the ADB server notifications: this // only showed up on Bob's new super-duper-fast desktop. // // We really ought to track down what's happening. But for now, we'll just disable // the USB-notification path, which was always redundant, anyway. } } }
void NotifyConnected(AndroidDevice device, string ipAddress) { string format = ipAddress==AndroidDevice.WifiDirectIPAddress.ToString() ? Resources.NotifyConnectedWifiDirect : Resources.NotifyConnected; NotifyConnectedMessage(format, device, ipAddress); }
void NotifyNotPingable(AndroidDevice device) { NotifyMessage(string.Format(Resources.NotifyNotPingable, device.UserIdentifier, device.WlanIpAddress)); }
void NotifyWifiNotRunning(AndroidDevice device) { NotifyMessage(string.Format(Resources.NotifyWifiOff, device.UserIdentifier, device.WlanIpAddress)); }
bool SendTcpipCommandAndConnect(AndroidDevice device, string ipAddress) { bool result = false; bool tcpipIssuedOk = true; try { // Restart the device listening on a port of interest. We don't know if he got there, // as we get no response from the command issued. this.tracer.Trace($" restarting {device.USBSerialNumber} adbd in TCPIP at {ipAddress}"); AdbHelper.Instance.TcpIp(AndroidDebugBridge.AdbServerSocketAddress, device.USBSerialNumber, adbdPort); } catch (Exception) { this.tracer.Trace($" restart of {device.USBSerialNumber} adbd failed"); tcpipIssuedOk = false; } if (tcpipIssuedOk) { // Give it a chance to restart. The actual time used here is a total guess, but // it does seem to work. Mostly (?). Thread.Sleep(1000); // Connect to the TCPIP version of that device this.tracer.Trace($" connecting to restarted {ipAddress} device"); if (AdbHelper.Instance.Connect(AndroidDebugBridge.AdbServerSocketAddress, ipAddress, adbdPort)) { NotifyConnected(device, ipAddress); // Remember to whom we last connected for later ADB Server restarts RememberLastTCPIPDevice(device, ipAddress); result = true; } } if (!result) { this.tracer.Trace($" failed to connect to {ipAddress}:{adbdPort}"); NotifyDisconnected(device, ipAddress); device.IPAddressLastConnected = null; } return result; }
bool?EnsureUSBConnectedDevicesAreOnTCPIP(string reason) // Iterate over all the extant Android devices (that ADB knows about) and make sure that each // one of them is listening on TCPIP. This method is idempotent, so you can call it as often // and as frequently as you like. Answer as to whether there were any devices known about by // the ADB server. { // Don't actually do anything if the user has asked us not to if (!this.armed) { return(null); } bool serverKnowsAboutAnyDevices = false; // We synchronize for paranoid reasons: we're not SURE we can be be called on // a whole range of threads, possibly simultaneously, but why take the chance? lock (this.deviceConnectionLock) { this.tracer.Trace($"v-----EnsureAdbDevicesAreOnTCPIP({reason})-----v"); // Get ourselves the list of devices that ADB currently knows about List <Device> devicesConnectedToAdbServer = AdbHelper.Instance.GetDevices(AndroidDebugBridge.AdbServerSocketAddress); this.androidDeviceDatabase.UpdateFromDevicesConnectedToAdbServer(devicesConnectedToAdbServer); // Do a bit of tracing foreach (Device device in devicesConnectedToAdbServer) { this.tracer.Trace($" usb:{device.USBSerialNumber} ipAddress:{device.WlanIpAddress} wifi:{(device.WlanIsRunning?"on":"off")} serial:{device.SerialNumber}"); } this.tracer.Trace($"---------------------------------"); foreach (AndroidDevice device in this.androidDeviceDatabase.ConnectedDevices) { this.tracer.Trace($" usb:{device.USBSerialNumber} ipAddress:{device.WlanIpAddress} wifi:{(device.WlanIsRunning?"on":"off")} connected:{device.IsAdbConnectedOnTcpip}"); } // Iterate over what's currently connected to ADB // AndroidDevice potentialLastDevice = null; bool connectedAny = false; bool wifiDirectAddrInUse = this.androidDeviceDatabase.IsWifiDirectIPAddressConnected; foreach (AndroidDevice device in this.androidDeviceDatabase.ConnectedDevices) { // Yes, the server knows about some devices serverKnowsAboutAnyDevices = true; if (device.IsAdbConnectedOnTcpip) { // ADB has a TCPIP connection for him; we're not going to add one // potentialLastDevice = potentialLastDevice ?? device; if (this.reconnectionToVerify != null) { // Is this the address we reconnected on? if (this.reconnectionToVerify.WlanIpAddress == device.WlanIpAddress) { // Did we reconnect to the same device? if (this.reconnectionToVerify.USBSerialNumber == device.USBSerialNumber) { // All is well this.tracer.Trace($" verify reconnected: all good: {this.reconnectionToVerify.WlanIpAddress} is still {device.USBSerialNumber}"); } else { // We reconnected to him, but he's the wrong guy. Disconnect. this.tracer.Trace($" verify reconnected: fail: {this.reconnectionToVerify.WlanIpAddress}: got: {device.USBSerialNumber} expected: {this.reconnectionToVerify.USBSerialNumber}; disconnecting"); AdbHelper.Instance.Disconnect(AndroidDebugBridge.AdbServerSocketAddress, device.WlanIpAddress, adbdPort); NotifyReconnected(Resources.NotifyReconnectedFail, device.UserIdentifier, device.WlanIpAddress); // If we're *still* porentially reconnecting to that same guy, stop that if (this.lastTPCIPConnected != null && this.lastTPCIPConnected.USBSerialNumber == this.reconnectionToVerify.USBSerialNumber) { ForgetLastTCPIPDevice(); } // And he's no longer a potential *later* reconnection if (potentialLastDevice == device) { potentialLastDevice = null; } } // Verification of reconnection is complete this.reconnectionToVerify = null; } } } else { // ADB doesn't already have a TCPIP connection for him. We'll try to make one if we can. // // Can we reach him over WifiDirect? if (!wifiDirectAddrInUse && IsPingable(AndroidDevice.WifiDirectIPAddress) && (IsWifiDirectGroupOwner(device) ?? false) && SendTcpipCommandAndConnect(device, AndroidDevice.WifiDirectIPAddress)) { this.tracer.Trace($"connected to {device.UserIdentifier} over WifiDirect!"); wifiDirectAddrInUse = true; connectedAny = true; } else if (string.IsNullOrEmpty(device.WlanIpAddress)) { NotifyNoIpAddress(device); } else if (!device.WlanIsRunning) { NotifyWifiNotRunning(device); } else { // He's not already connected on an IP network. But can we reach him? if (IsPingable(device.WlanIpAddress)) { // Connect to him if (SendTcpipCommandAndConnect(device, device.WlanIpAddress)) { connectedAny = true; } } else { NotifyNotPingable(device); } } } } // If we didn't do any connection here, remember something that ADB is ALREADY // connected to as a potential reconnection target for later if (!connectedAny && potentialLastDevice != null) { RememberLastTCPIPDevice(potentialLastDevice, potentialLastDevice.IPAddressLastConnected ?? potentialLastDevice.WlanIpAddress); } this.tracer.Trace($"^-----EnsureAdbDevicesAreOnTCPIP({reason})-----^"); } return(serverKnowsAboutAnyDevices); }
bool SendTcpipCommandAndConnect(AndroidDevice device, IPAddress ipAddress) { return(SendTcpipCommandAndConnect(device, ipAddress.ToString())); }
void NotifyConnectedMessage(string format, AndroidDevice device, string ipAddress) { NotifyMessage(string.Format(format, device.UserIdentifier, ipAddress)); }
void NotifyDisconnected(AndroidDevice device, string ipAddress) { string format = Resources.NotifyConnectedFail; NotifyConnectedMessage(format, device, ipAddress); }
void NotifyConnected(AndroidDevice device, string ipAddress) { string format = ipAddress == AndroidDevice.WifiDirectIPAddress.ToString() ? Resources.NotifyConnectedWifiDirect : Resources.NotifyConnected; NotifyConnectedMessage(format, device, ipAddress); }
bool? IsWifiDirectGroupOwner(AndroidDevice device) // Is this guy the group owner of a Wifi Direct Group? { try { // Example response: // p2p0: ip 192.168.49.1 mask 255.255.255.0 flags [up broadcast running multicast] CommandResultReceiver rcvr = new CommandResultReceiver(); AdbHelper.Instance.ExecuteRemoteCommand(AndroidDebugBridge.AdbServerSocketAddress, "ifconfig p2p0", device.SerialNumbers[0], rcvr); string regex=$"p2p0: ip ({Device.RegExIpAddr}) mask {Device.RegExIpAddr} flags \\[([a-zA-Z ]*)\\]"; Match match = Regex.Match(rcvr.Result, regex, RegexOptions.Compiled|RegexOptions.IgnoreCase|RegexOptions.Singleline); if (match.Success && match.Groups[1].Value==AndroidDevice.WifiDirectIPAddress.ToString()) { string[] splits = match.Groups[2].Value.ToLowerInvariant().Split(' '); if (splits.Contains("up")) { return true; } } } catch (Exception) { return null; } return false; }
bool SendTcpipCommandAndConnect(AndroidDevice device, IPAddress ipAddress) { return SendTcpipCommandAndConnect(device, ipAddress.ToString()); }
//----------------------------------------------------------------------------------------- // Operations //----------------------------------------------------------------------------------------- public AndroidDevice FromUSBSerialNumber(string usbSerialNumber) { if (string.IsNullOrEmpty(usbSerialNumber)) throw new System.ArgumentException($"'{nameof(usbSerialNumber)}' cannot be null or empty"); AndroidDevice result; if (!this.mpUsbToDevice.TryGetValue(usbSerialNumber, out result)) { result = new AndroidDevice(this) { USBSerialNumber = usbSerialNumber }; this.mpUsbToDevice[usbSerialNumber] = result; } return result; }
bool? EnsureUSBConnectedDevicesAreOnTCPIP(string reason) // Iterate over all the extant Android devices (that ADB knows about) and make sure that each // one of them is listening on TCPIP. This method is idempotent, so you can call it as often // and as frequently as you like. Answer as to whether there were any devices known about by // the ADB server. { // Don't actually do anything if the user has asked us not to if (!this.armed) return null; bool serverKnowsAboutAnyDevices = false; // We synchronize for paranoid reasons: we're not SURE we can be be called on // a whole range of threads, possibly simultaneously, but why take the chance? lock (this.deviceConnectionLock) { this.tracer.Trace($"v-----EnsureAdbDevicesAreOnTCPIP({reason})-----v"); // Get ourselves the list of devices that ADB currently knows about List<Device> devicesConnectedToAdbServer = AdbHelper.Instance.GetDevices(AndroidDebugBridge.AdbServerSocketAddress); this.androidDeviceDatabase.UpdateFromDevicesConnectedToAdbServer(devicesConnectedToAdbServer); // Do a bit of tracing foreach (Device device in devicesConnectedToAdbServer) { this.tracer.Trace($" usb:{device.USBSerialNumber} ipAddress:{device.WlanIpAddress} wifi:{(device.WlanIsRunning?"on":"off")} serial:{device.SerialNumber}"); } this.tracer.Trace($"---------------------------------"); foreach (AndroidDevice device in this.androidDeviceDatabase.ConnectedDevices) { this.tracer.Trace($" usb:{device.USBSerialNumber} ipAddress:{device.WlanIpAddress} wifi:{(device.WlanIsRunning?"on":"off")} connected:{device.IsAdbConnectedOnTcpip}"); } // Iterate over what's currently connected to ADB // AndroidDevice potentialLastDevice = null; bool connectedAny = false; bool wifiDirectAddrInUse = this.androidDeviceDatabase.IsWifiDirectIPAddressConnected; foreach (AndroidDevice device in this.androidDeviceDatabase.ConnectedDevices) { // Yes, the server knows about some devices serverKnowsAboutAnyDevices = true; if (device.IsAdbConnectedOnTcpip) { // ADB has a TCPIP connection for him; we're not going to add one // potentialLastDevice = potentialLastDevice ?? device; if (this.reconnectionToVerify != null) { // Is this the address we reconnected on? if (this.reconnectionToVerify.WlanIpAddress == device.WlanIpAddress) { // Did we reconnect to the same device? if (this.reconnectionToVerify.USBSerialNumber == device.USBSerialNumber) { // All is well this.tracer.Trace($" verify reconnected: all good: {this.reconnectionToVerify.WlanIpAddress} is still {device.USBSerialNumber}"); } else { // We reconnected to him, but he's the wrong guy. Disconnect. this.tracer.Trace($" verify reconnected: fail: {this.reconnectionToVerify.WlanIpAddress}: got: {device.USBSerialNumber} expected: {this.reconnectionToVerify.USBSerialNumber}; disconnecting"); AdbHelper.Instance.Disconnect(AndroidDebugBridge.AdbServerSocketAddress, device.WlanIpAddress, adbdPort); NotifyReconnected(Resources.NotifyReconnectedFail, device.UserIdentifier, device.WlanIpAddress); // If we're *still* porentially reconnecting to that same guy, stop that if (this.lastTPCIPConnected != null && this.lastTPCIPConnected.USBSerialNumber == this.reconnectionToVerify.USBSerialNumber) { ForgetLastTCPIPDevice(); } // And he's no longer a potential *later* reconnection if (potentialLastDevice == device) potentialLastDevice = null; } // Verification of reconnection is complete this.reconnectionToVerify = null; } } } else { // ADB doesn't already have a TCPIP connection for him. We'll try to make one if we can. // // Can we reach him over WifiDirect? if (!wifiDirectAddrInUse && IsPingable(AndroidDevice.WifiDirectIPAddress) && (IsWifiDirectGroupOwner(device) ?? false) && SendTcpipCommandAndConnect(device, AndroidDevice.WifiDirectIPAddress)) { this.tracer.Trace($"connected to {device.UserIdentifier} over WifiDirect!"); wifiDirectAddrInUse = true; connectedAny = true; } else if (string.IsNullOrEmpty(device.WlanIpAddress)) { NotifyNoIpAddress(device); } else if (!device.WlanIsRunning) { NotifyWifiNotRunning(device); } else { // He's not already connected on an IP network. But can we reach him? if (IsPingable(device.WlanIpAddress)) { // Connect to him if (SendTcpipCommandAndConnect(device, device.WlanIpAddress)) { connectedAny = true; } } else NotifyNotPingable(device); } } } // If we didn't do any connection here, remember something that ADB is ALREADY // connected to as a potential reconnection target for later if (!connectedAny && potentialLastDevice != null) { RememberLastTCPIPDevice(potentialLastDevice, potentialLastDevice.IPAddressLastConnected ?? potentialLastDevice.WlanIpAddress); } this.tracer.Trace($"^-----EnsureAdbDevicesAreOnTCPIP({reason})-----^"); } return serverKnowsAboutAnyDevices; }