diff --git a/CLAUDE.md b/CLAUDE.md index aef5e94..82466d2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -60,6 +60,11 @@ $ADB shell dumpsys activity exit-info com.scrollmeter.app.debug # why/when the $ADB exec-out screencap -p > "$SCRATCH/shot.png" # screenshots: let a subagent look; keep images out of the main context ``` +**The repo is public (2026-09-28).** `README.md` is the Czech download page for ordinary users (what the app does and +does not do, installation, permissions, safety); developer detail lives in `docs/development.md`. A user-visible change +(permission, screen, limitation) updates the README in the same PR. Publish every GitHub Release as **Latest, never +prerelease** — the README links `releases/latest`, which skips prereleases. + Device gotchas (OnePlus CPH2399, Android 14): - `settings put secure …` needs Developer options → **Zakázat sledování oprávnění** (very bottom); it survives a reboot. - `uiautomator dump` unbinds every accessibility service while it runs — the home screen then says "not running". Read our own layout with `dumpsys activity top` instead (it also sees Views inside a Compose `AndroidView`). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index fa85ad7..0b53ed4 100644 --- a/README.md +++ b/README.md @@ -1,168 +1,238 @@ +
+ # ScrollMeter -ScrollMeter is an Android app that measures how far content moves while you -scroll across your phone and converts that movement into real-world distance. +### Kolik toho denně nascrolluješ? -It uses Android Accessibility scroll events and processes all measurement data -locally on the device. +Screen time ti řekne, jak dlouho. ScrollMeter ti ukáže, jak daleko. +Každé posunutí feedu, článku nebo seznamu sečte a převede na metry a kilometry. -ScrollMeter measures scroll distance, not the raw physical trajectory of a -finger across the touchscreen. +**Zadarmo · bez reklam · bez účtu · bez internetu · Android 10+** -## Status +[**⬇️ Stáhnout aplikaci**](../../releases/latest) · [Jak ji nainstalovat](#jak-ji-nainstalovat-za-tři-minuty) · [Jaká oprávnění chce](#jaká-oprávnění-potřebuje) · [Je to bezpečné?](#je-to-bezpečné) -Project founded 2026-09-23. Phases 0–7 merged (`v0.0` … `v0.7`): bootstrap, measurement proof of concept -(GO/NO-GO gate), calibration, persistence with optional time in app, dashboard, history and apps, export and -settings, onboarding with the Play disclosure and English. Phase 8 (release hardening, `v0.8`) adds the signed -release build, the emulator matrix API 28–36, the battery protocol and the first release `v0.1.0`. Phase 9 -(`v0.9`, release `v0.2.0`) replaces the goal with a daily limit in colour and History + Apps with one -*Statistiky* screen (ADR-036). The app is for family phones, installed from the APK — not Google Play. -**Requires Android 10 (API 29) or newer** — Android 9 does not deliver the scroll events (ADR-033). -Manual on-phone checks still owed are listed under "Dluh ověření" in `handoff.md`. See `PLAN.md` (phases, -gates) and `handoff.md` (live state). +
-## Repository map +--- -| Path | What it is | -|---|---| -| `docs/SPEC.md` | The product + technical specification, v1.0 (binding) | -| `PLAN.md` | Development plan by phases 0–8 with Definition of Done (Czech) | -| `handoff.md` | Live state: toolchain pins, phase status, decisions log (Czech) | -| `docs/measurement-model.md` | What scroll distance is, formulas, calibration, fallback, fling | -| `docs/accessibility-policy.md` | Which Accessibility API we use, what we never read, Play disclosure | -| `docs/play-listing.md` | Draft Play listing, Accessibility declaration answers, Data safety, privacy policy text, video scenario | -| `docs/accuracy-testing.md` | Test protocol and the device / app compatibility tables | -| `docs/architecture.md` | Event pipeline, package layout, threading, data model | -| `docs/measurement-decisions.md` | ADR log for non-obvious decisions | -| `docs/prompts/` | Kick-off prompts for coding sessions | -| `tools/` | `analyze_debug_csv.py` (per-app analysis of debug CSVs), `device_accuracy.py` (adb-driven accuracy tests), `accuracy.py` (ground truth CSV vs measured CSV → MAE, MAPE), `check_manifest_policy.py` / `check_release_apk.py` (what a build may ship), `build_release.sh` (signed release) | -| `CLAUDE.md` | Rules for coding agents working in this repo | - -## Build and run (available from Phase 0) +## Ve zkratce -```bash -./gradlew assembleDebug # build -./gradlew testDebugUnitTest # JVM unit tests -./gradlew lintDebug # Android lint -./gradlew installDebug # install on the connected phone -``` +- 📏 **Měří vzdálenost scrollování** ve všech aplikacích a ukáže ji v metrech: dnes, za týden, za měsíc. +- 📴 **Nemá přístup k internetu.** Nemůže nic odeslat, ani kdyby chtěla. Všechno zůstává v telefonu. +- 🙈 **Nečte, co je na obrazovce.** Dozví se jen „v aplikaci X se obsah posunul o tolik pixelů". Žádné texty, zprávy ani hesla. +- 👤 **Žádný účet, žádné reklamy, žádná analytika.** Nikdo kromě tebe neví, že ji používáš. +- 🔓 **Celý kód je veřejný** tady v repozitáři, kdokoliv si může ověřit, co dělá. + +## Co uvidíš + + + + + + + + + + + + +
Přehled: dnešní vzdálenost proti dennímu limituStatistiky: aplikace podle vzdálenosti a časuSoukromí: co aplikace čte a co ne
Přehled
dnes proti dennímu limitu
Statistiky
den, týden, měsíc, po aplikacích
Soukromí
co čte a co nikdy
+ +## Co umí + +📊 **Dnes, tento týden, tento měsíc.** Karta *Dnes* ukazuje vzdálenost proti dennímu limitu, který si +nastavíš sám: zelená, od 70 % oranžová, nad limitem červená. A vždycky i slovy, třeba „Zbývá 80 m z limitu 500 m". + +📱 **Po aplikacích.** Kolik metrů v Instagramu, kolik v prohlížeči, kolik ve zprávách. Volitelně i kolik +času v každé aplikaci trávíš: „Instagram 1,21 km (3 h 40 min)". + +🏃 **Srovnání, ať si to představíš.** „To je přibližně délka jednoho běžeckého okruhu." Není to soutěž, +žádné rekordy ani odznaky. Jen číslo, které ti řekne víc než minuty. + +📐 **Kalibrace platební kartou.** Přiložíš kartu k displeji, posuneš čáru na její okraj a měření sedí +na milimetr tvého konkrétního telefonu. Bez kalibrace se použije odhad podle údajů displeje. + +🔔 **Dvě volitelná oznámení.** Když překročíš denní limit, a ráno shrnutí včerejška. Každé nejvýš jednou +denně, obě jsou ve výchozím stavu vypnutá. + +📤 **Export do CSV a smazání jedním tlačítkem.** Data si můžeš kdykoliv vzít do tabulky, nebo je všechna smazat. + +🇨🇿 🇬🇧 **Česky i anglicky**, podle jazyka telefonu. + +## Co to nedělá + +- ❌ **Neblokuje aplikace a nic ti nezakazuje.** Jen měří a ukazuje. Limit je informace, ne zámek. +- ❌ **Není to rodičovská kontrola.** Nikomu nic nehlásí, data neopustí telefon, na kterém je nainstalovaná. +- ❌ **Nečte obsah obrazovky.** Neví, co čteš, co píšeš, komu, ani na jaké stránce jsi. +- ❌ **Neměří dráhu prstu.** Měří, o kolik se posunul obsah. Po švihnutí prstem obsah ještě dojede, + takže vzdálenost bývá delší než pohyb prstu. To je záměr: měří se, kolik obsahu ti projelo před očima. +- ❌ **Neměří všude.** Některé aplikace systému scrollování nehlásí, typicky **YouTube**. V nich ScrollMeter + nenaměří nic a přizná to. Čas v aplikaci (když ho povolíš) se u nich ukáže i tak. +- ❌ **Nezálohuje se do cloudu** a data se nepřenesou na nový telefon. Kdo si je chce odnést, použije export. + +--- + +## Jak ji nainstalovat (za tři minuty) + +Aplikace **není v Google Play**, instaluje se ze souboru. Zní to hůř, než to je. +Potřebuješ **Android 10 nebo novější**. + +**1.** V telefonu otevři [**stránku ke stažení**](../../releases/latest) a klepni na soubor +`scrollmeter-….apk` (ten s koncovkou `.apk`, ne `.aab`). + +**2.** Telefon se zeptá, jestli soubor stáhnout → **Stáhnout**. + +**3.** Otevři stažený soubor, z lišty oznámení nebo v aplikaci *Soubory* → *Stažené*. + +**4.** Android řekne, že z tohohle zdroje instalovat nesmí. Klepni na **Nastavení**, zapni +**Povolit z tohoto zdroje** a vrať se zpátky. + +**5.** **Instalovat** → **Otevřít**. + +**6.** Aplikace tě provede úvodem. Na obrazovce *Povolit měření scrollování* si přečti, co bude číst a co ne, +a klepni na **Rozumím a chci pokračovat** → **Otevřít nastavení zpřístupnění**. + +

