Skip to content

feat(windows): honour Windows "metered connection" flag for downloading updates#16099

Draft
rc-swag wants to merge 9 commits into
masterfrom
feat/windows/13566/check-metered-connection
Draft

feat(windows): honour Windows "metered connection" flag for downloading updates#16099
rc-swag wants to merge 9 commits into
masterfrom
feat/windows/13566/check-metered-connection

Conversation

@rc-swag

@rc-swag rc-swag commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

This adds a helper unit which uses the windows API to obtain a ConnectionProfile. This profile provides information about the connection status and connectivity statistics. This includes the connection costs, roaming, restricted etc. It also can check to see if background networking activity has been restricted.

Using the recommened example this commit combines these to determine if a network is metered. It also provides access to the background network being restricted.

There is a call that IsBackgroundUpdateAllowed that will return true if a background update is allowed.

This is then use in the Update State Machine and also by update pop up.
UpdateStateMachine
Before downloading IsBackgroundUpdateAllowed is called

Update Pop Up
This uses the IsMetered call and adds a warning if to the user who is wanting to Install Now.
This message would be better as a banner in the Update Configuration tab, rather than a delphi tab. This is the most efficent place to add the message for now.

Fixes: #13566

Build-bot: release:windows

User Testing

Mark connection as metered

For this we need to use windows setting to set the test machines network to metered. Right click the network connection icon in the Windows System tray and select network & internet settings Selected the connected work and the change the toggle for Metered connection to On

Windows 11
Keyman_network_Metered

Windwos 10
image

TEST_RESTARTREQ_METERED

Use a keyboard update to test.

  1. Install Keyman version attached to his PR
  2. Download and install this older version of euro_latin
  3. Make sure you have change the connected network to metered as explanined above.
  4. Run Keyman
  5. Go into the Keyman Configuration and the Update Tab
  6. Press the check for updates button.
  7. It should find an update for Euro Latin.
  8. Press install updates ovbserve the warning is shown.
metered_warning

TEST_RESTARTREQ_NOT_METERED

This is to make sure a metered warning message is not present on non-metered connection.

  1. Install Keyman version attached to his PR
  2. Download and install this older version of euro_latin
  3. Run Keyman.
  4. Make sure you have change the connected network to metered OFF
  5. Go into the Keyman Configuration and the Update Tab
  6. Press the check for updates button.
  7. It should find an update for Euro Latin.
  8. Press install updates observe the metered warning is not shown.
not_metered_warning

TEST_NO_RESTARTREQ_METERED

This is to make sure a metered warning message is present but no other messages.

  1. Install Keyman version attached to his PR
  2. Download and install this older version of euro_latin
  3. Do not run Keyman, if it has run sign in and out again.
  4. Make sure you have change the connected network to metered OFF
  5. Go into the Keyman Configuration and the Update Tab
  6. Press the check for updates button.
  7. It should find an update for Euro Latin.
  8. Press install updates observe the metered warning is not shown.
metered_only

TEST_NO_READY_TO_INSTALL_NOT_METERED

This is to make sure a metered connection message is not shown when
we already have the download and are just in the WaitingRestart State.

  1. Install Keyman version attached to his PR
  2. Download and install this older version of euro_latin
  3. Make sure you have change the connected network to metered OFF
  4. Go into the Keyman Configuration and the Update Tab
  5. Press the check for updates button.
  6. It should find an update for Euro Latin.
  7. Close Configuration and the Keyman Splash screen if open.
  8. Change the connected network to metered ON
    1. Do not Run Keyman if Keyman has run you will need to sign out of the current windows session.
  9. Start Keyman
  10. A pop saying an update is ready observe the metered warning is not shown.
ready_no_metered

TEST_NO_BACKGROUND_UPDATE

  1. Install Keyman version attached to his PR
  2. Download and install this older version of sil_euro_latin.zip
  3. Close Keyman an Keyman Configuration
  4. Make sure you have change the connected network to metered as explanined above.
  5. Open Regedit WinR type regedit
  6. Go to the current user key update state found at (Computer\HKEY_CURRENT_USER\SOFTWARE\Keyman\Keyman Engine).
  7. If required set the update state back to usIdle
  8. Delete last update check time. This needs to be done otherwise it will stay in usIdle for 7 days.
  9. Open Windows Explorer at "C:\Users"yourusername"\AppData\Local\Keyman\UpdateCache" folder.
  10. Delete any *.kmp and *.exe files.
  11. Open a command prompt and go to where kmshell is installed e.g c:\Program Files (x86)\Keyman\Keyman Desktop
  12. run kmshell.exe -c This will run the configuration
  13. Go to the Window Explorer window that is looking at the UpdateCache folder press F5 to refresh the window. No *.kmp or *.exe should appear as we are on metetered connection.

