Skip to content

fix(settings): banner quyền Trợ năng tự cập nhật ngay khi user cấp quyền - #41

Merged
ptrinh merged 1 commit into
ptrinh:mainfrom
J2TEAM:fix/ax-banner-live-refresh
Aug 12, 2026
Merged

fix(settings): banner quyền Trợ năng tự cập nhật ngay khi user cấp quyền#41
ptrinh merged 1 commit into
ptrinh:mainfrom
J2TEAM:fix/ax-banner-live-refresh

Conversation

@J2TEAM

@J2TEAM J2TEAM commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Banner chỉ re-evaluate ở onAppear + didBecomeKey. Nhưng System Settings GIỮ focus sau khi user tick checkbox, nên cửa sổ Cài đặt không bao giờ thành key lại → chữ đỏ "chưa có quyền" đứng nguyên cạnh một quyền đã sống. Field report: "cấp quyền rồi nhưng vẫn báo" — user phải click lại vào cửa sổ, hoặc logout.

Hai nguyên nhân độc lập, sửa cả hai:

  1. Thiếu trigger. Nay subscribe com.apple.accessibility.api qua DistributedNotificationCenter — CÙNG signal main.swift đã observe để dựng lại tap. App vốn đã event-driven cho tap; chỉ banner bị bỏ sót.

  2. Đọc ra giá trị cũ. refreshAccessibilityStatus() gọi Accessibility.isTrusted, mà reader đó khi hết TTL trả .serveCachedAndRefresh: hand back giá trị CŨ rồi mới refresh ở background. Đúng cho keystroke path (cache tồn tại chính vì thế, và các path không được sai thì đọc TCC trực tiếp), sai cho UI — lần refresh đầu sau khi cấp quyền vẫn đọc false, và không có gì đọc lại nữa. Nên kể cả khi cửa sổ thành key lại, banner vẫn có thể đỏ. Thêm Accessibility.readTrustNow(): đồng bộ, bỏ qua cache, CHỈ dành cho UI path. Vẫn honor testTrustOverride trong #if DEBUG — không có nó thì SettingsModelTests/GonhanhHardeningTests sẽ đọc trạng thái TCC thật của máy build và fail tuỳ máy.

Đọc 2 lần cách 1.5s: ngay sau toggle tccd còn trả giá trị CŨ (cùng race và cùng con số delay mà TerminalTapController.trustMayHaveChanged đã phòng). Một lần đọc duy nhất có thể latch banner sai theo chiều ngược lại — báo "quyền OK" ngay sau khi user THU HỒI quyền. Không timer, không polling.

Xoá luôn nhu cầu "You may need to restart your Mac" trong chính text cảnh báo.

Banner chỉ re-evaluate ở onAppear + didBecomeKey. Nhưng System Settings GIỮ
focus sau khi user tick checkbox, nên cửa sổ Cài đặt không bao giờ thành key
lại → chữ đỏ "chưa có quyền" đứng nguyên cạnh một quyền đã sống. Field report:
"cấp quyền rồi nhưng vẫn báo" — user phải click lại vào cửa sổ, hoặc logout.

Hai nguyên nhân độc lập, sửa cả hai:

1. Thiếu trigger. Nay subscribe com.apple.accessibility.api qua
   DistributedNotificationCenter — CÙNG signal main.swift đã observe để dựng
   lại tap. App vốn đã event-driven cho tap; chỉ banner bị bỏ sót.

2. Đọc ra giá trị cũ. refreshAccessibilityStatus() gọi Accessibility.isTrusted,
   mà reader đó khi hết TTL trả .serveCachedAndRefresh: hand back giá trị CŨ
   rồi mới refresh ở background. Đúng cho keystroke path (cache tồn tại chính
   vì thế, và các path không được sai thì đọc TCC trực tiếp), sai cho UI — lần
   refresh đầu sau khi cấp quyền vẫn đọc false, và không có gì đọc lại nữa. Nên
   kể cả khi cửa sổ thành key lại, banner vẫn có thể đỏ. Thêm
   Accessibility.readTrustNow(): đồng bộ, bỏ qua cache, CHỈ dành cho UI path.
   Vẫn honor testTrustOverride trong #if DEBUG — không có nó thì
   SettingsModelTests/GonhanhHardeningTests sẽ đọc trạng thái TCC thật của máy
   build và fail tuỳ máy.

Đọc 2 lần cách 1.5s: ngay sau toggle tccd còn trả giá trị CŨ (cùng race và cùng
con số delay mà TerminalTapController.trustMayHaveChanged đã phòng). Một lần
đọc duy nhất có thể latch banner sai theo chiều ngược lại — báo "quyền OK" ngay
sau khi user THU HỒI quyền. Không timer, không polling.

Xoá luôn nhu cầu "You may need to restart your Mac" trong chính text cảnh báo.

164 AppTests pass, 0 fail.
@ptrinh
ptrinh merged commit 9bc52c0 into ptrinh:main Aug 12, 2026
ptrinh added a commit that referenced this pull request Aug 12, 2026
… + test readTrustNow

Hai điểm review của PR #41 (banner Trợ năng tự cập nhật):
1. DistributedNotificationCenter.publisher không đảm bảo deliver trên main
   (main.swift phải chỉ định queue: .main tường minh cùng lý do), mà handler
   mutate @published — thêm .receive(on: DispatchQueue.main).
2. readTrustNow() có test: honor testTrustOverride cả hai chiều, và không
   override thì khớp TCC thật + đồng bộ cache dùng chung.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ptrinh added a commit that referenced this pull request Aug 12, 2026
… cảm ơn @J2TEAM)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ptrinh

ptrinh commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Merged + ship trong v1.5.7 🙏 Có thêm follow-up nhỏ (2ccc59a): .receive(on: DispatchQueue.main) cho DNC publisher (delivery thread không được đảm bảo mà handler mutate @published) + test cho readTrustNow(). Cảm ơn bạn — chẩn đoán hai tầng rất chuẩn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants