Skip to content

Commit

Permalink
Merge branch 'epic/windows-updates' into chore/merge-master-into-wind…
Browse files Browse the repository at this point in the history
…ows-updates
  • Loading branch information
mcdurdin authored Dec 5, 2024
2 parents 1fd2a1b + e58e690 commit 974b16f
Show file tree
Hide file tree
Showing 41 changed files with 2,404 additions and 130 deletions.
52 changes: 52 additions & 0 deletions common/windows/delphi/general/Keyman.System.ExecutionHistory.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
Keyman is copyright (C) SIL Global. MIT License.
This module provides functionality to track the execution state of the Keyman
engine. It uses a global atom to record whether Keyman has started during the
current session and checks if it has previously run.
}
unit Keyman.System.ExecutionHistory;


interface

const
AtomName = 'KeymanSessionFlag';

function RecordKeymanStarted : Boolean;
function HasKeymanRun : Boolean;

implementation

uses
System.SysUtils,
Winapi.Windows,
KLog;

function RecordKeymanStarted : Boolean;
var
atom: WORD;
begin
atom := GlobalAddAtom(AtomName);
if atom = 0 then
begin
// TODO-WINDOWS-UPDATES: #10210 log to sentry
Result := False;
end
else
Result := True;
end;

function HasKeymanRun : Boolean;
begin
Result := GlobalFindAtom(AtomName) <> 0;
if not Result then
begin
if GetLastError <> ERROR_FILE_NOT_FOUND then
begin
// TODO-WINDOWS-UPDATES: log to Sentry
end;
end;
end;

end.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ TUpdateCheckResponsePackage = record

TUpdateCheckResponse = record
private
FOriginalData: string;
FInstallSize: Int64;
FInstallURL: string;
FNewVersion: string;
Expand All @@ -46,9 +47,13 @@ TUpdateCheckResponse = record
FFileName: string;
function ParseKeyboards(nodes: TJSONObject): Boolean;
function ParseLanguages(i: Integer; v: TJSONValue): Boolean;
function DoParse(const message, app, currentVersion: string): Boolean;
public
function Parse(const message: AnsiString; const app, currentVersion: string): Boolean;

procedure SaveToFile(const Filename: string);
function LoadFromFile(const Filename, app, currentVersion: string): Boolean;

property CurrentVersion: string read FCurrentVersion;
property NewVersion: string read FNewVersion;
property NewVersionWithTag: string read FNewVersionWithTag;
Expand All @@ -58,25 +63,32 @@ TUpdateCheckResponse = record
property ErrorMessage: string read FErrorMessage;
property Status: TUpdateCheckResponseStatus read FStatus;
property Packages: TUpdateCheckResponsePackages read FPackages;
property OriginalData: string read FOriginalData;
end;

implementation

uses
System.Classes,
System.Generics.Collections,
versioninfo;

{ TUpdateCheckResponse }

function TUpdateCheckResponse.Parse(const message: AnsiString; const app, currentVersion: string): Boolean;
begin
Result := DoParse(string(UTF8String(message)), app, currentVersion);
end;

function TUpdateCheckResponse.DoParse(const message, app, currentVersion: string): Boolean;
var
node, doc: TJSONObject;
begin
FOriginalData := message;
FCurrentVersion := currentVersion;
FStatus := ucrsNoUpdate;