TEST_BACKGROUND_UPDATE

This is a regresion test.

  1. Install Keyman version attached to his PR
  2. Download and install this older version of sil_euro_latin.zip
  3. Close Keyman an Keyman Configuration
  4. Make sure you have change the connected network metered to OFF as explanined above.
  5. Open Regedit WinR type regedit
  6. Go to the current user key update state found at (Computer\HKEY_CURRENT_USER\SOFTWARE\Keyman\Keyman Engine).
  7. If required set the update state back to usIdle
  8. Delete last update check time. This needs to be done otherwise it will stay in usIdle for 7 days.
  9. Open Windows Explorer at "C:\Users"yourusername"\AppData\Local\Keyman\UpdateCache" folder.
  10. Delete any *.kmp and *.exe files.
  11. Open a command prompt and go to where kmshell is installed e.g c:\Program Files (x86)\Keyman\Keyman Desktop
  12. run kmshell.exe -c This will run the configuration
  13. Go to the Window Explorer window that is looking at the UpdateCache folder press F5 to refresh the window. The sil_euro_latin.kmp should appear as we are not on a metered connection.

This adds a helper unit which uses the windows API to obtain a
ConnectionProfile. This profile provides information about the
connection status and connectivity statistics. This includes
the connection costs, roaming, restricted etc. It also can
check to see if background networking activity has been restricted.

Using the recommened example this commit combines these to determine
if a network is metered. It also provides access to the background
network being restricted.

Fixes: #13566
@github-project-automation github-project-automation Bot moved this to Todo in Keyman Jun 16, 2026
@keymanapp-test-bot keymanapp-test-bot Bot added the user-test-missing User tests have not yet been defined for the PR label Jun 16, 2026
@rc-swag rc-swag self-assigned this Jun 16, 2026
@keymanapp-test-bot

keymanapp-test-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

User Test Results

Test specification and instructions

  • TEST_RESTARTREQ_METERED (OPEN)
  • TEST_RESTARTREQ_NOT_METERED (OPEN)
  • TEST_NO_RESTARTREQ_METERED (OPEN)
  • TEST_NO_READY_TO_INSTALL_NOT_METERED (OPEN)
  • TEST_NO_BACKGROUND_UPDATE (PASSED) (notes)
  • TEST_BACKGROUND_UPDATE (PASSED) (notes)
Results Template
# Test Results

* **TEST_RESTARTREQ_METERED (OPEN):** notes
* **TEST_RESTARTREQ_NOT_METERED (OPEN):** notes
* **TEST_NO_RESTARTREQ_METERED (OPEN):** notes
* **TEST_NO_READY_TO_INSTALL_NOT_METERED (OPEN):** notes

Test Artifacts

@keymanapp-test-bot keymanapp-test-bot Bot added this to the A19S31 milestone Jun 16, 2026
@keymanapp-test-bot keymanapp-test-bot Bot added has-user-test user-test-required User tests have not been completed and removed user-test-missing User tests have not yet been defined for the PR labels Jun 16, 2026
rc-swag added 2 commits June 16, 2026 15:58
If the download has already occured before calling the pop up
then there is no reason to warn about the metered connection.
@rc-swag rc-swag marked this pull request as ready for review June 17, 2026 03:57
@rc-swag rc-swag requested a review from mcdurdin June 17, 2026 03:58
@rc-swag rc-swag changed the title feat(windows): add network connectivity tool feat(windows): honour Windows "metered connection" flag for downloading updates Jun 19, 2026
@keyman-server keyman-server modified the milestones: A19S31, A19S32 Jun 22, 2026
@Meng-Heng

Meng-Heng commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Test Prerequisite

  1. Windows 10 Bootcamp
  2. Keyman version 19.0.248-alpha-test-16099
  3. sil_euro_latin version 3.0.0

Test Results

  • TEST_WARNING_MESSAGE (PASSED):
  1. The metered connection is set to on
  2. Launch Keyman
  3. Go into the Keyman Configuration -> the Update Tab
  4. Press the check for updates button.
  5. Update for Eurolatin (SIL) appears
  6. Press install updates
  7. Confirm -- The pop-up window does have the metered warning.
  • TEST_NO_WARNING_MESSAGE_PART1 (PASSED):
  1. Launch Keyman
  2. The metered connection is off
  3. Go into the Keyman Configuration -> the Update Tab
  4. Press the check for updates button
  5. Update for Eurolatin (SIL) appears
  6. Press install updates
  7. Confirmed -- The pop-up window does not have the metered warning.
  • TEST_NO_WARNING_MESSAGE_PART2 (PASSED):
  1. Launch Keyman
  2. The metered connection stays off
  3. Go into the Keyman Configuration -> the Update Tab
  4. Press the check for updates button.
  5. Update for Eurolatin (SIL) appears
  6. Exit Keyman Configuration and the Keyman Splash screen from the tray
  7. Start Keyman
  8. Confirmed -- The pop-up window saying an update and does not have the metered warning
    image

