1. I Created This Problem Myself
My son is in the senior class of kindergarten. The first thing he does every morning upon waking is reach for the remote — so practiced he could find the right buttons blindfolded. He knows which key opens Bilibili, and he knows that when one episode ends, pressing forward one slot gets the next.
At first I allowed it. A kid wanting to watch cartoons isn’t an unreasonable request — I myself come home from work and scroll my phone endlessly. The problem is there’s no bottom to it: agree on one episode, and when it’s done he wants another; I say no, and the wheedling begins until I’m exasperated. Before I know it, an entire morning is gone — the two hours of his day when he’s most alert and most cooperative, handed over to the TV.
I tried hiding the remote — he’d find it. Tried unplugging the power — he’d plug it back in. Tried reasoning — he’d nod “uh-huh uh-huh” and resume watching the moment I turned around. I’ve yelled too — he cries, I feel terrible all day.
After cycling through every approach, I changed my thinking: don’t block him from watching — add a gate to “watching.” The gate isn’t about preventing him from going through; it’s about making him walk up to it himself.

2. What This Gate Looks Like
The app currently installed on the TV is one I wrote myself, package name com.awen.tvguard. Every cold boot — or wake from standby — the first screen isn’t Bilibili; it’s this. The flow has three steps: answer a few questions, learn today’s character, pass three quiz questions.
Boot questions. Three questions: did you finish breakfast, did you brush your teeth, is it time for school. Answer “yes” to proceed; answer “no” and it stops on that question, buttons locked for 60 seconds, sending him off to do the thing first. Whatever he answers, I can see on my phone.

Today’s character. One character per day, rotated and pushed down by my server-side service. Built-in library of 423 characters, ordered by common usage from senior kindergarten through first grade. The page shows the large character, stroke-by-stroke animation, stroke names (“2 strokes total: horizontal-turn-hook, left-falling”), pinyin with tone marks, and a “hear pronunciation” button.
Quiz gate. After learning, tap “I’ve learned it, let me try the quiz” — three questions: hear audio pick the character, see character pick the pinyin, hear audio pick the character again (last round uses a different set of distractors to prevent recognition-by-familiarity guessing). Pass all three to proceed; after passing, 15 minutes are unlocked.

