// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using Microsoft.Win32; using System; using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; namespace WPinternals { public enum NavigationSubject { Info, Mode, Install, About }; public enum PhoneInterfaces { Lumia_Normal, Lumia_Flash, Lumia_Label, Lumia_MassStorage, Lumia_Bootloader, Qualcomm_Download, Qualcomm_Flash, Lumia_BadMassStorage }; // Create this class on the UI thread, after the main-window of the application is initialized. // It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread. // The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window. // Therefore the main window must be created before the ViewModel is created. internal class MainViewModel : INotifyPropertyChanged { public PhoneInterfaces? CurrentInterface = null; public PhoneInterfaces? LastInterface = null; public NokiaPhoneModel CurrentModel = null; public PhoneNotifierViewModel PhoneNotifier; public LumiaInfoViewModel InfoViewModel; public LumiaModeViewModel ModeViewModel; public LumiaUnlockBootViewModel BootUnlockViewModel; public LumiaUnlockBootViewModel BootRestoreViewModel; public LumiaUnlockRootViewModel RootUnlockViewModel; public LumiaUnlockRootViewModel RootRestoreViewModel; public BackupViewModel BackupViewModel; public RestoreViewModel RestoreViewModel; public LumiaFlashRomViewModel LumiaFlashRomViewModel; public DumpRomViewModel DumpRomViewModel; public DownloadsViewModel DownloadsViewModel; private GettingStartedViewModel _GettingStartedViewModel = null; public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { if (MainSyncContext == SynchronizationContext.Current) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); else MainSyncContext.Post(s => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null); } } private ContextViewModel _ContextViewModel; public ContextViewModel ContextViewModel { get { return _ContextViewModel; } set { if (_ContextViewModel != value) { if (_ContextViewModel != null) _ContextViewModel.IsActive = false; _ContextViewModel = value; if (_ContextViewModel != null) { _ContextViewModel.Activate(); } OnPropertyChanged("ContextViewModel"); } } } private SynchronizationContext MainSyncContext; public MainViewModel() { MainSyncContext = SynchronizationContext.Current; LogFile.LogApplicationVersion(); // Set global callback for cases where Dependency Injection is not possible. App.NavigateToGettingStarted = () => { GettingStartedCommand.Execute(null); }; App.NavigateToUnlockBoot = () => { BootUnlockCommand.Execute(null); }; if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals") == null) Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey("WPInternals"); if ((Registration.IsPrerelease) && (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("NdaAccepted") == null)) { this.ContextViewModel = new DisclaimerAndNdaViewModel(Disclaimer_Accepted); } else if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("DisclaimerAccepted") == null) { this.ContextViewModel = new DisclaimerViewModel(Disclaimer_Accepted); } else if ((Registration.IsPrerelease) && !Registration.IsRegistered()) { ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed); } else StartOperation(); } void Disclaimer_Accepted() { ContextViewModel = null; if ((Registration.IsPrerelease) && !Registration.IsRegistered()) { ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed); } else StartOperation(); } void Registration_Completed() { ContextViewModel = null; StartOperation(); } void Registration_Failed() { ContextViewModel = new MessageViewModel("Registration failed", () => Environment.Exit(0)); ((MessageViewModel)ContextViewModel).SubMessage = "Check your filewall settings"; } public void StartOperation() { IsMenuEnabled = true; _GettingStartedViewModel = new GettingStartedViewModel( () => { ContextViewModel = new DisclaimerViewModel( () => ContextViewModel = _GettingStartedViewModel ); }, SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToBackup, SwitchToDumpFFU, SwitchToFlashRom, SwitchToDownload ); this.ContextViewModel = _GettingStartedViewModel; PhoneNotifier = new PhoneNotifierViewModel(); PhoneNotifier.NewDeviceArrived += PhoneNotifier_NewDeviceArrived; PhoneNotifier.DeviceRemoved += PhoneNotifier_DeviceRemoved; InfoViewModel = new LumiaInfoViewModel(PhoneNotifier, (TargetInterface) => { ModeViewModel.OnModeSwitchRequested(TargetInterface); ContextViewModel = ModeViewModel; }, () => { ContextViewModel = _GettingStartedViewModel; }); InfoViewModel.ActivateSubContext(null); ModeViewModel = new LumiaModeViewModel(PhoneNotifier, SwitchToInfoViewModel); ModeViewModel.ActivateSubContext(null); BootUnlockViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, true, SwitchToInfoViewModel); BootUnlockViewModel.ActivateSubContext(null); BootRestoreViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, false, SwitchToInfoViewModel); BootRestoreViewModel.ActivateSubContext(null); RootUnlockViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, true, SwitchToInfoViewModel); RootUnlockViewModel.ActivateSubContext(null); RootRestoreViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, false, SwitchToInfoViewModel); RootRestoreViewModel.ActivateSubContext(null); BackupViewModel = new BackupViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToInfoViewModel); BackupViewModel.ActivateSubContext(null); RestoreViewModel = new RestoreViewModel(PhoneNotifier, SwitchToDifferentInterface, SwitchToUnlockBoot, SwitchToFlashRom, SwitchToInfoViewModel); RestoreViewModel.ActivateSubContext(null); LumiaFlashRomViewModel = new LumiaFlashRomViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToDumpFFU, SwitchToBackup, SwitchToInfoViewModel); LumiaFlashRomViewModel.ActivateSubContext(null); DumpRomViewModel = new DumpRomViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom); DumpRomViewModel.ActivateSubContext(null); DownloadsViewModel = new DownloadsViewModel(PhoneNotifier); App.DownloadManager = DownloadsViewModel; PhoneNotifier.Start(); } internal void SwitchToInfoViewModel() { ContextViewModel = InfoViewModel; } internal void SwitchToUnlockBoot() { ContextViewModel = BootUnlockViewModel; } internal void SwitchToRestoreBoot() { ContextViewModel = BootRestoreViewModel; } internal void SwitchToUnlockRoot() { ContextViewModel = RootUnlockViewModel; } internal void SwitchToUndoRoot() { ContextViewModel = RootRestoreViewModel; } internal void SwitchToBackup() { ContextViewModel = BackupViewModel; } internal void SwitchToFlashRom() { ContextViewModel = LumiaFlashRomViewModel; } internal void SwitchToDumpFFU() { ContextViewModel = DumpRomViewModel; } internal void SwitchToDownload() { ContextViewModel = DownloadsViewModel; } internal void SwitchToDifferentInterface(PhoneInterfaces TargetInterface) { ModeViewModel.OnModeSwitchRequested(TargetInterface); ContextViewModel = ModeViewModel; } void PhoneNotifier_DeviceRemoved() { InfoViewModel.ActivateSubContext(null); } void PhoneNotifier_NewDeviceArrived(ArrivalEventArgs Args) { PhoneInterfaces? PreviousInterface = LastInterface; LastInterface = Args.NewInterface; if (App.InterruptBoot && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader)) { App.InterruptBoot = false; LogFile.Log("Found Lumia BootMgr and user forced to interrupt the boot process. Force to Flash-mode."); Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash)); } else { if (Args.NewInterface != PhoneInterfaces.Qualcomm_Download) App.InterruptBoot = false; if (ContextViewModel == null) ContextViewModel = InfoViewModel; else if (ContextViewModel.IsFlashModeOperation) { if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader)) { // The current screen is marked as "Flash operation". // When the bootloader is detected at this stage, it means a phone is booting and // it is possible that the phone is in a non-booting stage (not possible to boot past UEFI). // We will try to boot straight to Flash-mode, so that it will be possible to flash a new ROM. LogFile.Log("Found Lumia BootMgr while mode is not being switched. Screen is marked as Flash Operation. Force to Flash-mode."); Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash)); } } else { if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface != PhoneInterfaces.Lumia_Bootloader)) ContextViewModel = InfoViewModel; } } } private ICommand _InfoCommand = null; public ICommand InfoCommand { get { if (_InfoCommand == null) { _InfoCommand = new DelegateCommand(() => { ContextViewModel = InfoViewModel; }); } return _InfoCommand; } } private ICommand _ModeCommand = null; public ICommand ModeCommand { get { if (_ModeCommand == null) { _ModeCommand = new DelegateCommand(() => { ContextViewModel = ModeViewModel; }); } return _ModeCommand; } } private ICommand _BootUnlockCommand = null; public ICommand BootUnlockCommand { get { if (_BootUnlockCommand == null) { _BootUnlockCommand = new DelegateCommand(() => { ContextViewModel = BootUnlockViewModel; }); } return _BootUnlockCommand; } } private ICommand _BootRestoreCommand = null; public ICommand BootRestoreCommand { get { if (_BootRestoreCommand == null) { _BootRestoreCommand = new DelegateCommand(() => { ContextViewModel = BootRestoreViewModel; }); } return _BootRestoreCommand; } } private ICommand _RootUnlockCommand = null; public ICommand RootUnlockCommand { get { if (_RootUnlockCommand == null) { _RootUnlockCommand = new DelegateCommand(() => { ContextViewModel = RootUnlockViewModel; }); } return _RootUnlockCommand; } } private ICommand _RootUndoCommand = null; public ICommand RootUndoCommand { get { if (_RootUndoCommand == null) { _RootUndoCommand = new DelegateCommand(() => { ContextViewModel = RootRestoreViewModel; }); } return _RootUndoCommand; } } private ICommand _BackupCommand = null; public ICommand BackupCommand { get { if (_BackupCommand == null) { _BackupCommand = new DelegateCommand(() => { ContextViewModel = BackupViewModel; }); } return _BackupCommand; } } private ICommand _RestoreCommand = null; public ICommand RestoreCommand { get { if (_RestoreCommand == null) { _RestoreCommand = new DelegateCommand(() => { ContextViewModel = RestoreViewModel; }); } return _RestoreCommand; } } private ICommand _LumiaFlashRomCommand = null; public ICommand LumiaFlashRomCommand { get { if (_LumiaFlashRomCommand == null) { _LumiaFlashRomCommand = new DelegateCommand(() => { ContextViewModel = LumiaFlashRomViewModel; }); } return _LumiaFlashRomCommand; } } private ICommand _DumpRomCommand = null; public ICommand DumpRomCommand { get { if (_DumpRomCommand == null) { _DumpRomCommand = new DelegateCommand(() => { ContextViewModel = DumpRomViewModel; }); } return _DumpRomCommand; } } private ICommand _AboutCommand = null; public ICommand AboutCommand { get { if (_AboutCommand == null) { _AboutCommand = new DelegateCommand(() => { ContextViewModel = new AboutViewModel(); }); } return _AboutCommand; } } private ICommand _OpenWebSiteCommand = null; public ICommand OpenWebSiteCommand { get { if (_OpenWebSiteCommand == null) { _OpenWebSiteCommand = new DelegateCommand(() => { Process.Start("www.wpinternals.net"); }); } return _OpenWebSiteCommand; } } private ICommand _DonateCommand = null; public ICommand DonateCommand { get { if (_DonateCommand == null) { _DonateCommand = new DelegateCommand(() => { Process.Start("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VY8N7BCBT9CS4"); }); } return _DonateCommand; } } private ICommand _GettingStartedCommand = null; public ICommand GettingStartedCommand { get { if (_GettingStartedCommand == null) { _GettingStartedCommand = new DelegateCommand(() => { ContextViewModel = _GettingStartedViewModel; }); } return _GettingStartedCommand; } } private ICommand _DownloadCommand = null; public ICommand DownloadCommand { get { if (_DownloadCommand == null) { _DownloadCommand = new DelegateCommand(() => { ContextViewModel = DownloadsViewModel; }); } return _DownloadCommand; } } private bool _IsMenuEnabled = false; public bool IsMenuEnabled { get { return _IsMenuEnabled; } set { _IsMenuEnabled = value; OnPropertyChanged("IsMenuEnabled"); } } } }