Note

I did not get the exact message as in the test requirement (see the image right above this note)

  • TEST_NO_BACKGROUND_UPDATE (PASSED):
  1. Close Keyman and Keyman Configuration
  2. The metered connection is set to on
  3. Follow the instruction to delete last update check time in Computer\HKEY_CURRENT_USER\SOFTWARE\Keyman\Keyman Engine
  4. Open Windows Explorer at "C:\Users\havm\AppData\Local\Keyman\UpdateCache" folder
  5. Delete *.kmp file
  6. Open a command prompt and go to c:\Program Files (x86)\Keyman\Keyman Desktop
  7. Run kmshell.exe -c
  8. The Keyman Configuration, Update tab opens up
  9. Confirm – In Window Explorer window that is looking at the UpdateCache folder press, there is no *.kmp or *.exe appear as we are on metered connection.
  • TEST_BACKGROUND_UPDATE (PASSED):
  1. Uninstall and reinstall Keyman
  2. Launch Keyman and install the keyboard
  3. Close Keyman and Keyman Configuration
  4. The metered connection is set to off
  5. Follow the instruction to delete last update check time in Computer\HKEY_CURRENT_USER\SOFTWARE\Keyman\Keyman Engine
  6. Open Windows Explorer at "C:\Users\havm\AppData\Local\Keyman\UpdateCache" folder
  7. The folder is empty
  8. Open a command prompt and go to c:\Program Files (x86)\Keyman\Keyman Desktop
  9. Run kmshell.exe -c This will run the configuration
  10. Confirm – In the Window Explorer window that is looking at the UpdateCache folder, there is now a sil_euro_latin.kmp file as we are not on a metered connection.

Comment thread windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas Outdated
Comment thread windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas Outdated
Comment thread windows/src/desktop/kmshell/main/UfrmMain.pas Outdated
Comment thread windows/src/desktop/kmshell/util/UtilNetworkConnection.pas
Comment thread windows/src/desktop/kmshell/main/UfrmMain.pas Outdated
Comment thread windows/src/desktop/kmshell/main/Keyman.Configuration.UI.UfrmStartInstall.pas Outdated
Co-authored-by: Eberhard Beilharz <ermshiperete@users.noreply.github.com>
@keymanapp-test-bot keymanapp-test-bot Bot removed the user-test-required User tests have not been completed label Jun 23, 2026
@github-actions github-actions Bot added the user-test-required User tests have not been completed label Jun 23, 2026
@keymanapp-test-bot keymanapp-test-bot Bot removed the user-test-required User tests have not been completed label Jun 23, 2026
Comment thread windows/src/desktop/kmshell/main/UfrmMain.pas Outdated
Comment thread windows/src/desktop/kmshell/util/UtilNetworkConnection.pas
Comment on lines +829 to +831
if HasKeymanRun OR IsMetered then
begin
frmStartInstallNow := TfrmStartInstall.Create(nil, true);
frmStartInstallNow := TfrmStartInstall.Create(nil, HasKeymanRun, IsMetered);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From devin.ai:

Contradictory dialog messages when IsMetered=True and HasKeymanRun=False in Update_ApplyNow

In UfrmMain.pas:831, when HasKeymanRun is False but IsMetered is True, the form is created with RestartRequired=False and ReadyToInstall=False (default). This causes FormCreate at Keyman.Configuration.UI.UfrmStartInstall.pas:72-73 to show S_Ready_To_Install ("An update to Keyman has been downloaded and is ready to install") while simultaneously displaying the metered warning S_Metered_Warning ("You're on a metered connection. Downloading now may incur data charges") at line 77. These messages directly contradict each other: one says the update has already been downloaded, while the other warns about downloading costs. Before this PR, this code path didn't exist — the old code only showed the dialog when HasKeymanRun was true, always passing RestartRequired=true, so S_Ready_To_Install was never displayed here.