// TODO: test with UTF8 characters in response
doc := TJSONObject.ParseJSONValue(UTF8String(message)) as TJSONObject;
doc := TJSONObject.ParseJSONValue(UTF8String(FOriginalData)) as TJSONObject;
if doc = nil then
begin
FErrorMessage := Format('Invalid response:'#13#10'%s', [string(message)]);
Expand Down Expand Up @@ -168,4 +180,29 @@ function TUpdateCheckResponse.ParseLanguages(i: Integer; v: TJSONValue): Boolean
Result := True;
end;

function TUpdateCheckResponse.LoadFromFile(const Filename, app, currentVersion: string): Boolean;
var
ss: TStringStream;
begin
ss := TStringStream.Create('', TEncoding.UTF8);
try
ss.LoadFromFile(Filename);
Result := DoParse(ss.DataString, app, currentVersion);
finally
ss.Free;
end;
end;

procedure TUpdateCheckResponse.SaveToFile(const Filename: string);
var
ss: TStringStream;
begin
ss := TStringStream.Create(FOriginalData, TEncoding.UTF8);
try
ss.SaveToFile(Filename);
finally
ss.Free;
end;
end;

end.
9 changes: 9 additions & 0 deletions common/windows/delphi/general/KeymanPaths.pas
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ TKeymanPaths = class
const S_CEF_SubProcess = 'kmbrowserhost.exe';
const S_CEF_SubProcess_Developer = 'kmdbrowserhost.exe';
const S_CustomisationFilename = 'desktop_pro.pxx';

const S_KeymanAppData_UpdateCache = 'Keyman\UpdateCache\';
public
const S_KMShell = 'kmshell.exe';
const S_TSysInfoExe = 'tsysinfo.exe';
Expand All @@ -27,8 +29,10 @@ TKeymanPaths = class
const S_FallbackKeyboardPath = 'Keyboards\';
const S__Package = '_Package\';
const S_MCompileExe = 'mcompile.exe';
const S_UpdateCache_Metadata = 'cache.json';
class function ErrorLogPath(const app: string = ''): string; static;
class function KeymanHelpPath(const HelpFile: string): string; static;
class function KeymanUpdateCachePath(const filename: string = ''): string; static;
class function KeymanDesktopInstallPath(const filename: string = ''): string; static;
class function KeymanEngineInstallPath(const filename: string = ''): string; static;
class function KeymanDesktopInstallDir: string; static;
Expand Down Expand Up @@ -423,6 +427,11 @@ class function TKeymanPaths.KeymanHelpPath(const HelpFile: string): string;
Result := '';
end;

class function TKeymanPaths.KeymanUpdateCachePath(const filename: string): string;
begin
Result := GetFolderPath(CSIDL_LOCAL_APPDATA) + S_KeymanAppData_UpdateCache + filename;
end;

class function TKeymanPaths.RunningFromSource(var keyman_root: string): Boolean;
begin
// On developer machines, if we are running within the source repo, then use
Expand Down
8 changes: 6 additions & 2 deletions common/windows/delphi/general/RegistryKeys.pas
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,10 @@ interface

SRegValue_CharMapSourceData = 'charmap source data'; // LM

SRegValue_AvailableLanguages = 'available languages'; //CU
SRegValue_CurrentLanguage = 'current language'; //CU
SRegValue_AvailableLanguages = 'available languages'; // CU
SRegValue_CurrentLanguage = 'current language'; // CU

SRegValue_Update_State = 'update state'; // CU

{ Privacy }

Expand Down Expand Up @@ -312,8 +314,10 @@ interface
SRegValue_ActiveProject_Filename = 'project filename';
SRegValue_ActiveProject_SourcePath = 'source path';

SRegValue_AutomaticUpdates = 'automatic updates'; //CU
SRegValue_CheckForUpdates = 'check for updates'; // CU
SRegValue_LastUpdateCheckTime = 'last update check time'; // CU
SRegValue_ApplyNow = 'apply now'; // CU Start the install now even though it will require an restart

SRegValue_UpdateCheck_UseProxy = 'update check use proxy'; // CU
SRegValue_UpdateCheck_ProxyHost = 'update check proxy host'; // CU
Expand Down
5 changes: 5 additions & 0 deletions oem/firstvoices/windows/src/xml/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,11 @@
<!-- Introduced: 7.0.230.0 -->
<string name="koShowWelcome" comment="Startup options - show/hide welcome screen">Show welcome screen</string>

<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 18.0.96.0 -->
<string name="koAutomaticUpdate" comment="Automatically download updates in the background, for installation later">Automatically download updates in the background, for installation later</string>

<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 7.0.230.0 -->
Expand Down
10 changes: 9 additions & 1 deletion windows/src/desktop/kmshell/kmshell.dpr
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,15 @@ uses
Keyman.Configuration.System.HttpServer.App.TextEditorFonts in 'startup\help\Keyman.Configuration.System.HttpServer.App.TextEditorFonts.pas',
Keyman.Configuration.System.HttpServer.App.Locale in 'web\Keyman.Configuration.System.HttpServer.App.Locale.pas',
Keyman.System.AndroidStringToKeymanLocaleString in '..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas',
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas';
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas',
UpdateXMLRenderer in 'render\UpdateXMLRenderer.pas',
Keyman.System.UpdateCheckStorage in 'main\Keyman.System.UpdateCheckStorage.pas',
Keyman.System.RemoteUpdateCheck in 'main\Keyman.System.RemoteUpdateCheck.pas',
Keyman.System.UpdateStateMachine in 'main\Keyman.System.UpdateStateMachine.pas',
Keyman.System.DownloadUpdate in 'main\Keyman.System.DownloadUpdate.pas',
Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas',
Keyman.Configuration.UI.UfrmStartInstallNow in 'main\Keyman.Configuration.UI.UfrmStartInstallNow.pas' {frmInstallNow},
Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall};

{$R VERSION.RES}
{$R manifest.res}
Expand Down
25 changes: 20 additions & 5 deletions windows/src/desktop/kmshell/kmshell.dproj
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,20 @@
<DCCReference Include="web\Keyman.Configuration.System.HttpServer.App.Locale.pas"/>
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas"/>
<DCCReference Include="main\Keyman.Configuration.System.Main.pas"/>
<DCCReference Include="render\UpdateXMLRenderer.pas"/>
<DCCReference Include="main\Keyman.System.UpdateCheckStorage.pas"/>
<DCCReference Include="main\Keyman.System.RemoteUpdateCheck.pas"/>
<DCCReference Include="main\Keyman.System.UpdateStateMachine.pas"/>
<DCCReference Include="main\Keyman.System.DownloadUpdate.pas"/>
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas"/>
<DCCReference Include="main\Keyman.Configuration.UI.UfrmStartInstallNow.pas">
<Form>frmInstallNow</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="main\Keyman.Configuration.UI.UfrmStartInstall.pas">
<Form>frmStartInstall</Form>
<FormType>dfm</FormType>
</DCCReference>
<None Include="Profiling\AQtimeModule1.aqt"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>
Expand Down Expand Up @@ -415,21 +429,21 @@
<Platform value="Win64">False</Platform>
</Platforms>
<Deployment Version="3">
<DeployFile LocalName="kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
<DeployFile LocalName="bin\Win32\Debug\kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
<Platform Name="Win32">
<RemoteName>kmshell.rsm</RemoteName>
<RemoteName>kmshell.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="kmshell.exe" Configuration="Debug" Class="ProjectOutput">
<DeployFile LocalName="bin\Win32\Debug\kmshell.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>kmshell.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
<DeployFile LocalName="kmshell.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<RemoteName>kmshell.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
Expand Down Expand Up @@ -1228,6 +1242,7 @@
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<ModelSupport>False</ModelSupport>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
Expand Down
Binary file added windows/src/desktop/kmshell/kmshell.res
Binary file not shown.
11 changes: 11 additions & 0 deletions windows/src/desktop/kmshell/main/BackgroundUpdateStateDiagram.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
``` mermaid
stateDiagram
[*] --> Idle
Idle --> UpdateAvailable
UpdateAvailable --> Downloading
Downloading --> Installing
Downloading --> WaitingRestart
WaitingRestart --> Installing
Installing --> PostInstall
PostInstall --> Idle
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
object frmStartInstall: TfrmStartInstall
Left = 0
Top = 0
Caption = 'Keyman Update'
ClientHeight = 225
ClientWidth = 425
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object lblInstallUpdate: TLabel
Left = 128
Top = 96
Width = 175
Height = 19
Caption = 'Keyman update available'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -16
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object cmdInstall: TButton
Left = 228
Top = 184
Width = 75
Height = 25
Caption = 'Install'
ModalResult = 1
TabOrder = 0
end
object cmdLater: TButton
Left = 336
Top = 184
Width = 75
Height = 25
Caption = 'Close'
ModalResult = 8
TabOrder = 1
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
Keyman is copyright (C) SIL Global. MIT License.
// TODO-WINDOWS-UPDATES: Localise all the labels and captions.
}
unit Keyman.Configuration.UI.UfrmStartInstall;
interface

uses
System.Classes,
System.SysUtils,
System.Variants,
Vcl.Controls,
Vcl.Dialogs,
Vcl.ExtCtrls,
Vcl.Forms,
Vcl.Graphics,
Vcl.StdCtrls,
Winapi.Messages,
Winapi.Windows,
UfrmKeymanBase,
UserMessages;

type
TfrmStartInstall = class(TfrmKeymanBase)
cmdInstall: TButton;
cmdLater: TButton;
lblInstallUpdate: TLabel;
private
public
end;


implementation

{$R *.dfm}


end.
Loading

0 comments on commit 974b16f

Please sign in to comment.