Obrazovka Povolit měření scrollování: co aplikace používá a co nečte

+ +**7.** V nastavení najdi **ScrollMeter** (bývá v části *Stažené aplikace* nebo *Nainstalované aplikace*) +a zapni ho. Android ukáže obecné varování, co všechno služby Usnadnění *smějí*. ScrollMeter z toho +používá jen jedinou věc, viz [oprávnění](#jaká-oprávnění-potřebuje). Potvrď a vrať se do aplikace. + +> **Napsal Android „Omezené nastavení"?** Na Androidu 13 a novějším to je normální u každé aplikace +> nainstalované mimo obchod. Otevři **Nastavení → Aplikace → ScrollMeter**, vpravo nahoře klepni na **⋮** +> a zvol **Povolit omezená nastavení**. Pak krok 7 zopakuj. Aplikace na to má přímo tlačítko +> *Otevřít informace o aplikaci*. + +**8.** Kalibrace: klepni na **Zkalibrovat platební kartou** (asi minuta), nebo **Použít automatický odhad**. +Kalibrovat jde kdykoliv později. + +**9.** Volitelně povol **Čas v aplikacích**. Bez toho aplikace měří dál, jen neuvidíš minuty. -Requires JDK 21 for Gradle (pinned in `gradle/gradle-daemon-jvm.properties`) -and the Android SDK with platform 36 (`local.properties` → `sdk.dir`). +Hotovo. Teď normálně používej telefon a za chvíli se do ScrollMeteru podívej. -## Release build (Phase 8) +> **Aplikace se sama neaktualizuje.** Nemá přístup k internetu, takže se ani nedozví, že vyšla nová verze. +> **Každou novou verzi si stáhneš a nainstaluješ ručně**, stejným postupem jako tuhle první. Naměřená data +> i nastavení zůstanou. Kdo to nechce hlídat, přidá si tenhle repozitář do +> [Obtainium](https://github.com/ImranR98/Obtainium) a o aktualizacích se dozví sám. + +> **Google Play Protect** může u ručně instalované aplikace zobrazit varování. To je standardní hláška +> u všeho mimo obchod, ne nález něčeho škodlivého. + +--- + +## Jaká oprávnění potřebuje + +| Oprávnění | Povinné? | K čemu | Co z něj aplikace dostane | +|---|---|---|---| +| **Služba Usnadnění** (Zpřístupnění) | **ano** | Jediný způsob, jak se aplikace dozví o scrollování v *jiných* aplikacích. | Jen událost „obsah se posunul": v jaké aplikaci, kdy a o kolik pixelů. Nic víc. | +| **Přístup k údajům o využití** | ne | Čas strávený v jednotlivých aplikacích. | Kdy byla která aplikace na popředí. Ukládá se jen součet minut na aplikaci a den. | +| **Oznámení** | ne | Upozornění na překročený limit a ranní shrnutí. | Nic, jen smí poslat oznámení. Ptá se, až když oznámení zapneš. | + +**Co aplikace nechce a nemá:** přístup k **internetu**, polohu, kontakty, fotky a soubory, mikrofon, +kameru, seznam všech nainstalovaných aplikací, kreslení přes jiné aplikace, běh na popředí. + +### Proč Usnadnění a proč se ho nebát + +Usnadnění je silné oprávnění. Obecně umí číst obrazovku a ovládat telefon, a proto Android u každé +aplikace, která ho chce, ukáže stejné strašidelné varování. **Co konkrétní aplikace z Usnadnění skutečně +dostane, ale určuje její konfigurace**, a ta je u ScrollMeteru nastavená na minimum: + +- odebírá **jediný typ události**, „obsah se posunul" (`typeViewScrolled`), +- má výslovně **zakázáno číst obsah oken** (`canRetrieveWindowContent="false"`), takže text obrazovky + nedostane, ani kdyby o něj požádala, +- neovládá telefon, neklepe za tebe, nesleduje dotyky. + +Tuhle konfiguraci najdeš v souboru +[`accessibility_service_config.xml`](app/src/main/res/xml/accessibility_service_config.xml) a hlídají ji +automatické testy, které při jakémkoli rozšíření oprávnění selžou. + +--- + +## Je to bezpečné? + +### ✅ Proč tomu můžeš věřit + +- **Bez internetu nejde nic poslat.** Aplikace nemá oprávnění `INTERNET`. To není slib v podmínkách + použití, to je technická nemožnost: Android jí síť vůbec nepustí. V *Nastavení → Aplikace → ScrollMeter → + Mobilní data* uvidíš 0 B. +- **Neví, co čteš.** Ukládá jen čas, název balíčku aplikace (např. `com.instagram.android`), počet + posunutých pixelů a spočítanou vzdálenost. Nikdy text, zprávy, hesla, adresy stránek ani vyplněné formuláře. +- **Žádné cizí knihovny na sledování.** Žádná analytika, reklamní SDK, crash reporting ani Google Play Services. +- **Data jsou jen tvoje.** Vypnutá záloha do cloudu, z telefonu odejdou jen exportem, který spustíš ty. + *Nastavení → Data → Smazat všechna data* je smaže, odinstalace taky. +- **Otevřený kód.** Všechno, co aplikace dělá, je tady v repozitáři. Kdo nechce věřit mně, přeloží si ji + ze zdrojáku sám ([návod pro vývojáře](docs/development.md)). +- **Podepsané APK.** Každá verze je podepsaná stejným klíčem. Otisk certifikátu (SHA-256): + ``` + 04:6F:8C:D0:B0:73:23:F7:07:12:E1:12:53:CA:D7:FB:82:03:F2:68:C8:D8:10:53:78:3D:9C:1A:66:9C:0E:88 + ``` + Ověříš ho příkazem `apksigner verify --print-certs scrollmeter-….apk`. Otisky souborů jsou + v `SHA256SUMS` u každé verze. + +### ⚠️ Na co si dát pozor + +- **Usnadnění dávej jen aplikacím, kterým věříš.** To platí obecně, ne jen tady. Podvodné aplikace + ho zneužívají ke čtení obrazovky. Tahle aplikace z něj bere jen scrollování (viz výše), ale stahuj ji + **jen z téhle stránky**, ne z přeposlaných souborů nebo cizích webů. +- **Co naměří, ukazuje o tobě dost.** Z čísel je vidět, které aplikace používáš a jak moc. V telefonu jsou + v bezpečí, ale kdo má tvůj odemčený telefon, uvidí je taky. A exportované CSV už je obyčejný soubor: + kam ho pošleš, tam je. +- **Není to ověřený obchod.** Tuhle aplikaci nikdo cizí nekontroloval, žádný Google ani nezávislý audit. + Tvoje jistota je otevřený kód a to, že nemá internet. +- **Od roku 2027 může Google zpřísnit** instalaci aplikací mimo obchod na certifikovaných telefonech. + V Česku zatím platí postup výše beze změny. + +--- + +## Co zatím neumí + +- **YouTube a některé další aplikace neměří**, protože scrollování systému nehlásí. Týká se to i části + moderních aplikací postavených na nových seznamech v Jetpack Compose. +- **Přesnost je odhad.** Bez kalibrace se spoléhá na to, co o sobě hlásí displej, a to se u některých + telefonů o pár procent liší. Kalibrace kartou to srovná. +- **Některé telefony měření uspávají.** Hlavně OnePlus / Oppo / Realme (ColorOS) umí službu na pozadí + zabít, když dochází paměť. Aplikace to pozná a na přehledu ukáže červený pruh s tlačítkem *Zapnout měření*. + Zkusit můžeš vypnout pro ScrollMeter optimalizaci baterie; že to pomůže na každém telefonu, zatím ověřené není. +- **Vynucené zastavení vypne měření.** Když ScrollMeter v nastavení aplikací *vynuceně zastavíš*, Android mu + Usnadnění vypne a je potřeba ho zapnout znovu. +- **Jen jeden telefon.** Nic se nesynchronizuje, každý telefon měří sám za sebe. + +--- + +## Je to open source + +Tohle je koníček, ne produkt. Vznikl pro rodinu a vyvíjím ho, **jak mám čas a chuť**, bez roadmapy a bez termínů. + +Celý kód je venku pod **[GPL-3.0](LICENSE)**. Kdokoliv si ho může vzít, upravit, opravit nebo v projektu +pokračovat po svém. Licence hlídá jedinou věc: odvozená verze zůstane taky otevřená. + +- 🐛 **Chyba nebo nápad?** → [issue](../../issues) +- 🔧 **Chceš přispět kódem?** → pull requesty vítám, testy prosím taky +- 🍴 **Chceš to forknout?** → posluž si + +### Autor + +**Honza Hubka** — [honzahubka.cz](https://honzahubka.cz) · [LinkedIn](https://www.linkedin.com/in/honzahubka/) + +## Pro vývojáře + +Kotlin + Jetpack Compose, Room, DataStore. minSdk 29, compileSdk 36, žádné Google Play Services, žádná síť. ```bash -tools/build_release.sh # clean tree only: signed APK + AAB, both checked against the upload certificate, APK checked +./gradlew assembleDebug # APK v app/build/outputs/apk/debug/ +./gradlew testDebugUnitTest # unit testy +./gradlew lintDebug # Android lint ``` -Signing comes only from environment variables (`SIGNING_KEYSTORE_PATH`, `SIGNING_STORE_PASSWORD`, -`SIGNING_KEY_ALIAS`, `SIGNING_KEY_PASSWORD`, ADR-034); without them `assembleRelease` builds an unsigned APK -(CI does). The script takes the upload key from `~/.android-keystores/scrollmeter-upload.jks` and its password -from the macOS Keychain item `scrollmeter-upload-keystore` — neither is in the repository. Outputs: -`app/build/outputs/apk/release/app-release.apk` (what gets installed — the app is distributed as an APK to family -phones, not through Google Play) and `app/build/outputs/bundle/release/app-release.aab` (kept for a store, none planned). - -Release APKs are signed by `CN=ScrollMeter, O=Honza Hubka, C=CZ`, certificate SHA-256 -`04:6F:8C:D0:B0:73:23:F7:07:12:E1:12:53:CA:D7:FB:82:03:F2:68:C8:D8:10:53:78:3D:9C:1A:66:9C:0E:88` — -check a downloaded APK with `apksigner verify --print-certs app-release.apk`. - -## How to test the measurement POC (Phase 1) - -The debug build (`com.scrollmeter.app.debug`) adds two developer screens to the home screen: -**Debug měření** (the last 100 scroll events live) and **Testovací seznam** (our own list with an -exact ground truth). Release builds contain neither. - -1. **Install:** `./gradlew installDebug` with the phone connected over USB (USB debugging on). -2. **Enable the service** — either by hand: Settings → Accessibility → Downloaded / Installed apps → - *ScrollMeter — měření scrollování* → On; or over adb (POC only): - ```bash - ADB=~/Library/Android/sdk/platform-tools/adb - $ADB shell settings put secure enabled_accessibility_services com.scrollmeter.app.debug/com.scrollmeter.app.accessibility.ScrollAccessibilityService - $ADB shell settings put secure accessibility_enabled 1 - ``` - OnePlus / ColorOS refuses these writes until Developer options → **Zakázat sledování oprávnění** - (*Disable permission monitoring*, at the very bottom) is on. -3. **Check it runs:** open ScrollMeter — the card says *Měření je zapnuté* and the total since the - service started grows while you scroll anywhere. `adb shell dumpsys accessibility` lists the service - with `eventTypes=TYPE_VIEW_SCROLLED`. -4. **Own list with ground truth:** *Testovací seznam* → pick a surface (*View* = classic Android views, - *Column* = Compose `verticalScroll`, *Lazy* = Compose `LazyColumn`) → *Vynulovat* → scroll the list and - the carousel by hand. Each axis shows ground truth px, measured px and the error. *Lazy* is expected to - measure 0 (ADR-019). Automated version (Tests A–E of spec §36): - `python3 tools/device_accuracy.py --surface view,column,lazy --markdown`. -5. **Other apps:** *Debug měření* → *Vymazat* (the *v souboru* counter drops to 0) → go through the apps one - after another, 20–30 s each (slow scrolls, flings, horizontal carousels) — no need to come back in - between. Every event is written through to the phone's app-private storage, so the run survives the - system killing ScrollMeter (ColorOS does that under memory pressure; the service restarts by itself). - Apps behind a login screen (Instagram, TikTok, X) need an account to reach a feed. -6. **Collect and analyse** — no export needed; the analyser splits the run per app: - ```bash - $ADB exec-out run-as com.scrollmeter.app.debug cat files/debug/recording.csv > run.csv - python3 tools/analyze_debug_csv.py run.csv # per-app table: coverage, fallback, outliers, duplicates - $ADB logcat -s ScrollMeter:D # one line per event, live - ``` - *Export CSV* on the phone writes the same rows plus a device header (needed for the outlier-limit - column) to `/sdcard/Android/data/com.scrollmeter.app.debug/files/debug/` (`adb pull` that folder); - *Sdílet* sends it elsewhere. -7. **Switch the service off** when done: `$ADB shell settings delete secure enabled_accessibility_services` (an empty `put` fails with "Bad arguments") - or in Accessibility settings. - -## Calibration (Phase 2) - -Home → *Zkalibrovat displej* (or *Přesnost měření* → *Zkalibrovat platební kartou*). Hold the phone upright, -lay a payment card on the screen right of the blue vertical line with its top edge on the top line, and -move the bottom line to the card's bottom edge (slider, then − / + for single pixels) → *Uložit kalibraci*. -*Přesnost měření* then shows *Platební karta · 1 pixel = … mm* and the date. The card applies only to the -phone and display resolution it was made on (ADR-024); *Přeskočit – použít automatický odhad* goes back to -`xdpi`/`ydpi`. New calibration applies to new events only. - -Accuracy with the calibration in force: `python3 tools/device_accuracy.py --surface view,column --csv-out out/` -then `python3 tools/accuracy.py out/ground_truth.csv out/measured.csv`. The test list itself shows MAE / MAPE -over the runs of a series (*Vynulovat* closes a run, *Nová série* starts over). - -## Přehled and Statistiky (Phases 4, 5, 9) - -*Přehled* is the one main screen — no bottom bar; *Nastavení* sits behind the gear. The *Dnes* card shows -today's distance against the **daily limit** (500 m by default, or *Bez limitu*): green, orange from 70 %, red -over it, and always in words too ("Zbývá 80 m z limitu 500 m", "Překročeno o 120 m (limit 500 m)"). Below it -*Tento týden* and *Tento měsíc* with their total and average per day, the three apps scrolled most today and -one comparison ("To je přibližně délka jednoho běžeckého okruhu."). Every number is live — stored plus what -the service has not written yet. When the service is off, a red banner with *Zapnout měření* comes first. It -is not a competition: no goals, no records (ADR-036). - -Tapping *Dnes*, a week or a month opens **Statistiky**: *Den / Týden / Měsíc* with ‹ ›, for a week or month a -bar per day in its limit colour with the limit as a dashed line (tap a bar to open that day), and every app -of the period from the longest distance down, with the time in the app on the same row — "Chrome -1,21 km (3 h 40 min)". Apps with time but no scroll data (YouTube) show "— (2 h 15 min)" at the end. An app -opens its detail for that period: distance, share, time in app, scroll time, pace, a measurement-quality word -(never an accuracy percentage — ADR-029) and 30-day charts. Durations roll over from minutes to hours to days -("1 d 1 h 1 min"). Time in app needs Usage access; until it is granted a card offers it once (*Ukázat jak* → -a disclosure screen → Android settings), and the rows show no brackets. - -## Settings, export and notifications (Phase 6) - -*Nastavení* holds the service and Usage-access status, *Přesnost měření*, the daily limit (100 m – 5 km, a -custom 10 m – 100 km, or *Bez limitu*), *Vyloučené aplikace* (launcher, keyboard and System UI are suggested; an -excluded app disappears from every total, history and export and comes back when switched on again), units, -theme, the two opt-in notifications (over the limit, yesterday's summary — each at most once a day; on -Android 13+ the system asks for permission when one is switched on), *Exportovat CSV* (save `per_app.csv` / -`daily_summary.csv` through the system file picker, or share both), *Smazat všechna data* (optionally with the -settings and the card calibration), *Soukromí* and *O aplikaci* (version, device, the total measured since the first day); in debug builds also the -developer screens. -The CSV format is in ADR-031: comma separated, dot decimals, UTF-8 with BOM, an empty field means unknown. - -## Stored data and time in app (Phase 3) - -Distances are stored per day and app in an app-private Room database (`scrollmeter.db`) and survive app -restarts; Home shows *Dnes* from it (at most 10 s behind the live counter). Time in app is optional: grant -*Přístup k údajům o využití* to ScrollMeter in Android settings (on an emulator: -`adb shell appops set com.scrollmeter.app.debug GET_USAGE_STATS allow`) and open the app — it snapshots the -last days into `daily_app_usage`. Inspect a debug build's data with -`adb shell "run-as com.scrollmeter.app.debug sqlite3 databases/scrollmeter.db 'select * from daily_app_aggregate'"`. - -Note: `adb shell am force-stop` turns the accessibility service off (Android removes it from the enabled list); -turn it on again in Usnadnění. - -The debug CSV holds numbers and identifiers only (time, package, window id, view class, deltas, scroll -positions, distance, source, accepted/rejected) — never text from the screen. +Potřebuješ **JDK 21** a Android SDK s platformou 36. Build, podepsaný release, testovací protokoly +a měření přesnosti popisuje [`docs/development.md`](docs/development.md). + +| Dokument | O čem je | +|---|---| +| [`docs/development.md`](docs/development.md) | build, release, ruční testy, kalibrace, uložená data | +| [`docs/SPEC.md`](docs/SPEC.md) | produktová a technická specifikace | +| [`docs/measurement-model.md`](docs/measurement-model.md) | co je vzdálenost scrollování, vzorce, kalibrace | +| [`docs/accessibility-policy.md`](docs/accessibility-policy.md) | co z Usnadnění používáme a co nikdy nečteme | +| [`docs/architecture.md`](docs/architecture.md) | tok událostí, balíčky, vlákna, datový model | +| [`docs/measurement-decisions.md`](docs/measurement-decisions.md) | záznam rozhodnutí (ADR) | +| [`handoff.md`](handoff.md) | živý stav prací a otevřené body | diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..e662e0d --- /dev/null +++ b/docs/development.md @@ -0,0 +1,171 @@ +# ScrollMeter — for developers + +> The user-facing page (what the app does, permissions, installation) is the Czech [`README.md`](../README.md). +> This file is the developer reference: build, release, test protocols. + +ScrollMeter is an Android app that measures how far content moves while you +scroll across your phone and converts that movement into real-world distance. + +It uses Android Accessibility scroll events and processes all measurement data +locally on the device. + +ScrollMeter measures scroll distance, not the raw physical trajectory of a +finger across the touchscreen. + +## Status + +Project founded 2026-09-23. Phases 0–7 merged (`v0.0` … `v0.7`): bootstrap, measurement proof of concept +(GO/NO-GO gate), calibration, persistence with optional time in app, dashboard, history and apps, export and +settings, onboarding with the Play disclosure and English. Phase 8 (release hardening, `v0.8`) adds the signed +release build, the emulator matrix API 28–36, the battery protocol and the first release `v0.1.0`. Phase 9 +(`v0.9`, release `v0.2.0`) replaces the goal with a daily limit in colour and History + Apps with one +*Statistiky* screen (ADR-036). The app is for family phones, installed from the APK — not Google Play. +**Requires Android 10 (API 29) or newer** — Android 9 does not deliver the scroll events (ADR-033). +Manual on-phone checks still owed are listed under "Dluh ověření" in `handoff.md`. See `PLAN.md` (phases, +gates) and `handoff.md` (live state). + +## Repository map + +| Path | What it is | +|---|---| +| `docs/SPEC.md` | The product + technical specification, v1.0 (binding) | +| `PLAN.md` | Development plan by phases 0–8 with Definition of Done (Czech) | +| `handoff.md` | Live state: toolchain pins, phase status, decisions log (Czech) | +| `docs/measurement-model.md` | What scroll distance is, formulas, calibration, fallback, fling | +| `docs/accessibility-policy.md` | Which Accessibility API we use, what we never read, Play disclosure | +| `docs/play-listing.md` | Draft Play listing, Accessibility declaration answers, Data safety, privacy policy text, video scenario | +| `docs/accuracy-testing.md` | Test protocol and the device / app compatibility tables | +| `docs/architecture.md` | Event pipeline, package layout, threading, data model | +| `docs/measurement-decisions.md` | ADR log for non-obvious decisions | +| `docs/prompts/` | Kick-off prompts for coding sessions | +| `tools/` | `analyze_debug_csv.py` (per-app analysis of debug CSVs), `device_accuracy.py` (adb-driven accuracy tests), `accuracy.py` (ground truth CSV vs measured CSV → MAE, MAPE), `check_manifest_policy.py` / `check_release_apk.py` (what a build may ship), `build_release.sh` (signed release) | +| `CLAUDE.md` | Rules for coding agents working in this repo | + +## Build and run (available from Phase 0) + +```bash +./gradlew assembleDebug # build +./gradlew testDebugUnitTest # JVM unit tests +./gradlew lintDebug # Android lint +./gradlew installDebug # install on the connected phone +``` + +Requires JDK 21 for Gradle (pinned in `gradle/gradle-daemon-jvm.properties`) +and the Android SDK with platform 36 (`local.properties` → `sdk.dir`). + +## Release build (Phase 8) + +```bash +tools/build_release.sh # clean tree only: signed APK + AAB, both checked against the upload certificate, APK checked +``` + +Signing comes only from environment variables (`SIGNING_KEYSTORE_PATH`, `SIGNING_STORE_PASSWORD`, +`SIGNING_KEY_ALIAS`, `SIGNING_KEY_PASSWORD`, ADR-034); without them `assembleRelease` builds an unsigned APK +(CI does). The script takes the upload key from `~/.android-keystores/scrollmeter-upload.jks` and its password +from the macOS Keychain item `scrollmeter-upload-keystore` — neither is in the repository. Outputs: +`app/build/outputs/apk/release/app-release.apk` (what gets installed — the app is distributed as an APK to family +phones, not through Google Play) and `app/build/outputs/bundle/release/app-release.aab` (kept for a store, none planned). + +Release APKs are signed by `CN=ScrollMeter, O=Honza Hubka, C=CZ`, certificate SHA-256 +`04:6F:8C:D0:B0:73:23:F7:07:12:E1:12:53:CA:D7:FB:82:03:F2:68:C8:D8:10:53:78:3D:9C:1A:66:9C:0E:88` — +check a downloaded APK with `apksigner verify --print-certs app-release.apk`. + +## How to test the measurement POC (Phase 1) + +The debug build (`com.scrollmeter.app.debug`) adds two developer screens to the home screen: +**Debug měření** (the last 100 scroll events live) and **Testovací seznam** (our own list with an +exact ground truth). Release builds contain neither. + +1. **Install:** `./gradlew installDebug` with the phone connected over USB (USB debugging on). +2. **Enable the service** — either by hand: Settings → Accessibility → Downloaded / Installed apps → + *ScrollMeter — měření scrollování* → On; or over adb (POC only): + ```bash + ADB=~/Library/Android/sdk/platform-tools/adb + $ADB shell settings put secure enabled_accessibility_services com.scrollmeter.app.debug/com.scrollmeter.app.accessibility.ScrollAccessibilityService + $ADB shell settings put secure accessibility_enabled 1 + ``` + OnePlus / ColorOS refuses these writes until Developer options → **Zakázat sledování oprávnění** + (*Disable permission monitoring*, at the very bottom) is on. +3. **Check it runs:** open ScrollMeter — the card says *Měření je zapnuté* and the total since the + service started grows while you scroll anywhere. `adb shell dumpsys accessibility` lists the service + with `eventTypes=TYPE_VIEW_SCROLLED`. +4. **Own list with ground truth:** *Testovací seznam* → pick a surface (*View* = classic Android views, + *Column* = Compose `verticalScroll`, *Lazy* = Compose `LazyColumn`) → *Vynulovat* → scroll the list and + the carousel by hand. Each axis shows ground truth px, measured px and the error. *Lazy* is expected to + measure 0 (ADR-019). Automated version (Tests A–E of spec §36): + `python3 tools/device_accuracy.py --surface view,column,lazy --markdown`. +5. **Other apps:** *Debug měření* → *Vymazat* (the *v souboru* counter drops to 0) → go through the apps one + after another, 20–30 s each (slow scrolls, flings, horizontal carousels) — no need to come back in + between. Every event is written through to the phone's app-private storage, so the run survives the + system killing ScrollMeter (ColorOS does that under memory pressure; the service restarts by itself). + Apps behind a login screen (Instagram, TikTok, X) need an account to reach a feed. +6. **Collect and analyse** — no export needed; the analyser splits the run per app: + ```bash + $ADB exec-out run-as com.scrollmeter.app.debug cat files/debug/recording.csv > run.csv + python3 tools/analyze_debug_csv.py run.csv # per-app table: coverage, fallback, outliers, duplicates + $ADB logcat -s ScrollMeter:D # one line per event, live + ``` + *Export CSV* on the phone writes the same rows plus a device header (needed for the outlier-limit + column) to `/sdcard/Android/data/com.scrollmeter.app.debug/files/debug/` (`adb pull` that folder); + *Sdílet* sends it elsewhere. +7. **Switch the service off** when done: `$ADB shell settings delete secure enabled_accessibility_services` (an empty `put` fails with "Bad arguments") + or in Accessibility settings. + +## Calibration (Phase 2) + +Home → *Zkalibrovat displej* (or *Přesnost měření* → *Zkalibrovat platební kartou*). Hold the phone upright, +lay a payment card on the screen right of the blue vertical line with its top edge on the top line, and +move the bottom line to the card's bottom edge (slider, then − / + for single pixels) → *Uložit kalibraci*. +*Přesnost měření* then shows *Platební karta · 1 pixel = … mm* and the date. The card applies only to the +phone and display resolution it was made on (ADR-024); *Přeskočit – použít automatický odhad* goes back to +`xdpi`/`ydpi`. New calibration applies to new events only. + +Accuracy with the calibration in force: `python3 tools/device_accuracy.py --surface view,column --csv-out out/` +then `python3 tools/accuracy.py out/ground_truth.csv out/measured.csv`. The test list itself shows MAE / MAPE +over the runs of a series (*Vynulovat* closes a run, *Nová série* starts over). + +## Přehled and Statistiky (Phases 4, 5, 9) + +*Přehled* is the one main screen — no bottom bar; *Nastavení* sits behind the gear. The *Dnes* card shows +today's distance against the **daily limit** (500 m by default, or *Bez limitu*): green, orange from 70 %, red +over it, and always in words too ("Zbývá 80 m z limitu 500 m", "Překročeno o 120 m (limit 500 m)"). Below it +*Tento týden* and *Tento měsíc* with their total and average per day, the three apps scrolled most today and +one comparison ("To je přibližně délka jednoho běžeckého okruhu."). Every number is live — stored plus what +the service has not written yet. When the service is off, a red banner with *Zapnout měření* comes first. It +is not a competition: no goals, no records (ADR-036). + +Tapping *Dnes*, a week or a month opens **Statistiky**: *Den / Týden / Měsíc* with ‹ ›, for a week or month a +bar per day in its limit colour with the limit as a dashed line (tap a bar to open that day), and every app +of the period from the longest distance down, with the time in the app on the same row — "Chrome +1,21 km (3 h 40 min)". Apps with time but no scroll data (YouTube) show "— (2 h 15 min)" at the end. An app +opens its detail for that period: distance, share, time in app, scroll time, pace, a measurement-quality word +(never an accuracy percentage — ADR-029) and 30-day charts. Durations roll over from minutes to hours to days +("1 d 1 h 1 min"). Time in app needs Usage access; until it is granted a card offers it once (*Ukázat jak* → +a disclosure screen → Android settings), and the rows show no brackets. + +## Settings, export and notifications (Phase 6) + +*Nastavení* holds the service and Usage-access status, *Přesnost měření*, the daily limit (100 m – 5 km, a +custom 10 m – 100 km, or *Bez limitu*), *Vyloučené aplikace* (launcher, keyboard and System UI are suggested; an +excluded app disappears from every total, history and export and comes back when switched on again), units, +theme, the two opt-in notifications (over the limit, yesterday's summary — each at most once a day; on +Android 13+ the system asks for permission when one is switched on), *Exportovat CSV* (save `per_app.csv` / +`daily_summary.csv` through the system file picker, or share both), *Smazat všechna data* (optionally with the +settings and the card calibration), *Soukromí* and *O aplikaci* (version, device, the total measured since the first day); in debug builds also the +developer screens. +The CSV format is in ADR-031: comma separated, dot decimals, UTF-8 with BOM, an empty field means unknown. + +## Stored data and time in app (Phase 3) + +Distances are stored per day and app in an app-private Room database (`scrollmeter.db`) and survive app +restarts; Home shows *Dnes* from it (at most 10 s behind the live counter). Time in app is optional: grant +*Přístup k údajům o využití* to ScrollMeter in Android settings (on an emulator: +`adb shell appops set com.scrollmeter.app.debug GET_USAGE_STATS allow`) and open the app — it snapshots the +last days into `daily_app_usage`. Inspect a debug build's data with +`adb shell "run-as com.scrollmeter.app.debug sqlite3 databases/scrollmeter.db 'select * from daily_app_aggregate'"`. + +Note: `adb shell am force-stop` turns the accessibility service off (Android removes it from the enabled list); +turn it on again in Usnadnění. + +The debug CSV holds numbers and identifiers only (time, package, window id, view class, deltas, scroll +positions, distance, source, accepted/rejected) — never text from the screen. diff --git a/docs/img/onboarding-disclosure.png b/docs/img/onboarding-disclosure.png new file mode 100644 index 0000000..85d07e6 Binary files /dev/null and b/docs/img/onboarding-disclosure.png differ diff --git a/docs/img/prehled.png b/docs/img/prehled.png new file mode 100644 index 0000000..0146483 Binary files /dev/null and b/docs/img/prehled.png differ diff --git a/docs/img/soukromi.png b/docs/img/soukromi.png new file mode 100644 index 0000000..3c99296 Binary files /dev/null and b/docs/img/soukromi.png differ diff --git a/docs/img/statistiky.png b/docs/img/statistiky.png new file mode 100644 index 0000000..aeb405d Binary files /dev/null and b/docs/img/statistiky.png differ diff --git a/docs/play-listing.md b/docs/play-listing.md index e79de35..7155f52 100644 --- a/docs/play-listing.md +++ b/docs/play-listing.md @@ -150,7 +150,7 @@ signed with the upload key (ADR-034). The same commit's APK is the GitHub Releas What Honza does in Play Console, in this order: 1. Create the app (default language cs-CZ or en — open point in `handoff.md`), choose **Play App Signing** with Google-generated app signing key; upload `app-release.aab` to *Internal testing*. The upload key's certificate - (SHA-256 `04:6F:8C:D0:…:9C:0E:88`, full value in `README.md`) is registered by that first upload. + (SHA-256 `04:6F:8C:D0:…:9C:0E:88`, full value in `docs/development.md`) is registered by that first upload. 2. App content: privacy policy URL (text above — needs a public URL), Data safety (above), Accessibility API declaration with the video (above), `PACKAGE_USAGE_STATS` needs no form (ADR-021), content rating, target audience 16+ (above), ads: none. diff --git a/handoff.md b/handoff.md index 641e6a8..133ec90 100644 --- a/handoff.md +++ b/handoff.md @@ -6,9 +6,9 @@ ## Identita projektu - Lokální cesta: `/Users/hupcus/Documents/VIBE-CODE/SCROLLMETER` -- GitHub: [`hupcus/scrollmeter`](https://github.com/hupcus/scrollmeter) (privátní), založen 2026-09-23 v Phase 0 +- GitHub: [`hupcus/scrollmeter`](https://github.com/hupcus/scrollmeter) (**veřejný od 2026-09-28**, GPL-3.0), založen 2026-09-23 v Phase 0 - Package: `com.scrollmeter.app` (debug: `com.scrollmeter.app.debug`) -- Cíl (Honza, 2026-09-25): **aplikace pro rodinu**, instalace přes sideload APK; případně volně ke stažení na GitHubu (otevřené rozhodnutí). **Google Play není v plánu.** +- Cíl (Honza, 2026-09-25): **aplikace pro rodinu**, instalace přes sideload APK; od 2026-09-28 volně ke stažení z GitHub Releases (README = stránka ke stažení). **Google Play není v plánu.** ## Toolchain (závazný — ověřeno reálným buildem v Phase 0, 2026-09-23) @@ -466,9 +466,9 @@ Každý bod: co udělat, kdo, a co by špatný výsledek změnil. Pořadí = dop - [x] Výchozí jazyk: `values/` je čeština (D17) — pro rodinu správně; řešilo se jen kvůli zahraničnímu vydání na Play, které není v plánu (2026-09-25). - [x] Zásady ochrany soukromí s veřejnou URL — potřeboval je jen Google Play, který není v plánu (2026-09-25). Text zůstává v `docs/play-listing.md` a stejné informace ukazuje aplikace (Soukromí). - [x] Podpisový keystore pro release — Phase 8 (ADR-034): `~/.android-keystores/scrollmeter-upload.jks`, heslo v Klíčence, `tools/build_release.sh`. -- [ ] **Záloha upload keystoru** — Honza rozhodne kam (návrh: soubor do iCloud Drive › Klíče vedle záložního klíče Supabase, heslo zvlášť do správce hesel). Bez Google Play je klíč **jediná identita aplikace**: jeho ztráta = všichni v rodině musí aplikaci odinstalovat a přijdou o data (CSV export existuje, import ne). +- [ ] **Záloha upload keystoru** — Honza rozhodne kam (návrh: soubor zvlášť od hesla, heslo do správce hesel). Bez Google Play je klíč **jediná identita aplikace**: jeho ztráta = všichni v rodině musí aplikaci odinstalovat a přijdou o data (CSV export existuje, import ne). - [ ] **Ověření vývojáře Androidu (Google, globálně od 2027):** na certifikovaných telefonech půjde neověřená aplikace instalovat jen přes adb nebo „pokročilý postup“ (režim vývojáře, restart, 24 h čekání). Pro rodinu stačí **bezplatný účet „limited distribution“** v Android Developer Console: až 20 autorizovaných zařízení (párování QR kódem / odkazem se souhlasem na telefonu), bez dokladu totožnosti, potřebuje Google účet s dvoufázovým ověřením a platební profil (jméno, adresa); registrovat jde jen balíček, který Android ještě neviděl → `com.scrollmeter.app` zaregistrovat (Honza) před rokem 2027. Pro cizí lidi (veřejné stažení) by platilo plné ověření vývojáře. Zdroje: developer.android.com/developer-verification/guides/limited-distribution, android-developers.googleblog.com (03/2026). V ČR zatím beze změny (2026 jen BR, ID, SG, TH). -- [ ] **Veřejné stažení z GitHubu** — rozhodnutí Honzy: (a) zveřejnit celé repo (před tím audit historie na citlivé údaje), (b) samostatné veřejné repo jen s releasy (kód zůstane privátní), (c) nic — APK posílat rodině přímo. Veřejné releasy navíc umožní aktualizace přes Obtainium (aplikace sama nemá `INTERNET`, takže se aktualizovat neumí). +- [x] **Veřejné stažení z GitHubu** — Honza 2026-09-28 zvolil (a) „stejně jako detektor“: celé repo veřejné, GPL-3.0, české README pro uživatele. Původní varianty: (a) zveřejnit celé repo (před tím audit historie na citlivé údaje), (b) samostatné veřejné repo jen s releasy (kód zůstane privátní), (c) nic — APK posílat rodině přímo. Veřejné releasy navíc umožní aktualizace přes Obtainium (aplikace sama nemá `INTERNET`, takže se aktualizovat neumí). - [ ] **Android 9 (API 28)** — nepodporovaný od Phase 8 (ADR-033, minSdk 29). Vrátit by ho šlo jen s `typeWindowStateChanged` ve službě = změna tvrdého pravidla → jen s Honzovým souhlasem; doporučení: nechat (podíl Androidu 9 je malý a klesá). - [ ] Compose `Column` pomalé tahy podměřuje o 6–11 % (3 události na tah; MAPE přesto < 5 %). Hledat až s Compose lazy (ADR-019), stejný zdroj. - [ ] Ticker flushů (10 s) se po flushi po 50 událostech nerestartuje → při souvislém scrollu ~65 % zápisů navíc (115 místo ~70 za 10 min, každý ~0 ms). Zvážit až podle V8. @@ -476,6 +476,14 @@ Každý bod: co udělat, kdo, a co by špatný výsledek změnil. Pořadí = dop ## Log rozhodnutí (nejnovější nahoře) +### 2026-09-28 — veřejné repo a stránka ke stažení (Honza, Opus 5.5) +- Honza: ScrollMeter instalovatelný přímo z GitHubu „stejně jako detektor“ (`hupcus/detektor-mapy`) → varianta (a): repo veřejné, licence GPL-3.0 jako u detektoru. +- Před zveřejněním audit celé historie (všechny revize): žádná hesla, tokeny ani klíče; osobní údaje jen e-mail autora commitů a sériové číslo testovacího OnePlusu. Keystore a jeho heslo v gitu nikdy nebyly. +- `README.md` je česká stránka pro uživatele (co dělá / nedělá, instalace vč. „Omezeného nastavení“, oprávnění, bezpečnost); vývojářský obsah přesunut do `docs/development.md`. Screenshoty v `docs/img/` z emulátoru (release APK, reálně naměřená data). +- Release `v0.2.0` přepnut z prerelease na Latest, aby fungoval odkaz `releases/latest`. **Každý další release publikovat jako Latest** (ne prerelease), jinak odkaz v README ukáže starou verzi. +- Pro cizí lidi platí od 2027 plné ověření vývojáře Androidu (ne „limited distribution“) — README na to upozorňuje, rozhodnutí o registraci zůstává otevřené. + + ### 2026-09-25 — Phase 9 Statistiky + denní limit (Opus 5.5, návrh Fable 5.1) - Honza: období s rozpadem po aplikacích, čas na stejném řádku, „není to soutěž“ — cíl → limit se zelenou / oranžovou / červenou. Detail ADR-036. - Rozhodnuto samostatně (výchozí doporučení): žádná spodní lišta, Nastavení pod ozubeným kolem; limit 500 m zapnutý (kdo si v 0.1.0 nastavil cíl, má ho jako limit); oranžová od 70 %; týden / měsíc podle průměru na den; srovnání „Pro představu“ zůstává; oznámení o rekordu a gamifikace (SPEC §47) pryč.