2016-06-01 18:17:11 -07:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using MatterHackers.Agg ;
2017-08-20 02:34:39 -07:00
using MatterHackers.Agg.Platform ;
2016-06-01 18:17:11 -07:00
using MatterHackers.Agg.UI ;
using MatterHackers.Localizations ;
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling ;
using MatterHackers.MatterControl.DataStorage ;
using MatterHackers.MatterControl.CustomWidgets ;
using MatterHackers.MatterControl.PrinterCommunication ;
using MatterHackers.SerialPortCommunication.FrostedSerial ;
#if __ANDROID__
using Com.Hoho.Android.Usbserial.Driver ;
using Android.Hardware.Usb ;
using Android.Content ;
#endif
namespace MatterHackers.MatterControl
2017-08-20 02:34:39 -07:00
{
2017-11-08 15:56:37 -08:00
public class SetupWizardTroubleshooting : DialogPage
2016-06-01 18:17:11 -07:00
{
2018-07-11 15:32:03 -07:00
private GuiWidget nextButton ;
2016-06-01 18:17:11 -07:00
private CriteriaRow connectToPrinterRow ;
2016-06-07 17:23:41 -07:00
// Used in Android
private System . Threading . Timer checkForPermissionTimer ;
2018-07-12 09:22:28 -07:00
private PrinterConfig printer ;
2016-06-07 17:23:41 -07:00
2016-06-01 18:17:11 -07:00
#if __ANDROID__
private static UsbManager usbManager
{
get { return ( UsbManager ) Android . App . Application . Context . ApplicationContext . GetSystemService ( Context . UsbService ) ; }
}
#endif
2018-07-12 09:22:28 -07:00
public SetupWizardTroubleshooting ( PrinterConfig printer )
2016-06-01 18:17:11 -07:00
{
2017-08-23 15:51:29 -07:00
this . WindowTitle = "Troubleshooting" . Localize ( ) ;
2018-07-12 09:22:28 -07:00
this . printer = printer ;
2017-08-23 15:51:29 -07:00
2016-06-01 18:17:11 -07:00
RefreshStatus ( ) ;
2018-07-11 15:32:03 -07:00
nextButton = theme . CreateDialogButton ( "Continue" . Localize ( ) ) ;
nextButton . Click + = ( s , e ) = > UiThread . RunOnIdle ( this . DialogWindow . Close ) ;
2016-06-01 18:17:11 -07:00
nextButton . Visible = false ;
2017-08-23 17:27:30 -07:00
this . AddPageAction ( nextButton ) ;
2016-06-01 18:17:11 -07:00
2018-11-16 08:44:56 -08:00
// Register listeners
printer . Connection . CommunicationStateChanged + = Connection_CommunicationStateChanged ;
2016-06-01 18:17:11 -07:00
}
2018-11-16 08:44:56 -08:00
public void Connection_CommunicationStateChanged ( object test , EventArgs args )
2016-06-01 18:17:11 -07:00
{
2018-11-16 08:44:56 -08:00
if ( printer . Connection . CommunicationState = = CommunicationStates . Connected & & connectToPrinterRow ! = null )
2016-06-01 18:17:11 -07:00
{
connectToPrinterRow . SetSuccessful ( ) ;
nextButton . Visible = true ;
}
}
2017-10-18 09:24:29 -07:00
protected override void OnCancel ( out bool abortCancel )
{
abortCancel = true ;
UiThread . RunOnIdle ( ( ) = >
{
2018-06-19 15:02:25 -07:00
this . DialogWindow . ChangeToPage < AndroidConnectDevicePage > ( ) ;
2017-10-18 09:24:29 -07:00
} ) ;
}
2018-08-23 16:44:11 -07:00
public override void OnClosed ( EventArgs e )
2016-06-01 18:17:11 -07:00
{
2018-11-16 08:44:56 -08:00
// Unregister listeners
printer . Connection . CommunicationStateChanged - = Connection_CommunicationStateChanged ;
if ( checkForPermissionTimer ! = null )
2016-06-01 18:17:11 -07:00
{
checkForPermissionTimer . Dispose ( ) ;
}
base . OnClosed ( e ) ;
}
private void RefreshStatus ( )
{
CriteriaRow . ResetAll ( ) ;
// Clear the main container
2018-11-03 10:12:27 -07:00
contentRow . CloseAllChildren ( ) ;
2016-06-01 18:17:11 -07:00
// Regen and refresh the troubleshooting criteria
2018-07-12 09:22:28 -07:00
var printerNameLabel = new TextWidget ( string . Format ( "{0}:" , "Connection Troubleshooting" . Localize ( ) ) , 0 , 0 , labelFontSize )
{
2018-11-03 09:13:07 -07:00
TextColor = theme . TextColor ,
2018-07-12 09:22:28 -07:00
Margin = new BorderDouble ( bottom : 10 )
} ;
2016-06-01 18:17:11 -07:00
#if __ANDROID__
2016-07-18 16:11:33 -07:00
IUsbSerialPort serialPort = FrostedSerialPort . LoadSerialDriver ( null ) ;
2016-06-01 18:17:11 -07:00
#if ANDROID7
// Filter out the built-in 002 device and select the first item from the list
// On the T7 Android device, there is a non-printer device always registered at usb/002/002 that must be ignored
UsbDevice usbPrintDevice = usbManager . DeviceList . Values . Where ( d = > d . DeviceName ! = "/dev/bus/usb/002/002" ) . FirstOrDefault ( ) ;
#else
UsbDevice usbPrintDevice = usbManager . DeviceList . Values . FirstOrDefault ( ) ;
#endif
UsbStatus usbStatus = new UsbStatus ( ) {
IsDriverLoadable = ( serialPort ! = null ) ,
HasUsbDevice = true ,
HasUsbPermission = false ,
AnyUsbDeviceExists = usbPrintDevice ! = null
} ;
if ( ! usbStatus . IsDriverLoadable )
{
usbStatus . HasUsbDevice = usbPrintDevice ! = null ;
if ( usbStatus . HasUsbDevice ) {
// TODO: Testing specifically for UsbClass.Comm seems fragile but no better alternative exists without more research
usbStatus . UsbDetails = new UsbDeviceDetails ( ) {
ProductID = usbPrintDevice . ProductId ,
VendorID = usbPrintDevice . VendorId ,
DriverClass = usbManager . DeviceList . Values . First ( ) . DeviceClass = = Android . Hardware . Usb . UsbClass . Comm ? "cdcDriverType" : "ftdiDriverType"
} ;
usbStatus . Summary = string . Format ( "No USB device definition found. Click the 'Fix' button to add an override for your device " , usbStatus . UsbDetails . VendorID , usbStatus . UsbDetails . ProductID ) ;
}
}
usbStatus . HasUsbPermission = usbStatus . IsDriverLoadable & & FrostedSerialPort . HasPermissionToDevice ( serialPort ) ;
2018-11-03 20:00:51 -07:00
contentRow . AddChild ( printerNameLabel ) ;
2016-06-01 18:17:11 -07:00
2018-11-03 20:00:51 -07:00
contentRow . AddChild ( new CriteriaRow (
2018-07-12 17:13:55 -07:00
"USB Connection" ,
2016-06-01 18:17:11 -07:00
"Retry" ,
"No USB device found. Check and reseat cables and try again" ,
2018-07-12 17:13:55 -07:00
usbStatus . AnyUsbDeviceExists ,
( ) = > UiThread . RunOnIdle ( RefreshStatus ) ,
theme ) ) ;
2016-06-01 18:17:11 -07:00
2018-11-03 20:00:51 -07:00
contentRow . AddChild ( new CriteriaRow (
2018-07-12 17:13:55 -07:00
"USB Driver" ,
2016-06-01 18:17:11 -07:00
"Fix" ,
usbStatus . Summary ,
2018-07-12 17:13:55 -07:00
usbStatus . IsDriverLoadable ,
( ) = >
{
2016-06-01 18:17:11 -07:00
string overridePath = Path . Combine ( ApplicationDataStorage . ApplicationUserDataPath , "data" , "usboverride.local" ) ;
UsbDeviceDetails usbDetails = usbStatus . UsbDetails ;
File . AppendAllText ( overridePath , string . Format ( "{0},{1},{2}\r\n" , usbDetails . VendorID , usbDetails . ProductID , usbDetails . DriverClass ) ) ;
UiThread . RunOnIdle ( ( ) = > RefreshStatus ( ) ) ;
2018-07-12 17:13:55 -07:00
} ,
theme ) ) ;
2016-06-01 18:17:11 -07:00
2018-11-03 20:00:51 -07:00
contentRow . AddChild ( new CriteriaRow (
2018-07-12 17:13:55 -07:00
"USB Permission" ,
2016-06-01 18:17:11 -07:00
"Request Permission" ,
"Click the 'Request Permission' button to gain Android access rights" ,
2018-07-12 17:13:55 -07:00
usbStatus . HasUsbPermission ,
( ) = >
{
2016-06-01 18:17:11 -07:00
2018-07-12 17:13:55 -07:00
if ( checkForPermissionTimer = = null )
2016-06-01 18:17:11 -07:00
{
2018-07-12 17:13:55 -07:00
checkForPermissionTimer = new System . Threading . Timer ( ( state ) = >
{
2016-06-01 18:17:11 -07:00
2018-07-12 17:13:55 -07:00
if ( FrostedSerialPort . HasPermissionToDevice ( serialPort ) )
2016-06-01 18:17:11 -07:00
{
UiThread . RunOnIdle ( this . RefreshStatus ) ;
checkForPermissionTimer . Dispose ( ) ;
}
} , null , 200 , 200 ) ;
}
FrostedSerialPort . RequestPermissionToDevice ( serialPort ) ;
2018-07-12 17:13:55 -07:00
} ,
theme ) ) ;
2016-06-01 18:17:11 -07:00
#endif
connectToPrinterRow = new CriteriaRow (
2017-12-04 10:39:08 -08:00
"Connect to Printer" . Localize ( ) ,
"Connect" . Localize ( ) ,
"Click the 'Connect' button to retry the original connection attempt" . Localize ( ) ,
2016-06-01 18:17:11 -07:00
false ,
2018-07-12 09:22:28 -07:00
( ) = > printer . Connection . Connect ( ) ,
theme ) ;
2016-06-01 18:17:11 -07:00
2018-11-03 10:12:27 -07:00
contentRow . AddChild ( connectToPrinterRow ) ;
2016-06-01 18:17:11 -07:00
if ( CriteriaRow . ActiveErrorItem ! = null ) {
2018-07-12 09:22:28 -07:00
var errorText = new FlowLayoutWidget ( ) {
2016-06-01 18:17:11 -07:00
Padding = new BorderDouble ( 0 , 15 )
} ;
2018-07-12 09:22:28 -07:00
errorText . AddChild (
new TextWidget ( CriteriaRow . ActiveErrorItem . ErrorText )
{
2018-10-15 18:25:53 -07:00
TextColor = theme . PrimaryAccentColor
2018-07-12 09:22:28 -07:00
} ) ;
2016-06-01 18:17:11 -07:00
2018-11-03 10:12:27 -07:00
contentRow . AddChild ( errorText ) ;
2016-06-01 18:17:11 -07:00
}
}
private class CriteriaRow : FlowLayoutWidget
{
public static CriteriaRow ActiveErrorItem { get ; private set ; }
public string ErrorText { get ; private set ; }
private static bool stillSuccessful = true ;
private static int criteriaCount = 0 ;
2017-10-31 11:43:25 -07:00
private static Color disabledTextColor = new Color ( 0.35 , 0.35 , 0.35 ) ;
private static Color disabledBackColor = new Color ( 0.22 , 0.22 , 0.22 ) ;
private static Color toggleColor = new Color ( Color . Gray . red + 2 , Color . Gray . green + 2 , Color . Gray . blue + 2 ) ;
2016-06-01 18:17:11 -07:00
2018-07-12 09:22:28 -07:00
public CriteriaRow ( string itemText , string fixitText , string errorText , bool succeeded , Action fixAction , ThemeConfig theme )
2017-02-01 16:39:24 -08:00
: base ( FlowDirection . LeftToRight )
2016-06-01 18:17:11 -07:00
{
2017-08-07 15:47:27 -07:00
HAnchor = HAnchor . Stretch ;
VAnchor = VAnchor . Absolute ;
2016-06-01 18:17:11 -07:00
ErrorText = errorText ;
base . Height = 40 ;
base . AddChild ( new TextWidget ( string . Format ( " {0}. {1}" , criteriaCount + 1 , itemText ) ) {
2017-10-31 11:43:25 -07:00
TextColor = stillSuccessful ? Color . White : disabledTextColor ,
2017-08-07 15:47:27 -07:00
VAnchor = VAnchor . Center
2016-06-01 18:17:11 -07:00
} ) ;
if ( stillSuccessful & & ! succeeded )
{
ActiveErrorItem = this ;
}
base . AddChild ( new HorizontalSpacer ( ) ) ;
if ( stillSuccessful ) {
if ( succeeded )
{
// Add checkmark image
AddSuccessIcon ( ) ;
} else {
// Add Fix button
2018-07-12 09:22:28 -07:00
var button = theme . CreateDialogButton ( fixitText ) ;
2017-08-07 15:47:27 -07:00
button . VAnchor = VAnchor . Center ;
2016-06-01 18:17:11 -07:00
button . Padding = new BorderDouble ( 3 , 8 ) ;
2018-07-11 15:32:03 -07:00
button . Click + = ( s , e ) = > fixAction ? . Invoke ( ) ;
2016-06-01 18:17:11 -07:00
base . AddChild ( button ) ;
}
}
2017-12-04 10:39:08 -08:00
if ( stillSuccessful )
2016-06-01 18:17:11 -07:00
{
2017-10-31 11:43:25 -07:00
this . BackgroundColor = ( criteriaCount % 2 = = 0 ) ? Color . Gray : toggleColor ;
2016-06-01 18:17:11 -07:00
}
else
{
this . BackgroundColor = disabledBackColor ;
}
stillSuccessful & = succeeded ;
criteriaCount + + ;
}
public void SetSuccessful ( )
{
this . RemoveChild ( this . Children . Last ( ) ) ;
ActiveErrorItem = null ;
AddSuccessIcon ( ) ;
}
public static void ResetAll ( )
{
criteriaCount = 0 ;
stillSuccessful = true ;
ActiveErrorItem = null ;
}
private void AddSuccessIcon ( )
{
2017-08-20 02:34:39 -07:00
base . AddChild ( new ImageWidget ( AggContext . StaticData . LoadImage ( Path . Combine ( "Icons" , "426.png" ) ) ) {
2017-08-07 15:47:27 -07:00
VAnchor = VAnchor . Center
2016-06-01 18:17:11 -07:00
} ) ;
}
}
private class UsbStatus
{
public bool HasUsbDevice { get ; set ; }
public bool IsDriverLoadable { get ; set ; }
public string Summary { get ; set ; }
public bool HasUsbPermission { get ; set ; }
public bool AnyUsbDeviceExists { get ; set ; }
public UsbDeviceDetails UsbDetails { get ; set ; }
}
private class UsbDeviceDetails
{
public int VendorID { get ; set ; }
public int ProductID { get ; set ; }
public string DriverClass { get ; set ; }
}
}
}