Honest disclosure here: the gate says “I’ve learned it and can write it,” but the TV has no stylus — the app can’t verify whether he actually wrote it. This step currently relies on his word. The real checking is done by his kindergarten teacher, and by his mom flipping through his writing notebook at night. I originally wanted to add a handwriting-tracing component but got stuck and never did it — ultimately because I was lazy.
3. Fifteen Minutes Is a Hard Cap
After passing, a single session is 15 minutes — roughly the length of one episode of whatever he’s watching; daily cumulative cap is 30 minutes. Once used up, he waits until tomorrow.
When time’s up, it doesn’t just black-screen — it freezes the picture on a notice page with a 5-minute countdown. During those 5 minutes I can extend from my phone, or he can answer a two-digit multiplication problem on the TV and enter the parental password. Originally I had it shut off at time’s end; after two days I realized that even I had to power on the whole TV just to watch the news, so I changed it to “stay on that page” — same effect for him (he still can’t watch anything), much more convenient for me.
There are also two no-watch periods: weekday daytime (school hours) and every evening after 8 PM. Holidays follow the State Council’s official schedule — statutory holidays don’t count as school days; weekend make-up class days still get blocked. This schedule is the same one used in my phone’s ROM.
4. Fights with the TV to Make It Stick
This TV is a Hisense VIDAA, Android 11. It doesn’t allow third-party apps like mine to have authority in the system, so the following pitfalls were unavoidable.
Boot broadcast disabled by the ROM. The app receives BOOT_COMPLETED on first boot; 11 seconds later, the system writes my receiver into disabledComponents — after that I never receive the boot broadcast again. The fix isn’t in code: you have to go into “Xiaoju Assistant → Startup Management” on the TV and enable “TV Guard,” letting the ROM itself whitelist it.
Can’t bring up UI from background. The kid presses HOME on the remote and he’s free; to bring him back I need to startActivity from background — but the log shows only one line: Abort background activity starts, screen doesn’t budge. After exhaustive research, the only exemption the ROM honors is the “floating window” permission. The problem: this permission resets on every boot. So on my home server (machine 46), a daemon script runs every 10 seconds checking whether the TV’s adb is online, and re-grants the permission immediately. This is also why whether the cold-boot first screen lands on the guard page depends on whether the home server is running — sounds absurd, but it’s the only path left after exhausting all alternatives.
HOME key can’t be intercepted, so I “recapture” instead. HOME is a system-level key; apps can only swallow keys within their own interface, not the remote’s HOME. So every 5 seconds the background checks the foreground app; if it’s not Bilibili (meaning it’s not my app), kill it and relaunch. Pitfall here: after relaunching, you must hold still for 25 seconds without acting, because during cold-start’s first dozen seconds the foreground still shows the launcher — judging too eagerly creates a “just launched, immediately killed” death loop.
Network dropout at wake. This TV resets its network adapter when resuming from standby — in practice it takes five or six seconds to reconnect. But it launches the “last used app” 0.1 seconds after network recovery. If the last app was Bilibili, it starts in a no-network state and freezes on “load failed, press OK to retry.” So I changed the wake-launch target to my guard app: the guard waits until network is truly stable for 3 seconds, then launches Bilibili.
Remote has no number keys. Parental unlock requires answering a math problem then entering a password. I assumed entering a password just needed an on-screen numeric keypad — but in practice these keys simply cannot be emitted; only the on-screen soft keyboard works. After answering the math question, to submit, focus must be on “Confirm” — if focus is still on a digit when you press Confirm, it types a digit into the field instead. This bug took two days to fix because it worked perfectly in my desktop simulator.
Architecture isn’t complex: on the TV is an Android app (no Gradle — aapt2 + javac + d8 + zipalign + apksigner, one build.sh produces the package); on machine 46 at home runs a small Go service storing config and the character library, pulled by the TV every minute; on my phone I open a management page to adjust per-session allowance, daily allowance, and today’s character. Plus a pure server-side failsafe script — if the app gets uninstalled or the process killed, it can still put the TV into standby on the same schedule.
5. One Month In — Honest Assessment
This system went up in mid-September; it’s been nearly a month.
The good: he still wants to watch TV in the morning, but he’ll first glance at today’s character; he watches less — from “an entire morning” to “two 15-minute blocks”; I don’t have to play villain every morning — rules are enforced by the machine, I’m only responsible for maintaining the machine. One day at dinner he said “Daddy, today’s character was XXX” — I pretended to be cool about it, but inside I was quite pleased.
The not-so-good, or rather what I’m uncertain about:
He does the quiz seriously in order to watch TV. This is fundamentally still “trading rewards for behavior” — same mechanism as gold stars, same as KPIs. I just criticized this exact approach in my “Why Home Hurts” reading notes (link) — then turned around and used it myself. I acknowledge the contradiction.
My defense: I don’t expect this app to make him love learning. I only want to do two things. One: make “watching TV” something you have to actively earn rather than something that’s just there when you wake up. Two: break the automatic “wake up → open Bilibili” chain by inserting a brain-engaging action in between. As for the character learning itself — one per day, 300+ per year — it’s better than nothing.
There’s also a question I still don’t have an answer to: when he’s older, will he resent learning characters because “characters are the price of watching TV.” When that day comes, this approach will need revision.
6. Finally
The most rule-abiding thing in our household now is that TV. It asks my child three questions daily, gives him one character, quizzes him three times — with more patience than I have. It won’t casually let him through because I’m running late, and it won’t soften because he cries.
I don’t plan to make this into a general-purpose product for others. It’s a biased device made specifically for my own kid. The day he finds it annoying and starts negotiating with me — I’ll revise it. Anyway, modifying it is easier than modifying myself.
What tomorrow’s character will be, I haven’t checked yet. The backend on my phone can show me.
评论
0 条评论