rc-swag and others added 3 commits June 25, 2026 10:49
Co-authored-by: Eberhard Beilharz <ermshiperete@users.noreply.github.com>
Keyman currenlty only supports Windows 10 and 11
so the exception was low risk. If it is not available we
return false as metered connections werent possilble before
this the functionality will be the consistent with those
windows versions. i.e. always updating in the background
@rc-swag rc-swag requested a review from ermshiperete June 25, 2026 04:05
@keymanapp-test-bot keymanapp-test-bot Bot added the user-test-required User tests have not been completed label Jun 25, 2026
@rc-swag

rc-swag commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@Meng-Heng We need to test some scenarios again after my changes thanks.

@mcdurdin mcdurdin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks really solid.

One thing: I am not that comfortable with the UI of the dialog -- the red background is not consistent with styling of the rest of the app and I think we should use a standard Warning icon instead. Happy for that to be a follow-up PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the modern file naming scheme:

Keyman.Configuration.Util.NetworkConnection.pas?

Comment on lines +19 to +38
function IsMetered: Boolean;

(**
* Checks if background data usage is explicitly restricted by the current network profile.
*
* @returns True if background data usage is restricted, False otherwise.
*)
function IsBackgroundDataRestricted: Boolean;

(**
* Determines whether background updates are blocked.
*
* @returns True if background updates are blocked, False if allowed.
*
* Note: Currently this checks for metered connection OR background
data usage restricted. If a configuration item is added that
provides the option to download on metered connections then
this should be updated to include that logic
*)
function IsBackgroundUpdateBlocked: Boolean;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These would be better in a class, because otherwise they land in the global namespace in Delphi, which is very cluttered already.

type
  TUtilNetworkConnection = class // or TNetworkConnection?
    class function IsMetered: Boolean; static;
    class function IsBackgroundDataRestricted: Boolean; static;
    class function IsBackgroundUpdateBlocked: Boolean; static;
  end;

Comment on lines +50 to +51
Profile: IConnectionProfile;
CostLevel: IConnectionCost;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to initialize COM before these functions are called? If so, we should call that out in the docs

try
// Get the profile currently providing internet access
Profile := TNetworkInformation.GetInternetConnectionProfile;
if Profile <> nil then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if Profile <> nil then
if Assigned(Profile) then

Normal Delphi pattern

// If the WinRT network APIs are unavailable or throw (e.g. unusual
// Windows SKUs, containers, Network List Manager service stopped),
// treat the connection as non-metered so updates are not blocked.
Result := False;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we report errors on Sentry please? (Silent swallowing of the error is okay)

except
on E: Exception do
// See IsMetered: default to not-restricted if the WinRT APIs throw.
Result := False;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto Sentry

FResult, InstallNow: Boolean;
frmStartInstallNow: TfrmStartInstall;
IsMetered: Boolean;
EInstallScenario: TInstallCase;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EInstallScenario: TInstallCase;
InstallCase: TInstallCase;

The prefix E is usually reserved for exceptions. And why not call it InstallCase to match the type name?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long story I initally called it InstallScenario, but then I found following that unwritten enum rule of the small letter preffix it became
isRestartRequiredMetered etc. Which when reading through the code again got confused with the actual word "is" so I changed the name as "ic" avoided the confusion. It is a shame because Scenario sounds better.

Comment on lines +680 to +681
// We are ready to install Metered warning not needed even if on Metered connection
frmStartInstall := TfrmStartInstall.Create(nil, TInstallCase.icReadyToInstallNotMetered);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// We are ready to install Metered warning not needed even if on Metered connection
frmStartInstall := TfrmStartInstall.Create(nil, TInstallCase.icReadyToInstallNotMetered);
// We are ready to install Metered warning not needed even if on Metered connection
frmStartInstall := TfrmStartInstall.Create(nil, TInstallCase.icReadyToInstallNotMetered);

icRestartRequiredMetered,
icRestartRequiredNotMetered,
icReadyToInstallNotMetered, // Metered warning never needed if ReadyToInstall
icNoInstallMessageMetered

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this install case name confusing; is the following name accurate?

Suggested change
icNoInstallMessageMetered
icReadyToDownloadWarnMetered

I guess my confusion extends to the dialog box as well -- would it be possible for the dialog box to say something to clarify that a download is required, something like this?

The update has not yet been downloaded.
and
You're on a metered connection. Downloading now may incur data charges.

@Meng-Heng

Copy link
Copy Markdown
Contributor

@Meng-Heng We need to test some scenarios again after my changes thanks.

Noted with thanks, @rc-swag. I'll test this tomorrow.

@rc-swag rc-swag marked this pull request as draft June 25, 2026 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

feat(windows): honour Windows "metered connection" flag for downloading updates

5 participants