Repository navigation
feat: todo and sms sample apps, alarm and calendar iterations, zh/en, release installer - #2
Merged
Merged
Conversation
added 30 commits
October 9, 2026 00:58
…owlist, no-debug-code, plugin package, i18n and checksum steps for the sample app release APKs (+ unit tests, dry run verified)
…s it (上午 7:30 / 7:30 AM); text-producing functions take a Texts provider (R4, R8) The marker position comes from getBestDateTimePattern(locale, "hmm") instead of being hard-coded after the digits. Format.kt functions now take a Texts / ClockStyle (Context overloads kept as thin wrappers) so JVM tests assert the real values/ and values-en/ resources in both languages. Adds a resource parity test (keys, placeholders, plurals, no CJK in English).
…tem_next tool (A2) - intent/: AlarmIntentParser (SET/DISMISS/SNOOZE extras -> request; Calendar.SUNDAY..SATURDAY -> DayOfWeek; strict range/type checks, no crash), AlarmIntentHandler (create with de-duplication / dismiss / snooze on the existing repository), IntentFeedback (user-visible Toast text + whether to open a screen, via Texts, zh + en strings). - AlarmRepository.createOrReuse (same time + label + days is reused, a disabled twin is turned back on), snooze(id, minutes) for EXTRA_ALARM_SNOOZE_DURATION; RingControl.snooze takes an optional length. - alarm_system_next: AlarmManager.getNextAlarmClock() behind a SystemAlarmInfo interface (fake in JVM tests); owned_by_this_app from showIntent.getCreatorPackage(). Existing tools unchanged. - debug SelfTestReceiver covers the new tool. 146 JVM tests.
…debug 接收器、四页界面、126 个 JVM 测试
…pose UI (zh/en), debug self-test, JVM tests
…e, app language entry (A1, A3, R5) - AlarmIntentActivity (NoDisplay, exported, com.android.alarm.permission.SET_ALARM) handles SET_ALARM / DISMISS_ALARM / SNOOZE_ALARM; MainActivity answers SHOW_ALARMS and, for a SET_ALARM without a time, opens the new-alarm page (per AlarmClock docs). EXTRA_SKIP_UI creates without a screen and says so with a Toast. - Ring-on-time page (list menu): exact alarms, notifications, full-screen alerts, battery optimization, plus text guidance for Xiaomi/Huawei/Honor/OPPO/vivo/OnePlus (autostart, background activity, lock in recents). Battery uses the optimization LIST page, not the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission (Play policy; setAlarmClock already works in Doze). The permission banners share SystemSettings with the page. - locales_config.xml (zh, en) + android:localeConfig + a Language menu entry opening the system per-app language settings. - debug: dump shows who owns the system's next alarm; 'manufacturer' command fakes Build.MANUFACTURER for the vendor guidance.
… local SQLite calendar, windowed repository, account semantics
Design (docs/next-apps-plan.md section 2, C1-C7):
- CalendarBackend interface with three implementations: LocalBackend (the app's SQLite, kept as "this device" calendars, still loads the
whole small table into memory), SystemBackend (CalendarContract Provider: Instances expand recurring events, Events/Reminders for
writes, ContentObserver for cloud-sync changes), and a fake in the tests. CalendarRepository routes by the id prefix
(local:<uuid> / sys:<n>; ids without a prefix, e.g. from old notifications, are local).
- Existing local data is kept: the SQLite rows keep their bare UUID ids, the prefix is added/stripped at the backend boundary; DB v2 only adds
calendars.name_key.
- Repository state is a viewport: the UI reports the range it needs (month +-1, week -2..+3, agenda horizon) with setWindow, the snapshot is
loaded in the background and refreshed by the provider observer. Tool-side calls are blocking and always read live.
- Tool semantics (names and required parameters unchanged, fields only added): calendar_list gains account/account_type/source/writable/storage,
is_default now marks the default WRITE calendar; calendar_create only creates local calendars; calendar_delete/rename refuse account
calendars; event_create writes to the configurable default write calendar (user choice, else the first writable+visible non-local calendar,
else the local one; never the "primary" calendar); no permission -> fixed English error, never an exception, local calendars keep working.
- Recurrence: none/daily/weekly/monthly/yearly + recurrence_until <-> RRULE (UTC UNTIL for timed, date UNTIL for all-day, DURATION not DTEND,
P{n}D for all-day); anything else (COUNT, INTERVAL>1, multi BYDAY, 2TU, RDATE/EXDATE) is reported as recurrence "custom" with the rrule text and
the series refuses updates.
- Events created by the app are tagged with CUSTOM_APP_PACKAGE; debug reset only clears tagged events + local data.
- R3: the default calendar name is a marker (name_key) translated on display; R4: week range via ICU DateIntervalFormat; R5: locales_config.
JVM: 174 tests (99 before): mapping functions, routing with a fake system backend, migration of a legacy database, tool semantics.
…数 sample-apps.md 第 4 节的前三个 App 的两处计数改为 take(3)
…er the status bar, hero counts top-level todos, safe-zone launcher icon, shorter English quick-add hint
…t the manufacturer debug command note
…elong to the calendar), README: system intents, ring-on-time page, language, alarm_system_next, known behaviour (V4 results)
…7 (ring-on-time page, vendor guidance, 12-hour clock, intent-created list, skip_ui toast, 1.3x font)
…e UI, debug fixtures/probe/self-test modes, SKILL.md for account calendars - Home banner for READ/WRITE_CALENDAR (grant, then 'open settings' once the system will not ask again; refreshes on resume), Settings screen (app language via ACTION_APP_LOCALE_SETTINGS, permission state, default write calendar), calendar list grouped by account with source / read-only / default tags, editor shows the account and locks the calendar of existing account events, delete confirmation names the account (no undo for account events), custom-repeat events are view/delete only. - ContentObserver is registered only after the permission is granted (registering without it throws SecurityException); Provider change notifications arrive several seconds late on API 36, so the UI also refreshes on resume. - Debug only (emulator guards): provider_setup/teardown fake account calendars, provider_probe/provider_watch (C1 experiments), seed in zh/en, McpSelfTestReceiver modes system (46 checks) and denied (18 checks); reset only deletes events tagged with CUSTOM_APP_PACKAGE plus local data. - plugin 1.1.0; SKILL.md rewritten for account/local calendars, default write calendar, custom repeat, permission error.
…s), screenshots zh/en
…rements, unverified list, domestic account setup), zh/en screenshots, debug dump refreshes the permission state, settings value layout - README: two kinds of calendars, design summary, permission flow, tool semantics, RRULE mapping, reminders, C1 results measured on the API 36 emulator (CUSTOM_APP_PACKAGE is a convention not a boundary, observer needs the permission and is delayed 7-10 s, DTEND trap for recurring events), explicit 'not verified' list for devices with accounts (Google sync, Feishu CalDAV write-back, ...), CalDAV setup for Xiaomi / Honor / DAVx5 with what was and was not confirmed against the vendor pages. - Screenshots: 13 zh + 17 en (month, agenda, calendars with account/source tags, editor, detail, delete dialog naming the account, permission banner, settings, week, dark, 1.3x font, small screen); all data synthetic, accounts are fake example.com ones on the emulator. - Settings rows show the value under the title (no truncation at 1.3x); default-calendar picker has an 'Automatic' row with a hint.
…creenshot; fix(todo): lint (LocalResources, scaffold padding, cursor)
…README(V1 实测结论、S1–S6、权限门)、中英文截图 33 张
# Conflicts: # core/extensions/src/test/kotlin/org/agentos/extensions/samples/SamplePluginsConformanceTest.kt
…m_next; conformance test covers five apps / 44 tools and checks all five doc tables
…explains why sms is a sample app; permissions allowlist for todo and sms
…me data constant (i18n-ok), drop calendar's UiData.kt from the allowlist (R4 fixed)
… to-do items in the panel NoteSchedulePrompt: four places for each thing (event for a stretch of time, to-do for a done state, alarm only for ringing, information stays in the note), one thing one item, and a degrade rule when a tool is not in the catalog (no todo plugin: leave it in the note and tell the user). NotesToolScope gains todo_create (ignored by AgentOS when the todo plugin is missing). ScheduleItems/SchedulePanel get a TODO kind so a created to-do is not shown as '0 alarms'.
…day separator by resource, i18n waivers - res/xml/locales_config.xml (zh, en) + android:localeConfig; home overflow menu 'Language' opens Settings.ACTION_APP_LOCALE_SETTINGS - ScheduleFormat: weekday separator comes from agent_day_separator instead of locale.language checks; pure repeatText() with zh/en tests - i18n-ok waivers for the three text-analysis literals; notes lines removed from tools/check-i18n.allowlist
…; a task with its own due/status is a to-do
added 28 commits
October 9, 2026 09:50
…ssages), not Chinese sentences; wire carries {key,args}
- ManifestError.message / UnsupportedPart.reason / PluginProblem.message are MessageRef; PluginProblem gets a location (field path / skill directory)
- SkillFrontmatter.Parsed.problems and ExtensionSkillPort problems are MessageRef too (read_skill errors for the model were already English: unchanged)
- ExtWire: problems[].message / unsupported[].detail are {key,args}; skillProblems carry the directory in location (tests/device/mcp-plugin/run.py follows)
- tests: key + args assertions; ExtMessagesTest checks every produced message is registered with the right arity
- allowlist: 4 core/extensions files removed
…ey, desktop access in en and zh, normal and 1.3x font
…s in Chinese and English - values/strings_p3.xml + values-en/strings_p3.xml (plugins_*, plugin_detail_*, callers_*, ext_msg_*) - Plugins / AcpCallers / PluginPage / PluginsActivity / PluginDetailActivity / AuthorizedAppsActivity take Strings; plurals for counts and relative times - ExtCoreMessages: core/extensions message key -> resource table; Plugins.frame / frameLocation sanitise third-party arguments (quotes of every language -> ', brackets out where bracketed) - D12: the plugin name is the app's own label (PackageManager, follows the system language), falling back to plugin.json displayName; always shown with the package name - tests: zh + en for every text function, PluginFramingTest (hostile names carrying every delimiter through both languages), ExtCoreMessagesTest (keys, placeholders, arity), ExtWireTest (problems as key + args) - allowlist: 6 app files removed
# Conflicts: # tools/check-i18n.allowlist
# Conflicts: # tools/check-i18n.allowlist
… TypographyDashes ignore on the two frontmatter messages
…ps); allowlist is now empty
…e TypographyDashes
…tions as measured; unverified items stated)
…ugin / enable and always-allow dialogs / authorized apps, en and zh, plus 1.3x font in en
…h, normal and 1.3x font, README
…ENDAR with pm grant (D6) and revokes them again afterwards; 117/117 scripted on the merged tree
… event; a real model reads the plan's 'remind me half an hour before' as an alarm and skips the event (5 of 5 runs), the new wording passed 3 of 3 full runs
…(what was done, evidence, what differs from the plan, what is unverified)
…one, what is not verified, restore evidence)
…tions, new todo and sms), notes routing, zh/en across the sample apps and the AgentOS app (P1-P3), i18n gate, sample release packaging, e2e driver for five apps Real-phone check on the Pixel 8 at b0f5a6a (docs/assets/realphone-2026-10-09/README.md); what is not verified is listed in docs/next-apps-plan.md section 12.
…, AGENTS.md section 7); regression test
…ested git worktrees
tools/install.sh (POSIX sh, runs under sh/bash/dash/zsh; zh/en messages) takes the files of a release page in one folder and: verifies every file against SHA256SUMS before touching the phone, picks the phone (refuses to guess between several), runs tools/check-device.sh (itself checksum-verified), asks for confirmation, flashes with `magisk --install-module` or `ksud module install`, reboots, then reads the module's OWN install verdict from supervisor.log (a new `install: org.agentos.app result=` line, not just "the App is there") and installs the sample apps with `adb install -r` (no data cleared). The messages app is only installed when named. Exit 3 = flashed but the AgentOS App did not appear. AGENTOS_ADB_ROOT=1 is the same emulator switch check-device.sh and smoke-test.sh have. tools/package-release.py runs package-module.py and package-samples.py into a fresh working folder, copies install.sh, check-device.sh, INSTALL.md and the bilingual release notes, writes one SHA256SUMS and build-info.json, and checks the folder again (every APK signed by one certificate, the zip has what install.sh reads). --allow-unsigned gives an -unsigned dry run that install.sh refuses. There is no debug variant: package-samples.py's checks are written for release builds and are not loosened. docs/install.md (zh first, en below) lists what the script cannot do - unlock/root, USB debugging, the Superuser prompt, the rescue path, the model key, notification and battery grants, enabling plugins, the SMS "restricted settings" step, upgrading from a test build, what to read when the App does not appear - and docs/runbooks/release.md is the maintainer's signing / tag / upload procedure. README and README.en.md point to both. Verification: 84 install.sh tests against a fake adb (English and Chinese locale, each case run in both; a mutation check showed the Chinese run catches `$VAR` followed by a full-width character, which the English run cannot), 15 package-release tests, shellcheck -S error and dash/bash --posix syntax as in CI. On an adb-root API 35 emulator: the pre-flight caught a differently signed AgentOS; a full run flashed, rebooted and installed the four default samples (exit 0) and `--samples-only --samples sms` installed the messages app without granting anything; the module's own script wrote result=installed then result=same. NOT verified: that real Magisk or KernelSU accept the zip (a stand-in `magisk` and a boot hook that does what Magisk does at boot were used, outside the repository), any real phone, and a signed release made with the project certificate (a throwaway certificate was used, then discarded).
…install.md and the release runbook
The default output folders of package-release.py and package-samples.py were not ignored, so signed APKs, the module zip and SHA256SUMS would show up as untracked files in the repository. Found while building the first signed release; the release runbook now says so.
CI on the PR failed :core:runtime:test twice (553 tests, 2 failed), in code this change does not touch, and both pass on main CI: - SessionMcpServersAcpTest "a server that cannot be reached ...": session/new returns before the session_info_update that carries the per-server outcome is read; infoMetas().last() then hit an empty list. Wait until that notification has arrived. - DesktopGatewayCoreTest "too many connections are refused with busy": the gateway writes the handshake reply before it registers the connection, so a second client could be let in. Wait until the first connection is registered. Only waits were added; no assertion was removed or loosened and no production code changed. Not reproduced locally (full runtime suite 0 failures twice, the two classes 3 of 3 after the change): the cause is read from the code and matches the CI traces, and the real check is the CI run of this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
做了什么、为什么
落地
docs/next-apps-plan.md(现已入库,文末第 12 节是实施记录):SET_ALARM/DISMISS_ALARM/SNOOZE_ALARM/SHOW_ALARMS;只读工具alarm_system_next;“保证准时响铃”检查页CalendarContract)与本机日历并存;权限、重复规则映射(读不全的标custom并拒改)、reset只清自己创建的outbox状态机、无权限时“仅撰写模式”;发送是高风险,每次确认todo_create)tools/check-i18n.py(CI 新增 job,lint.xml翻译类设为 error,debug 伪本地化);五个示例 App 和 AgentOS 主 App(确认框、授权框、错误提示、引导、设置、插件页、已授权 App 页)全部中英文;tools/check-i18n.allowlist已清空tools/package-samples.py、tools/package-release.py、tools/install.sh(刷模块 + 装示例)、docs/install.md、docs/runbooks/release.md、中英发布说明sample_apps_e2e.py扩展到五个 App(含跨 App 的第 9 节场景)这个 PR 很大(86 个提交、586 个文件),建议按上表的区域分块评审。
设计取舍 / 已知限制
MessageRef),app 层按资源渲染;第三方文字的定界符清理覆盖所有语言的引号和括号(有伪造结尾的单测)。这是内部 IPC 的 JSON 形状变化({key,args}),不是公开契约。验证
./gradlew test lint :app:assembleRelease --rerun-tasks -Pagentos.skipPiBundle=true:3855 个测试,0 失败(core/runtime里原有的 23 个跳过),lint 0 error./gradlew --stacktrace test lint assembleDebug assembleRelease :app:assembleReleaseTest -Pagentos.skipPiBundle=true在b0f5a6a上 BUILD SUCCESSFUL;tools/tests137 个、设备脚本单测 175 个、check-i18n0 error、shellcheck-S error0 个问题grep -cE 'Debug(Call|Tool)?Receiver'= 0;五个示例的 release dex 和 manifest 里 debug 类 / 组件各 0;AgentOS release 导出组件仍是 3 个(AcpService、ConversationActivity、ApprovalFrontActivity)真机测试
ro.build.fingerprint=google/shiba/shiba:15/BP1A.250505.005.B1/13277630:user/release-keysb0f5a6a959ef9ba37b3ae797998a494999e6fa0f(已合入当时最新 main)。之后只改了文档、图片、发布 / 门禁脚本和.gitignore,app/ core/ sdk/ plugins/ runner/ module/没有任何改动(git diff --stat b0f5a6a <HEAD> -- app core sdk plugins runner module为空)。sample_apps_e2e.py会reset三个示例 App、third_party.py会pm clear主 App,这台是日常用的手机,有真实数据,所以没跑。真机上只做了不清数据的定向检查(adb install -r覆盖安装,pm clear一次都没用):SET_ALARMIntent(skip_ui)建出的闹钟登记到系统,alarm_system_next对其归属判断正确,测完在界面里删掉SelfTestReceiver32/32,自测后无遗留adb reverse与测试前一致。证据和截图:docs/assets/realphone-2026-10-09/--live --tunnel(key 留在电脑上,不进手机)adb screencap)--live运行里 logcat 0 次(15779 行)、结果文件 0 次;真机没有用到 keydelivered;--live单 App 用例通过install.sh只在 adb-root 模拟器上用替身magisk验证过文档与契约
docs/sample-apps.md(待办 4.4、短信 4.5、alarm_system_next、日历数据层与 dump / reset 口径)、docs/extensions.md4.4(日历不再放自带插件,D1)、docs/third-party-acp.md(备忘录 toolScope 为三项)、docs/development.md、README*.md,新增docs/install.md、docs/runbooks/release.md、docs/release-notes/0.1.0.md、docs/next-apps-plan.mdsdk:acp-android、sdk:plugin-sdk、ACP 协议、plugin.json格式、错误码、IAgentControl.aidl都没有动。内部接口有一处形状变化:IExtensionHost.aidl(org.agentos.internal,AgentOS 自己的:agent与界面之间)方法签名没变,但它传的 JSON 里problems[].message、unsupported[].detail、skillProblems[].message由中文字符串变成{key,args}(并新增location),注释里已同步;消费方只有本仓库的插件页,已一并改完并有测试alarmAlarmIntentActivity,exported=true,要求系统标准权限com.android.alarm.permission.SET_ALARM:让语音助手和别的 App 能用标准AlarmClockIntent 建 / 关 / 贪睡闹钟。参数逐项校验(小时、分钟、星期),非法值明确拒绝;skip_ui时弹 Toast;不返回内部状态alarmMainActivity增加SHOW_ALARMS过滤器(本来就是导出的 launcher)todo、sms的*McpService:exported=true,要求org.agentos.permission.BIND_MCP_SERVICE,和已有的闹钟 / 日历 / 备忘录服务一致todo、sms的 launcherMainActivity:todo不读任何 Intent 参数;sms读一个整数 extratab(限制在 0–3),只用来选择打开哪个页签,不返回数据、不改状态风险与回滚
git revert本 PR 的合并提交。日历见上面的数据库降级说明。