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
{
2016-06-08 09:31:26 -07:00
public class SetupWizardTroubleshooting : WizardPage
2016-06-01 18:17:11 -07:00
{
private Button nextButton ;
2016-12-29 06:55:12 -08:00
private EventHandler unregisterEvents ;
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 ;
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
2016-06-07 15:45:50 -07:00
public SetupWizardTroubleshooting ( )
2016-06-01 18:17:11 -07:00
{
2017-08-23 15:51:29 -07:00
this . WindowTitle = "Troubleshooting" . Localize ( ) ;
2016-06-01 18:17:11 -07:00
RefreshStatus ( ) ;
2016-06-07 15:45:50 -07:00
nextButton = textImageButtonFactory . Generate ( "Continue" . Localize ( ) ) ;
nextButton . Click + = ( sender , e ) = > UiThread . RunOnIdle ( this . WizardWindow . 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
// Register for connection notifications
2017-09-17 21:08:16 -07:00
ApplicationController . Instance . ActivePrinter . Connection . CommunicationStateChanged . RegisterEvent ( ConnectionStatusChanged , ref unregisterEvents ) ;
2016-06-01 18:17:11 -07:00
}
public void ConnectionStatusChanged ( object test , EventArgs args )
{
2017-09-17 21:08:16 -07:00
if ( ApplicationController . Instance . ActivePrinter . 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 ( ( ) = >
{
this . WizardWindow . ChangeToPage < AndroidConnectDevicePage > ( ) ;
} ) ;
}
2017-02-03 13:06:08 -08:00
public override void OnClosed ( ClosedEventArgs e )
2016-06-01 18:17:11 -07:00
{
if ( checkForPermissionTimer ! = null )
{
checkForPermissionTimer . Dispose ( ) ;
}
2016-06-07 17:23:41 -07:00
unregisterEvents ? . Invoke ( this , null ) ;
2016-06-01 18:17:11 -07:00
base . OnClosed ( e ) ;
}
private void RefreshStatus ( )
{
CriteriaRow . ResetAll ( ) ;
// Clear the main container
contentRow . CloseAllChildren ( ) ;
// Regen and refresh the troubleshooting criteria
TextWidget printerNameLabel = new TextWidget ( string . Format ( "{0}:" , "Connection Troubleshooting" . Localize ( ) ) , 0 , 0 , labelFontSize ) ;
2016-06-02 17:46:49 -07:00
printerNameLabel . TextColor = ActiveTheme . Instance . PrimaryTextColor ;
2016-06-01 18:17:11 -07:00
printerNameLabel . Margin = new BorderDouble ( bottom : 10 ) ;
#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 ) ;
contentRow . AddChild ( printerNameLabel ) ;
contentRow . AddChild ( new CriteriaRow (
"USB Connection" ,
"Retry" ,
"No USB device found. Check and reseat cables and try again" ,
usbStatus . AnyUsbDeviceExists ,
( ) = > UiThread . RunOnIdle ( RefreshStatus ) ) ) ;
contentRow . AddChild ( new CriteriaRow (
"USB Driver" ,
"Fix" ,
usbStatus . Summary ,
usbStatus . IsDriverLoadable ,
( ) = > {
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 ( ) ) ;
} ) ) ;
contentRow . AddChild ( new CriteriaRow (
"USB Permission" ,
"Request Permission" ,
"Click the 'Request Permission' button to gain Android access rights" ,
usbStatus . HasUsbPermission ,
( ) = > {
if ( checkForPermissionTimer = = null )
{
checkForPermissionTimer = new System . Threading . Timer ( ( state ) = > {
if ( FrostedSerialPort . HasPermissionToDevice ( serialPort ) )
{
UiThread . RunOnIdle ( this . RefreshStatus ) ;
checkForPermissionTimer . Dispose ( ) ;
}
} , null , 200 , 200 ) ;
}
FrostedSerialPort . RequestPermissionToDevice ( serialPort ) ;
} ) ) ;
#endif
connectToPrinterRow = new CriteriaRow (
"Connect to Printer" ,
"Connect" ,
"Click the 'Connect' button to retry the original connection attempt" ,
false ,
2017-09-18 07:20:06 -07:00
( ) = > ApplicationController . Instance . ActivePrinter . Connection . Connect ( ) ) ;
2016-06-01 18:17:11 -07:00
contentRow . AddChild ( connectToPrinterRow ) ;
if ( CriteriaRow . ActiveErrorItem ! = null ) {
FlowLayoutWidget errorText = new FlowLayoutWidget ( ) {
Padding = new BorderDouble ( 0 , 15 )
} ;
errorText . AddChild ( new TextWidget ( CriteriaRow . ActiveErrorItem . ErrorText ) {
TextColor = ActiveTheme . Instance . PrimaryAccentColor
} ) ;
contentRow . AddChild ( errorText ) ;
}
}
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 ;
private static RGBA_Bytes disabledTextColor = new RGBA_Bytes ( 0.35 , 0.35 , 0.35 ) ;
private static RGBA_Bytes disabledBackColor = new RGBA_Bytes ( 0.22 , 0.22 , 0.22 ) ;
private static RGBA_Bytes toggleColor = new RGBA_Bytes ( RGBA_Bytes . Gray . red + 2 , RGBA_Bytes . Gray . green + 2 , RGBA_Bytes . Gray . blue + 2 ) ;
2017-02-01 16:39:24 -08:00
public CriteriaRow ( string itemText , string fixitText , string errorText , bool succeeded , Action fixAction )
: 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
TextImageButtonFactory buttonFactory = new TextImageButtonFactory ( ) ;
ErrorText = errorText ;
base . Height = 40 ;
base . AddChild ( new TextWidget ( string . Format ( " {0}. {1}" , criteriaCount + 1 , itemText ) ) {
TextColor = stillSuccessful ? RGBA_Bytes . 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
2017-08-13 14:17:34 -07:00
Button button = buttonFactory . Generate ( fixitText . Localize ( ) ) ;
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 ) ;
button . Click + = ( sender , e ) = > fixAction ( ) ;
base . AddChild ( button ) ;
}
}
if ( stillSuccessful )
{
this . BackgroundColor = ( criteriaCount % 2 = = 0 ) ? RGBA_Bytes . Gray : toggleColor ;
}
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 ; }
}
}
}