[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n.kotlin\n/local.properties\n.idea\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "NeoWellbeingOverlay/.gitignore",
    "content": "overlay.apk.us\noverlay.apk.uz\n"
  },
  {
    "path": "NeoWellbeingOverlay/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<!--suppress ALL -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"org.eu.droid_ng.wellbeing.overlay\">\n    <overlay android:isStatic=\"true\" android:priority=\"9999\" android:targetPackage=\"android\"/>\n    <application android:hasCode=\"false\" android:label=\"Neo Wellbeing overlay\"/>\n</manifest>\n"
  },
  {
    "path": "NeoWellbeingOverlay/Makefile",
    "content": "KEY := android\nKEYSTORE := ~/.local/publish.keystore\nDEFAULT: overlay.apk\nclean:\n\trm -f overlay.apk overlay.apk.uz overlay.apk.us\n\noverlay.apk.us: res AndroidManifest.xml\n\taapt p -M AndroidManifest.xml -S res -I $$ANDROID_SDK_ROOT/platforms/android-29/android.jar -F overlay.apk.us\n\noverlay.apk.uz: overlay.apk.us\n\tjarsigner -keystore $(KEYSTORE) -signedjar overlay.apk.uz overlay.apk.us $(KEY)\n\noverlay.apk: overlay.apk.uz\n\tzipalign 4 overlay.apk.uz overlay.apk\n"
  },
  {
    "path": "NeoWellbeingOverlay/README",
    "content": "Creation process of overlay.apk:\n\n  make KEY=android KEYSTORE=my.keystore\n"
  },
  {
    "path": "NeoWellbeingOverlay/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"config_defaultWellbeingPackage\">org.eu.droid_ng.wellbeing</string>\n    <string name=\"config_systemWellbeing\">org.eu.droid_ng.wellbeing</string>\n</resources>\n"
  },
  {
    "path": "README.md",
    "content": "Work in progress. Will eat your cat.\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build"
  },
  {
    "path": "app/build.gradle.kts",
    "content": "import java.nio.file.Files\n\nplugins {\n\tid(\"com.android.application\")\n\tid(\"org.jetbrains.kotlin.android\")\n\tid(\"com.google.devtools.ksp\")\n}\n\nandroid {\n\tnamespace = \"org.eu.droid_ng.wellbeing\"\n\tcompileSdk = 35\n\n\tdefaultConfig {\n\t\tapplicationId = \"org.eu.droid_ng.wellbeing\"\n\t\tminSdk = 29\n\t\t//noinspection OldTargetApi TODO\n\t\ttargetSdk = 33\n\t\tversionCode = 4\n\t\tversionName = \"0.2.2\"\n\n\t\tjavaCompileOptions {\n\t\t\tannotationProcessorOptions {\n\t\t\t\targuments += mapOf(\"room.schemaLocation\" to \"$projectDir/schemas\")\n\t\t\t}\n\t\t}\n\t}\n\n\tsigningConfigs {\n\t\tregister(\"release\") {\n\t\t\tif (project.hasProperty(\"RELEASE_KEY_ALIAS\")) {\n\t\t\t\tstoreFile = file(project.properties[\"RELEASE_STORE_FILE\"].toString())\n\t\t\t\tstorePassword = project.properties[\"RELEASE_STORE_PASSWORD\"].toString()\n\t\t\t\tkeyAlias = project.properties[\"RELEASE_KEY_ALIAS\"].toString()\n\t\t\t\tkeyPassword = project.properties[\"RELEASE_KEY_PASSWORD\"].toString()\n\t\t\t}\n\t\t}\n\t}\n\n\tbuildTypes {\n\t\trelease {\n\t\t\tisMinifyEnabled = true\n\t\t\tsetProguardFiles(listOf(getDefaultProguardFile(\"proguard-android-optimize.txt\"), \"proguard-rules.pro\"))\n\t\t\tif (project.hasProperty(\"RELEASE_KEY_ALIAS\")) {\n\t\t\t\tsigningConfig = signingConfigs.getByName(\"release\")\n\t\t\t} else {\n\t\t\t\tlogger.warn(\"Using debug signing configs!\")\n\t\t\t\tsigningConfig = signingConfigs.getByName(\"debug\")\n\t\t\t}\n\t\t}\n\t\tdebug {\n\t\t\tif (project.hasProperty(\"RELEASE_KEY_ALIAS\")) {\n\t\t\t\tsigningConfig = signingConfigs.getByName(\"release\")\n\t\t\t} else {\n\t\t\t\tlogger.warn(\"Using debug signing configs!\")\n\t\t\t\tsigningConfig = signingConfigs.getByName(\"debug\")\n\t\t\t}\n\t\t}\n\t}\n\n\tsourceSets {\n\t\tgetByName(\"main\") {\n\t\t\tjava.srcDirs(\"src/main/java_magisk\")\n\t\t\tkotlin.srcDirs(\"src/main/java_magisk\")\n\t\t}\n\t}\n\n\tcompileOptions {\n\t\tsourceCompatibility = JavaVersion.VERSION_17\n\t\ttargetCompatibility = JavaVersion.VERSION_17\n\t}\n\n\tkotlin {\n\t\tjvmToolchain(17)\n\t}\n}\n\nksp {\n\targ(\"room.schemaLocation\", \"$projectDir/schemas\")\n}\n\ndependencies {\n\timplementation(project(\":shared\"))\n\tval roomVersion = \"2.4.0-alpha05\" // Android 13 (https://cs.android.com/android/platform/superproject/+/android-13.0.0_r31:prebuilts/sdk/current/androidx/m2repository/androidx/room/room-runtime/;bpv=1)\n\t//noinspection GradleDependency\n\timplementation(\"androidx.room:room-runtime:$roomVersion\")\n\t//noinspection GradleDependency\n\tannotationProcessor(\"androidx.room:room-compiler:$roomVersion\")\n\t//noinspection GradleDependency\n\tksp(\"androidx.room:room-compiler:$roomVersion\")\n\n\timplementation(\"androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4\")\n\n\timplementation(\"androidx.recyclerview:recyclerview:1.3.2\")\n\timplementation(\"androidx.constraintlayout:constraintlayout:2.1.4\")\n\timplementation(\"androidx.preference:preference-ktx:1.2.1\")\n\timplementation(\"androidx.appcompat:appcompat:1.7.0\")\n\timplementation(\"com.google.android.material:material:1.12.0\")\n\n\timplementation(\"com.github.AppDevNext:AndroidChart:3.1.0.15\")\n}\n\nval outDir = rootProject.layout.buildDirectory.asFile.get()\nval magiskDir = File(\"$outDir/magisk_module\")\nval zipName = \"NeoWellbeing-${android.defaultConfig.versionName}.zip\"\nval zipFile = File(outDir, zipName)\nval magiskModuleProp = mapOf(\n\t\"id\" to \"neo_wellbeing\",\n\t\"name\" to \"Neo Wellbeing systemless\",\n\t\"version\" to android.defaultConfig.versionName,\n\t\"versionCode\" to android.defaultConfig.versionCode,\n\t\"minApi\" to android.defaultConfig.minSdk,\n\t\"support\" to \"https://github.com/NeoApplications/Neo-Wellbeing\",\n\t\"config\" to \"org.eu.droid_ng.wellbeing\",\n\t\"author\" to \"nift4\",\n\t\"description\" to \"Neo Wellbeing is an open source reimplementation of Wellbeing\"\n)\n\ntasks.register(\"assembleMagiskModule\", Task::class) {\n\tval root = rootDir\n\tval magisk = magiskDir\n\tvar modulePropText = \"\"\n\tval appApk = file(\"$root/app/build/outputs/apk/release/app-release.apk\")\n\tval frameworkApk = file(\"$root/framework/build/outputs/apk/release/framework-release.apk\")\n\tmagiskModuleProp.forEach { (k, v) -> modulePropText += \"$k=$v\\n\" }\n\n\tdependsOn(\":app:assembleRelease\")\n\tdependsOn(\":framework:assembleRelease\")\n\tdoLast {\n\t\tmagisk.deleteRecursively()\n\t\tmagisk.mkdirs()\n\t\tFile(\"$magisk/module.prop\").writeText(modulePropText)\n\t\tFile(\"${magisk.path}/system/priv-app/NeoWellbeing\").mkdirs()\n\t\tFiles.copy(appApk.toPath(),\n\t\t\t\tFile(\"${magisk.path}/system/priv-app/NeoWellbeing/NeoWellbeing.apk\").toPath())\n\t\tFile(\"${magisk.path}/system/priv-app/NeoWellbeingFramework\").mkdirs()\n\t\tFiles.copy(frameworkApk.toPath(),\n\t\t\t\tFile(\"${magisk.path}/system/priv-app/NeoWellbeingFramework/NeoWellbeingFramework.apk\").toPath())\n\t\tFile(\"${magisk.path}/system/product/overlay/NeoWellbeingOverlay\").mkdirs()\n\t\tFiles.copy(File(\"$root/NeoWellbeingOverlay/overlay.apk\").toPath(),\n\t\t\t\tFile(\"${magisk.path}/system/product/overlay/NeoWellbeingOverlay/NeoWellbeingOverlay.apk\").toPath())\n\t\tFile(\"${magisk.path}/system/etc/permissions\").mkdirs()\n\t\tFiles.copy(File(\"$root/app/src/main/privapp-permissions-wellbeing.xml\").toPath(),\n\t\t\t\tFile(\"${magisk.path}/system/etc/permissions/privapp-permissions-wellbeing.xml\").toPath())\n\t\tFile(\"${magisk.path}/META-INF/com/google/android\").mkdirs()\n\t\tFile(\"${magisk.path}/META-INF/com/google/android/updater-script\").writeText(\"#MAGISK\")\n\t\tFiles.copy(File(\"$root/app/update-binary\").toPath(),\n\t\t\t\tFile(\"${magisk.path}/META-INF/com/google/android/update-binary\").toPath())\n\t\tFiles.copy(File(\"$root/app/customize.sh\").toPath(),\n\t\t\t\tFile(\"${magisk.path}/customize.sh\").toPath())\n\t}\n}\n\ntasks.register(\"zipMagiskModule\", Zip::class) {\n\tfrom(magiskDir)\n\tarchiveFileName = zipName\n\tdestinationDirectory = outDir\n\tdependsOn(\":app:assembleMagiskModule\")\n}\n\ntasks.register(\"pushMagiskModule\", Exec::class) {\n\tcommandLine(\"adb\", \"push\", zipFile.absolutePath, \"/data/local/tmp/$zipName\")\n\tdependsOn(\":app:zipMagiskModule\")\n}\n\ntasks.register(\"testMagiskModule\", Exec::class) {\n\tsetIgnoreExitValue(true)\n\tcommandLine(\"adb\", \"shell\", \"su\", \"-c\",\n\t\t\t\"magisk --install-module /data/local/tmp/\" + zipName +\n\t\t\t\t\t\" && (/system/bin/svc power reboot || /system/bin/reboot)\")\n\tdependsOn(\":app:pushMagiskModule\")\n}\n"
  },
  {
    "path": "app/customize.sh",
    "content": "#!/bin/sh\n\nif [ \"$API\" -lt 29 ]; then\n  abort \"! Neo Wellbeing requires Android 10 or later\"\nfi\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n-dontobfuscate"
  },
  {
    "path": "app/schemas/org.eu.droid_ng.wellbeing.shared.StatDb/1.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"cbf447b404076250e80614e02b0d462e\",\n    \"entities\": [\n      {\n        \"tableName\": \"StatEntry\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` INTEGER NOT NULL, `unit` TEXT NOT NULL, `type` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`date`, `unit`, `type`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"date\",\n            \"columnName\": \"date\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"unit\",\n            \"columnName\": \"unit\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"count\",\n            \"columnName\": \"count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"date\",\n            \"unit\",\n            \"type\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cbf447b404076250e80614e02b0d462e')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/src/main/Android.bp",
    "content": "android_app {\n    name: \"NeoWellbeing\",\n    defaults: [\"platform_app_defaults\"],\n    static_libs: [\n        \"NeoWellbeing-shared\",\n        \"androidx.annotation_annotation\",\n        \"androidx.core_core\",\n        \"androidx.recyclerview_recyclerview\",\n        \"androidx-constraintlayout_constraintlayout\",\n        \"androidx.lifecycle_lifecycle-runtime\",\n        \"androidx.preference_preference\",\n        \"androidx.recyclerview_recyclerview\",\n        \"androidx.preference_preference\",\n        \"androidx.appcompat_appcompat\",\n        \"com.google.android.material_material\",\n    ], //TODO: needs rework\n    resource_dirs: [\"res\"],\n\n    srcs: [\n        \"java/**/*.java\",\n        \"java/**/*.kt\",\n    ],\n\n    platform_apis: true,\n    privileged: true,\n    certificate: \"platform\",\n    required: [\"privapp-permissions-wellbeing.xml\"],\n\n}\n\nprebuilt_etc {\n    name: \"privapp-permissions-wellbeing.xml\",\n\n    src: \"privapp-permissions-wellbeing.xml\",\n    sub_dir: \"permissions\",\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-feature\n        android:name=\"android.hardware.telephony\"\n        android:required=\"false\" />\n\n    <uses-permission\n        android:name=\"android.permission.SUSPEND_APPS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission\n        android:name=\"android.permission.SYSTEM_APPLICATION_OVERLAY\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n    <uses-permission\n        android:name=\"android.permission.PACKAGE_USAGE_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.OBSERVE_APP_USAGE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CONTROL_DISPLAY_SATURATION\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_SECURE_SETTINGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.ACCESS_INSTANT_APPS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INTERACT_ACROSS_PROFILES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.START_ACTIVITIES_FROM_BACKGROUND\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.SCHEDULE_EXACT_ALARM\" />\n    <uses-permission\n        android:name=\"android.permission.MODIFY_PHONE_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MODIFY_QUIET_MODE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.READ_DREAM_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_DREAM_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.READ_WALLPAPER_INTERNAL\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.SET_WALLPAPER_COMPONENT\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.SET_WALLPAPER\" />\n    <uses-permission\n        android:name=\"android.permission.SET_WALLPAPER_DIM_AMOUNT\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.GET_PACKAGE_SIZE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NOTIFICATION_POLICY\" />\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n    <uses-permission\n        android:name=\"android.permission.QUERY_ALL_PACKAGES\"\n        tools:ignore=\"QueryAllPackagesPermission\" />\n    <uses-permission\n        android:name=\"android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_ROLE_HOLDERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.REAL_GET_TASKS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.START_TASKS_FROM_RECENTS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MODIFY_DAY_NIGHT_MODE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.ACCESS_AMBIENT_CONTEXT_EVENT\" />\n    <uses-permission\n        android:name=\"android.permission.START_CROSS_PROFILE_ACTIVITIES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.USE_EXACT_ALARM\" />\n    <uses-permission android:name=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\" />\n\n    <queries>\n        <package android:name=\"org.eu.droid_ng.wellbeing.framework\" />\n\n        <intent>\n            <action android:name=\"android.intent.action.MAIN\" />\n\n            <category android:name=\"android.intent.category.HOME\" />\n        </intent>\n        <intent>\n            <action android:name=\"android.intent.action.DIAL\" />\n\n            <category android:name=\"android.intent.category.DEFAULT\" />\n        </intent>\n    </queries>\n\n    <application\n        android:name=\".Wellbeing\"\n        android:allowBackup=\"true\"\n        android:dataExtractionRules=\"@xml/data_extraction_rules\"\n        android:forceQueryable=\"true\"\n        android:fullBackupContent=\"@xml/backup_rules\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:testOnly=\"false\"\n        android:theme=\"@style/AppTheme\"\n        tools:targetApi=\"s\">\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.MONKEY\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.android.apps.wellbeing.action.HOME\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n        <!-- Use activity-alias for launcher activity to allow easy enable/disable -->\n        <activity-alias\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:targetActivity=\".ui.MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity-alias>\n        <!-- Use activity-alias for settings activity to allow easy enable/disable -->\n        <activity-alias\n            android:name=\".SettingsActivity\"\n            android:exported=\"true\"\n            android:targetActivity=\".ui.MainActivity\">\n            <intent-filter>\n                <action android:name=\"com.android.settings.action.IA_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"com.android.settings.category\"\n                android:value=\"com.android.settings.category.ia.homepage\" />\n            <meta-data\n                android:name=\"com.android.settings.summary\"\n                android:resource=\"@string/setting_desc\" />\n            <meta-data\n                android:name=\"com.android.settings.title\"\n                android:resource=\"@string/app_name\" />\n            <meta-data\n                android:name=\"com.android.settings.icon\"\n                android:resource=\"@drawable/ic_settings\" />\n            <meta-data\n                android:name=\"com.android.settings.order\"\n                android:value=\"1\" />\n            <meta-data\n                android:name=\"com.android.settings.bg.argb\"\n                android:value=\"-16725933\" />\n            <meta-data\n                android:name=\"com.android.settings.keyhint\"\n                android:value=\"neo_wellbeing\" />\n        </activity-alias>\n\n        <activity\n            android:name=\".ui.DashboardActivity\"\n            android:exported=\"false\"\n            android:label=\"@string/dashboard\" />\n        <activity\n            android:name=\".prefs.FocusModeActivity\"\n            android:exported=\"false\"\n            android:label=\"@string/focus_mode\" />\n        <activity\n            android:name=\".prefs.BedtimeMode\"\n            android:exported=\"false\"\n            android:label=\"@string/bedtime_mode\" />\n        <activity\n            android:name=\".prefs.AppTimers\"\n            android:exported=\"false\"\n            android:label=\"@string/app_timers\" />\n        <activity\n            android:name=\".prefs.ManualSuspendActivity\"\n            android:exported=\"false\"\n            android:label=\"@string/manually\" />\n        <activity\n            android:name=\".prefs.SettingsActivity\"\n            android:exported=\"false\"\n            android:label=\"@string/title_activity_settings\" />\n\n        <activity\n            android:name=\".prefs.ScheduleActivity\"\n            android:exported=\"false\"\n            android:label=\"@string/schedule\" />\n        <activity\n            android:name=\".ui.ShowSuspendedAppDetails\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/dialog_btn_settings\"\n            android:permission=\"android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS\"\n            android:taskAffinity=\"\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SHOW_SUSPENDED_APP_DETAILS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".ui.TakeBreakDialogActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/focus_mode_break\"\n            android:taskAffinity=\"\" />\n\n        <receiver\n            android:name=\".widget.ScreenTimeAppWidget\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"org.eu.droid_ng.wellbeing.APPWIDGET_UPDATE\" /> <!-- for manually updating -->\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/appwidget_screen_time\" />\n        </receiver>\n\n        <receiver\n            android:name=\".broadcast.ManuallyUnsuspendBroadcastReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\".broadcast.BootReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\".broadcast.NextAlarmChangedReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.app.action.NEXT_ALARM_CLOCK_CHANGED\" />\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\".broadcast.AppTimersBroadcastReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\" />\n        <receiver\n            android:name=\".broadcast.NotificationBroadcastReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\" />\n        <receiver\n            android:name=\".broadcast.AlarmFiresBroadcastReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\".lib.FocusModeQSTile\"\n            android:exported=\"true\"\n            android:icon=\"@drawable/outline_badge_24\"\n            android:label=\"@string/focus_mode\"\n            android:permission=\"android.permission.BIND_QUICK_SETTINGS_TILE\">\n            <intent-filter>\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.service.quicksettings.ACTIVE_TILE\"\n                android:value=\"true\" />\n            <meta-data\n                android:name=\"android.service.quicksettings.TOGGLEABLE_TILE\"\n                android:value=\"true\" />\n        </service>\n        <service\n            android:name=\".lib.BedtimeModeQSTile\"\n            android:exported=\"true\"\n            android:icon=\"@drawable/baseline_bedtime_24\"\n            android:label=\"@string/bedtime_mode\"\n            android:permission=\"android.permission.BIND_QUICK_SETTINGS_TILE\">\n            <intent-filter>\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.service.quicksettings.ACTIVE_TILE\"\n                android:value=\"true\" />\n            <meta-data\n                android:name=\"android.service.quicksettings.TOGGLEABLE_TILE\"\n                android:value=\"true\" />\n        </service>\n        <service\n            android:name=\".lib.WellbeingStateHost\"\n            android:enabled=\"true\"\n            android:exported=\"false\" />\n        <!-- to-do: On A13, implement com.google.android.apps.wellbeing.action.ACTION_WIND_DOWN_STATE_CHANGED -->\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/Wellbeing.kt",
    "content": "package org.eu.droid_ng.wellbeing\n\nimport android.app.Application\nimport org.eu.droid_ng.wellbeing.shared.BugUtils\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport kotlin.system.exitProcess\n\nclass Wellbeing : Application() {\n\tcompanion object {\n\t\tprivate lateinit var application: Wellbeing\n\n\t\tfun getService(): WellbeingService {\n\t\t\treturn application.getServiceInternal()\n\t\t}\n\t}\n\n\tprivate lateinit var service: WellbeingService\n\n\toverride fun onCreate() {\n\t\tsuper.onCreate()\n\t\tapplication = this\n\t\tBugUtils.maybeInit(this)\n\t\tThread.setDefaultUncaughtExceptionHandler { _, paramThrowable ->\n\t\t\tBugUtils.get()?.onBugAdded(paramThrowable, System.currentTimeMillis())\n\t\t\texitProcess(2)\n\t\t}\n\n\t\tservice = WellbeingService(this)\n\t}\n\n\tprivate fun getServiceInternal(): WellbeingService {\n\t\treturn service\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/AlarmFiresBroadcastReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\n\nclass AlarmFiresBroadcastReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context?, intent: Intent?) {\n\t\tintent?.identifier?.let { WellbeingService.get().onAlarmFired(it) }\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/AppTimersBroadcastReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\n\nclass AppTimersBroadcastReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent) {\n\t\t// Looks weird, but we don't want to crash if someone feeds us junk\n\t\tintent.getStringExtra(\"uniqueObserverId\")?.let {\n\t\t\tWellbeingService.get().onAppTimerExpired(\n\t\t\t\tintent.getIntExtra(\"observerId\", -1),\n\t\t\t\tit\n\t\t\t)\n\t\t}\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/BootReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\n\nclass BootReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent) {\n\t\tif (\"android.intent.action.BOOT_COMPLETED\" != intent.action) {\n\t\t\t/* Make sure no one is trying to fool us */\n\t\t\treturn\n\t\t}\n\t\tWellbeingService.get().onBootCompleted()\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/ManuallyUnsuspendBroadcastReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.widget.Toast\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\n\nclass ManuallyUnsuspendBroadcastReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent) {\n\t\tif (\"android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY\" != intent.action) {\n\t\t\t/* Make sure no one is trying to fool us */\n\t\t\treturn\n\t\t}\n\t\tval packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)\n\t\tif (packageName == null) {\n\t\t\t/* Make sure we have a package name */\n\t\t\tToast.makeText(\n\t\t\t\tcontext,\n\t\t\t\t\"Assertion failure (0xAC): packageName is null. Please report this to the developers!\",\n\t\t\t\tToast.LENGTH_LONG\n\t\t\t).show()\n\t\t\tBUG(\"packageName == null (0xAC)\")\n\t\t\treturn\n\t\t}\n\t\tWellbeingService.get().onManuallyUnsuspended(packageName)\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/NextAlarmChangedReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport org.eu.droid_ng.wellbeing.lib.AlarmCoordinator\n\nclass NextAlarmChangedReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent?) {\n\t\tif (\"android.app.action.NEXT_ALARM_CLOCK_CHANGED\" != intent?.action) {\n\t\t\t/* Make sure no one is trying to fool us */\n\t\t\treturn\n\t\t}\n\t\tAlarmCoordinator(context).updateState()\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/broadcast/NotificationBroadcastReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.broadcast\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\n\nclass NotificationBroadcastReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent) {\n\t\t// Looks weird, but we don't want to crash if someone feeds us junk\n\t\tintent.action?.let { WellbeingService.get().onNotificationActionClick(it) }\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ext.kt",
    "content": "package org.eu.droid_ng.wellbeing\n\nfun String.Companion.join(delimiter: String, strings: Iterable<CharSequence?>): String {\n\treturn java.lang.String.join(delimiter, strings)\n}\n\nfun String.Companion.join(delimiter: String, strings: Array<String?>): String {\n\treturn String.join(delimiter, strings.toList())\n}\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/AlarmCoordinator.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.app.AlarmManager\nimport android.content.Context\nimport java.time.Instant\nimport java.time.LocalDateTime\nimport java.time.ZoneId\n\nclass AlarmCoordinator(private val context: Context) {\n\tfun updateState() {\n\t\tval am = context.getSystemService(AlarmManager::class.java)\n\t\tval next = am.nextAlarmClock\n\t\tif (next == null) {\n\t\t\tScheduleUtils.dropAlarm(context, \"alc\", am)\n\t\t} else {\n\t\t\tScheduleUtils.setAlarm(context, \"alc\", LocalDateTime.ofInstant(Instant.ofEpochMilli(next.triggerTime), ZoneId.systemDefault()), am)\n\t\t}\n\t}\n\n\tfun fired() {\n\t\tWellbeingService.get().doTrigger(true) { it is TimeChargerTriggerCondition && it.endOnAlarm }\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/QSTiles.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.service.quicksettings.Tile.STATE_ACTIVE\nimport android.service.quicksettings.Tile.STATE_INACTIVE\nimport android.service.quicksettings.TileService\nimport org.eu.droid_ng.wellbeing.R\n\nclass FocusModeQSTile : TileService() {\n\toverride fun onStartListening() {\n\t\tsuper.onStartListening()\n\t\tval tw = WellbeingService.get()\n\t\tval state = tw.getState()\n\n\t\tval tile = qsTile\n\t\ttile.state = if (state.isFocusModeEnabled()) STATE_ACTIVE else STATE_INACTIVE\n\t\ttile.subtitle = getString(if (state.isFocusModeEnabled()) R.string.on else R.string.off)\n\t\ttile.updateTile()\n\t}\n\n\toverride fun onClick() {\n\t\tsuper.onClick()\n\n\t\tval tw = WellbeingService.get()\n\t\tval state = tw.getState()\n\t\tif (state.isFocusModeEnabled())\n\t\t\ttw.disableFocusMode()\n\t\telse\n\t\t\ttw.enableFocusMode()\n\t}\n}\n\nclass BedtimeModeQSTile : TileService() {\n\toverride fun onStartListening() {\n\t\tsuper.onStartListening()\n\t\tval tw = WellbeingService.get()\n\t\tval state = tw.getState()\n\n\t\tval tile = qsTile\n\t\ttile.state = if (state.isBedtimeModeEnabled()) STATE_ACTIVE else STATE_INACTIVE\n\t\ttile.subtitle = getString(if (state.isBedtimeModeEnabled()) R.string.on else R.string.off)\n\t\ttile.updateTile()\n\t}\n\n\toverride fun onClick() {\n\t\tsuper.onClick()\n\n\t\tval tw = WellbeingService.get()\n\t\tval state = tw.getState()\n\t\ttw.setBedtimeMode(!state.isBedtimeModeEnabled())\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/ScheduleUtils.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.app.AlarmManager\nimport android.app.PendingIntent\nimport android.appwidget.AppWidgetManager\nimport android.appwidget.AppWidgetProvider\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.os.BatteryManager\nimport android.os.Handler\nimport org.eu.droid_ng.wellbeing.broadcast.AlarmFiresBroadcastReceiver\nimport java.time.DayOfWeek\nimport java.time.LocalDateTime\nimport java.time.ZoneId\nimport java.time.temporal.TemporalAdjusters\n\nclass ScheduleUtils {\n\tcompanion object {\n\t\tprivate fun getPintentForId(context: Context, id: String): PendingIntent {\n\t\t\treturn PendingIntent.getBroadcast(\n\t\t\t\tcontext, 0,\n\t\t\t\tIntent(context, AlarmFiresBroadcastReceiver::class.java).addFlags(Intent.FLAG_RECEIVER_FOREGROUND).setIdentifier(id),\n\t\t\t\tPendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT\n\t\t\t)\n\t\t}\n\n\t\tfun dropAlarm(context: Context, id: String, alarmManager: AlarmManager? = null, pintent: PendingIntent? = null) {\n\t\t\t(alarmManager ?: context.getSystemService(AlarmManager::class.java))\n\t\t\t\t.cancel(pintent ?: getPintentForId(context, id))\n\t\t}\n\n\t\tfun setAlarm(context: Context, id: String, time: LocalDateTime, alarmManager: AlarmManager? = null, pintent: PendingIntent? = null) {\n\t\t\tval am = alarmManager ?: context.getSystemService(AlarmManager::class.java)\n\t\t\tval pi = pintent ?: getPintentForId(context, id)\n\t\t\tdropAlarm(context, id, am, pi)\n\t\t\tam.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,\n\t\t\t\ttime.withSecond(0).atZone(ZoneId.systemDefault()).toEpochSecond() * 1000L, pi)\n\t\t}\n\n\t\tfun ensureWidgetAlarmSet(context: Context, handler: Handler, intervalSec: Long, widget: Class<out AppWidgetProvider>) {\n\t\t\tval millis = intervalSec * 1000L\n\t\t\tval am = context.getSystemService(AlarmManager::class.java) as AlarmManager\n\t\t\tval awm = AppWidgetManager.getInstance(context)\n\t\t\tval rawIntent = Intent(context, widget)\n\t\t\trawIntent.action = \"org.eu.droid_ng.wellbeing.APPWIDGET_UPDATE\"\n\t\t\tval intent = PendingIntent.getBroadcast(context, widget.hashCode(), rawIntent, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE)\n\t\t\tif (awm.getAppWidgetIds(ComponentName(context, widget)).isNotEmpty()) { /* widget exists */\n\t\t\t\t// inexact + no wakeup + repeating (=android batching) alarm to save battery\n\t\t\t\tam.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 0, millis, intent)\n\t\t\t\t// handler for while wellbeing running\n\t\t\t\thandler.postDelayed(object : Runnable {\n\t\t\t\t\toverride fun run() {\n\t\t\t\t\t\tcontext.sendBroadcast(rawIntent)\n\t\t\t\t\t\thandler.postDelayed(this, millis)\n\t\t\t\t\t}\n\t\t\t\t}, millis)\n\t\t\t} else {\n\t\t\t\tam.cancel(intent)\n\t\t\t}\n\t\t}\n\n\t\tfun ensureStatProcessorAlarmSet(context: Context, handler: Handler) {\n\t\t\tval am = context.getSystemService(AlarmManager::class.java) as AlarmManager\n\t\t\tval millis = 12 * 60 * 60 * 1000L // 12 hours\n\t\t\tval intent = getPintentForId(context, \"__STATS\")\n\t\t\t// inexact + no wakeup + repeating (=android batching) alarm to save battery\n\t\t\tam.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 0, millis, intent)\n\t\t\t// handler for while wellbeing running\n\t\t\thandler.postDelayed(object : Runnable {\n\t\t\t\toverride fun run() {\n\t\t\t\t\tWellbeingService.get().bgHandler.post { WellbeingService.get().onProcessStats(true) }\n\t\t\t\t\thandler.postDelayed(this, millis)\n\t\t\t\t}\n\t\t\t}, millis)\n\t\t}\n\t}\n}\n\ninterface Trigger {\n\tval id: String\n\tval iid: String\n\tval enabled: Boolean\n\tfun setup(applicationContext: Context)\n\tfun dispose(applicationContext: Context)\n}\n\ninterface Condition {\n\tval id: String\n\tfun isFulfilled(applicationContext: Context): Boolean\n}\n\nclass TimeChargerTriggerCondition(\n\toverride val id: String,\n\toverride val iid: String,\n\toverride val enabled: Boolean,\n\tval startHour: Int,\n\tval startMinute: Int,\n\tval endHour: Int,\n\tval endMinute: Int,\n\tval weekdays: BooleanArray, // length = 7, 0 = monday, 6 = sunday\n\tval needCharger: Boolean,\n\tval endOnAlarm: Boolean\n) : Trigger, Condition {\n\toverride fun setup(applicationContext: Context) {\n\t\tif (!weekdays.any { it }) return // bail if no weekday is enabled\n\t\tif (!enabled) return\n\t\tval now = LocalDateTime.now().withNano(0)\n\t\tval cwd = if (!weekdays[now.dayOfWeek.ordinal]) {\n\t\t\tval offset = now.dayOfWeek.ordinal\n\t\t\tvar r = now\n\t\t\tfor (i in 0..6) {\n\t\t\t\tval j = (i + offset) % 7\n\t\t\t\tif (weekdays[j]) {\n\t\t\t\t\tr = now.with(TemporalAdjusters.next(DayOfWeek.of(j + 1)))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (r == now) {\n\t\t\t\tthrow IllegalStateException(\"this cannot happen, r == now\")\n\t\t\t}\n\t\t\tr\n\t\t} else now\n\t\tvar offset = cwd.dayOfWeek.ordinal\n\t\tvar nwd = cwd\n\t\tfor (i in 1..7) {\n\t\t\tval j = (i + offset) % 7\n\t\t\tif (weekdays[j]) {\n\t\t\t\tnwd = cwd.with(TemporalAdjusters.next(DayOfWeek.of(j + 1)))\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (nwd == cwd) {\n\t\t\tthrow IllegalStateException(\"this cannot happen, nwd == cwd\")\n\t\t}\n\t\tval start = cwd.withSecond(0).withHour(startHour).withMinute(startMinute).let {\n\t\t\tif (now.isEqual(it) || now.isAfter(it)) {\n\t\t\t\tnwd.withSecond(0).withHour(startHour).withMinute(startMinute)\n\t\t\t} else {\n\t\t\t\tit\n\t\t\t}\n\t\t}\n\t\tnwd = start\n\t\toffset = start.dayOfWeek.ordinal\n\t\tfor (i in 1..7) {\n\t\t\tval j = (i + offset) % 7\n\t\t\tif (weekdays[j]) {\n\t\t\t\tnwd = start.with(TemporalAdjusters.next(DayOfWeek.of(j + 1)))\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (nwd == start) {\n\t\t\tthrow IllegalStateException(\"this cannot happen, nwd == start\")\n\t\t}\n\t\tval end = cwd.withSecond(0).withHour(endHour).withMinute(endMinute).let {\n\t\t\tif (now.isEqual(it) || now.isAfter(it)) {\n\t\t\t\tnwd.withSecond(0).withHour(endHour).withMinute(endMinute)\n\t\t\t} else {\n\t\t\t\tit\n\t\t\t}\n\t\t}\n\t\tScheduleUtils.setAlarm(applicationContext, iid, start)\n\t\tScheduleUtils.setAlarm(applicationContext, \"expire::$iid\", end)\n\t}\n\n\toverride fun dispose(applicationContext: Context) {\n\t\tScheduleUtils.dropAlarm(applicationContext, iid)\n\t\tScheduleUtils.dropAlarm(applicationContext, \"expire::$iid\")\n\t}\n\n\toverride fun isFulfilled(applicationContext: Context): Boolean {\n\t\tval now = LocalDateTime.now().withNano(0)\n\t\treturn (enabled && weekdays[now.dayOfWeek.ordinal] && run {\n\t\t\tval end = now.withSecond(0).withHour(endHour).withMinute(endMinute)\n\t\t\tval start = now.withSecond(0).withHour(startHour).withMinute(startMinute).let {\n\t\t\t\tif (it.isAfter(end)) {\n\t\t\t\t\tit.minusDays(1)\n\t\t\t\t} else {\n\t\t\t\t\tit\n\t\t\t\t}\n\t\t\t}\n\t\t\t(now.isAfter(start) || now.isEqual(start)) && now.isBefore(end)\n\t\t}) && (!needCharger || run {\n\t\t\tval batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { applicationContext.registerReceiver(null, it) }\n\n\t\t\tval chargePlug: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) ?: -1\n\t\t\tchargePlug == BatteryManager.BATTERY_PLUGGED_USB ||\n\t\t\t\t\tchargePlug == BatteryManager.BATTERY_PLUGGED_AC\n\t\t})\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/State.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nclass State(private val value: Int) {\n\tcompanion object {\n\t\t/* Update of State (partially) failed */\n\t\tconst val STATE_UPDATE_FAILURE = 1\n\t\t/* Focus mode currently: Enabled (also set if break is taken at the moment) */\n\t\tconst val STATE_FOCUS_MODE_ENABLED = 2\n\t\t/* Focus mode currently: Break (Global) */\n\t\tconst val STATE_FOCUS_MODE_GLOBAL_BREAK = 4\n\t\t/* Focus mode currently: Break (Per-App) */\n\t\tconst val STATE_FOCUS_MODE_APP_BREAK = 8\n\t\t/* Manual suspension */\n\t\tconst val STATE_MANUAL_SUSPEND = 16\n\t\t/* App timer set */\n\t\tconst val STATE_APP_TIMER_SET = 32\n\t\t/* App timer expired */\n\t\tconst val STATE_APP_TIMER_EXPIRED = 64\n\t\t/* App timer break */\n\t\tconst val STATE_APP_TIMER_BREAK = 128\n\t\t/* Bedtime mode enabled */\n\t\tconst val STATE_BED_MODE = 256\n\t}\n\n\tprivate fun isPresent(bitmask: Int): Boolean {\n\t\treturn (value and bitmask) > 0\n\t}\n\n\tfun toInt(): Int {\n\t\treturn value\n\t}\n\n\tfun hasUpdateFailed(): Boolean {\n\t\treturn isPresent(STATE_UPDATE_FAILURE)\n\t}\n\n\tfun isFocusModeEnabled(): Boolean {\n\t\treturn isPresent(STATE_FOCUS_MODE_ENABLED)\n\t}\n\n\tfun isOnFocusModeBreakGlobal(): Boolean {\n\t\treturn isPresent(STATE_FOCUS_MODE_GLOBAL_BREAK)\n\t}\n\n\tfun isOnFocusModeBreakPartial(): Boolean {\n\t\treturn isPresent(STATE_FOCUS_MODE_APP_BREAK)\n\t}\n\n\tfun isSuspendedManually(): Boolean {\n\t\treturn isPresent(STATE_MANUAL_SUSPEND)\n\t}\n\n\tfun isAppTimerSet(): Boolean {\n\t\treturn isPresent(STATE_APP_TIMER_SET)\n\t}\n\n\tfun isAppTimerExpired(): Boolean {\n\t\treturn isPresent(STATE_APP_TIMER_EXPIRED)\n\t}\n\n\tfun isAppTimerBreak(): Boolean {\n\t\treturn isPresent(STATE_APP_TIMER_BREAK)\n\t}\n\n\tfun isBedtimeModeEnabled(): Boolean {\n\t\treturn isPresent(STATE_BED_MODE)\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/Utils.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.annotation.SuppressLint\nimport android.app.usage.UsageEvents\nimport android.app.usage.UsageEvents.Event\nimport android.app.usage.UsageStatsManager\nimport android.content.ComponentName\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.content.res.Resources\nimport android.util.Log\nimport org.eu.droid_ng.wellbeing.shim.PackageManagerDelegate\nimport java.time.*\nimport java.util.*\n\n\nobject Utils {\n    private const val MOST_USED_PKG_CACHE_SIZE: Int = 3\n    private const val MOST_USED_PKG_MIN_USAGE_MINS: Long = 5\n    private var calculatedUsageStats: Map<String, Duration>? = null\n    private var calculatedScreenTime: Duration? = null\n    private var mostUsedPackages: Array<String>? = null\n    const val PACKAGE_MANAGER_MATCH_INSTANT = 0x00800000\n    val blackListedPackages: HashSet<String> = HashSet()\n    val restrictedPackages: HashSet<String> = HashSet()\n\n    private fun eventsStr(events: Iterable<Event>): String {\n        val b = StringBuilder()\n        b.append(\"[\")\n        for (element in events) {\n            b.append(\"el(t=\").append(element.eventType).append(\"), \")\n        }\n        b.replace(b.length - 2, b.length - 1, \"]\")\n        return b.toString()\n    }\n\n    fun clearUsageStatsCache(usm: UsageStatsManager?, pm: PackageManager?, pmd: PackageManagerDelegate?, recalculate: Boolean) {\n        calculatedUsageStats = null\n        calculatedScreenTime = null\n        mostUsedPackages = null\n        if (recalculate) {\n            updateApplicationBlackLists(pm!!, pmd!!)\n            checkInitializeCache(usm!!)\n        }\n    }\n\n    fun getTimeUsed(usm: UsageStatsManager, packageName: String?): Duration {\n        checkInitializeCache(usm)\n        return calculatedUsageStats!!.getOrDefault(packageName, Duration.ZERO)\n    }\n\n    fun getTimeUsed(usm: UsageStatsManager, packageNames: Array<String?>): Duration {\n        checkInitializeCache(usm)\n        var d = Duration.ZERO\n        for (packageName in packageNames) {\n            d = d.plus(calculatedUsageStats!!.getOrDefault(packageName, Duration.ZERO))\n        }\n        return if (d.isNegative) Duration.ZERO else d\n    }\n\n    fun getScreenTime(usm: UsageStatsManager): Duration {\n        checkInitializeCache(usm)\n        return calculatedScreenTime!!\n    }\n\n    fun getMostUsedPackages(usm: UsageStatsManager): Array<String> {\n        checkInitializeCache(usm)\n        return mostUsedPackages!!\n    }\n\n    private fun checkInitializeCache(usm: UsageStatsManager) {\n        if (calculatedUsageStats != null) return\n        // Cache not available. Calculate it once and keep it.\n        val z = ZoneId.systemDefault()\n        val startTime = LocalDateTime.now().with(LocalTime.MIN) // Start of day\n            .atZone(z).toEpochSecond() * 1000\n        val result = calculateUsageStats(usm, startTime, System.currentTimeMillis())\n        calculatedScreenTime = result.first\n        calculatedUsageStats = result.second.first\n        mostUsedPackages = result.second.second\n    }\n\n    fun calculateUsageStats(usm: UsageStatsManager, startTimeMillis: Long, endTimeMillis: Long): Pair<Duration, Pair<Map<String, Duration>, Array<String>>> {\n        val usageEvents: UsageEvents = usm.queryEvents(startTimeMillis, endTimeMillis)\n        var currentEvent: Event\n        val e = HashMap<String, ArrayList<Event>>()\n        while (usageEvents.hasNextEvent()) {\n            currentEvent = Event() // TODO don't allocate all of them\n            usageEvents.getNextEvent(currentEvent)\n            e.computeIfAbsent(currentEvent.packageName) { ArrayList() }.add(currentEvent)\n        }\n        // Calculate usageStats\n        val myCalculatedUsageStats = HashMap<String, Duration>()\n        e.forEach { (pkgName: String, events: ArrayList<Event>) ->\n            val openActivities = hashMapOf<String, Long>()\n            for (event in events.sortedWith { a, b ->\n                val c = a.timeStamp.compareTo(b.timeStamp)\n                if (c != 0) return@sortedWith c\n                val d = a.eventType == Event.ACTIVITY_RESUMED || a.eventType == 4 /* CONTINUE_PREVIOUS_DAY */\n                val f = b.eventType == Event.ACTIVITY_RESUMED || b.eventType == 4 /* CONTINUE_PREVIOUS_DAY */\n                return@sortedWith d.compareTo(f)\n            }) {\n                when (event.eventType) {\n                    Event.ACTIVITY_PAUSED -> {\n                        val start = openActivities.remove(event.className)\n                        if (start != null)\n                            myCalculatedUsageStats[pkgName] = myCalculatedUsageStats\n                                .getOrDefault(pkgName, Duration.ZERO).plus(\n                                    Duration.ofMillis(event.timeStamp - start))\n                        else\n                            Log.w(\"WellbeingUtils\", \"got ACTIVITY_PAUSED for ${event.className} at ${event.timeStamp} but didn't remember it starting\")\n                    }\n                    Event.DEVICE_SHUTDOWN, 3 /* END_OF_DAY */ -> {\n                        while (openActivities.isNotEmpty()) {\n                            myCalculatedUsageStats[pkgName] = myCalculatedUsageStats\n                                .getOrDefault(pkgName, Duration.ZERO).plus(\n                                    Duration.ofMillis(event.timeStamp -\n                                            openActivities.remove(openActivities.keys.first())!!\n                                    ))\n                        }\n                    }\n                    Event.ACTIVITY_RESUMED, 4 /* CONTINUE_PREVIOUS_DAY */ ->\n                        openActivities[event.className] = event.timeStamp\n                }\n            }\n        }\n        // Calculate screenTime + mostUsedPackages\n        var screenTimeTmp: Duration = Duration.ZERO\n        val mostUsedPackagesTmp = arrayOfNulls<String>(MOST_USED_PKG_CACHE_SIZE)\n        val mostUsedPackageTime = Array(MOST_USED_PKG_CACHE_SIZE) { MOST_USED_PKG_MIN_USAGE_MINS }\n        myCalculatedUsageStats.forEach { (pkgName: String, duration: Duration) ->\n            val seconds: Long\n            if (!blackListedPackages.contains(pkgName)) {\n                screenTimeTmp = screenTimeTmp.plus(duration)\n                seconds = duration.seconds\n            } else seconds = 0\n            if (!restrictedPackages.contains(pkgName) && seconds > mostUsedPackageTime[MOST_USED_PKG_CACHE_SIZE - 1]) {\n                var index = 0\n                while (seconds <= mostUsedPackageTime[index]) {\n                    index++\n                }\n                System.arraycopy(mostUsedPackagesTmp, index,\n                        mostUsedPackagesTmp, index + 1,\n                        (MOST_USED_PKG_CACHE_SIZE - 1) - index)\n                System.arraycopy(mostUsedPackageTime, index,\n                        mostUsedPackageTime, index + 1,\n                        (MOST_USED_PKG_CACHE_SIZE - 1) - index)\n                mostUsedPackagesTmp[index] = pkgName\n                mostUsedPackageTime[index] = seconds\n            }\n        }\n        val myMostUsedPackages: Array<String>\n        if (mostUsedPackagesTmp[MOST_USED_PKG_CACHE_SIZE - 1] != null) {\n            @Suppress(\"UNCHECKED_CAST\")\n            myMostUsedPackages = mostUsedPackagesTmp as Array<String>\n        } else if (mostUsedPackagesTmp[0] == null) {\n            myMostUsedPackages = emptyArray()\n        } else {\n            var arraySize = MOST_USED_PKG_CACHE_SIZE\n            while (arraySize --> 0) {\n                if (mostUsedPackagesTmp[arraySize] != null) {\n                    arraySize + 1\n                    break\n                }\n            }\n            @Suppress(\"UNCHECKED_CAST\")\n            myMostUsedPackages = mostUsedPackagesTmp.copyOf(arraySize) as Array<String>\n        }\n        return Pair(screenTimeTmp, Pair(myCalculatedUsageStats, myMostUsedPackages))\n    }\n\n    @SuppressLint(\"DiscouragedApi\")\n    private fun updateApplicationBlackLists(pm: PackageManager, pmd: PackageManagerDelegate) {\n        blackListedPackages.clear()\n        restrictedPackages.clear()\n\n        blackListedPackages.add(\"com.android.systemui\")\n\n        val resId = Resources.getSystem().getIdentifier(\n                \"config_recentsComponentName\", \"string\", \"android\")\n        if (resId != 0) {\n            val recentsComponent = ComponentName.unflattenFromString(\n                    Resources.getSystem().getString(resId))\n            if (recentsComponent != null)\n                restrictedPackages.add(recentsComponent.packageName)\n        }\n        var intent = Intent(Intent.ACTION_MAIN)\n        intent.addCategory(Intent.CATEGORY_HOME)\n        addDefaultHandlersToBlacklist(pm, intent, restrictedPackages)\n        restrictedPackages.addAll(blackListedPackages)\n        restrictedPackages.add(\"com.android.settings\")\n        // Add every system dialer to the blacklist\n        intent = Intent(Intent.ACTION_DIAL)\n        intent.addCategory(Intent.CATEGORY_DEFAULT)\n        addDefaultHandlersToBlacklist(pm, intent, restrictedPackages)\n        restrictedPackages.add(\"org.eu.droid_ng.wellbeing\")\n        //Log.d(\"Utils\", \"Hard Blacklisted packages: $blackListedPackages\")\n        //Log.d(\"Utils\", \"Soft Blacklisted packages: $restrictedPackages\")\n        val packages = pm.getInstalledApplications(PackageManager.GET_META_DATA).map { it.packageName }.toTypedArray()\n        restrictedPackages.addAll(pmd.getUnsuspendablePackages(packages))\n    }\n\n    private fun addDefaultHandlersToBlacklist(pm: PackageManager, intent: Intent, blacklist: HashSet<String>) {\n        // Add the system handlers to the blacklist\n        val resolveInfoList = pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY)\n        if (resolveInfoList.isNotEmpty()) {\n            for (resolveInfo in resolveInfoList) {\n                blacklist.add(resolveInfo.activityInfo.packageName)\n            }\n        }\n        // Add the default handler to the blacklist\n        val resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)\n        if (resolveInfo != null) {\n            blacklist.add(resolveInfo.activityInfo.packageName)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/WellbeingAirplaneState.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.content.Context\nimport android.provider.Settings\n\nenum class WellbeingAirplaneState(val airplaneModeState: Boolean, val systemAirplaneModeState: Boolean, val wellbeingAirplaneModeState: Boolean) {\n    DISABLED_BY_SYSTEM(false, false, false) {\n        override fun onReceiveAirplaneEnabled(): WellbeingAirplaneState {\n            return ENABLED_BY_SYSTEM\n        }\n\n        override fun onEnableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return ENABLED_DESPITE_SYSTEM\n        }\n    },\n    ENABLED_BY_SYSTEM(true, true, false) {\n        override fun onReceiveAirplaneDisabled(): WellbeingAirplaneState {\n            return DISABLED_BY_SYSTEM\n        }\n\n        override fun onEnableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return ENABLED_WITH_SYSTEM\n        }\n    },\n    ENABLED_WITH_SYSTEM(true, true, true) {\n        override fun onReceiveAirplaneDisabled(): WellbeingAirplaneState {\n            return DISABLED_DESPITE_WELLBEING_SYSTEM\n        }\n\n        override fun onDisableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return ENABLED_BY_SYSTEM\n        }\n    },\n    ENABLED_DESPITE_SYSTEM(true, false, true) {\n        override fun onReceiveAirplaneDisabled(): WellbeingAirplaneState {\n            return DISABLED_DESPITE_WELLBEING\n        }\n\n        override fun onDisableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return DISABLED_BY_SYSTEM\n        }\n    },\n    DISABLED_DESPITE_WELLBEING_SYSTEM(false, false, true) {\n        override fun onReceiveAirplaneEnabled(): WellbeingAirplaneState {\n            return ENABLED_WITH_SYSTEM\n        }\n\n        override fun onDisableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return DISABLED_BY_SYSTEM\n        }\n    },\n    DISABLED_DESPITE_WELLBEING(false, false, true) {\n        override fun onReceiveAirplaneEnabled(): WellbeingAirplaneState {\n            return ENABLED_DESPITE_SYSTEM\n        }\n\n        override fun onDisableAirplaneByWellbeing(): WellbeingAirplaneState {\n            return DISABLED_BY_SYSTEM\n        }\n    };\n\n    open fun onDisableAirplaneByWellbeing(): WellbeingAirplaneState {\n        return this\n    }\n\n    open fun onEnableAirplaneByWellbeing(): WellbeingAirplaneState {\n        return this\n    }\n\n    open fun onReceiveAirplaneDisabled(): WellbeingAirplaneState {\n        return this\n    }\n\n    open fun onReceiveAirplaneEnabled(): WellbeingAirplaneState {\n        return this\n    }\n\n    open fun shouldRestoreAirplaneMode(): Boolean {\n        return this.airplaneModeState != this.systemAirplaneModeState\n    }\n\n    companion object {\n        fun isAirplaneModeOn(context: Context): Boolean {\n            return Settings.Global.getInt(context.contentResolver,\n                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/WellbeingService.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.app.*\nimport android.app.usage.UsageStatsManager\nimport android.appwidget.AppWidgetProvider\nimport android.content.*\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.os.BatteryManager\nimport android.os.Build\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.service.quicksettings.TileService\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.Wellbeing\nimport org.eu.droid_ng.wellbeing.broadcast.AppTimersBroadcastReceiver\nimport org.eu.droid_ng.wellbeing.broadcast.NotificationBroadcastReceiver\nimport org.eu.droid_ng.wellbeing.join\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport org.eu.droid_ng.wellbeing.lib.Utils.getTimeUsed\nimport org.eu.droid_ng.wellbeing.shared.Database\nimport org.eu.droid_ng.wellbeing.shared.ExactTime\nimport org.eu.droid_ng.wellbeing.shared.TimeDimension\nimport org.eu.droid_ng.wellbeing.shared.WellbeingFrameworkClient\nimport org.eu.droid_ng.wellbeing.shim.PackageManagerDelegate\nimport org.eu.droid_ng.wellbeing.shim.PackageManagerDelegate.SuspendDialogInfo\nimport org.eu.droid_ng.wellbeing.ui.MainActivity\nimport org.eu.droid_ng.wellbeing.ui.TakeBreakDialogActivity\nimport org.eu.droid_ng.wellbeing.widget.ScreenTimeAppWidget\nimport java.time.Duration\nimport java.time.LocalDateTime\nimport java.time.temporal.ChronoUnit\nimport java.util.*\nimport java.util.concurrent.TimeUnit\nimport java.util.function.Consumer\nimport java.util.stream.Collectors\n\n\nclass WellbeingService(private val context: Context) : WellbeingFrameworkClient.ConnectionCallback {\n\tprivate var host: WellbeingStateHost? = null\n\t// systemApp should always be true, only used for development purposes.\n\tprivate val systemApp: Boolean = (context.applicationInfo.flags and\n\t\t\t(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP or ApplicationInfo.FLAG_SYSTEM)) > 1\n\tprivate val frameworkService: WellbeingFrameworkClient =\n\t\t\tWellbeingFrameworkClient(context, this)\n\n\tfun bindToHost(newhost: WellbeingStateHost?) {\n\t\thost = newhost\n\t\tif (host != null) {\n\t\t\tonServiceStartedCallbacks.toTypedArray().forEach {\n\t\t\t\tit.run()\n\t\t\t\tonServiceStartedCallbacks.remove(it)\n\t\t\t}\n\t\t}\n\t}\n\tprivate val stateCallbacks: ArrayList<Consumer<WellbeingService>> = ArrayList()\n\n\tfun addStateCallback(callback: Consumer<WellbeingService>) {\n\t\tstateCallbacks.add(callback)\n\t}\n\n\tfun removeStateCallback(callback: Consumer<WellbeingService>) {\n\t\tstateCallbacks.remove(callback)\n\t}\n\n\tprivate fun onStateChanged() {\n\t\tupdateServiceStatus()\n\t\tstateCallbacks.forEach { it.accept(this) }\n\n\t\t//Log.i(\"WellbeingImpl\", \"found \" + frameworkService.getEventCount(\"unlock\", TimeDimension.MONTH, LocalDateTime.now().minusMonths(1), LocalDateTime.now()) + \" unlocks\") TODO\n\t}\n\n\tprivate val onServiceStartedCallbacks: ArrayList<Runnable> = ArrayList()\n\n\tprivate fun startService(lateNotify: Boolean = false) {\n\t\tif (host != null) {\n\t\t\treturn\n\t\t}\n\t\tval client = WellbeingStateClient(context)\n\t\tclient.startService(lateNotify)\n\t}\n\n\tprivate fun startServiceAnd(lateNotify: Boolean = false, callback: Runnable? = null) {\n\t\tif (host != null) {\n\t\t\tcallback?.run()\n\t\t\treturn\n\t\t}\n\t\tif (callback != null) {\n\t\t\tonServiceStartedCallbacks.add(callback)\n\t\t}\n\t\tstartService(lateNotify)\n\t}\n\n\tprivate fun stopService() {\n\t\thost?.stop()\n\t}\n\n\tfun getInstalledApplications(flags: Int = 0): List<ApplicationInfo> {\n\t\tval newflags = (when(systemApp) {\n\t\t\ttrue -> Utils.PACKAGE_MANAGER_MATCH_INSTANT\n\t\t\tfalse -> 0\n\t\t} or flags)\n\t\treturn if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n\t\t\tpm.getInstalledApplications(PackageManager.ApplicationInfoFlags.of(newflags.toLong()))\n\t\t} else {\n\t\t\tpm.getInstalledApplications(newflags)\n\t\t}\n\t}\n\n\t@Throws(PackageManager.NameNotFoundException::class)\n\tfun getApplicationInfo(packageName: String, matchUninstalled: Boolean = true, flags: Int = 0): ApplicationInfo {\n\t\tval newflags = when(matchUninstalled) {\n\t\t\ttrue -> PackageManager.MATCH_UNINSTALLED_PACKAGES\n\t\t\tfalse -> 0\n\t\t} or when(systemApp) {\n\t\t\ttrue -> Utils.PACKAGE_MANAGER_MATCH_INSTANT\n\t\t\tfalse -> 0\n\t\t} or PackageManager.MATCH_ALL or flags\n\t\treturn if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n\t\t\tpm.getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(newflags.toLong()))\n\t\t} else {\n\t\t\tpm.getApplicationInfo(packageName, newflags)\n\t\t}\n\t}\n\n\t@Throws(PackageManager.NameNotFoundException::class)\n\tfun getApplicationLabel(packageName: String, matchUninstalled: Boolean = true): CharSequence {\n\t\treturn pm.getApplicationLabel(getApplicationInfo(packageName, matchUninstalled))\n\t}\n\n\tcompanion object {\n\t\tfun get(): WellbeingService {\n\t\t\treturn Wellbeing.getService()\n\t\t}\n\n\t/* **** main part of service starts here **** */\n\n\t\tconst val INTENT_ACTION_TAKE_BREAK = \"org.eu.droid_ng.wellbeing.TAKE_BREAK\"\n\t\tconst val INTENT_ACTION_QUIT_BREAK = \"org.eu.droid_ng.wellbeing.QUIT_BREAK\"\n\t\tconst val INTENT_ACTION_QUIT_BED = \"org.eu.droid_ng.wellbeing.QUIT_BED\"\n\t\tconst val INTENT_ACTION_QUIT_FOCUS = \"org.eu.droid_ng.wellbeing.QUIT_FOCUS\"\n\t\tconst val INTENT_ACTION_UNSUSPEND_ALL = \"org.eu.droid_ng.wellbeing.UNSUSPEND_ALL\"\n\t\tval breakTimeOptions = intArrayOf(1, 3, 5, 10, 15) // keep in sync with getUseAppForString\n\t}\n\n\tprivate val handler = Handler.createAsync(context.mainLooper)\n\tprivate val pm = context.packageManager\n\tval pmd = PackageManagerDelegate(pm)\n\tval cdm = PackageManagerDelegate.getColorDisplayManager(context)\n\tval usm = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager\n\tprivate val alc = AlarmCoordinator(context)\n\tprivate val notificationManager = context.getSystemService(NotificationManager::class.java) as NotificationManager\n\tprivate val bgThread = HandlerThread(\"WellbeingService\").also { it.start() }\n\tval bgHandler = Handler(bgThread.looper)\n\tprivate val db = Database(context, bgHandler, 0)\n\n\tprivate var airplaneState: WellbeingAirplaneState\n\tprivate var airplaneStateLogical: Boolean = false\n\tprivate var triggers: Set<Trigger> = HashSet()\n\n\tprivate val oidMap = context.getSharedPreferences(\"AppTimersInternal\", 0)\n\tprivate val config = context.getSharedPreferences(\"appTimers\", 0)\n\tprivate val sched = context.getSharedPreferences(\"sched\", 0)\n\n\tvar focusModeAllApps = true\n\tprivate var focusModeInvertSelection = false\n\tprivate var focusModeBreakTimeDialog = -1\n\tprivate var focusModeBreakTimeNotification = -1\n\tprivate var manualSuspendDialog = false\n\tprivate var manualSuspendAllApps = false\n\tprivate var appTimerDialogBreakTime = -1\n\tprivate var bedtimeGreyscale = true\n\tprivate var bedtimeAirplaneMode = true\n\tprivate var reminderMin = -1\n\tprivate var lastStatsProcessed = 0L\n\n\tprivate fun loadSettings() {\n\t\tval prefs = context.getSharedPreferences(\"service\", 0)\n\t\tval bedmode = context.getSharedPreferences(\"bedtime_mode\", 0)\n\t\tfocusModeBreakTimeNotification = Integer.parseInt(prefs.getString(\"focus_notification\", focusModeBreakTimeNotification.toString()) ?: focusModeBreakTimeNotification.toString())\n\t\tfocusModeBreakTimeDialog = Integer.parseInt(prefs.getString(\"focus_dialog\", focusModeBreakTimeDialog.toString()) ?: focusModeBreakTimeDialog.toString())\n\t\tmanualSuspendDialog = prefs.getBoolean(\"manual_dialog\", manualSuspendDialog)\n\t\tmanualSuspendAllApps = prefs.getBoolean(\"manual_all\", manualSuspendAllApps)\n\t\tfocusModeAllApps = prefs.getBoolean(\"focus_all\", focusModeAllApps)\n\t\tfocusModeInvertSelection = prefs.getBoolean(\"focus_whitelist\", focusModeInvertSelection)\n\t\tappTimerDialogBreakTime = Integer.parseInt(prefs.getString(\"app_timer_dialog\", appTimerDialogBreakTime.toString()) ?: appTimerDialogBreakTime.toString())\n\t\treminderMin = Integer.parseInt(prefs.getString(\"app_timer_reminder\", reminderMin.toString()) ?: reminderMin.toString())\n\t\tbedtimeGreyscale = bedmode.getBoolean(\"greyscale\", bedtimeGreyscale)\n\t\tbedtimeAirplaneMode = bedmode.getBoolean(\"airplane_mode\", bedtimeAirplaneMode)\n\n\t\talc.updateState()\n\t}\n\n\tprivate fun loadSchedcfg() {\n\t\tsched.getStringSet(\"triggers\", HashSet())?.stream()?.map { raw ->\n\t\t\tval values = raw.split(\";;\")\n\t\t\tif (values.size < 2) throw IllegalStateException(\"invalid value $raw\")\n\t\t\treturn@map when (values[0]) {\n\t\t\t\t\"time\" -> {\n\t\t\t\t\tval bools = BooleanArray(7); for (i in bools.indices) if (values[8].toInt() and (1 shl i) != 0) bools[i] = true // bitmask -> boolean[]\n\t\t\t\t\tTimeChargerTriggerCondition(values[1], values[2], values[3].toBooleanStrict(), values[4].toInt(), values[5].toInt(), values[6].toInt(), values[7].toInt(), bools, values[9].toBooleanStrict(), values[10].toBooleanStrict())\n\t\t\t\t}\n\t\t\t\telse -> {\n\t\t\t\t\tthrow IllegalStateException(\"invalid trigger type ${values[0]}\")\n\t\t\t\t}\n\t\t\t}\n\t\t}?.collect(Collectors.toSet())?.let { triggers = it }\n\n\t\tensureSchedSetup()\n\t}\n\n\tprivate fun writeSchedcfg() {\n\t\tval s = sched.edit().clear()\n\n\t\ts.putStringSet(\"triggers\", triggers.stream().map {\n\t\t\twhen (it) {\n\t\t\t\tis TimeChargerTriggerCondition -> {\n\t\t\t\t\tvar bits = 0; for (i in 0 until it.weekdays.size) if (it.weekdays[i]) bits = bits or (1 shl i) // boolean[] -> bitmask\n\t\t\t\t\t\"time;;${it.id};;${it.iid};;${it.enabled};;${it.startHour};;${it.startMinute};;${it.endHour};;${it.endMinute};;${bits};;${it.needCharger};;${it.endOnAlarm}\"\n\t\t\t\t}\n\t\t\t\telse -> throw IllegalStateException(\"unknown trigger ${it::class.qualifiedName}\")\n\t\t\t}\n\t\t}.collect(Collectors.toSet()))\n\n\t\ts.apply()\n\t}\n\n\tprivate fun updateWidget(widget: Class<out AppWidgetProvider>) {\n\t\tval intent = Intent(context, widget)\n\t\tintent.action = \"org.eu.droid_ng.wellbeing.APPWIDGET_UPDATE\"\n\t\tcontext.sendBroadcast(intent)\n\t}\n\n\tprivate var bedtimeModeEnabled = false\n\tprivate var isFocusModeEnabled = false\n\tprivate var isFocusModeBreak /* global break */ = false\n\tprivate val perAppState: HashMap<String /* packageName */, Int /* does NOT contain global flags like FOCUS_MODE_ENABLED or FOCUS_MODE_GLOBAL_BREAK, so always use getAppState() when reading */> = HashMap()\n\n\tinit {\n\t\tUtils.clearUsageStatsCache(usm, pm, pmd, true)\n\t\tairplaneState = when (WellbeingAirplaneState.isAirplaneModeOn(context)) {\n\t\t\ttrue -> WellbeingAirplaneState.ENABLED_BY_SYSTEM\n\t\t\tfalse -> WellbeingAirplaneState.DISABLED_BY_SYSTEM\n\t\t}\n\t\tonStateChanged() // includes loadSettings()\n\t\tScheduleUtils.ensureWidgetAlarmSet(context, handler, 60, ScreenTimeAppWidget::class.java)\n\t\tScheduleUtils.ensureStatProcessorAlarmSet(context, handler)\n\n\t\tval channel = NotificationChannel(\n\t\t\t\"reminder\",\n\t\t\tcontext.getString(R.string.channel2_name),\n\t\t\tNotificationManager.IMPORTANCE_HIGH\n\t\t)\n\t\tchannel.description = context.getString(R.string.channel2_description)\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n\t\t\tchannel.isBlockable = true\n\t\t}\n\t\tnotificationManager.createNotificationChannel(channel)\n\n\t\tcontext.registerReceiver(object : BroadcastReceiver() {\n\t\t\toverride fun onReceive(p0: Context?, p1: Intent?) {\n\t\t\t\tonUpdatePowerConnection()\n\t\t\t}\n\t\t}, IntentFilter(Intent.ACTION_BATTERY_CHANGED))\n\t\tcontext.registerReceiver(object : BroadcastReceiver() {\n\t\t\toverride fun onReceive(p0: Context?, p1: Intent?) {\n\t\t\t\tairplaneState = if (WellbeingAirplaneState.isAirplaneModeOn(context)) {\n\t\t\t\t\tairplaneState.onReceiveAirplaneEnabled()\n\t\t\t\t} else {\n\t\t\t\t\tairplaneState.onReceiveAirplaneDisabled()\n\t\t\t\t}\n\t\t\t}\n\t\t}, IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED))\n\t\tframeworkService.tryConnect()\n\t}\n\n\toverride fun onWellbeingFrameworkConnected(initial: Boolean) {\n\t\tif (hasWellbeingAirplaneModeCapabilities()) {\n\t\t\tif (airplaneState.wellbeingAirplaneModeState != airplaneStateLogical) {\n\t\t\t\tsetWellbeingAirplaneMode(airplaneStateLogical)\n\t\t\t} else if (initial) {\n\t\t\t\tval prefs = context.getSharedPreferences(\"restore_state\", 0)\n\t\t\t\tif (prefs.getBoolean(\"restore_airplane_mode\", false) &&\n\t\t\t\t\t\t!airplaneState.wellbeingAirplaneModeState) {\n\t\t\t\t\tprefs.edit().remove(\"restore_airplane_mode\").apply()\n\t\t\t\t\tframeworkService.setAirplaneMode(false)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toverride fun onWellbeingFrameworkDisconnected() {}\n\n\t// Service / Global state. Do not confuse with per-app state, that's using the same values.\n\tfun getState(includeAppState: Boolean = true): State {\n\t\tval value =\n\t\t\t(if (bedtimeModeEnabled) State.STATE_BED_MODE else 0) or\n\t\t\t(if (isFocusModeEnabled) State.STATE_FOCUS_MODE_ENABLED else 0) or\n\t\t\t(if (isFocusModeBreak) State.STATE_FOCUS_MODE_GLOBAL_BREAK else 0) or\n\t\t\t(if (includeAppState && (perAppState.entries.stream().filter { (it.value and State.STATE_FOCUS_MODE_APP_BREAK) > 0 }.findAny().isPresent)) State.STATE_FOCUS_MODE_APP_BREAK else 0) or\n\t\t\t(if (includeAppState && (perAppState.entries.stream().filter { (it.value and State.STATE_MANUAL_SUSPEND) > 0 }.findAny().isPresent)) State.STATE_MANUAL_SUSPEND else 0) or\n\t\t\t(if (includeAppState && (perAppState.entries.stream().filter { (it.value and State.STATE_APP_TIMER_SET) > 0 }.findAny().isPresent)) State.STATE_APP_TIMER_SET else 0) or\n\t\t\t(if (includeAppState && (perAppState.entries.stream().filter { (it.value and State.STATE_APP_TIMER_EXPIRED) > 0 }.findAny().isPresent)) State.STATE_APP_TIMER_EXPIRED else 0) or\n\t\t\t(if (includeAppState && (perAppState.entries.stream().filter { (it.value and State.STATE_APP_TIMER_BREAK) > 0 }.findAny().isPresent)) State.STATE_APP_TIMER_BREAK else 0)\n\n\t\treturn State(value)\n\t}\n\n\tfun getAppState(packageName: String): State {\n\t\tvar value = perAppState.getOrDefault(packageName, 0)\n\n\t\t/* apply matching global flags */\n\t\tval global = getState(false).toInt()\n\t\tif ((value and State.STATE_FOCUS_MODE_ENABLED) > 0) {\n\t\t\tvalue = value or (global and State.STATE_FOCUS_MODE_GLOBAL_BREAK)\n\t\t}\n\n\t\t/* apply app timer flags */\n\t\tif (config.getInt(packageName, -1) > 0) {\n\t\t\tvalue = value or State.STATE_APP_TIMER_SET\n\t\t}\n\t\tif ((value and State.STATE_APP_TIMER_SET) > 0 && Duration.ofMinutes(config.getInt(packageName, 0).toLong()).minus(getTimeUsed(usm, packageName)).toMinutes() <= 0) {\n\t\t\tvalue = value or State.STATE_APP_TIMER_EXPIRED\n\t\t}\n\t\tif ((value and State.STATE_APP_TIMER_SET) > 0 && oidMap.contains(ParsedUoid(\"AppBreak\", 0, arrayOf(packageName)).toString())) {\n\t\t\tvalue = value or State.STATE_APP_TIMER_BREAK\n\t\t}\n\n\t\treturn State(value)\n\t}\n\n\tfun setBedtimeMode(enable: Boolean) {\n\t\tloadSettings()\n\t\tbedtimeModeEnabled = enable\n\n\t\tif (bedtimeGreyscale) {\n\t\t\tcdm.setSaturationLevel(if (enable) 0 else 100)\n\t\t}\n\n\t\tsetWellbeingAirplaneMode(enable && bedtimeAirplaneMode)\n\n\t\tonStateChanged()\n\n\t\tdoUpdateTile(BedtimeModeQSTile::class.java)\n\t}\n\n\tprivate fun hasWellbeingAirplaneModeCapabilities(): Boolean {\n\t\treturn frameworkService.versionCode() >= 1\n\t}\n\n\tfun setWellbeingAirplaneMode(enable: Boolean) {\n\t\tairplaneStateLogical = enable\n\t\tval oldState = airplaneState\n\t\tif (!hasWellbeingAirplaneModeCapabilities()) {\n\t\t\t// Allow partial update when in state that\n\t\t\t// previously had airplane mode capabilities\n\t\t\tif (oldState.wellbeingAirplaneModeState && !enable) {\n\t\t\t\tairplaneState = airplaneState.onDisableAirplaneByWellbeing()\n\t\t\t\tif (oldState.shouldRestoreAirplaneMode() !=\n\t\t\t\t\t\tairplaneState.shouldRestoreAirplaneMode()) {\n\t\t\t\t\tval prefs = context.getSharedPreferences(\"restore_state\", 0)\n\t\t\t\t\tprefs.edit().putBoolean(\"restore_airplane_mode\",\n\t\t\t\t\t\t\tairplaneState.shouldRestoreAirplaneMode()).apply()\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tairplaneState = when(enable) {\n\t\t\ttrue -> airplaneState.onEnableAirplaneByWellbeing()\n\t\t\tfalse -> airplaneState.onDisableAirplaneByWellbeing()\n\t\t}\n\t\tif (airplaneState.airplaneModeState !=\n\t\t\t\toldState.airplaneModeState) {\n\t\t\tframeworkService.setAirplaneMode(\n\t\t\t\t\tairplaneState.airplaneModeState)\n\t\t}\n\t\tif (airplaneState.shouldRestoreAirplaneMode()\n\t\t\t\t!= oldState.shouldRestoreAirplaneMode()) {\n\t\t\tval prefs = context.getSharedPreferences(\"restore_state\", 0)\n\t\t\tprefs.edit().putBoolean(\"restore_airplane_mode\",\n\t\t\t\t\tairplaneState.shouldRestoreAirplaneMode()).apply()\n\t\t}\n\t}\n\n\tfun onAppTimerExpired(observerId: Int, uniqueObserverId: String) {\n\t\tvar msg: String\n\t\tvar uoid: String = uniqueObserverId\n\t\tif (oidMap.getInt(uoid, -2) != observerId) {\n\t\t\tmsg = \"Warning: unknown oid/uoid - $observerId / $uoid - this might be an bug? Trying to recover.\"\n\t\t\tToast.makeText(context, msg, Toast.LENGTH_LONG).show()\n\t\t\tBUG(msg)\n\t\t\tuoid = oidMap.all.entries.stream().filter { a -> observerId == a.value }\n\t\t\t\t.findAny().get().key\n\t\t}\n\n\t\tval parsed = ParsedUoid.from(uoid)\n\t\tmsg = \"AppTimersInternal: success oid:\" + observerId + \" action:\" + parsed.action + \" timeMillis:\" + parsed.timeMillis + \" pkgs:\" + String.join(\",\", parsed.pkgs)\n\t\tLog.i(\"AppTimersInternal\", msg)\n\n\t\twhen (parsed.action) {\n\t\t\t\"AppTimer\", \"AppLimit\" -> {\n\t\t\t\tdropAppTimer(parsed)\n\t\t\t\tparsed.pkgs.forEach {\n\t\t\t\t\tif (it == null) return@forEach\n\t\t\t\t\tupdateSuspendStatusForApp(it)\n\t\t\t\t}\n\t\t\t}\n\t\t\t\"Reminder\" -> {\n\t\t\t\tdropAppTimer(parsed)\n\t\t\t\tparsed.pkgs.forEach {\n\t\t\t\t\tif (it == null) return@forEach\n\t\t\t\t\tval text = context.resources.getQuantityString(\n\t\t\t\t\t\tR.plurals.app_timer_reminder_title,\n\t\t\t\t\t\treminderMin, reminderMin\n\t\t\t\t\t)\n\t\t\t\t\tval n = Notification.Builder(context, \"reminder\")\n\t\t\t\t\t\t.setWhen(System.currentTimeMillis())\n\t\t\t\t\t\t.setSmallIcon(R.drawable.ic_focus_mode)\n\t\t\t\t\t\t.setOnlyAlertOnce(true)\n\t\t\t\t\t\t.setContentTitle(text)\n\t\t\t\t\t\t.setTicker(text)\n\t\t\t\t\t\t.setContentText(\n\t\t\t\t\t\t\tcontext.getString(\n\t\t\t\t\t\t\t\tR.string.app_timer_reminder,\n\t\t\t\t\t\t\t\tgetApplicationLabel(it)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\tnotificationManager.notify(\n\t\t\t\t\t\t(System.currentTimeMillis() / 1000).toInt(),\n\t\t\t\t\t\tn.build()\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\t\"AppBreak\" -> endBreak(parsed.pkgs)\n\t\t\telse -> {\n\t\t\t\tToast.makeText(context, msg, Toast.LENGTH_LONG).show()\n\t\t\t\tBUG(msg)\n\t\t\t\tdropAppTimer(parsed)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fun endBreak(pkgs: Array<String?>) {\n\t\tval u = ParsedUoid(\"AppBreak\", 0, pkgs)\n\t\tif (!oidMap.contains(u.toString())) return\n\t\tdropAppTimer(u)\n\t\tpkgs.forEach {\n\t\t\tif (it == null) return@forEach\n\t\t\tupdateSuspendStatusForApp(it)\n\t\t}\n\t}\n\n\tprivate fun loadAppTimer(packageName: String) {\n\t\tval s = arrayOf<String?>(packageName)\n\t\tval i = config.getInt(packageName, -1)\n\t\tval m = Duration.ofMinutes(i.toLong()).minus(getTimeUsed(usm, s))\n\t\tif (i > 0 && m.toMinutes() > 0)\n\t\t\tsetAppTimer(s, m, getTimeUsed(usm, s))\n\t\tupdateSuspendStatusForApp(packageName)\n\t}\n\n\tprivate fun takeAppTimerBreak(packageNames: Array<String?>, breakMins: Int) {\n\t\tval u = ParsedUoid(\"AppBreak\", 0, packageNames).toString()\n\t\tif (!oidMap.contains(u)) {\n\t\t\tupdatePrefs(u, makeOid())\n\t\t}\n\t\tsetAppTimerInternal(u, packageNames, Duration.ofMinutes(breakMins.toLong()), getTimeUsed(usm, packageNames))\n\t\tpackageNames.forEach {\n\t\t\tif (it != null) {\n\t\t\t\tupdateSuspendStatusForApp(it)\n\t\t\t}\n\t\t}\n\t}\n\n\tfun takeAppTimerBreakWithDialog(activityContext: Activity, endActivity: Boolean, packageNames: Array<String?>) {\n\t\tval optionsS: Array<String> = Arrays.stream(breakTimeOptions).mapToObj { i ->\n\t\t\tcontext.resources.getQuantityString(R.plurals.break_mins, i, i)\n\t\t}.toArray { arrayOfNulls<String>(it) }\n\t\tval b = AlertDialog.Builder(activityContext)\n\t\t\t.setTitle(R.string.focus_mode_break)\n\t\t\t.setNegativeButton(R.string.cancel) { d, _ -> d.dismiss() }\n\t\t\t.setItems(optionsS) { _, i ->\n\t\t\t\tval breakMins = breakTimeOptions[i]\n\t\t\t\ttakeAppTimerBreak(packageNames, breakMins)\n\t\t\t\tif (endActivity) activityContext.finish()\n\t\t\t}\n\t\tb.show()\n\t}\n\n\tprivate fun loadAppTimers() {\n\t\toidMap.edit().clear().apply()\n\t\tfor (pkg in config.all.keys) {\n\t\t\tloadAppTimer(pkg)\n\t\t}\n\t}\n\n\tfun onUpdateAppTimerPreference(pkgName: String, oldLimit: Duration) {\n\t\tval s = arrayOf<String?>(pkgName)\n\t\tvar u = ParsedUoid(\"AppTimer\", oldLimit.toMillis(), s)\n\t\tif (oidMap.contains(u.toString())) dropAppTimer(u)\n\t\tu = ParsedUoid(\"AppLimit\", oldLimit.toMillis(), s)\n\t\tif (oidMap.contains(u.toString())) dropAppTimer(u)\n\t\tu = ParsedUoid(\"AppBreak\", 0, s)\n\t\tif (oidMap.contains(u.toString())) dropAppTimer(u)\n\t\tu = ParsedUoid(\"Reminder\", 0, s)\n\t\tif (oidMap.contains(u.toString())) dropAppTimer(u)\n\t\tloadAppTimer(pkgName)\n\t}\n\n\tfun onBootCompleted() {\n\t\t// Try to reconnect to frameworkService if the first connection failed.\n\t\tframeworkService.tryConnect()\n\t\tloadAppTimers()\n\t\tdoUpdateTile(FocusModeQSTile::class.java)\n\t\tdoUpdateTile(BedtimeModeQSTile::class.java)\n\t\tonStateChanged()\n\t}\n\n\t@Suppress(\"unchecked_cast\") // AIDL\n\tfun getBugs(): MutableMap<Long, String> {\n\t\treturn frameworkService.bugs as MutableMap<Long, String>\n\t}\n\n\tprivate fun doUpdateTile(tile: Class<out TileService>) {\n\t\tTileService.requestListeningState(context, ComponentName(context, tile))\n\t}\n\n\tprivate fun updateServiceStatus() {\n\t\tloadSettings()\n\t\tloadSchedcfg()\n\t\tupdateWidget(ScreenTimeAppWidget::class.java)\n\t\tval state = getState()\n\t\tval needServiceRunning = state.isFocusModeEnabled() || state.isSuspendedManually() || state.isBedtimeModeEnabled()\n\t\tval next = {\n\t\t\tif (state.isFocusModeEnabled()) {\n\t\t\t\tif (state.isOnFocusModeBreakGlobal()) {\n\t\t\t\t\thost?.updateNotification(\n\t\t\t\t\t\tR.string.focus_mode,\n\t\t\t\t\t\tR.string.notification_focus_mode_break,\n\t\t\t\t\t\tR.drawable.outline_badge_24,\n\t\t\t\t\t\tarrayOf(\n\t\t\t\t\t\t\thost?.buildAction(\n\t\t\t\t\t\t\t\tR.string.focus_mode_break_end, R.drawable.ic_take_break, Intent(\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t\t).setAction(INTENT_ACTION_QUIT_BREAK), true\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\thost?.buildAction(\n\t\t\t\t\t\t\t\tR.string.focus_mode_off, R.drawable.baseline_cancel_24, Intent(\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t\t).setAction(INTENT_ACTION_QUIT_FOCUS), true\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t),\n\t\t\t\t\t\tIntent(context, MainActivity::class.java)\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\thost?.updateNotification(\n\t\t\t\t\t\tR.string.focus_mode,\n\t\t\t\t\t\tR.string.notification_focus_mode,\n\t\t\t\t\t\tR.drawable.outline_badge_24,\n\t\t\t\t\t\tarrayOf(\n\t\t\t\t\t\t\tif (focusModeBreakTimeNotification == -1) host?.buildAction(\n\t\t\t\t\t\t\t\tR.string.focus_mode_break, R.drawable.ic_take_break, Intent(\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tTakeBreakDialogActivity::class.java\n\t\t\t\t\t\t\t\t), false\n\t\t\t\t\t\t\t) else host?.buildAction(\n\t\t\t\t\t\t\t\tR.string.focus_mode_break, R.drawable.ic_take_break, Intent(\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t\t).setAction(INTENT_ACTION_TAKE_BREAK), true\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\thost?.buildAction(\n\t\t\t\t\t\t\t\tR.string.focus_mode_off, R.drawable.baseline_cancel_24, Intent(\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t\t).setAction(INTENT_ACTION_QUIT_FOCUS), true\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t),\n\t\t\t\t\t\tIntent(context, MainActivity::class.java)\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (state.isSuspendedManually()) {\n\t\t\t\thost?.updateNotification(\n\t\t\t\t\tR.string.notification_title,\n\t\t\t\t\tR.string.notification_manual,\n\t\t\t\t\tR.drawable.ic_baseline_person_24,\n\t\t\t\t\tarrayOf(\n\t\t\t\t\t\thost?.buildAction(\n\t\t\t\t\t\t\tR.string.unsuspend_all, R.drawable.baseline_exit_to_app_24, Intent(\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t).setAction(INTENT_ACTION_UNSUSPEND_ALL), true\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t\tIntent(context, MainActivity::class.java)\n\t\t\t\t)\n\t\t\t} else if (state.isBedtimeModeEnabled()) {\n\t\t\t\thost?.updateNotification(\n\t\t\t\t\tR.string.bedtime_mode,\n\t\t\t\t\tR.string.bedtime_desc,\n\t\t\t\t\tR.drawable.baseline_bedtime_24,\n\t\t\t\t\tarrayOf(\n\t\t\t\t\t\thost?.buildAction(\n\t\t\t\t\t\t\tR.string.disable, R.drawable.baseline_cancel_24, Intent(\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tNotificationBroadcastReceiver::class.java\n\t\t\t\t\t\t\t).setAction(INTENT_ACTION_QUIT_BED), true\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t\tIntent(context, MainActivity::class.java)\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\thost?.updateDefaultNotification()\n\t\t\t}\n\t\t}\n\t\tif (needServiceRunning) {\n\t\t\tif (host == null) {\n\t\t\t\tstartServiceAnd {\n\t\t\t\t\tnext()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnext()\n\t\t\t}\n\t\t} else {\n\t\t\tif (host != null) {\n\t\t\t\tstopService()\n\t\t\t}\n\t\t\tnext()\n\t\t}\n\t}\n\n\tfun onManuallyUnsuspended(packageName: String) {\n\t\tval state = getAppState(packageName)\n\t\tif (state.isFocusModeEnabled() && !(state.isOnFocusModeBreakGlobal() || state.isOnFocusModeBreakPartial())) {\n\t\t\tif (focusModeAllApps) {\n\t\t\t\ttakeFocusModeBreak(focusModeBreakTimeDialog)\n\t\t\t} else {\n\t\t\t\ttakeFocusModeBreak(arrayOf(packageName), focusModeBreakTimeDialog)\n\t\t\t}\n\t\t} else if (state.isSuspendedManually()) {\n\t\t\tif (manualSuspendAllApps) {\n\t\t\t\tmanualUnsuspend(null) // unsuspend all\n\t\t\t} else {\n\t\t\t\tmanualUnsuspend(arrayOf(packageName))\n\t\t\t}\n\t\t} else {\n\t\t\tBUG(\"Unable to handle manual unsuspend\")\n\t\t}\n\t}\n\n\tprivate fun getUseAppForString(time: Int): Int {\n\t\t// keep in sync with breakTimeOptions\n\t\treturn when (time) {\n\t\t\t1 -> R.string.break_dialog_1\n\t\t\t3 -> R.string.break_dialog_3\n\t\t\t5 -> R.string.break_dialog_5\n\t\t\t10 -> R.string.break_dialog_10\n\t\t\t15 -> R.string.break_dialog_15\n\t\t\telse -> {\n\t\t\t\tthrow IllegalArgumentException(\"$time needs to be in breakTimeOptions list\")\n\t\t\t}\n\t\t}\n\t}\n\n\tfun onNotificationActionClick(action: String) {\n\t\twhen (action) {\n\t\t\tINTENT_ACTION_UNSUSPEND_ALL -> {\n\t\t\t\tmanualUnsuspend(null)\n\t\t\t}\n\t\t\tINTENT_ACTION_TAKE_BREAK -> {\n\t\t\t\ttakeFocusModeBreak(focusModeBreakTimeNotification)\n\t\t\t}\n\t\t\tINTENT_ACTION_QUIT_BREAK -> {\n\t\t\t\tendFocusModeBreak()\n\t\t\t}\n\t\t\tINTENT_ACTION_QUIT_FOCUS -> {\n\t\t\t\tdisableFocusMode()\n\t\t\t}\n\t\t\tINTENT_ACTION_QUIT_BED -> {\n\t\t\t\tsetBedtimeMode(false)\n\t\t\t}\n\t\t\telse -> {\n\t\t\t\tBUG(\"invalid notification action: $action\")\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fun updateSuspendStatusForApp(packageName: String) {\n\t\tval state = getAppState(packageName)\n\t\tval f: Array<String> = if (state.isFocusModeEnabled() && !(state.isOnFocusModeBreakGlobal() || state.isOnFocusModeBreakPartial())) {\n\t\t\tval label: CharSequence = try {\n\t\t\t\tgetApplicationLabel(packageName, false)\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\tBUG(\"tried to suspend nonexistant app: $packageName\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tval di = SuspendDialogInfo.Builder()\n\t\t\t\t.setTitle(R.string.focus_mode_enabled)\n\t\t\t\t.setMessage(context.getString(R.string.focus_mode_dialog, label))\n\t\t\t\t.setIcon(R.drawable.ic_focus_mode)\n\t\t\t\t.setNeutralButtonText(if (focusModeBreakTimeDialog == -1) R.string.dialog_btn_settings else getUseAppForString(focusModeBreakTimeDialog))\n\t\t\t\t.setNeutralButtonAction(if (focusModeBreakTimeDialog == -1) SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS else SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND)\n\t\t\t\t.build()\n\t\t\tpmd.setPackagesSuspended(arrayOf(packageName), true, null, null, di)\n\t\t} else if (state.isSuspendedManually()) {\n\t\t\tval di = SuspendDialogInfo.Builder()\n\t\t\t\t.setTitle(R.string.dialog_title)\n\t\t\t\t.setMessage(R.string.dialog_message)\n\t\t\t\t.setIcon(R.drawable.ic_baseline_app_blocking_24)\n\t\t\t\t.setNeutralButtonText(if (!manualSuspendDialog) R.string.dialog_btn_settings else (if (manualSuspendAllApps) R.string.unsuspend_all else R.string.unsuspend))\n\t\t\t\t.setNeutralButtonAction(if (!manualSuspendDialog) SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS else SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND)\n\t\t\t\t.build()\n\t\t\tpmd.setPackagesSuspended(arrayOf(packageName), true, null, null, di)\n\t\t} else if (state.isAppTimerExpired() && !state.isAppTimerBreak()) {\n\t\t\tpmd.setPackagesSuspended(\n\t\t\t\tarrayOf(packageName), true, null, null, SuspendDialogInfo.Builder()\n\t\t\t\t\t.setTitle(R.string.app_timers)\n\t\t\t\t\t.setMessage(context.getString(R.string.app_timer_exceed_f, getApplicationLabel(packageName)))\n\t\t\t\t\t.setNeutralButtonText(if (appTimerDialogBreakTime == -1) R.string.dialog_btn_settings else getUseAppForString(appTimerDialogBreakTime))\n\t\t\t\t\t.setNeutralButtonAction(if (appTimerDialogBreakTime == -1) SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS else SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND)\n\t\t\t\t\t.setIcon(R.drawable.ic_focus_mode).build()\n\t\t\t)\n\t\t} else {\n\t\t\tpmd.setPackagesSuspended(arrayOf(packageName), false, null, null, null)\n\t\t}\n\t\tfor (s in f) {\n\t\t\tBUG(\"Failed to (un)suspend package: $s\")\n\t\t}\n\t}\n\n\tprivate fun setFocusModeStateForPkgInternal(s: String, suspend: Boolean, forBreak: Boolean, forAppBreak: Boolean) {\n\t\tif (suspend) {\n\t\t\tperAppState[s] = (perAppState.getOrDefault(s, 0) or State.STATE_FOCUS_MODE_ENABLED) and State.STATE_FOCUS_MODE_APP_BREAK.inv()\n\t\t} else {\n\t\t\tif (forBreak) {\n\t\t\t\tif (forAppBreak) {\n\t\t\t\t\tperAppState[s] = perAppState.getOrDefault(s, 0) or (State.STATE_FOCUS_MODE_APP_BREAK)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tperAppState[s] = perAppState.getOrDefault(s, 0) and (State.STATE_FOCUS_MODE_ENABLED.inv() and State.STATE_FOCUS_MODE_APP_BREAK.inv())\n\t\t\t}\n\t\t}\n\n\t\tupdateSuspendStatusForApp(s)\n\t}\n\n\tprivate fun isValidFocusPkg(packageName: String): Boolean {\n\t\treturn !Utils.blackListedPackages.contains(packageName) && !Utils.restrictedPackages.contains(packageName)\n\t}\n\n\tfun enableFocusMode() {\n\t\tloadSettings()\n\n\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\tval st = spref.getStringSet(\"focus_mode\", null)\n\t\tif (st == null) {\n\t\t\tBUG(\"st == null\")\n\t\t\treturn\n\t\t}\n\n\t\tisFocusModeEnabled = true\n\t\tisFocusModeBreak = false\n\n\t\tfor (s in getInstalledApplications(PackageManager.GET_META_DATA))\n\t\t\tif (((!focusModeInvertSelection && st.contains(s.packageName)) || (focusModeInvertSelection && !st.contains(s.packageName))) && isValidFocusPkg(s.packageName))\n\t\t\t\tsetFocusModeStateForPkgInternal(s.packageName, suspend = true, forBreak = false, forAppBreak = false)\n\n\t\tonStateChanged()\n\n\t\tdoUpdateTile(FocusModeQSTile::class.java)\n\t}\n\n\tfun disableFocusMode() {\n\t\tloadSettings()\n\n\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\tval st = spref.getStringSet(\"focus_mode\", null)\n\t\tif (st == null) {\n\t\t\tBUG(\"st == null\")\n\t\t\treturn\n\t\t}\n\n\t\tif (isFocusModeBreak) {\n\t\t\thandler.removeCallbacks(breakEndedCallback)\n\t\t}\n\t\toneAppUnsuspendCallbacks.forEach { handler.removeCallbacks(it) }\n\t\toneAppUnsuspendCallbacks.clear()\n\n\t\tisFocusModeEnabled = false\n\t\tisFocusModeBreak = false\n\n\t\tfor (s in getInstalledApplications(PackageManager.GET_META_DATA))\n\t\t\tif (((!focusModeInvertSelection && st.contains(s.packageName)) || (focusModeInvertSelection && !st.contains(s.packageName))) && isValidFocusPkg(s.packageName))\n\t\t\t\tsetFocusModeStateForPkgInternal(s.packageName, suspend = false, forBreak = false, forAppBreak = false)\n\n\t\tonStateChanged()\n\n\t\tdoUpdateTile(FocusModeQSTile::class.java)\n\t}\n\n\t// Runs every 12 hours\n\tfun onProcessStats(inBackground: Boolean) {\n\t\tval knownKeys = HashSet<String>()\n\t\tknownKeys.add(\"usage\")\n\t\t// Data saved for ~10 days. We make sure we don't delete correct data, so even if there is no data, it's OK.\n\t\tval absStart = ExactTime.plus(LocalDateTime.now(), TimeDimension.DAY, if (!inBackground) -3 else -10)\n\t\tval absEnd =  ExactTime.plus(LocalDateTime.now(), TimeDimension.DAY, 1)\n\t\tval dimension = TimeDimension.HOUR\n\t\tvar startTime = absStart\n\t\tvar endTime =\n\t\t\tExactTime.plus(startTime, dimension, 1)\n\t\twhile ((startTime.isAfter(absStart) || startTime.isEqual(absStart)) && startTime.isBefore(absEnd) && endTime.isAfter(absStart) && (endTime.isBefore(absEnd) || endTime.isEqual(absEnd))) {\n\t\t\tval result =\n\t\t\t\tUtils.calculateUsageStats(\n\t\t\t\t\tusm,\n\t\t\t\t\tExactTime.of(startTime, dimension) * 1000L,\n\t\t\t\t\t(ExactTime.of(endTime, dimension) - 1L) * 1000L\n\t\t\t\t)\n\t\t\tval calculatedScreenTime = result.first\n\t\t\tval calculatedUsageStats = result.second.first\n\t\t\tval curValue =\n\t\t\t\tdb.getCountFor(\"usage\", dimension, startTime,  ExactTime.plus(startTime, dimension, 1))\n\t\t\tval newValue = calculatedScreenTime.toMinutes()\n\t\t\tif (newValue > curValue)\n\t\t\t\tdb.insert(\"usage\", startTime, dimension, calculatedScreenTime.toMinutes())\n\t\t\tcalculatedUsageStats.forEach {\n\t\t\t\tval key = \"usage_${it.key}\"\n\t\t\t\tval curVal =\n\t\t\t\t\tdb.getCountFor(key, dimension, startTime,  ExactTime.plus(startTime, dimension, 1))\n\t\t\t\tval newVal = it.value.toMinutes()\n\t\t\t\tif (newVal > curVal)\n\t\t\t\t\tdb.insert(key, startTime, dimension, it.value.toMinutes())\n\t\t\t\tknownKeys.add(key)\n\t\t\t}\n\t\t\tstartTime = endTime\n\t\t\tendTime = ExactTime.plus(startTime, dimension, 1)\n\t\t}\n\t\tknownKeys.forEach { db.consolidate(it, true) }\n\t\tlastStatsProcessed = System.currentTimeMillis()\n\t}\n\n\tfun getEventStatsByType(type: String, dimension: TimeDimension, from: LocalDateTime, to: LocalDateTime): Long {\n\t\treturn db.getCountFor(type, dimension, from, to)\n\t}\n\n\tfun getEventStatsByPrefix(prefix: String, dimension: TimeDimension, from: LocalDateTime, to: LocalDateTime): Map<String, Long> {\n\t\treturn db.getTypesForPrefix(prefix, dimension, from, to)\n\t}\n\n\tfun onFocusModePreferenceChanged(packageName: String) {\n\t\tloadSettings()\n\n\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\tval st = spref.getStringSet(\"focus_mode\", null)\n\t\tif (st == null) {\n\t\t\tBUG(\"st == null\")\n\t\t\treturn\n\t\t}\n\n\t\tsetFocusModeStateForPkgInternal(packageName, isFocusModeEnabled && isValidFocusPkg(packageName) &&\n\t\t\t\t((!focusModeInvertSelection && st.contains(packageName)) || (focusModeInvertSelection && !st.contains(packageName)))\n\t\t\t\t&& !isFocusModeBreak, isFocusModeEnabled && isFocusModeBreak, false)\n\t}\n\n\tfun takeFocusModeBreakWithDialog(activityContext: Activity, endActivity: Boolean, packageNames: Array<String>?) {\n\t\tloadSettings()\n\n\t\tval optionsS: Array<String> = Arrays.stream(breakTimeOptions).mapToObj { i ->\n\t\t\tcontext.resources.getQuantityString(R.plurals.break_mins, i, i)\n\t\t}.toArray { arrayOfNulls<String>(it) }\n\t\tval b = AlertDialog.Builder(activityContext)\n\t\t\t.setTitle(R.string.focus_mode_break)\n\t\t\t.setNegativeButton(R.string.cancel) { d, _ -> d.dismiss() }\n\t\t\t.setItems(optionsS) { _, i ->\n\t\t\t\tval breakMins = breakTimeOptions[i]\n\t\t\t\ttakeFocusModeBreak(packageNames, breakMins)\n\t\t\t\tif (endActivity) activityContext.finish()\n\t\t\t}\n\t\tb.show()\n\t}\n\n\tprivate val breakEndedCallback = Runnable { endFocusModeBreak(false) }\n\n\tfun endFocusModeBreak(needCancel: Boolean = true) {\n\t\tloadSettings()\n\n\t\tif (!isFocusModeEnabled) {\n\t\t\tBUG(\"Focus mode not active\")\n\t\t\treturn\n\t\t}\n\t\tif (!isFocusModeBreak) {\n\t\t\tBUG(\"No focus mode break active\")\n\t\t\treturn\n\t\t}\n\n\t\tif (needCancel) {\n\t\t\thandler.removeCallbacks(breakEndedCallback)\n\t\t}\n\n\t\tisFocusModeBreak = false\n\n\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\tval st = spref.getStringSet(\"focus_mode\", null)\n\t\tif (st == null) {\n\t\t\tBUG(\"st == null\")\n\t\t\treturn\n\t\t}\n\n\t\tfor (packageName in st) {\n\t\t\tsetFocusModeStateForPkgInternal(packageName, suspend = true, forBreak = true, forAppBreak = false)\n\t\t}\n\n\t\tonStateChanged()\n\t}\n\n\tprivate val oneAppUnsuspendCallbacks = ArrayList<Runnable>()\n\n\tprivate fun takeFocusModeBreak(packageNames: Array<String>?, breakMins: Int) {\n\t\tloadSettings()\n\n\t\tif (packageNames == null) {\n\t\t\ttakeFocusModeBreak(breakMins)\n\t\t\treturn\n\t\t}\n\t\tif (!isFocusModeEnabled) {\n\t\t\tBUG(\"Focus mode not active\")\n\t\t\treturn\n\t\t}\n\t\tif (isFocusModeBreak) {\n\t\t\tBUG(\"Focus mode break active\")\n\t\t\treturn\n\t\t}\n\n\t\tfor (packageName in packageNames) {\n\t\t\tsetFocusModeStateForPkgInternal(packageName, suspend = false, forBreak = true, forAppBreak = true)\n\t\t}\n\t\tval r = object : Runnable {\n\t\t\toverride fun run() {\n\t\t\t\toneAppUnsuspendCallbacks.remove(this)\n\t\t\t\tfor (packageName in packageNames) {\n\t\t\t\t\tsetFocusModeStateForPkgInternal(packageName, isFocusModeEnabled, isFocusModeEnabled, true)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toneAppUnsuspendCallbacks.add(r)\n\t\thandler.postDelayed(r, breakMins * 60 * 1000L)\n\n\t\tonStateChanged()\n\t}\n\n\tfun takeFocusModeBreak(breakMins: Int) {\n\t\tloadSettings()\n\n\t\tif (!isFocusModeEnabled) {\n\t\t\tBUG(\"Focus mode not active\")\n\t\t\treturn\n\t\t}\n\t\tif (isFocusModeBreak) {\n\t\t\tBUG(\"Focus mode break active\")\n\t\t\treturn\n\t\t}\n\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\tval st = spref.getStringSet(\"focus_mode\", null)\n\t\tif (st == null) {\n\t\t\tBUG(\"st == null\")\n\t\t\treturn\n\t\t}\n\n\t\tisFocusModeBreak = true\n\n\t\tfor (packageName in st) {\n\t\t\tsetFocusModeStateForPkgInternal(packageName, suspend = false, forBreak = true, forAppBreak = false)\n\t\t}\n\n\t\thandler.postDelayed(breakEndedCallback, breakMins * 60 * 1000L)\n\n\t\tonStateChanged()\n\t}\n\n\tfun manualSuspend(packageNamesI: Array<String>?) {\n\t\tloadSettings()\n\n\t\tval packageNames: Array<String> = if (packageNamesI == null) {\n\t\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\t\tval packageNamesT = spref.getStringSet(\"manual_suspend\", null)\n\t\t\tif (packageNamesT == null) {\n\t\t\t\tBUG(\"packagesNames == null\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpackageNamesT.toTypedArray()\n\t\t} else packageNamesI\n\n\t\tfor (s in packageNames) {\n\t\t\tperAppState[s] = perAppState.getOrDefault(s, 0) or State.STATE_MANUAL_SUSPEND\n\t\t\tupdateSuspendStatusForApp(s)\n\t\t}\n\n\t\tonStateChanged()\n\t}\n\n\tfun manualUnsuspend(packageNamesI: Array<String>?) {\n\t\tloadSettings()\n\n\t\tval packageNames: Array<String> = if (packageNamesI == null) {\n\t\t\tval spref = context.getSharedPreferences(\"appLists\", 0)\n\t\t\tval packageNamesT = spref.getStringSet(\"manual_suspend\", null)\n\t\t\tif (packageNamesT == null) {\n\t\t\t\tBUG(\"packagesNames == null\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpackageNamesT.toTypedArray()\n\t\t} else packageNamesI\n\n\t\tfor (s in packageNames) {\n\t\t\tperAppState[s] = perAppState.getOrDefault(s, 0) and State.STATE_MANUAL_SUSPEND.inv()\n\t\t\tupdateSuspendStatusForApp(s)\n\t\t}\n\n\t\tonStateChanged()\n\t}\n\n\n\t// start time limit core\n\tprivate fun updatePrefs(key: String, value: Int) {\n\t\tif (value < 0) {\n\t\t\toidMap.edit().remove(key).apply()\n\t\t} else {\n\t\t\toidMap.edit().putInt(key, value).apply()\n\t\t}\n\t}\n\n\tprivate fun makeOid(): Int {\n\t\tval vals: Collection<*> = oidMap.all.values\n\t\t// try to save time by starting at size value\n\t\tfor (i in vals.size..999) {\n\t\t\tif (!vals.contains(i)) return i\n\t\t}\n\t\t// if all high values are used up, try all values\n\t\tfor (i in 0..999) {\n\t\t\tif (!vals.contains(i)) return i\n\t\t}\n\t\tthrow IllegalStateException(\"more than 1000 observers registered\")\n\t}\n\n\tprivate class ParsedUoid(val action: String, val timeMillis: Long, val pkgs: Array<String?>) {\n\t\toverride fun toString(): String {\n\t\t\treturn action + \":\" + timeMillis + \"//\" + java.lang.String.join(\":\", *pkgs)\n\t\t}\n\n\t\tcompanion object {\n\t\t\tfun from(uoid: String): ParsedUoid {\n\t\t\t\tval l = uoid.indexOf(\":\")\n\t\t\t\tval ll = uoid.indexOf(\"//\")\n\t\t\t\tval action = uoid.substring(0, l)\n\t\t\t\tval timeMillis = uoid.substring(l + 1, ll).toLong()\n\t\t\t\tval pkgs: Array<String?> =\n\t\t\t\t\tuoid.substring(ll + 2).split(\":\".toRegex()).dropLastWhile { it.isEmpty() }\n\t\t\t\t\t\t.toTypedArray()\n\t\t\t\treturn ParsedUoid(action, timeMillis, pkgs)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fun setUnhintedAppTimerInternal(\n\t\toid: Int,\n\t\tuoid: String,\n\t\ttoObserve: Array<String?>,\n\t\ttimeLimit: Duration\n\t) {\n\t\tval i = Intent(context, AppTimersBroadcastReceiver::class.java)\n\t\ti.putExtra(\"observerId\", oid)\n\t\ti.putExtra(\"uniqueObserverId\", uoid)\n\t\tval pintent: PendingIntent =\n\t\t\tPendingIntent.getBroadcast(context, oid, i, PendingIntent.FLAG_IMMUTABLE)\n\t\tPackageManagerDelegate.registerAppUsageObserver(\n\t\t\tusm,\n\t\t\toid,\n\t\t\ttoObserve,\n\t\t\ttimeLimit.toMillis(),\n\t\t\tTimeUnit.MILLISECONDS,\n\t\t\tpintent\n\t\t)\n\t}\n\n\tprivate fun setHintedAppTimerInternal(\n\t\toid: Int,\n\t\tuoid: String,\n\t\ttoObserve: Array<String?>,\n\t\ttimeLimit: Duration,\n\t\ttimeUsed: Duration\n\t) {\n\t\tval i = Intent(context, AppTimersBroadcastReceiver::class.java)\n\t\ti.putExtra(\"observerId\", oid)\n\t\ti.putExtra(\"uniqueObserverId\", uoid)\n\t\tval pIntent =\n\t\t\tPendingIntent.getBroadcast(context, oid, i, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)\n\t\tPackageManagerDelegate.registerAppUsageLimitObserver(\n\t\t\tusm,\n\t\t\toid,\n\t\t\ttoObserve,\n\t\t\ttimeLimit,\n\t\t\ttimeUsed,\n\t\t\tpIntent\n\t\t)\n\t}\n\n\tprivate fun setAppTimerInternal(\n\t\tuoid: String,\n\t\ttoObserve: Array<String?>,\n\t\ttimeLimit: Duration,\n\t\ttimeUsed: Duration?\n\t) {\n\t\tval oid: Int = oidMap.getInt(uoid, -1)\n\t\tif (timeUsed == null) {\n\t\t\tsetUnhintedAppTimerInternal(oid, uoid, toObserve, timeLimit)\n\t\t} else {\n\t\t\tsetHintedAppTimerInternal(oid, uoid, toObserve, timeLimit, timeUsed)\n\t\t}\n\t}\n\n\tprivate fun dropAppTimer(parsedUoid: ParsedUoid) {\n\t\tval uoid = parsedUoid.toString()\n\t\tupdatePrefs(uoid, -1) //delete pref\n\t\tif (parsedUoid.action != \"AppLimit\") {\n\t\t\tPackageManagerDelegate.unregisterAppUsageLimitObserver(usm, oidMap.getInt(uoid, -1))\n\t\t} else {\n\t\t\tPackageManagerDelegate.unregisterAppUsageObserver(usm, oidMap.getInt(uoid, -1))\n\t\t}\n\t}\n\n\tprivate fun setAppTimer(\n\t\ttoObserve: Array<String?>,\n\t\ttimeLimit: Duration,\n\t\ttimeUsed: Duration?\n\t) {\n\t\t// AppLimit: do not provide info to launcher, use registerAppUsageObserver\n\t\t// AppTimer: provide info to launcher, use registerAppUsageLimitObserver\n\t\tval uoid = ParsedUoid(\n\t\t\tif (timeUsed == null) \"AppLimit\" else \"AppTimer\",\n\t\t\ttimeLimit.toMillis(),\n\t\t\ttoObserve\n\t\t).toString()\n\t\tvar timeLimitInternal = timeLimit\n\t\tif (timeUsed != null) {\n\t\t\ttimeLimitInternal = timeLimitInternal.minus(timeUsed)\n\t\t}\n\t\tif (!oidMap.contains(uoid)) {\n\t\t\tupdatePrefs(uoid, makeOid())\n\t\t}\n\t\tif (reminderMin > 0 && timeLimitInternal.toMinutes() > reminderMin) {\n\t\t\tval u = ParsedUoid(\"Reminder\", 0, toObserve).toString()\n\t\t\tif (!oidMap.contains(u)) {\n\t\t\t\tupdatePrefs(u, makeOid())\n\t\t\t}\n\t\t\tsetAppTimerInternal(u, toObserve, timeLimitInternal.minus(reminderMin.toLong(), ChronoUnit.MINUTES), null)\n\t\t}\n\t\tsetAppTimerInternal(uoid, toObserve, timeLimitInternal, timeUsed)\n\t}\n\t// end time limit core\n\n\tfun onUpdatePowerConnection() {\n\t\tval batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { context.registerReceiver(null, it) }\n\n\t\tval chargePlug: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) ?: -1\n\t\tval charging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB ||\n\t\t\t\tchargePlug == BatteryManager.BATTERY_PLUGGED_AC\n\n\t\tdoTrigger(!charging) { it is TimeChargerTriggerCondition && it.needCharger }\n\t}\n\n\tprivate fun ensureSchedSetup() {\n\t\ttriggers.forEach { it.setup(context) }\n\t}\n\n\tprivate fun triggerFired(expire: Boolean, trigger: Trigger) {\n\t\twhen (trigger.id) {\n\t\t\t\"bedtime_mode\" -> {\n\t\t\t\tif (expire && bedtimeModeEnabled) {\n\t\t\t\t\tsetBedtimeMode(false)\n\t\t\t\t} else if (!expire) {\n\t\t\t\t\tsetBedtimeMode(true)\n\t\t\t\t}\n\t\t\t}\n\t\t\t\"focus_mode\" -> {\n\t\t\t\tif (expire && isFocusModeEnabled) {\n\t\t\t\t\tdisableFocusMode()\n\t\t\t\t} else if (!expire) {\n\t\t\t\t\tenableFocusMode()\n\t\t\t\t}\n\t\t\t}\n\t\t\telse -> {\n\t\t\t\tBUG(\"invalid trigger id ${trigger.id} expire=$expire\")\n\t\t\t}\n\t\t}\n\t}\n\n\tfun doTrigger(expire: Boolean, condition: (Trigger) -> Boolean) {\n\t\ttriggers.forEach { fired ->\n\t\t\tif (condition(fired) && // is this the trigger we're searching for?\n\t\t\t\t(expire || // is this an deactivation request?\n\t\t\t\t\t\t(fired !is Condition) || // if this trigger is an condition, it needs to be fulfilled\n\t\t\t\t\t\tfired.isFulfilled(context))) {\n\t\t\t\ttriggerFired(expire, fired)\n\t\t\t}\n\t\t}\n\t}\n\n\tfun onAlarmFired(id: String) {\n\t\tif (\"alc\" == id) {\n\t\t\talc.fired()\n\t\t\treturn\n\t\t}\n\t\tif (\"__STATS\" == id) {\n\t\t\tbgHandler.post { onProcessStats(true) }\n\t\t\treturn\n\t\t}\n\t\tvar t = false\n\t\tval nid = if (id.startsWith(\"expire::\")) {\n\t\t\tt = true\n\t\t\tid.substring(8)\n\t\t} else id\n\t\tdoTrigger(t) { it is TimeChargerTriggerCondition && it.iid == nid }\n\t}\n\n\tfun setTriggersForId(id: String, triggersIn: Array<out Trigger>) {\n\t\ttriggers.filter { id == it.id }.forEach { it.dispose(context) }\n\t\ttriggers = triggers.filterNot { id == it.id }.toSet().plus(triggersIn)\n\t\twriteSchedcfg()\n\t\tensureSchedSetup()\n\t}\n\n\tfun getTriggersForId(id: String): List<Trigger> {\n\t\treturn triggers.filter { id == it.id }\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/lib/WellbeingStateUtil.kt",
    "content": "package org.eu.droid_ng.wellbeing.lib\n\nimport android.app.*\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.graphics.drawable.Icon\nimport android.os.Binder\nimport android.os.Build\nimport android.os.IBinder\nimport android.util.Log\nimport android.widget.Toast\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport org.eu.droid_ng.wellbeing.lib.WellbeingStateHost.LocalBinder\nimport org.eu.droid_ng.wellbeing.ui.MainActivity\nimport java.util.function.Consumer\n\n// Helper to connect to WellbeingStateHost\nclass WellbeingStateClient(context: Context) {\n    // Our context\n    private val context = context.applicationContext\n\n    // Don't attempt to unbind from the service unless the client has received some\n    // information about the service's state.\n    private var mShouldUnbind = false\n\n    // To invoke the bound service, first make sure that this value\n    // is not null.\n    private var mBoundService: WellbeingStateHost? = null\n\n    // Callback when service is connected\n    private var callback: Consumer<WellbeingService?>? = null\n\n    // Connection callback utility\n    private val mConnection: ServiceConnection = object : ServiceConnection {\n        override fun onServiceConnected(className: ComponentName, service: IBinder) {\n            mBoundService = try {\n                (service as LocalBinder).service\n            } catch (e: ClassCastException) {\n                Log.e(\"WellbeingStateClient\", Log.getStackTraceString(e))\n                Toast.makeText(\n                    context,\n                    \"Assertion failure (0xAE): Service is in another process. Please report this to the developers!\",\n                    Toast.LENGTH_SHORT\n                ).show()\n                BUG(\"0xAE: ${Log.getStackTraceString(e)}\")\n                return\n            }\n            callback!!.accept(mBoundService!!.state)\n        }\n\n        override fun onServiceDisconnected(className: ComponentName) {\n            mBoundService = null\n        }\n\n        /*override fun onNullBinding(className: ComponentName) {\n\t\t\tToast.makeText(context, \"Assertion failure (0xAF): Service is null. Please report this to the developers!\",\n\t\t\t\t\tToast.LENGTH_SHORT).show()\n\t\t\tBUG(\"service is null (0xAF)\")\n\t\t}*/\n    }\n\n    //backward compatibility does what we want, so ignore warning\n    @Suppress(\"deprecation\")\n    fun isServiceRunning(): Boolean {\n        val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n        for (service in manager.getRunningServices(Int.MAX_VALUE)) {\n            if (WellbeingStateHost::class.java.name == service.service.className) {\n                return true\n            }\n        }\n        return false\n    }\n\n    fun doBindService(\n        callback: Consumer<WellbeingService?>,\n        canHandleFailure: Boolean,\n        maybeStartService: Boolean = false,\n        lateNotify: Boolean = false\n    ): Boolean {\n        this.callback = callback\n        if (mBoundService != null) {\n            callback.accept(mBoundService!!.state)\n            return true\n        }\n        return if (isServiceRunning() && context.bindService(\n                Intent(context, WellbeingStateHost::class.java),\n                mConnection, Context.BIND_IMPORTANT\n            )\n        ) {\n            mShouldUnbind = true\n            true\n        } else {\n            if (maybeStartService) {\n                startService(lateNotify)\n                if (doBindService(callback, canHandleFailure = true, maybeStartService = false, lateNotify)) {\n                    return true\n                } else if (!canHandleFailure) {\n                    Toast.makeText(\n                        context,\n                        \"Assertion failure (0xAA): Failed to start service. Please report this to the developers!\",\n                        Toast.LENGTH_SHORT\n                    ).show()\n                    BUG(\"didn't start service (0xAA)\")\n                }\n            } else if (!canHandleFailure) {\n                Toast.makeText(\n                    context,\n                    \"Assertion failure (0xAD): Failed to find service. Please report this to the developers!\",\n                    Toast.LENGTH_SHORT\n                ).show()\n                BUG(\"no service (0xAD)\")\n            }\n            false\n        }\n    }\n\n    fun startService(lateNotify: Boolean = false) {\n        val i = Intent(context, WellbeingStateHost::class.java)\n        i.putExtra(\"lateNotify\", lateNotify)\n        context.startForegroundService(i)\n    }\n\n    fun killService() {\n        context.stopService(Intent(context, WellbeingStateHost::class.java))\n    }\n}\n\n// Fancy class holding WellbeingService & a notification\nclass WellbeingStateHost : Service() {\n    var state: WellbeingService? = null\n    private var lateNotify = false\n    private var mStopped = false\n\n    // Unique Identification Number for the Notification.\n    private val notificationId = 325563\n    private val channelId = \"service_notif\"\n\n    /**\n     * Class for clients to access.  Because we know this service always\n     * runs in the same process as its clients, we don't need to deal with\n     * IPC.\n     */\n    inner class LocalBinder : Binder() {\n        val service: WellbeingStateHost\n            get() = this@WellbeingStateHost\n    }\n\n    override fun onCreate() {\n        state = WellbeingService.get()\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        val notificationManager = getSystemService(\n            NotificationManager::class.java\n        )\n        val channel = NotificationChannel(\n            channelId,\n            getString(R.string.channel_name),\n            NotificationManager.IMPORTANCE_LOW\n        )\n        channel.description = getString(R.string.channel_description)\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            channel.isBlockable = true\n        }\n        notificationManager.createNotificationChannel(channel)\n        if (intent != null) {\n            lateNotify = intent.getBooleanExtra(\"lateNotify\", lateNotify)\n        }\n\n        val n = buildDefaultNotification()\n\n        // Notification ID cannot be 0.\n        startForeground(notificationId, n)\n\n        state?.bindToHost(this)\n\n        return START_STICKY\n    }\n\n    fun buildAction(\n        actionText: Int,\n        actionIcon: Int,\n        actionIntent: Intent?,\n        isBroadcast: Boolean\n    ): Notification.Action {\n        val pendingIntent = if (isBroadcast) {\n            PendingIntent.getBroadcast(this, 0, actionIntent!!, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)\n        } else {\n            PendingIntent.getActivity(this, 0, actionIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)\n        }\n        val builder = Notification.Action.Builder(\n            Icon.createWithResource(applicationContext, actionIcon),\n            getText(actionText),\n            pendingIntent\n        )\n            .setAllowGeneratedReplies(false).setContextual(true)\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            builder.setAuthenticationRequired(true)\n        }\n        return builder.build()\n    }\n\n    private fun buildNotification(\n        title: Int,\n        text: String,\n        icon: Int,\n        actions: Array<Notification.Action?>,\n        notificationIntent: Intent\n    ): Notification {\n        val pendingIntent =\n            PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)\n        val b = Notification.Builder(this, channelId)\n            .setSmallIcon(icon) // the status icon\n            .setTicker(text) // the status text\n            .setWhen(System.currentTimeMillis()) // the time stamp\n            .setContentTitle(getText(title)) // the label of the entry\n            .setContentText(text) // the contents of the entry\n            .setContentIntent(pendingIntent) // The intent to send when the entry is clicked\n            .setOnlyAlertOnce(true) // don't headsup/bling twice\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !lateNotify) {\n            b.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE) // do not wait with showing the notification\n        }\n        if (lateNotify) lateNotify = false\n        for (action in actions) {\n            if (action != null)\n                b.addAction(action)\n        }\n        return b.build()\n    }\n\n    private fun buildDefaultNotification(): Notification {\n        val text = R.string.notification_desc\n        val title = R.string.notification_title\n        val icon = R.drawable.ic_stat_name\n        val notificationIntent = Intent(this, MainActivity::class.java)\n        return buildNotification(title, getString(text), icon, arrayOf(), notificationIntent)\n    }\n\n    private fun updateNotification(n: Notification) {\n        if (mStopped) return\n        getSystemService(NotificationManager::class.java).notify(notificationId, n)\n    }\n\n    private fun updateNotification(\n        title: Int,\n        text: String,\n        icon: Int,\n        actions: Array<Notification.Action?>,\n        notificationIntent: Intent\n    ) {\n        updateNotification(buildNotification(title, text, icon, actions, notificationIntent))\n    }\n\n    fun updateNotification(\n        title: Int,\n        text: Int,\n        icon: Int,\n        actions: Array<Notification.Action?>,\n        notificationIntent: Intent\n    ) {\n        updateNotification(title, getString(text), icon, actions, notificationIntent)\n    }\n\n    fun updateDefaultNotification() {\n        updateNotification(buildDefaultNotification())\n    }\n\n    fun stop() {\n        mStopped = true\n        stopForeground(STOP_FOREGROUND_REMOVE)\n        stopSelf()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        state?.bindToHost(null)\n    }\n\n    override fun onBind(intent: Intent): IBinder {\n        return mBinder\n    }\n\n    // This is the object that receives interactions from clients.  See\n    // RemoteService for a more complete example.\n    private val mBinder: IBinder = LocalBinder()\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/AppTimers.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.content.pm.ResolveInfo\nimport android.graphics.drawable.Drawable\nimport android.os.Bundle\nimport android.os.Handler\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.NumberPicker\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.appcompat.widget.AppCompatImageButton\nimport androidx.appcompat.widget.AppCompatImageView\nimport androidx.appcompat.widget.AppCompatTextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.checkbox.MaterialCheckBox\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.Utils\nimport org.eu.droid_ng.wellbeing.lib.Utils.clearUsageStatsCache\nimport org.eu.droid_ng.wellbeing.lib.Utils.getTimeUsed\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport org.eu.droid_ng.wellbeing.prefs.AppTimers.AppTimersRecyclerViewAdapter.AppTimerViewHolder\nimport java.text.Collator\nimport java.time.Duration\nimport java.util.stream.Collectors\n\nclass AppTimers : AppCompatActivity() {\n\tprivate var ati: WellbeingService? = null\n\tprivate var h: Handler? = null\n\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\th = Handler(mainLooper)\n\t\tati = get()\n\t\tsetContentView(R.layout.activity_app_timers)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\tval r = findViewById<RecyclerView>(R.id.appTimerPkgs)\n\t\tThread {\n\t\t\tval a = AppTimersRecyclerViewAdapter(\n\t\t\t\tthis,\n\t\t\t\tati!!.getInstalledApplications(PackageManager.GET_META_DATA)\n\t\t\t)\n\t\t\th!!.post {\n\t\t\t\tfindViewById<View>(R.id.appTimerLoading).visibility = View.GONE\n\t\t\t\tr.adapter = a\n\t\t\t\tr.visibility = View.VISIBLE\n\t\t\t}\n\t\t}.start()\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n\n\tinner class AppTimersRecyclerViewAdapter(context: Context, mData: List<ApplicationInfo>) :\n\t\tRecyclerView.Adapter<AppTimerViewHolder>() {\n\t\tprivate val inflater: LayoutInflater = LayoutInflater.from(context)\n\t\tprivate val mData: List<ApplicationInfo>\n\t\tprivate val pm: PackageManager = context.packageManager\n\t\tval prefs: SharedPreferences = context.getSharedPreferences(\"appTimers\", 0)\n\t\tval enabledMap: MutableMap<String, Int> = HashMap()\n\n\t\tinit {\n\t\t\tprefs.all.forEach { (k: String, v: Any?) ->\n\t\t\t\tif (v !is Int) {\n\t\t\t\t\tLog.e(\"OpenWellbeing\", \"Failed to parse $k\")\n\t\t\t\t\treturn@forEach\n\t\t\t\t}\n\t\t\t\tenabledMap[k] = v\n\t\t\t}\n\t\t\tval collator = Collator.getInstance()\n\t\t\t// Sort alphabetically by display name\n\t\t\tval nc = Comparator<ApplicationInfo> { a, b ->\n\t\t\t\tval durationA = getTimeUsed(\n\t\t\t\t\tati!!.usm, a.packageName\n\t\t\t\t)\n\t\t\t\tval durationB = getTimeUsed(ati!!.usm, b.packageName)\n\t\t\t\tval x = durationA.compareTo(durationB)\n\t\t\t\tif (x != 0) return@Comparator -x\n\t\t\t\tval displayA: CharSequence = getAppNameForPkgName(a.packageName)\n\t\t\t\tval displayB: CharSequence = getAppNameForPkgName(b.packageName)\n\t\t\t\tcollator.compare(displayA, displayB)\n\t\t\t}\n\t\t\tval mainIntent = Intent(Intent.ACTION_MAIN, null)\n\t\t\t\t.addCategory(Intent.CATEGORY_LAUNCHER)\n\n\t\t\t// We already force include user apps, so let's only iterate over system apps\n\t\t\tval hasLauncherIcon =\n\t\t\t\tpm.queryIntentActivities(mainIntent, PackageManager.MATCH_SYSTEM_ONLY)\n\t\t\t\t\t.stream().map { a: ResolveInfo -> a.activityInfo.packageName }\n\t\t\t\t\t.collect(Collectors.toList())\n\t\t\tthis.mData = mData.stream().filter {\n\t\t\t\t// Filter out system apps without launcher icon and Default Launcher\n\t\t\t\tval isUser =\n\t\t\t\t\t(it.flags and (ApplicationInfo.FLAG_UPDATED_SYSTEM_APP or ApplicationInfo.FLAG_SYSTEM)) < 1\n\t\t\t\t!Utils.blackListedPackages.contains(it.packageName) && (isUser || hasLauncherIcon.contains(\n\t\t\t\t\tit.packageName\n\t\t\t\t))\n\t\t\t}.sorted { a, b ->\n\t\t\t\t// Enabled goes first\n\t\t\t\tval hasA = enabledMap.getOrDefault(a.packageName, 0) != 0\n\t\t\t\tval hasB = enabledMap.getOrDefault(b.packageName, 0) != 0\n\t\t\t\tif (hasA && hasB) return@sorted nc.compare(a, b)\n\t\t\t\telse if (hasA) return@sorted -1\n\t\t\t\telse if (hasB) return@sorted 1\n\t\t\t\telse return@sorted nc.compare(a, b)\n\t\t\t}.collect(Collectors.toList())\n\t\t}\n\n\t\toverride fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppTimerViewHolder {\n\t\t\tval view = inflater.inflate(R.layout.appitem, parent, false)\n\t\t\treturn AppTimerViewHolder(view)\n\t\t}\n\n\t\toverride fun getItemCount(): Int {\n\t\t\treturn mData.size\n\t\t}\n\n\t\toverride fun onBindViewHolder(holder: AppTimerViewHolder, position: Int) {\n\t\t\tval i = mData[position]\n\t\t\tval mins = prefs.getInt(i.packageName, 0)\n\t\t\tholder.apply(i, mins)\n\t\t}\n\n\t\tinner class AppTimerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\t\t\tprivate val container: ViewGroup = itemView.findViewById(R.id.container)\n\t\t\tprivate val appIcon: AppCompatImageView = itemView.findViewById(R.id.appIcon)\n\t\t\tprivate val appName: AppCompatTextView = itemView.findViewById(R.id.appName2)\n\t\t\tprivate val appTimerInfo: AppCompatTextView = itemView.findViewById(R.id.pkgName)\n\t\t\tprivate val actionButton = AppCompatImageButton(itemView.context)\n\n\t\t\tinit {\n\t\t\t\tactionButton.setImageDrawable(\n\t\t\t\t\tAppCompatResources.getDrawable(\n\t\t\t\t\t\titemView.context, R.drawable.ic_focus_mode\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\tactionButton.background = null\n\t\t\t\tval checkBox = itemView.findViewById<MaterialCheckBox>(R.id.isChecked)\n\t\t\t\tval parent = checkBox.parent as ViewGroup\n\t\t\t\tval idx = parent.indexOfChild(checkBox)\n\t\t\t\tparent.removeView(checkBox)\n\t\t\t\tparent.addView(actionButton, idx)\n\t\t\t}\n\n\t\t\tfun apply(info: ApplicationInfo, mins: Int) {\n\t\t\t\tval restricted = Utils.restrictedPackages.contains(info.packageName)\n\t\t\t\tappIcon.setImageDrawable(getAppIconForPkgName(info.packageName))\n\t\t\t\tappName.text = getAppNameForPkgName(info.packageName)\n\t\t\t\tapplyText(\n\t\t\t\t\tmins, Math.toIntExact(\n\t\t\t\t\t\tgetTimeUsed(\n\t\t\t\t\t\t\tati!!.usm, info.packageName\n\t\t\t\t\t\t).toMinutes()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\tactionButton.isEnabled = !restricted\n\t\t\t\tcontainer.setOnClickListener {\n\t\t\t\t\tif (restricted) return@setOnClickListener\n\t\t\t\t\tval realmins = enabledMap.getOrDefault(info.packageName, 0)\n\t\t\t\t\tval numberPicker = NumberPicker(this@AppTimers)\n\t\t\t\t\tnumberPicker.minValue = 0\n\t\t\t\t\tnumberPicker.maxValue = 9999 //i mean why not\n\t\t\t\t\tnumberPicker.value = realmins\n\t\t\t\t\tAlertDialog.Builder(this@AppTimers)\n\t\t\t\t\t\t.setTitle(pm.getApplicationLabel(info))\n\t\t\t\t\t\t.setView(numberPicker)\n\t\t\t\t\t\t.setNegativeButton(R.string.cancel) { _, _ -> }\n\t\t\t\t\t\t.setPositiveButton(R.string.ok) { _, _ ->\n\t\t\t\t\t\t\tupdateMins(info.packageName, realmins, numberPicker.value)\n\t\t\t\t\t\t}\n\t\t\t\t\t\t.show()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate fun updateMins(pkgName: String, oldmins: Int, mins: Int) {\n\t\t\t\tenabledMap[pkgName] = mins\n\t\t\t\tprefs.edit().putInt(pkgName, mins).apply()\n\t\t\t\tapplyText(\n\t\t\t\t\tmins, Math.toIntExact(\n\t\t\t\t\t\tgetTimeUsed(\n\t\t\t\t\t\t\tati!!.usm, pkgName\n\t\t\t\t\t\t).toMinutes()\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\tThread {\n\t\t\t\t\tclearUsageStatsCache(ati!!.usm, pm, get().pmd, true)\n\t\t\t\t\th!!.post {\n\t\t\t\t\t\tapplyText(\n\t\t\t\t\t\t\tmins, Math.toIntExact(\n\t\t\t\t\t\t\t\tgetTimeUsed(\n\t\t\t\t\t\t\t\t\tati!!.usm, pkgName\n\t\t\t\t\t\t\t\t).toMinutes()\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\tati!!.onUpdateAppTimerPreference(\n\t\t\t\t\t\t\tpkgName,\n\t\t\t\t\t\t\tDuration.ofMinutes(oldmins.toLong())\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}.start()\n\t\t\t}\n\n\t\t\tprivate fun applyText(mins: Int, mins2: Int) {\n\t\t\t\tappTimerInfo.text = itemView.context.getString(\n\t\t\t\t\tR.string.desc_container,\n\t\t\t\t\tif (mins == 0) itemView.context.getString(R.string.no_timer) else itemView.context.resources.getQuantityString(\n\t\t\t\t\t\tR.plurals.break_mins,\n\t\t\t\t\t\tmins,\n\t\t\t\t\t\tmins\n\t\t\t\t\t),\n\t\t\t\t\titemView.context.resources.getQuantityString(R.plurals.break_mins, mins2, mins2)\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\tfun getAppNameForPkgName(tag: String): String {\n\t\treturn appNames.computeIfAbsent(tag) { packageName ->\n\t\t\tval pm = packageManager\n\t\t\ttry {\n\t\t\t\tval i = pm.getApplicationInfo(packageName, 0)\n\t\t\t\treturn@computeIfAbsent pm.getApplicationLabel(i).toString()\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent packageName\n\t\t\t}\n\t\t}\n\t}\n\n\tfun getAppIconForPkgName(tag: String): Drawable {\n\t\treturn appIcons.computeIfAbsent(tag) { packageName ->\n\t\t\tval pm = packageManager\n\t\t\ttry {\n\t\t\t\treturn@computeIfAbsent pm.getApplicationIcon(packageName)\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent AppCompatResources.getDrawable(\n\t\t\t\t\tthis@AppTimers,\n\t\t\t\t\tandroid.R.drawable.sym_def_app_icon\n\t\t\t\t)!!\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate val appIcons = hashMapOf<String, Drawable>()\n\tprivate val appNames = hashMapOf<String, String>()\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/BedtimeMode.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.material.checkbox.MaterialCheckBox\nimport com.google.android.material.materialswitch.MaterialSwitch\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport java.util.function.Consumer\n\nclass BedtimeMode : AppCompatActivity() {\n\tprivate val sc = Consumer { tw: WellbeingService ->\n\t\tval bt = findViewById<MaterialSwitch>(R.id.topsw)\n\t\tbt.isChecked = tw.getState(false).isBedtimeModeEnabled()\n\t}\n\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tsetContentView(R.layout.activity_bedtime_mode)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\tval tw = get()\n\t\tval prefs = getSharedPreferences(\"bedtime_mode\", 0)\n\n\t\tval bt = findViewById<MaterialSwitch>(R.id.topsw)\n\t\tfindViewById<View>(R.id.topsc).setOnClickListener { v: View? ->\n\t\t\tval b = !tw.getState(false).isBedtimeModeEnabled()\n\t\t\ttw.setBedtimeMode(b)\n\t\t\tbt.isChecked = b\n\t\t}\n\t\tbt.isChecked = tw.getState(false).isBedtimeModeEnabled()\n\t\tval checkBox2 = findViewById<MaterialCheckBox>(R.id.checkBox2)\n\t\tcheckBox2.isChecked = prefs.getBoolean(\"greyscale\", false)\n\t\tfindViewById<View>(R.id.greyscaleCheckbox).setOnClickListener { v: View? ->\n\t\t\tval b = !prefs.getBoolean(\"greyscale\", false)\n\t\t\tcheckBox2.isChecked = b\n\t\t\tval g = tw.getState(false).isBedtimeModeEnabled()\n\t\t\tprefs.edit().putBoolean(\"greyscale\", b).apply()\n\t\t\tif (g) {\n\t\t\t\ttw.cdm.setSaturationLevel(if (b) 0 else 100)\n\t\t\t}\n\t\t}\n\t\tval checkBox3 = findViewById<MaterialCheckBox>(R.id.checkBox3)\n\t\tcheckBox3.isChecked = prefs.getBoolean(\"airplane_mode\", false)\n\t\tfindViewById<View>(R.id.airplaneModeCheckbox).setOnClickListener { v: View? ->\n\t\t\tval b = !prefs.getBoolean(\"airplane_mode\", false)\n\t\t\tcheckBox3.isChecked = b\n\t\t\tval g = tw.getState(false).isBedtimeModeEnabled()\n\t\t\tprefs.edit().putBoolean(\"airplane_mode\", b).apply()\n\t\t\tif (g) {\n\t\t\t\ttw.setWellbeingAirplaneMode(b)\n\t\t\t}\n\t\t}\n\t\tfindViewById<View>(R.id.schedule).setOnClickListener { v: View? ->\n\t\t\tstartActivity(\n\t\t\t\tIntent(\n\t\t\t\t\tthis, ScheduleActivity::class.java\n\t\t\t\t).putExtra(\"type\", \"bedtime_mode\")\n\t\t\t\t\t.putExtra(\"name\", getString(R.string.bedtime_mode))\n\t\t\t)\n\t\t}\n\n\t\t//TODO: do not disturb\n\t\t//TODO: disable AOD(A11)\n\t\t//TODO: dim the wallpaper(A13)\n\t\t//TODO: dark theme(A13)\n\t\ttw.addStateCallback(sc)\n\t}\n\n\toverride fun onDestroy() {\n\t\tsuper.onDestroy()\n\t\tval tw = get()\n\t\ttw.removeStateCallback(sc)\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/DayPicker.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.widget.FrameLayout\nimport androidx.appcompat.widget.AppCompatToggleButton\nimport org.eu.droid_ng.wellbeing.R\nimport java.util.Calendar\nimport java.util.function.Consumer\n\nclass DayPicker(context: Context, attrs: AttributeSet?, defStyle: Int)\n\t: FrameLayout(context, attrs, defStyle) {\n\tprivate var views: Array<AppCompatToggleButton>\n\tvar values = BooleanArray(7) // Monday -> Sunday like Java DayOfWeek\n\t\tset(value) {\n\t\t\tfield = value\n\t\t\tfor (i in 0..6) {\n\t\t\t\tval v = views[i]\n\t\t\t\tval javaDayOfWeek = Math.floorMod((i + firstDayOfWeek), 7)\n\t\t\t\tv.isChecked = field[javaDayOfWeek]\n\t\t\t}\n\t\t}\n\tprivate var firstDayOfWeek = 0\n\tprivate var onValuesChangeListener: Consumer<BooleanArray>? = null\n\n\tconstructor(context: Context, attrs: AttributeSet?) : this(\n\t\tcontext, attrs, 0\n\t)\n\tconstructor(context: Context) : this(context, null)\n\n\tinit {\n\t\tinflate(context, R.layout.dpicker, this)\n\t\tval day1 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay1)\n\t\tval day2 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay2)\n\t\tval day3 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay3)\n\t\tval day4 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay4)\n\t\tval day5 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay5)\n\t\tval day6 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay6)\n\t\tval day7 = findViewById<AppCompatToggleButton>(R.id.dayPickerDay7)\n\t\tviews = arrayOf(day1, day2, day3, day4, day5, day6, day7)\n\n\t\tfirstDayOfWeek = (Calendar.getInstance().firstDayOfWeek - 2) % 7\n\t\tfor (i in 0..6) {\n\t\t\tval v = views[i]\n\t\t\tvar textToSet: Int\n\t\t\tval javaDayOfWeek = Math.floorMod((i + firstDayOfWeek), 7)\n\t\t\ttextToSet = when (javaDayOfWeek + 2) {\n\t\t\t\tCalendar.MONDAY -> R.string.dpicker_monday\n\t\t\t\tCalendar.TUESDAY -> R.string.dpicker_tuesday\n\t\t\t\tCalendar.WEDNESDAY -> R.string.dpicker_wednesday\n\t\t\t\tCalendar.THURSDAY -> R.string.dpicker_thursday\n\t\t\t\tCalendar.FRIDAY -> R.string.dpicker_friday\n\t\t\t\tCalendar.SATURDAY -> R.string.dpicker_saturday\n\t\t\t\tCalendar.SUNDAY -> R.string.dpicker_sunday\n\t\t\t\telse -> R.string.dpicker_sunday\n\t\t\t}\n\t\t\tval textToSet2: CharSequence = context.getString(textToSet)\n\t\t\tv.textOn = textToSet2\n\t\t\tv.textOff = textToSet2\n\t\t\tv.setOnCheckedChangeListener { _, isChecked ->\n\t\t\t\tvalues[javaDayOfWeek] = isChecked\n\t\t\t\tif (onValuesChangeListener != null) {\n\t\t\t\t\tonValuesChangeListener!!.accept(values)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.values = values // call setter\n\t}\n\tfun setOnValuesChangeListener(onValuesChangeListener: Consumer<BooleanArray>?) {\n\t\tthis.onValuesChangeListener = onValuesChangeListener\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/FocusModeActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.animation.LayoutTransition\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.AppCompatTextView\nimport androidx.appcompat.widget.LinearLayoutCompat\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.materialswitch.MaterialSwitch\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport java.util.function.Consumer\n\nclass FocusModeActivity : AppCompatActivity() {\n\tprivate val sc = Consumer<WellbeingService> { updateUi() }\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tsetContentView(R.layout.activity_focusmode)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\tval layoutTransition =\n\t\t\t(findViewById<View>(R.id.focusModeRoot) as LinearLayoutCompat).layoutTransition\n\t\tlayoutTransition.enableTransitionType(LayoutTransition.CHANGING)\n\n\t\tfindViewById<View>(R.id.schedule).setOnClickListener {\n\t\t\tstartActivity(\n\t\t\t\tIntent(\n\t\t\t\t\tthis, ScheduleActivity::class.java\n\t\t\t\t).putExtra(\"type\", \"focus_mode\").putExtra(\"name\", getString(R.string.focus_mode))\n\t\t\t)\n\t\t}\n\n\t\tval tw = get()\n\t\ttw.addStateCallback(sc)\n\n\t\tval r = findViewById<RecyclerView>(R.id.focusModePkgs)\n\t\tr.adapter = PackageRecyclerViewAdapter(\n\t\t\tthis,\n\t\t\ttw.getInstalledApplications(PackageManager.GET_META_DATA),\n\t\t\t\"focus_mode\"\n\t\t) { packageName: String? ->\n\t\t\ttw.onFocusModePreferenceChanged(\n\t\t\t\tpackageName!!\n\t\t\t)\n\t\t}\n\n\t\tupdateUi()\n\t}\n\n\toverride fun onDestroy() {\n\t\tsuper.onDestroy()\n\t\tval tw = get()\n\t\ttw.removeStateCallback(sc)\n\t}\n\n\tprivate fun updateUi() {\n\t\tval tw = get()\n\t\tval state = tw.getState()\n\t\tval toggle = findViewById<MaterialSwitch>(R.id.topsw)\n\t\ttoggle.isChecked = state.isFocusModeEnabled()\n\t\tfindViewById<View>(R.id.topsc).setOnClickListener {\n\t\t\tif (state.isFocusModeEnabled()) {\n\t\t\t\ttw.disableFocusMode()\n\t\t\t} else {\n\t\t\t\ttw.enableFocusMode()\n\t\t\t}\n\t\t}\n\t\tval takeBreak = findViewById<View>(R.id.takeBreak)\n\t\t(findViewById<View>(R.id.title) as AppCompatTextView).setText(if (state.isOnFocusModeBreakGlobal()) R.string.focus_mode_break_end else R.string.focus_mode_break)\n\t\ttakeBreak.setOnClickListener {\n\t\t\tif (state.isOnFocusModeBreakGlobal()) {\n\t\t\t\ttw.endFocusModeBreak()\n\t\t\t} else {\n\t\t\t\ttw.takeFocusModeBreakWithDialog(this@FocusModeActivity, false, null)\n\t\t\t}\n\t\t}\n\t\ttakeBreak.visibility = if (state.isFocusModeEnabled()) View.VISIBLE else View.GONE\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/ManualSuspendActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.pm.PackageManager\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.button.MaterialButton\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\n\nclass ManualSuspendActivity : AppCompatActivity() {\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tsetContentView(R.layout.activity_manual_suspend)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\tval suspendbtn = findViewById<MaterialButton>(R.id.suspendbtn)\n\t\tval unsuspendbtn = findViewById<MaterialButton>(R.id.desuspendbtn)\n\t\tval pkgList = findViewById<RecyclerView>(R.id.pkgList)\n\t\tval a: PackageRecyclerViewAdapter\n\t\tpkgList.adapter = PackageRecyclerViewAdapter(\n\t\t\tthis,\n\t\t\tpackageManager.getInstalledApplications(PackageManager.GET_META_DATA),\n\t\t\t\"manual_suspend\", null\n\t\t).also { a = it }\n\t\tval tw = get()\n\t\tsuspendbtn.setOnClickListener { v: View? -> tw.manualSuspend(null) }\n\t\tunsuspendbtn.setOnClickListener { v: View? ->\n\t\t\ttw.manualUnsuspend(\n\t\t\t\ta.prefs.getStringSet(\"manual_suspend\", HashSet())!!.toTypedArray<String>()\n\t\t\t)\n\t\t}\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/PackageRecyclerViewAdapter.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.content.pm.ResolveInfo\nimport android.graphics.drawable.Drawable\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.CheckBox\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.recyclerview.widget.RecyclerView\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.Utils\nimport org.eu.droid_ng.wellbeing.prefs.PackageRecyclerViewAdapter.PackageNameViewHolder\nimport java.text.Collator\nimport java.util.function.Consumer\nimport java.util.stream.Collectors\n\ninternal class PackageRecyclerViewAdapter(\n\tprivate val mContext: Context,\n\tmData: List<ApplicationInfo>,\n\tprivate val settingsKey: String,\n\tprivate val callback: Consumer<String?>?\n) : RecyclerView.Adapter<PackageNameViewHolder>() {\n\tprivate val inflater: LayoutInflater = LayoutInflater.from(mContext)\n\tprivate val mData: List<ApplicationInfo>\n\tprivate val enabledArr: MutableList<String?>\n\tprivate val pm: PackageManager = mContext.packageManager\n\tval prefs: SharedPreferences = mContext.getSharedPreferences(\"appLists\", 0)\n\n\toverride fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PackageNameViewHolder {\n\t\tval view = inflater.inflate(R.layout.appitem, parent, false)\n\t\treturn PackageNameViewHolder(view)\n\t}\n\n\toverride fun getItemCount(): Int {\n\t\treturn mData.size\n\t}\n\n\toverride fun onBindViewHolder(holder: PackageNameViewHolder, position: Int) {\n\t\tholder.apply(mData[position].packageName)\n\t}\n\n\tinner class PackageNameViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\t\tprivate val container: View = itemView.findViewById(R.id.container)\n\t\tprivate val appIcon: ImageView = itemView.findViewById(R.id.appIcon)\n\t\tprivate val appName: TextView = itemView.findViewById(R.id.appName2)\n\t\tprivate val pkgName: TextView = itemView.findViewById(R.id.pkgName)\n\t\tprivate val checkBox: CheckBox = itemView.findViewById(R.id.isChecked)\n\n\t\t@SuppressLint(\"ApplySharedPref\")\n\t\tfun apply(packageName: String?) {\n\t\t\tappIcon.setImageDrawable(getAppIconForPkgName(packageName))\n\t\t\tappName.text = getAppNameForPkgName(packageName)\n\t\t\tpkgName.text = packageName\n\t\t\tcheckBox.isChecked = enabledArr.contains(packageName)\n\t\t\tcontainer.setOnClickListener {\n\t\t\t\tvar enabled = enabledArr.contains(packageName)\n\t\t\t\tenabled = !enabled\n\t\t\t\tcheckBox.isChecked = enabled\n\t\t\t\tif (enabled) {\n\t\t\t\t\tenabledArr.add(packageName)\n\t\t\t\t} else {\n\t\t\t\t\tenabledArr.remove(packageName)\n\t\t\t\t}\n\t\t\t\tprefs.edit().putStringSet(settingsKey, HashSet(enabledArr)).commit()\n\t\t\t\tcallback?.accept(packageName)\n\t\t\t}\n\t\t}\n\t}\n\n\n\tfun getAppNameForPkgName(tag: String?): String {\n\t\treturn appNames.computeIfAbsent(tag) { packageName ->\n\t\t\ttry {\n\t\t\t\tval i = pm.getApplicationInfo(packageName!!, 0)\n\t\t\t\treturn@computeIfAbsent pm.getApplicationLabel(i).toString()\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent packageName!!\n\t\t\t}\n\t\t}\n\t}\n\n\tfun getAppIconForPkgName(tag: String?): Drawable {\n\t\treturn appIcons.computeIfAbsent(tag) { packageName: String? ->\n\t\t\ttry {\n\t\t\t\treturn@computeIfAbsent pm.getApplicationIcon(packageName!!)\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent AppCompatResources.getDrawable(\n\t\t\t\t\tmContext,\n\t\t\t\t\tandroid.R.drawable.sym_def_app_icon\n\t\t\t\t)!!\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate val appIcons: HashMap<String?, Drawable> = HashMap()\n\tprivate val appNames: HashMap<String?, String> = HashMap()\n\n\tinit {\n\t\tval focusAppsS = prefs.getStringSet(this.settingsKey, HashSet())!!\n\t\tenabledArr = ArrayList(focusAppsS)\n\t\tval collator = Collator.getInstance()\n\t\t// Sort alphabetically by display name\n\t\tval nc = java.util.Comparator { a: ApplicationInfo, b: ApplicationInfo ->\n\t\t\tval displayA: CharSequence = getAppNameForPkgName(a.packageName)\n\t\t\tval displayB: CharSequence = getAppNameForPkgName(b.packageName)\n\t\t\tcollator.compare(displayA, displayB)\n\t\t}\n\t\tval mainIntent = Intent(Intent.ACTION_MAIN, null)\n\t\t\t.addCategory(Intent.CATEGORY_LAUNCHER)\n\n\t\t// We already force include user apps, so let's only iterate over system apps\n\t\tval hasLauncherIcon = pm.queryIntentActivities(mainIntent, PackageManager.MATCH_SYSTEM_ONLY)\n\t\t\t.stream().map { a: ResolveInfo -> a.activityInfo.packageName }\n\t\t\t.collect(Collectors.toList())\n\t\tthis.mData = mData.stream().filter { i: ApplicationInfo ->\n\t\t\t// Filter out system apps without launcher icon and Settings, Dialer and Wellbeing\n\t\t\tval isUser =\n\t\t\t\t(i.flags and (ApplicationInfo.FLAG_UPDATED_SYSTEM_APP or ApplicationInfo.FLAG_SYSTEM)) < 1\n\t\t\t!Utils.restrictedPackages.contains(i.packageName) && (isUser || hasLauncherIcon.contains(\n\t\t\t\ti.packageName\n\t\t\t))\n\t\t}.sorted { a: ApplicationInfo, b: ApplicationInfo ->\n\t\t\t// Enabled goes first\n\t\t\tval hasA = enabledArr.contains(a.packageName)\n\t\t\tval hasB = enabledArr.contains(b.packageName)\n\t\t\tif (hasA && hasB) return@sorted nc.compare(a, b)\n\t\t\telse if (hasA) return@sorted -1\n\t\t\telse if (hasB) return@sorted 1\n\t\t\telse return@sorted nc.compare(a, b)\n\t\t}.collect(Collectors.toList())\n\t}\n}\n\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/ScheduleActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.os.Bundle\nimport android.util.Log\nimport android.util.TypedValue\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.AppCompatTextView\nimport androidx.appcompat.widget.LinearLayoutCompat\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport org.eu.droid_ng.wellbeing.lib.TimeChargerTriggerCondition\nimport org.eu.droid_ng.wellbeing.lib.Trigger\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport java.util.function.Consumer\n\nclass ScheduleActivity : AppCompatActivity() {\n\tprivate var type: String? = null\n\tprivate lateinit var data: MutableList<Trigger>\n\tprivate var cardHost: LinearLayoutCompat? = null\n\tprivate var noCardNotification: AppCompatTextView? = null\n\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tval intent = intent\n\t\ttype = null\n\t\tif (intent != null && intent.hasExtra(\"type\")) {\n\t\t\ttype = intent.getStringExtra(\"type\")\n\t\t}\n\t\tif (type == null) {\n\t\t\tLog.e(\"ScheduleActivity\", \"intent or type is null\")\n\t\t\tfinish()\n\t\t\treturn\n\t\t}\n\t\tsetContentView(R.layout.activity_schedule)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\tif (intent!!.hasExtra(\"name\")) {\n\t\t\tactionBar.title = intent.getStringExtra(\"name\")\n\t\t}\n\t\tfindViewById<View>(R.id.floating_action_button).setOnClickListener {\n\t\t\tdata.add(\n\t\t\t\tTimeChargerTriggerCondition(\n\t\t\t\t\ttype!!,\n\t\t\t\t\tSystem.currentTimeMillis().toString(),\n\t\t\t\t\ttrue,\n\t\t\t\t\t7,\n\t\t\t\t\t0,\n\t\t\t\t\t18,\n\t\t\t\t\t0,\n\t\t\t\t\tbooleanArrayOf(true, true, true, true, true, true, true),\n\t\t\t\t\tneedCharger = false,\n\t\t\t\t\tendOnAlarm = false\n\t\t\t\t)\n\t\t\t)\n\t\t\tupdateUi()\n\t\t\tupdateServiceStatus()\n\t\t}\n\t\tcardHost = findViewById(R.id.cardHost)\n\t\tnoCardNotification = AppCompatTextView(this)\n\t\tnoCardNotification!!.setText(R.string.add_schedule_info)\n\n\t\tval tw = get()\n\t\tdata = tw.getTriggersForId(type!!).toMutableList()\n\t\tupdateUi()\n\t}\n\n\tprivate fun updateUi() {\n\t\tcardHost!!.removeAllViews()\n\n\t\tfor (e in data) {\n\t\t\tif (e is TimeChargerTriggerCondition) {\n\t\t\t\tval scv = ScheduleCardView(this)\n\t\t\t\tscv.timeData = e\n\t\t\t\tscv.onValuesChangedCallback = Consumer { iid ->\n\t\t\t\t\tdata.replaceAll {\n\t\t\t\t\t\tif (it.iid == iid) scv.timeData else it\n\t\t\t\t\t}\n\t\t\t\t\tupdateUi()\n\t\t\t\t\tupdateServiceStatus()\n\t\t\t\t}\n\t\t\t\tscv.onDeleteCardCallback = Consumer { iid ->\n\t\t\t\t\tdata.removeIf { it.iid == iid }\n\t\t\t\t\tupdateUi()\n\t\t\t\t\tupdateServiceStatus()\n\t\t\t\t}\n\t\t\t\tcardHost!!.addView(scv)\n\t\t\t\tval m = LinearLayoutCompat.LayoutParams(scv.layoutParams)\n\t\t\t\tm.setMargins(\n\t\t\t\t\t0,\n\t\t\t\t\tTypedValue.applyDimension(\n\t\t\t\t\t\tTypedValue.COMPLEX_UNIT_DIP,\n\t\t\t\t\t\t10f,\n\t\t\t\t\t\tresources.displayMetrics\n\t\t\t\t\t).toInt(),\n\t\t\t\t\t0,\n\t\t\t\t\t0\n\t\t\t\t)\n\t\t\t\tscv.layoutParams = m\n\t\t\t} else {\n\t\t\t\tBUG(\"Cannot display \" + e.javaClass.canonicalName)\n\t\t\t}\n\t\t}\n\t\tif (data.size < 1) {\n\t\t\tcardHost!!.addView(noCardNotification)\n\t\t}\n\t}\n\n\tprivate fun updateServiceStatus() {\n\t\tval tw = get()\n\t\ttw.setTriggersForId(type!!, data.toTypedArray<Trigger>())\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/ScheduleCardView.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.view.View\nimport android.widget.FrameLayout\nimport androidx.appcompat.widget.AppCompatCheckBox\nimport com.google.android.material.materialswitch.MaterialSwitch\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.TimeChargerTriggerCondition\nimport java.time.LocalTime\nimport java.util.function.Consumer\n\nclass ScheduleCardView(context: Context, attrs: AttributeSet?, defStyleAttr: Int)\n\t: FrameLayout(context, attrs, defStyleAttr) {\n\tconstructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)\n\tconstructor(context: Context) : this(context, null)\n\n\tprivate var startTime: TimeSettingView\n\tprivate var endTime: TimeSettingView\n\tprivate var daypicker: DayPicker\n\tprivate var enable: MaterialSwitch\n\tprivate var charger: AppCompatCheckBox\n\tprivate var alarm: AppCompatCheckBox\n\tvar onValuesChangedCallback: Consumer<String?>? = null\n\tvar onDeleteCardCallback: Consumer<String?>? = null\n\tvar id: String? = null\n\tvar iid: String? = null\n\n\tinit {\n\t\tinflate(context, R.layout.schedule_card, this)\n\n\t\tstartTime = findViewById(R.id.startTime)\n\t\tendTime = findViewById(R.id.endTime)\n\t\tdaypicker = findViewById(R.id.dayPicker)\n\t\tenable = findViewById(R.id.enableCheckBox)\n\t\tcharger = findViewById(R.id.chargerCheckBox)\n\t\talarm = findViewById(R.id.alarmCheckBox)\n\n\t\tdaypicker.values = booleanArrayOf(true, true, true, true, true, true, true)\n\t\tstartTime.setData(LocalTime.of(7, 0))\n\t\tendTime.setData(LocalTime.of(18, 0))\n\t\tstartTime.setOnTimeChangedListener {\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tendTime.setOnTimeChangedListener {\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tdaypicker.setOnValuesChangeListener {\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tenable.setOnCheckedChangeListener { _, _ ->\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tfindViewById<View>(R.id.chargerLayout).setOnClickListener {\n\t\t\tcharger.isChecked = !charger.isChecked\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tfindViewById<View>(R.id.alarmLayout).setOnClickListener {\n\t\t\talarm.isChecked = !alarm.isChecked\n\t\t\tif (onValuesChangedCallback != null) {\n\t\t\t\tonValuesChangedCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t\tfindViewById<View>(R.id.delete).setOnClickListener {\n\t\t\tif (onDeleteCardCallback != null) {\n\t\t\t\tonDeleteCardCallback!!.accept(iid)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar timeData: TimeChargerTriggerCondition\n\t\tget() {\n\t\t\tval s = startTime.getData()\n\t\t\tval e = endTime.getData()\n\t\t\treturn TimeChargerTriggerCondition(\n\t\t\t\tid!!,\n\t\t\t\tiid!!,\n\t\t\t\tenable.isChecked,\n\t\t\t\ts.hour,\n\t\t\t\ts.minute,\n\t\t\t\te.hour,\n\t\t\t\te.minute,\n\t\t\t\tdaypicker.values,\n\t\t\t\tcharger.isChecked,\n\t\t\t\talarm.isChecked\n\t\t\t)\n\t\t}\n\t\tset(t) {\n\t\t\tid = t.id\n\t\t\tiid = t.iid\n\t\t\tenable.isChecked = t.enabled\n\t\t\tstartTime.setData(LocalTime.of(t.startHour, t.startMinute))\n\t\t\tendTime.setData(LocalTime.of(t.endHour, t.endMinute))\n\t\t\tdaypicker.values = t.weekdays\n\t\t\tcharger.isChecked = t.needCharger\n\t\t\talarm.isChecked = t.endOnAlarm\n\t\t}\n}\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/SettingsActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Intent\nimport android.os.Build\nimport android.os.Bundle\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.formatDateForRender\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.get\nimport org.eu.droid_ng.wellbeing.shim.PackageManagerDelegate\nimport java.util.Objects\n\nclass SettingsActivity : AppCompatActivity() {\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tsetContentView(R.layout.settings_activity)\n\t\tif (savedInstanceState == null) {\n\t\t\tsupportFragmentManager\n\t\t\t\t.beginTransaction()\n\t\t\t\t.replace(R.id.settings, SettingsFragment())\n\t\t\t\t.commit()\n\t\t}\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n\n\tclass SettingsFragment : PreferenceFragmentCompat() {\n\t\toverride fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n\t\t\tpreferenceManager.sharedPreferencesName = \"service\"\n\t\t\tsetPreferencesFromResource(R.xml.root_preferences, rootKey)\n\n\t\t\tif (!PackageManagerDelegate.canSetNeutralButtonAction()) {\n\t\t\t\t(Objects.requireNonNull<Any?>(findPreference(\"manual_dialog\")) as Preference).isEnabled =\n\t\t\t\t\tfalse\n\t\t\t\t(Objects.requireNonNull<Any?>(findPreference(\"focus_dialog\")) as Preference).isEnabled =\n\t\t\t\t\tfalse\n\t\t\t}\n\t\t\tval bugs = get()!!.getBugs() + WellbeingService.get().getBugs()\n\t\t\tif (bugs.isNotEmpty()) {\n\t\t\t\tval bugMap = bugs.toList().sortedBy { it.first }.map { Pair(formatDateForRender(it.first), it.second) }\n\t\t\t\tval a = bugMap.map { it.first }.toTypedArray<String>()\n\t\t\t\tval bp = findPreference<Preference>(\"bugs\")!!\n\t\t\t\tbp.isVisible = true\n\t\t\t\tbp.onPreferenceClickListener =\n\t\t\t\t\tPreference.OnPreferenceClickListener {\n\t\t\t\t\t\tAlertDialog.Builder(requireActivity())\n\t\t\t\t\t\t\t.setTitle(R.string.bug_viewer)\n\t\t\t\t\t\t\t.setAdapter(\n\t\t\t\t\t\t\t\tArrayAdapter(\n\t\t\t\t\t\t\t\t\trequireActivity(),\n\t\t\t\t\t\t\t\t\tandroid.R.layout.simple_list_item_1,\n\t\t\t\t\t\t\t\t\ta\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t) { _, pos ->\n\t\t\t\t\t\t\t\tval key = a[pos]\n\t\t\t\t\t\t\t\tval value = bugMap[pos].second\n\t\t\t\t\t\t\t\tAlertDialog.Builder(requireActivity())\n\t\t\t\t\t\t\t\t\t.setTitle(key)\n\t\t\t\t\t\t\t\t\t.setMessage(value)\n\t\t\t\t\t\t\t\t\t.setPositiveButton(R.string.share) { _, _ ->\n\t\t\t\t\t\t\t\t\t\tval sendIntent = Intent()\n\t\t\t\t\t\t\t\t\t\tsendIntent.setAction(Intent.ACTION_SEND)\n\t\t\t\t\t\t\t\t\t\tsendIntent.putExtra(Intent.EXTRA_TEXT, value)\n\t\t\t\t\t\t\t\t\t\tsendIntent.setType(\"text/plain\")\n\n\t\t\t\t\t\t\t\t\t\tval shareIntent = Intent.createChooser(sendIntent, null)\n\t\t\t\t\t\t\t\t\t\tstartActivity(shareIntent)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t.setNeutralButton(R.string.copy_to_clipboard) { _, _ ->\n\t\t\t\t\t\t\t\t\t\tval clipboard = requireActivity().getSystemService(\n\t\t\t\t\t\t\t\t\t\t\tCLIPBOARD_SERVICE\n\t\t\t\t\t\t\t\t\t\t) as ClipboardManager\n\t\t\t\t\t\t\t\t\t\tval clip = ClipData.newPlainText(\"Bug report\", value)\n\t\t\t\t\t\t\t\t\t\tclipboard.setPrimaryClip(clip)\n\t\t\t\t\t\t\t\t\t\tif (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {\n\t\t\t\t\t\t\t\t\t\t\t// T+ have built in indicator\n\t\t\t\t\t\t\t\t\t\t\tToast.makeText(\n\t\t\t\t\t\t\t\t\t\t\t\tactivity,\n\t\t\t\t\t\t\t\t\t\t\t\tR.string.copied,\n\t\t\t\t\t\t\t\t\t\t\t\tToast.LENGTH_LONG\n\t\t\t\t\t\t\t\t\t\t\t).show()\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t.setNegativeButton(R.string.cancel) { _, _ -> }\n\t\t\t\t\t\t\t\t\t.show()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t.setNegativeButton(R.string.cancel) { _, _ -> }\n\t\t\t\t\t\t\t.show()\n\t\t\t\t\t\ttrue\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/prefs/TimeSettingView.kt",
    "content": "package org.eu.droid_ng.wellbeing.prefs\n\nimport android.app.TimePickerDialog\nimport android.content.Context\nimport android.text.SpannableString\nimport android.text.format.DateFormat\nimport android.text.style.RelativeSizeSpan\nimport android.util.AttributeSet\nimport android.view.View\nimport android.widget.TimePicker\nimport androidx.appcompat.widget.AppCompatTextView\nimport java.time.LocalTime\nimport java.util.Locale\nimport java.util.function.Consumer\n\nclass TimeSettingView : AppCompatTextView {\n\tconstructor(context: Context?) : super(context!!) {\n\t\tinitView()\n\t}\n\n\tconstructor(context: Context?, attrs: AttributeSet?) : super(\n\t\tcontext!!, attrs\n\t) {\n\t\tinitView()\n\t}\n\n\tconstructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(\n\t\tcontext!!, attrs, defStyleAttr\n\t) {\n\t\tinitView()\n\t}\n\n\tprivate var data: LocalTime = LocalTime.of(0, 0)\n\tprivate var extraText = \"\"\n\tprivate val use24h = DateFormat.is24HourFormat(context)\n\tprivate var onTimeChangedListener: Consumer<LocalTime>? = null\n\n\tprivate fun initView() {\n\t\tupdateText()\n\t\tsetOnClickListener { v: View? ->\n\t\t\tTimePickerDialog(context, { tp: TimePicker?, h: Int, m: Int ->\n\t\t\t\tdata = LocalTime.of(h, m)\n\t\t\t\tupdateText()\n\t\t\t\tif (onTimeChangedListener != null) {\n\t\t\t\t\tonTimeChangedListener!!.accept(data)\n\t\t\t\t}\n\t\t\t}, data.hour, data.minute, use24h).show()\n\t\t}\n\t}\n\n\tprivate fun updateText() {\n\t\tvar hour: Int\n\t\tval minute: Int\n\t\tval amPmSymbol: String\n\t\tval o = extraText.length + 1\n\t\tif (use24h) {\n\t\t\thour = data.hour\n\t\t\tminute = data.minute\n\t\t\tamPmSymbol = \"\"\n\t\t} else {\n\t\t\thour = data.hour % 12\n\t\t\tif (hour == 0) {\n\t\t\t\thour = 12\n\t\t\t}\n\t\t\tminute = data.minute\n\t\t\tamPmSymbol = \" \" + (if (data.hour < 12) \"AM\" else \"PM\")\n\t\t}\n\t\tval s = extraText + \" \" + String.format(Locale.ROOT, \"%02d\", hour) + \":\" + String.format(\n\t\t\tLocale.ROOT, \"%02d\", minute\n\t\t) + amPmSymbol\n\t\tval spannableString = SpannableString(s)\n\t\tspannableString.setSpan(RelativeSizeSpan(1.5f), o, o + 2, 0) // hour\n\t\tspannableString.setSpan(RelativeSizeSpan(1.5f), o + 3, o + 5, 0) // minute\n\t\ttext = spannableString\n\t}\n\n\tfun setExtraText(extraText: String) {\n\t\tthis.extraText = extraText\n\t\tupdateText()\n\t}\n\n\tfun setData(data: LocalTime) {\n\t\tthis.data = data\n\t\tupdateText()\n\t}\n\n\tfun getData(): LocalTime {\n\t\treturn data\n\t}\n\n\tfun setOnTimeChangedListener(onTimeChangedListener: Consumer<LocalTime>?) {\n\t\tthis.onTimeChangedListener = onTimeChangedListener\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/shared/Database.kt",
    "content": "package org.eu.droid_ng.wellbeing.shared\n\nimport android.content.Context\nimport android.os.Handler\nimport android.util.Log\nimport androidx.room.Database\nimport androidx.room.Dao\nimport androidx.room.Delete\nimport androidx.room.Entity\nimport androidx.room.Insert\nimport androidx.room.OnConflictStrategy\nimport androidx.room.Query\nimport androidx.room.Room\nimport androidx.room.RoomDatabase\nimport androidx.room.Update\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport java.time.Instant\nimport java.time.LocalDateTime\nimport java.time.LocalTime\nimport java.time.ZoneId\n\n@Entity(primaryKeys = [\"date\", \"unit\", \"type\"])\nprivate data class StatEntry(\n\t// Unix time because yes\n\tval date: Long,\n\tval unit: TimeDimension = TimeDimension.ERROR,\n\tval type: String,\n\n\tval count: Long,\n) {\n\toverride fun toString(): String {\n\t\treturn \"StatEntry{date=$date, unit=$unit, count=$count}\"\n\t}\n}\n\nenum class TimeDimension {\n\tYEAR, MONTH, DAY, HOUR, ERROR\n}\n\nobject ExactTime {\n\tprivate fun ofHour(date: LocalDateTime): LocalDateTime {\n\t\treturn date.withMinute(0).withSecond(0).withNano(0)\n\t}\n\n\tprivate fun ofDay(date: LocalDateTime): LocalDateTime {\n\t\treturn ofHour(date.with(LocalTime.MIN))\n\t}\n\n\tprivate fun ofMonth(date: LocalDateTime): LocalDateTime {\n\t\treturn ofDay(date.withDayOfMonth(1))\n\t}\n\n\tprivate fun ofYear(date: LocalDateTime): LocalDateTime {\n\t\treturn ofMonth(date.withMonth(1))\n\t}\n\n\tfun ofUnit(date: LocalDateTime, dimension: TimeDimension): LocalDateTime {\n\t\treturn when(dimension) {\n\t\t\tTimeDimension.YEAR -> ofYear(date)\n\t\t\tTimeDimension.MONTH -> ofMonth(date)\n\t\t\tTimeDimension.DAY -> ofDay(date)\n\t\t\tTimeDimension.HOUR -> ofHour(date)\n\t\t\telse -> LocalDateTime.now()\n\t\t}\n\t}\n\n\tfun of(date: LocalDateTime, dimension: TimeDimension): Long {\n\t\treturn ofUnit(date, dimension).atZone(ZoneId.systemDefault()).toEpochSecond()\n\t}\n\n\tfun plus(old: LocalDateTime, dimension: TimeDimension?, count: Int): LocalDateTime {\n\t\twhen (dimension) {\n\t\t\tTimeDimension.YEAR -> return old.plusYears(count.toLong())\n\t\t\tTimeDimension.MONTH -> return old.plusMonths(count.toLong())\n\t\t\tTimeDimension.DAY -> return old.plusDays(count.toLong())\n\t\t\tTimeDimension.HOUR -> return old.plusHours(count.toLong())\n\t\t\telse -> {}\n\t\t}\n\t\tthrow IllegalArgumentException()\n\t}\n\n}\n\n@Dao\nprivate abstract class StatDao {\n\t@Insert(onConflict = OnConflictStrategy.ABORT)\n\tabstract fun insert(stat: StatEntry)\n\n\t@Insert(onConflict = OnConflictStrategy.REPLACE)\n\tabstract fun replace(stat: StatEntry)\n\n\t@Update\n\tabstract fun update(stat: StatEntry)\n\n\t@Delete\n\tabstract fun delete(stat: StatEntry)\n\n\t@Query(\n\t\t\"SELECT MIN(statentry.date) FROM statentry WHERE statentry.type = :type\"\n\t)\n\tabstract fun getEarliest(type: String): Long\n\n\t@Query(\n\t\t\"SELECT * FROM statentry WHERE statentry.type LIKE :prefix || '%' AND statentry.unit = :unit AND \" +\n\t\t\t\t\"statentry.date >= :min AND statentry.date < :max\"\n\t)\n\tabstract fun findStatsOfPrefixBetween(prefix: String, unit: TimeDimension, min: Long, max: Long): List<StatEntry>\n\n\t@Query(\n\t\t\"SELECT * FROM statentry WHERE statentry.type = :type AND statentry.unit = :unit AND \" +\n\t\t\t\t\"statentry.date >= :min AND statentry.date < :max\"\n\t)\n\tabstract fun findStatsOfTypeBetween(type: String, unit: TimeDimension, min: Long, max: Long): List<StatEntry>\n\n\t@Query(\n\t\t\"SELECT * FROM statentry WHERE statentry.type = :type AND statentry.unit = :unit AND \" +\n\t\t\t\t\"statentry.date = :date\"\n\t)\n\tabstract fun findStatsOfTypeWhere(type: String, unit: TimeDimension, date: Long): List<StatEntry>\n\n\tfun insert(type: String, date: LocalDateTime, dimension: TimeDimension, count: Long) {\n\t\tinsert(StatEntry(ExactTime.of(date, dimension), dimension, type, count))\n\t}\n\n\tfun replace(type: String, date: LocalDateTime, dimension: TimeDimension, count: Long) {\n\t\treplace(StatEntry(ExactTime.of(date, dimension), dimension, type, count))\n\t}\n\n\tfun increment(type: String, date: LocalDateTime, dimension: TimeDimension) {\n\t\tval results = findStatsOfTypeWhere(type, dimension, ExactTime.of(date, dimension))\n\t\tif (results.size > 1) {\n\t\t\t// Should never happen\n\t\t\tBUG(\"FATAL, destroying invalid data! results.size(${results.size}) > 1, ${results.joinToString(\";; \")}\")\n\t\t\tLog.e(\"WellbeingDatabase\", \"FATAL, destroying invalid data! results.size(${results.size}) > 1\")\n\t\t\tfor (i in 1..<results.size)\n\t\t\t\tdelete(results[i])\n\t\t}\n\t\tif (results.isEmpty()) {\n\t\t\tinsert(type, date, dimension, 1)\n\t\t} else {\n\t\t\tval oldEntry = results[0]\n\t\t\tupdate(StatEntry(oldEntry.date, oldEntry.unit, oldEntry.type,oldEntry.count + 1))\n\t\t}\n\t}\n}\n\n@Database(entities = [StatEntry::class], version = 1)\nprivate abstract class StatDb : RoomDatabase() {\n\tabstract fun statDao(): StatDao\n}\n\nclass Database(context: Context, private val bgHandler: Handler, private val consolidateDelay: Int) {\n\tprivate val db = Room.databaseBuilder(\n\t\tcontext,\n\t\tStatDb::class.java, \"stats\"\n\t).build()\n\tprivate val dao = db.statDao()\n\tprivate var lastConsolidate = 0L\n\n\tfun incrementNow(type: String) {\n\t\twhile (lastConsolidate == -1L) {\n\t\t\tThread.sleep(100)\n\t\t}\n\t\tdao.increment(type, LocalDateTime.now(), TimeDimension.HOUR)\n\t\tmaybeConsolidate(type)\n\t}\n\n\tfun insert(type: String, date: LocalDateTime, dimension: TimeDimension, count: Long) {\n\t\twhile (lastConsolidate == -1L) {\n\t\t\tThread.sleep(100)\n\t\t}\n\t\tdao.replace(type, date, dimension, count)\n\t\tmaybeConsolidate(type)\n\t}\n\n\tfun getCountFor(type: String, dimension: TimeDimension, from: LocalDateTime, to: LocalDateTime): Long {\n\t\twhile (lastConsolidate == -1L) {\n\t\t\tThread.sleep(100)\n\t\t}\n\t\tval tfrom = ExactTime.of(from, dimension)\n\t\tval tto = ExactTime.of(to, dimension)\n\t\tval results = dao.findStatsOfTypeBetween(type, dimension, tfrom, tto)\n\t\tif (results.isEmpty()) {\n\t\t\tval newdim = TimeDimension.entries[dimension.ordinal + 1]\n\t\t\tif (newdim == TimeDimension.ERROR) return 0\n\t\t\treturn getCountFor(type, newdim, from, to)\n\t\t}\n\t\tvar count = 0L\n\t\tresults.forEach { count += it.count }\n\t\tmaybeConsolidate(type)\n\t\treturn count\n\t}\n\n\tfun getTypesForPrefix(prefix: String, dimension: TimeDimension, from: LocalDateTime, to: LocalDateTime): Map<String, Long> {\n\t\twhile (lastConsolidate == -1L) {\n\t\t\tThread.sleep(100)\n\t\t}\n\t\tval tfrom = ExactTime.of(from, dimension)\n\t\tval tto = ExactTime.of(to, dimension)\n\t\tval results = dao.findStatsOfPrefixBetween(prefix, dimension, tfrom, tto)\n\t\tif (results.isEmpty()) {\n\t\t\tval newdim = TimeDimension.entries[dimension.ordinal + 1]\n\t\t\tif (newdim == TimeDimension.ERROR) return hashMapOf()\n\t\t\treturn getTypesForPrefix(prefix, newdim, from, to)\n\t\t}\n\t\tmaybeConsolidate(prefix)\n\t\tval fresult = HashMap<String, Long>()\n\t\tresults.forEach { fresult.merge(it.type, it.count) { old, new -> old + new } }\n\t\treturn fresult\n\t}\n\n\tprivate fun maybeConsolidate(type: String) {\n\t\tif (consolidateDelay > 0) {\n\t\t\tbgHandler.postDelayed({\n\t\t\t\tif (lastConsolidate + consolidateDelay > System.currentTimeMillis()) {\n\t\t\t\t\treturn@postDelayed\n\t\t\t\t}\n\t\t\t\tconsolidate(type)\n\t\t\t}, consolidateDelay / 2L)\n\t\t}\n\t}\n\n\tfun consolidate(type: String, every: Boolean = false) {\n\t\tif (lastConsolidate == -1L) return\n\t\tlastConsolidate = -1L\n\t\tval earliest = LocalDateTime.ofInstant(\n\t\t\tInstant.ofEpochSecond(dao.getEarliest(type)), ZoneId.systemDefault())\n\t\tconsolidateUnit(type,\n\t\t\tTimeDimension.DAY, { it.minusDays(1) }, false, earliest, LocalDateTime.now().minusDays(7)) // hour -> day. store hourly stats for 7 days\n\t\tconsolidateUnit(type,\n\t\t\tTimeDimension.MONTH, { it.minusMonths(1) }, false, earliest, LocalDateTime.now().minusMonths(3)) // day -> month. store daily stats for 3 months\n\t\tconsolidateUnit(type,\n\t\t\tTimeDimension.YEAR, { it.minusYears(1) }, every, earliest, LocalDateTime.now().minusYears(10)) // month -> year. store monthly stats for 10 years\n\t\tlastConsolidate = System.currentTimeMillis()\n\t}\n\n\tprivate fun consolidateUnit(type: String, dimension: TimeDimension, genFrom: (LocalDateTime) -> LocalDateTime, every: Boolean, earliest: LocalDateTime, last: LocalDateTime = LocalDateTime.now()) {\n\t\tif (!ExactTime.ofUnit(last, dimension).isAfter(earliest)) return\n\t\tval from = genFrom(last)\n\t\tval to = ExactTime.of(last, dimension)\n\t\tval newdim = TimeDimension.entries[dimension.ordinal + 1]\n\t\tif (newdim == TimeDimension.ERROR) return\n\t\tval results = dao.findStatsOfTypeBetween(type, newdim, ExactTime.of(from, dimension), to)\n\t\tvar count = 0L\n\t\tresults.forEach {\n\t\t\tcount += it.count\n\t\t}\n\t\tif (count > 0) {\n\t\t\tdao.insert(type, from, dimension, count)\n\t\t\tresults.forEach {\n\t\t\t\tdao.delete(it)\n\t\t\t}\n\t\t}\n\t\tif (every || results.isNotEmpty()) {\n\t\t\tconsolidateUnit(type, dimension, genFrom, every, earliest, from)\n\t\t}\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/shared/WellbeingFrameworkClient.kt",
    "content": "package org.eu.droid_ng.wellbeing.shared\n\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.os.Handler\nimport android.os.IBinder\nimport android.os.Looper\nimport android.os.RemoteException\nimport android.util.Log\nimport org.eu.droid_ng.wellbeing.framework.IWellbeingFrameworkService\n\nclass WellbeingFrameworkClient(\n\tprivate val context: Context,\n\tprivate val wellbeingService: ConnectionCallback\n) : IWellbeingFrameworkService {\n\tprivate val serviceConnection: ServiceConnection\n\tprivate var wellbeingFrameworkService: IWellbeingFrameworkService? = null\n\tprivate var binder: IBinder? = null\n\tprivate var versionCode = 0\n\tprivate var initial = true\n\n\tinit {\n\t\tserviceConnection = object : ServiceConnection {\n\t\t\toverride fun onServiceConnected(name: ComponentName, service: IBinder) {\n\t\t\t\twellbeingFrameworkService = IWellbeingFrameworkService.Stub.asInterface(\n\t\t\t\t\tservice.also {\n\t\t\t\t\t\tbinder = it\n\t\t\t\t\t})\n\t\t\t\ttry {\n\t\t\t\t\tversionCode = wellbeingFrameworkService!!.versionCode()\n\t\t\t\t} catch (e: Exception) {\n\t\t\t\t\tLog.e(\"WellbeingFrameworkService\", \"Failed to get framework version\", e)\n\t\t\t\t\tinvalidateConnection()\n\t\t\t\t\tcontext.unbindService(this)\n\t\t\t\t}\n\t\t\t\tif (binder != null || initial) {\n\t\t\t\t\tnotifyWellbeingService()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toverride fun onServiceDisconnected(name: ComponentName) {\n\t\t\t\tinvalidateConnection()\n\t\t\t\tif (versionCode > -2) HANDLER.post { tryConnect() }\n\t\t\t}\n\n\t\t\toverride fun onBindingDied(name: ComponentName) {\n\t\t\t\tinvalidateConnection()\n\t\t\t}\n\n\t\t\toverride fun onNullBinding(name: ComponentName) {\n\t\t\t\tinvalidateConnection()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fun invalidateConnection() {\n\t\twellbeingFrameworkService = DEFAULT\n\t\tversionCode = 0\n\t\tbinder = null\n\t\twellbeingService.onWellbeingFrameworkDisconnected()\n\t}\n\n\tprivate fun notifyWellbeingService() {\n\t\tinitial.let {\n\t\t\tinitial = false\n\t\t\twellbeingService.onWellbeingFrameworkConnected(it)\n\t\t}\n\t}\n\n\tfun tryConnect() {\n\t\tif (versionCode() < 0) return\n\t\tif (binder == null || !(binder!!.isBinderAlive && binder!!.pingBinder())) {\n\t\t\tversionCode = -1\n\t\t\ttry {\n\t\t\t\tcontext.bindService(\n\t\t\t\t\tFRAMEWORK_SERVICE_INTENT, serviceConnection,\n\t\t\t\t\tContext.BIND_NOT_FOREGROUND or Context.BIND_ALLOW_OOM_MANAGEMENT or Context.BIND_WAIVE_PRIORITY or Context.BIND_ABOVE_CLIENT\n\t\t\t\t)\n\t\t\t} catch (e: Exception) {\n\t\t\t\tLog.e(\"WellbeingFrameworkService\", \"Failed to bind framework service\", e)\n\t\t\t\tif (versionCode == -1) {\n\t\t\t\t\tversionCode = 0\n\t\t\t\t\tif (initial) {\n\t\t\t\t\t\tnotifyWellbeingService()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfun tryDisconnect() {\n\t\tif (versionCode() < 1) return\n\t\tif (binder != null && binder!!.isBinderAlive && binder!!.pingBinder()) {\n\t\t\tversionCode = -2\n\t\t\tcontext.unbindService(serviceConnection)\n\t\t}\n\t}\n\n\t// since 1\n\toverride fun versionCode(): Int {\n\t\tif (binder != null && !binder!!.isBinderAlive) {\n\t\t\tinvalidateConnection()\n\t\t}\n\t\treturn versionCode\n\t}\n\n\t// since 1\n\t@Throws(RemoteException::class)\n\toverride fun setAirplaneMode(value: Boolean) {\n\t\tif (versionCode() < 1) return\n\t\twellbeingFrameworkService!!.setAirplaneMode(value)\n\t}\n\n\t// only in 2\n\t@Deprecated(\"superseded by UsageEvents\")\n\t@Throws(RemoteException::class)\n\toverride fun onNotificationPosted(packageName: String) {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// only in 2\n\t@Deprecated(\"superseded by UsageEvents\")\n\t@Throws(RemoteException::class)\n\toverride fun getEventCount(type: String?, dimension: Int, from: Long, to: Long): Long {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// only in 2\n\t@Deprecated(\"superseded by UsageEvents\")\n\t@Throws(RemoteException::class)\n\toverride fun getTypesForPrefix(prefix: String?, dimension: Int, from: Long, to: Long): MutableMap<Any?, Any?> {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// since 3\n\toverride fun getBugs(): MutableMap<Any?, Any?> {\n\t\tif (versionCode() < 3) return mutableMapOf()\n\t\treturn wellbeingFrameworkService!!.getBugs()\n\t}\n\n\toverride fun asBinder(): IBinder {\n\t\treturn binder!!\n\t}\n\n\tcompanion object {\n\t\tprivate val HANDLER = Handler(Looper.getMainLooper())\n\t\tprivate val FRAMEWORK_SERVICE_INTENT =\n\t\t\tIntent(\"org.eu.droid_ng.wellbeing.framework.FRAMEWORK_SERVICE\")\n\t\t\t\t.setPackage(\"org.eu.droid_ng.wellbeing.framework\")\n\t\tprivate val DEFAULT: IWellbeingFrameworkService = IWellbeingFrameworkService.Default()\n\n\t\tinit {\n\t\t\tIWellbeingFrameworkService.Stub.setDefaultImpl(DEFAULT)\n\t\t}\n\t}\n\n\tinterface ConnectionCallback {\n\t\tfun onWellbeingFrameworkConnected(initial: Boolean)\n\t\tfun onWellbeingFrameworkDisconnected()\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ui/DashboardActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.ui\n\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.graphics.drawable.Drawable\nimport android.icu.text.SimpleDateFormat\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.text.format.DateFormat\nimport android.util.ArrayMap\nimport android.util.Pair\nimport android.util.TypedValue\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.annotation.ColorInt\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.appcompat.widget.AppCompatImageButton\nimport androidx.appcompat.widget.AppCompatImageView\nimport androidx.appcompat.widget.AppCompatTextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.github.mikephil.charting.charts.BarChart\nimport com.github.mikephil.charting.charts.PieChart\nimport com.github.mikephil.charting.data.BarData\nimport com.github.mikephil.charting.data.BarDataSet\nimport com.github.mikephil.charting.data.BarEntry\nimport com.github.mikephil.charting.data.PieData\nimport com.github.mikephil.charting.data.PieDataSet\nimport com.github.mikephil.charting.data.PieEntry\nimport com.github.mikephil.charting.utils.ColorTemplate\nimport com.google.android.material.checkbox.MaterialCheckBox\nimport com.google.android.material.chip.Chip\nimport com.google.android.material.datepicker.MaterialDatePicker\nimport com.google.android.material.timepicker.MaterialTimePicker\nimport com.google.android.material.timepicker.TimeFormat\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport org.eu.droid_ng.wellbeing.shared.ExactTime.ofUnit\nimport org.eu.droid_ng.wellbeing.shared.ExactTime.plus\nimport org.eu.droid_ng.wellbeing.shared.TimeDimension\nimport org.eu.droid_ng.wellbeing.ui.DashboardActivity.DashboardRecyclerViewAdapter.DashboardViewHolder\nimport java.text.Collator\nimport java.time.Instant\nimport java.time.LocalDateTime\nimport java.time.ZoneId\nimport java.util.Date\nimport java.util.concurrent.atomic.AtomicInteger\nimport java.util.concurrent.atomic.AtomicLong\nimport java.util.function.BiFunction\nimport java.util.function.Consumer\nimport java.util.function.Function\nimport java.util.function.Supplier\n\nclass DashboardActivity : AppCompatActivity() {\n\tprivate lateinit var ht: HandlerThread\n\tprivate lateinit var bgHandler: Handler\n\tprivate val appIcons = hashMapOf<String, Drawable>()\n\tprivate val appNames = hashMapOf<String, String>()\n\tprivate lateinit var whatStrings: Array<String?>\n\tprivate lateinit var whenStrings: Array<String?>\n\tprivate lateinit var thisStrings: Array<String>\n\tprivate var whatValue: Int = WhatStat.SCREEN_TIME.ordinal\n\tprivate var whenValue: Int = TimeDimension.DAY.ordinal\n\tprivate var mStart: LocalDateTime? = null\n\tprivate lateinit var chipWhen: Chip\n\tprivate lateinit var chipWhat: Chip\n\tprivate lateinit var chipStart: Chip\n\tprivate var didProcessTime = false\n\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tht = HandlerThread(\"DashboardActivity\")\n\t\tht.start()\n\t\tbgHandler = Handler(ht.looper)\n\t\tsetContentView(R.layout.activity_dashboard)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\t\twhatStrings = resources.getStringArray(R.array.chip_what_entries)\n\t\twhenStrings = resources.getStringArray(R.array.chip_when_entries)\n\t\tthisStrings = resources.getStringArray(R.array.chip_this_entries)\n\t\tchipWhen = findViewById(R.id.chip_when)\n\t\tchipWhat = findViewById(R.id.chip_what)\n\t\tchipStart = findViewById(R.id.chip_start)\n\t\tchipWhen.setOnClickListener {\n\t\t\tshowChipDialog(whenStrings, R.string.time_dimension_to_display, whenValue) { i: Int ->\n\t\t\t\twhenValue = i\n\t\t\t\trefresh(true)\n\t\t\t}\n\t\t}\n\t\tchipWhat.setOnClickListener {\n\t\t\tshowChipDialog(whatStrings, R.string.stat_to_display, whatValue) { i: Int ->\n\t\t\t\twhatValue = i\n\t\t\t\trefresh(false)\n\t\t\t}\n\t\t}\n\t\tchipStart.setOnClickListener {\n\t\t\tval `when` = TimeDimension.entries[whenValue]\n\t\t\tval dp = MaterialDatePicker.Builder.datePicker()\n\t\t\t\t.setTitleText(R.string.select_date)\n\t\t\t\t.setSelection(\n\t\t\t\t\tmStart!!.withHour(12).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()\n\t\t\t\t)\n\t\t\t\t.build()\n\t\t\tdp.addOnPositiveButtonClickListener { date: Long? ->\n\t\t\t\tif (`when` == TimeDimension.HOUR) {\n\t\t\t\t\tval tp = MaterialTimePicker.Builder()\n\t\t\t\t\t\t.setTitleText(R.string.select_hour)\n\t\t\t\t\t\t.setTimeFormat(if (DateFormat.is24HourFormat(this)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H)\n\t\t\t\t\t\t.setInputMode(MaterialTimePicker.INPUT_MODE_CLOCK)\n\t\t\t\t\t\t.setHour(mStart!!.hour)\n\t\t\t\t\t\t.setMinute(mStart!!.minute)\n\t\t\t\t\t\t.build()\n\t\t\t\t\ttp.addOnPositiveButtonClickListener {\n\t\t\t\t\t\tmStart = ofUnit(\n\t\t\t\t\t\t\tLocalDateTime.ofInstant(\n\t\t\t\t\t\t\t\tInstant.ofEpochMilli(\n\t\t\t\t\t\t\t\t\tdate!!\n\t\t\t\t\t\t\t\t), ZoneId.systemDefault()\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.withHour(tp.hour).withMinute(tp.minute), `when`\n\t\t\t\t\t\t)\n\t\t\t\t\t\trefresh(false)\n\t\t\t\t\t}\n\t\t\t\t\ttp.show(supportFragmentManager, \"chipStartTime\")\n\t\t\t\t} else {\n\t\t\t\t\tmStart = ofUnit(\n\t\t\t\t\t\tLocalDateTime.ofInstant(\n\t\t\t\t\t\t\tInstant.ofEpochMilli(\n\t\t\t\t\t\t\t\tdate!!\n\t\t\t\t\t\t\t), ZoneId.systemDefault()\n\t\t\t\t\t\t), `when`\n\t\t\t\t\t)\n\t\t\t\t\trefresh(false)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdp.show(supportFragmentManager, \"chipStartDate\")\n\t\t}\n\t\trefresh(true)\n\t}\n\n\tprivate fun refresh(resetDate: Boolean) {\n\t\tbgHandler.post {\n\t\t\tif (resetDate) mStart = ofUnit(LocalDateTime.now(), TimeDimension.entries[whenValue])\n\t\t\tupdateLabels()\n\t\t\tshowData {\n\t\t\t\tif (whatValue == WhatStat.SCREEN_TIME.ordinal && !didProcessTime) {\n\t\t\t\t\tget().onProcessStats(false) // takes a long time\n\t\t\t\t\tdidProcessTime = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toverride fun onDestroy() {\n\t\tsuper.onDestroy()\n\t\tht.quitSafely()\n\t}\n\n\tprivate fun updateLabels() {\n\t\trunOnUiThread {\n\t\t\tchipWhen.text = whenStrings[whenValue]\n\t\t\tchipWhat.text = whatStrings[whatValue]\n\t\t\tchipStart.text = fancyDate(mStart)\n\t\t}\n\t}\n\n\tprivate fun showChipDialog(\n\t\tvalues: Array<String?>?,\n\t\ttitle: Int,\n\t\tcurrentValue: Int,\n\t\tnewValueConsumer: Consumer<Int>\n\t) {\n\t\tval atom = AtomicInteger(currentValue)\n\t\tAlertDialog.Builder(this)\n\t\t\t.setSingleChoiceItems(\n\t\t\t\tvalues,\n\t\t\t\tcurrentValue\n\t\t\t) { _, which -> atom.set(which) }\n\t\t\t.setTitle(title)\n\t\t\t.setNeutralButton(R.string.cancel) { _, _ -> }\n\t\t\t.setPositiveButton(R.string.ok) { _, _ ->\n\t\t\t\tnewValueConsumer.accept(\n\t\t\t\t\tatom.get()\n\t\t\t\t)\n\t\t\t}\n\t\t\t.show()\n\t}\n\n\tprivate fun showData(preProcess: Runnable) {\n\t\tval what = WhatStat.entries[whatValue]\n\t\tval `when` = TimeDimension.entries[whenValue]\n\t\tshowData(\n\t\t\tpreProcess,\n\t\t\twhat.isRemote,\n\t\t\tif (`when` != TimeDimension.HOUR) what.tName else null,\n\t\t\twhat.prefix,\n\t\t\t`when`,\n\t\t\tmStart,\n\t\t\tplus(\n\t\t\t\tmStart!!, `when`, 1\n\t\t\t),\n\t\t\tgetString(R.string.stat_view_name, whatStrings[whatValue], whenStrings[whenValue]),\n\t\t\twhat.getSubtitleGenerator(\n\t\t\t\tthis\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate fun showData(\n\t\tpreProcess: Runnable,\n\t\tremote: Boolean,\n\t\tid: String?,\n\t\tprefix: String?,\n\t\tdimension: TimeDimension,\n\t\tstart: LocalDateTime?,\n\t\tend: LocalDateTime?,\n\t\tname: String?,\n\t\tsubtitleGenerator: BiFunction<String, Long, String?>?\n\t) {\n\t\tbgHandler.post {\n\t\t\tshowData(preProcess,\n\t\t\t\tif (prefix == null) null else Supplier<Map<String, Long>> {\n\t\t\t\t\tif (remote) /*get().getRemoteEventStatsByPrefix(prefix, dimension, start!!, end!!) TODO*/ hashMapOf()\n\t\t\t\t\telse get().getEventStatsByPrefix(prefix, dimension, start!!, end!!)\n\t\t\t\t},\n\t\t\t\tif (id == null) null else Supplier<Map<Int, Long>> {\n\t\t\t\t\tval count: MutableMap<Int, Long> = ArrayMap()\n\t\t\t\t\tval myDimension = TimeDimension.entries[dimension.ordinal + 1]\n\t\t\t\t\tvar newStart = start\n\t\t\t\t\tvar newEnd = plus(newStart!!, myDimension, 1)\n\t\t\t\t\tvar count2 =\n\t\t\t\t\t\tif (myDimension == TimeDimension.HOUR) 0 else 1 // hours start at 0 (midnight); days and months at 1\n\t\t\t\t\twhile ((newStart!!.isAfter(start) || newStart.isEqual(start)) && newStart.isBefore(\n\t\t\t\t\t\t\tend\n\t\t\t\t\t\t) && newEnd.isAfter(start) && (newEnd.isBefore(end) || newEnd.isEqual(end))\n\t\t\t\t\t) {\n\t\t\t\t\t\tcount[count2++] = if (remote) /*get().getRemoteEventStatsByType(\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\tmyDimension,\n\t\t\t\t\t\t\tnewStart,\n\t\t\t\t\t\t\tnewEnd\n\t\t\t\t\t\t) TODO */ 0\n\t\t\t\t\t\telse get().getEventStatsByType(id, myDimension, newStart, newEnd)\n\t\t\t\t\t\tnewStart = plus(newStart, myDimension, 1)\n\t\t\t\t\t\tnewEnd = plus(newEnd, myDimension, 1)\n\t\t\t\t\t}\n\t\t\t\t\tcount\n\t\t\t\t},\n\t\t\t\tname,\n\t\t\t\tif (prefix == null) null else Function { tag: String -> tag.substring(prefix.length) },\n\t\t\t\tsubtitleGenerator\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate fun showData(\n\t\tpreProcess: Runnable,\n\t\trawDataGenerator: Supplier<Map<String, Long>>?,\n\t\trawData2Generator: Supplier<Map<Int, Long>>?,\n\t\tdesc: String?,\n\t\tpackageNameGenerator: Function<String, String>?,\n\t\tsubtitleGenerator: BiFunction<String, Long, String?>?\n\t) {\n\t\trunOnUiThread {\n\t\t\tfindViewById<View>(R.id.dashboardLoading).visibility = View.VISIBLE\n\t\t\tfindViewById<View>(R.id.dashboardContainer).visibility = View.GONE\n\t\t}\n\t\tpreProcess.run()\n\t\tval bar = findViewById<BarChart>(R.id.chart)\n\t\tval pie = findViewById<PieChart>(R.id.chart2)\n\t\tval rawData: Map<String, Long>? = rawDataGenerator?.get()\n\t\tval rawData2: Map<Int, Long>? = rawData2Generator?.get()\n\t\tval pieEntries: MutableList<PieEntry> = ArrayList()\n\t\trawData?.forEach { (tag, count) ->\n\t\t\tpieEntries.add(\n\t\t\t\tPieEntry(\n\t\t\t\t\tcount.toFloat(), getAppNameForPkgName(\n\t\t\t\t\t\tpackageNameGenerator!!.apply(tag)\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\t\tpieEntries.sortWith { a, b ->\n\t\t\tb.value.compareTo(a.value)\n\t\t}\n\t\tif (pieEntries.size > 4) {\n\t\t\tval count = AtomicLong()\n\t\t\tval others = pieEntries.subList(4, pieEntries.size)\n\t\t\tothers.forEach(Consumer { p: PieEntry -> count.addAndGet(p.value.toLong()) })\n\t\t\tothers.clear()\n\t\t\tpieEntries.add(PieEntry(count.get().toFloat(), \"Other\"))\n\t\t}\n\t\trunOnUiThread {\n\t\t\tval set = PieDataSet(pieEntries, \"\")\n\t\t\tset.setColors(*ColorTemplate.JOYFUL_COLORS)\n\t\t\tval data = PieData(set)\n\t\t\tpie.data = data\n\t\t\tpie.description.text = desc\n\n\t\t\tpie.data.setValueTextColor(getAttrColor(com.google.android.material.R.attr.colorOnSurface))\n\t\t\tpie.setEntryLabelColor(getAttrColor(com.google.android.material.R.attr.colorOnSurface))\n\t\t\t//pie.getDescription().setTextSize(getTextSize(com.google.android.material.R.attr.tabTextAppearance));\n\t\t\tpie.description.textColor =\n\t\t\t\tgetAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tpie.setHoleColor(getAttrColor(com.google.android.material.R.attr.colorSurface))\n\t\t\tpie.legend.textColor = getAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tpie.legend.isWordWrapEnabled = true\n\t\t\tpie.invalidate() // refresh\n\t\t}\n\t\tval barEntries: MutableList<BarEntry> = ArrayList()\n\t\tval total2 = AtomicLong()\n\t\trawData2?.forEach { (tag: Int, count: Long) ->\n\t\t\tbarEntries.add(BarEntry(tag.toFloat(), count.toFloat()))\n\t\t\ttotal2.addAndGet(count)\n\t\t}\n\t\trunOnUiThread {\n\t\t\tval set = BarDataSet(barEntries, \"\")\n\t\t\tset.setColors(*ColorTemplate.MATERIAL_COLORS)\n\t\t\tval data = BarData(set)\n\t\t\tbar.data = data\n\t\t\tbar.description.text = getString(R.string.total, total2.get())\n\n\t\t\tbar.xAxis.textColor = getAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tbar.axisLeft.textColor = getAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tbar.axisRight.textColor =\n\t\t\t\tgetAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tbar.data.setValueTextColor(getAttrColor(com.google.android.material.R.attr.colorOnSurface))\n\t\t\t//bar.getDescription().setTextSize(getTextSize(com.google.android.material.R.attr.tabTextAppearance));\n\t\t\tbar.description.textColor =\n\t\t\t\tgetAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tbar.legend.textColor = getAttrColor(com.google.android.material.R.attr.colorOnSurface)\n\t\t\tbar.legend.isWordWrapEnabled = true\n\t\t\tbar.invalidate() // refresh\n\t\t}\n\n\t\tval r = findViewById<RecyclerView>(R.id.dashboardPkgs)\n\t\tval adapter: RecyclerView.Adapter<*>? = if (rawData != null) {\n\t\t\tDashboardRecyclerViewAdapter(this, rawData, packageNameGenerator, subtitleGenerator)\n\t\t} else {\n\t\t\tnull\n\t\t}\n\t\trunOnUiThread {\n\t\t\tif (rawData != null) {\n\t\t\t\tpie.visibility = View.VISIBLE\n\t\t\t} else {\n\t\t\t\tpie.visibility = View.GONE\n\t\t\t}\n\t\t\tif (rawData2 != null) {\n\t\t\t\tbar.visibility = View.VISIBLE\n\t\t\t} else {\n\t\t\t\tbar.visibility = View.GONE\n\t\t\t}\n\t\t\tif (pieEntries.isEmpty() && barEntries.isEmpty()) {\n\t\t\t\tfindViewById<View>(R.id.noData).visibility = View.VISIBLE\n\t\t\t} else {\n\t\t\t\tfindViewById<View>(R.id.noData).visibility = View.GONE\n\t\t\t}\n\t\t\tr.adapter = adapter\n\t\t\tfindViewById<View>(R.id.dashboardLoading).visibility = View.GONE\n\t\t\tfindViewById<View>(R.id.dashboardContainer).visibility = View.VISIBLE\n\t\t}\n\t}\n\n\tinner class DashboardRecyclerViewAdapter(\n\t\tcontext: Context?,\n\t\tdata: Map<String, Long>,\n\t\tpackageNameGenerator: Function<String, String>?,\n\t\tprivate val subtitleGenerator: BiFunction<String, Long, String?>?\n\t) : RecyclerView.Adapter<DashboardViewHolder>() {\n\t\tprivate val inflater: LayoutInflater = LayoutInflater.from(context)\n\t\tprivate val mData: MutableList<Pair<String, Long>> = ArrayList()\n\n\t\tinit {\n\t\t\tval collator = Collator.getInstance()\n\n\t\t\tdata.forEach { (i, j) ->\n\t\t\t\tval include = j > 0\n\t\t\t\tif (include) mData.add(\n\t\t\t\t\tPair(\n\t\t\t\t\t\tpackageNameGenerator!!.apply(i), j\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t}\n\t\t\tmData.sortWith { a, b ->\n\t\t\t\tval countA = a.second\n\t\t\t\tval countB = b.second\n\t\t\t\tval x = if (countA == null || countB == null) 0 else countA.compareTo(countB)\n\t\t\t\tif (x != 0) return@sortWith -x\n\t\t\t\tval displayA: CharSequence = getAppNameForPkgName(a.first)\n\t\t\t\tval displayB: CharSequence = getAppNameForPkgName(b.first)\n\t\t\t\tcollator.compare(displayA, displayB)\n\t\t\t}\n\t\t}\n\n\t\toverride fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashboardViewHolder {\n\t\t\tval view = inflater.inflate(R.layout.appitem, parent, false)\n\t\t\treturn DashboardViewHolder(view)\n\t\t}\n\n\t\toverride fun getItemCount(): Int {\n\t\t\treturn mData.size\n\t\t}\n\n\t\toverride fun onBindViewHolder(holder: DashboardViewHolder, position: Int) {\n\t\t\tval i = mData[position]\n\t\t\tholder.apply(i)\n\t\t}\n\n\t\tinner class DashboardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\t\t\tprivate val appIcon: AppCompatImageView = itemView.findViewById(R.id.appIcon)\n\t\t\tprivate val appName: AppCompatTextView = itemView.findViewById(R.id.appName2)\n\t\t\tprivate val subtitle: AppCompatTextView = itemView.findViewById(R.id.pkgName)\n\n\t\t\tinit {\n\t\t\t\tval actionButton = AppCompatImageButton(itemView.context)\n\t\t\t\tactionButton.setImageDrawable(\n\t\t\t\t\tAppCompatResources.getDrawable(\n\t\t\t\t\t\titemView.context, R.drawable.ic_focus_mode\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\tactionButton.background = null\n\t\t\t\tval checkBox = itemView.findViewById<MaterialCheckBox>(R.id.isChecked)\n\t\t\t\tval parent = checkBox.parent as ViewGroup\n\t\t\t\t//val idx = parent.indexOfChild(checkBox)\n\t\t\t\tparent.removeView(checkBox)\n\t\t\t\t//parent.addView(actionButton, idx)\n\t\t\t}\n\n\t\t\tfun apply(info: Pair<String, Long>) {\n\t\t\t\tappIcon.setImageDrawable(getAppIconForPkgName(info.first))\n\t\t\t\tappName.text = getAppNameForPkgName(info.first)\n\t\t\t\tsubtitle.text = subtitleGenerator!!.apply(info.first, info.second)\n\t\t\t}\n\t\t}\n\t}\n\n\tfun getAppNameForPkgName(tag: String): String {\n\t\treturn appNames.computeIfAbsent(tag) { packageName ->\n\t\t\tval pm = packageManager\n\t\t\ttry {\n\t\t\t\tval i = pm.getApplicationInfo(packageName, 0)\n\t\t\t\treturn@computeIfAbsent pm.getApplicationLabel(i).toString()\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent packageName\n\t\t\t}\n\t\t}\n\t}\n\n\tfun getAppIconForPkgName(tag: String): Drawable {\n\t\treturn appIcons.computeIfAbsent(tag) { packageName ->\n\t\t\tval pm = packageManager\n\t\t\ttry {\n\t\t\t\treturn@computeIfAbsent pm.getApplicationIcon(packageName)\n\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\treturn@computeIfAbsent AppCompatResources.getDrawable(\n\t\t\t\t\tthis@DashboardActivity,\n\t\t\t\t\tandroid.R.drawable.sym_def_app_icon\n\t\t\t\t)!!\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fun getAttrColor(attr: Int): Int {\n\t\tval typedValue = TypedValue()\n\t\tval theme = theme\n\t\ttheme.resolveAttribute(attr, typedValue, true)\n\t\t@ColorInt val color = typedValue.data\n\t\treturn color\n\t}\n\n\tprivate fun getTextSize(size: Int): Int {\n\t\tval typedValue = TypedValue()\n\t\ttheme.resolveAttribute(size, typedValue, true)\n\t\tval textSizeAttr = intArrayOf(android.R.attr.textSize)\n\t\tval a = obtainStyledAttributes(typedValue.data, textSizeAttr)\n\t\tval textSize = a.getDimensionPixelSize(0, -1)\n\t\ta.recycle()\n\t\treturn textSize\n\t}\n\n\tenum class WhatStat(\n\t\tval tName: String,\n\t\tval prefix: String?,\n\t\tval isRemote: Boolean,\n\t\tprivate val subtitleGeneratorGenerator: (Context) -> BiFunction<String, Long, String?>?\n\t) {\n\t\tSCREEN_TIME(\n\t\t\t\"usage\",\n\t\t\t\"usage_\",\n\t\t\tfalse,\n\t\t\t{ ctx ->\n\t\t\t\tBiFunction { _, count ->\n\t\t\t\t\tctx.resources.getQuantityString(\n\t\t\t\t\t\tR.plurals.break_mins,\n\t\t\t\t\t\tcount.toInt(),\n\t\t\t\t\t\tcount.toInt()\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}),\n\t\tNOTIFICATIONS(\n\t\t\t\"notif\",\n\t\t\t\"notif_\",\n\t\t\ttrue,\n\t\t\t{ ctx ->\n\t\t\t\tBiFunction { _, count ->\n\t\t\t\t\tctx.resources.getQuantityString(\n\t\t\t\t\t\tR.plurals.notifications_count,\n\t\t\t\t\t\tcount.toInt(), count\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}),\n\t\tUNLOCK(\"unlock\", null, true, { null });\n\n\t\tfun getSubtitleGenerator(context: Context): BiFunction<String, Long, String?>? {\n\t\t\treturn subtitleGeneratorGenerator(context)\n\t\t}\n\t}\n\n\t// \"Today\"/\"This week\"/etc or locale-sensible date\n\tprivate fun fancyDate(start: LocalDateTime?): String {\n\t\tif (plus(\n\t\t\t\tLocalDateTime.now(),\n\t\t\t\tTimeDimension.entries[whenValue],\n\t\t\t\t-1\n\t\t\t).isBefore(start) && !start!!.isAfter(\n\t\t\t\tLocalDateTime.now()\n\t\t\t)\n\t\t) {\n\t\t\treturn thisStrings[whenValue]\n\t\t}\n\t\tif (whenValue == TimeDimension.HOUR.ordinal) {\n\t\t\treturn SimpleDateFormat.getDateTimeInstance().format(\n\t\t\t\tDate(\n\t\t\t\t\tstart!!.atZone(ZoneId.systemDefault()).toEpochSecond() * 1000L\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\t\treturn SimpleDateFormat.getDateInstance()\n\t\t\t.format(Date(start!!.atZone(ZoneId.systemDefault()).toEpochSecond() * 1000L))\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ui/MainActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.ui\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.material.appbar.MaterialToolbar\nimport org.eu.droid_ng.wellbeing.R\n\nclass MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.settings_activity)\n        // Set the toolbar as support action so we can access it from fragments.\n        val topAppBar = findViewById<MaterialToolbar>(R.id.topbar)\n        setSupportActionBar(topAppBar)\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n        // Launch settings preference fragment\n        if (savedInstanceState == null) {\n            supportFragmentManager\n                .beginTransaction()\n                .replace(R.id.settings, MainPreferenceFragment())\n                .commit()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ui/MainPreferenceFragment.kt",
    "content": "package org.eu.droid_ng.wellbeing.ui\n\nimport android.os.Bundle\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport java.util.function.Consumer\n\nclass MainPreferenceFragment : PreferenceFragmentCompat() {\n\n    private val service: WellbeingService by lazy {\n        WellbeingService.get()\n    }\n\n    private val stateCallback = Consumer<WellbeingService> { _: WellbeingService ->\n        // Update summary on new state\n        updateSummary()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        setPreferencesFromResource(R.xml.main_preferences, rootKey)\n        findPreference<Preference>(\"manual\")?.apply {\n            val show = requireActivity().getSharedPreferences(\"service\", 0)\n                .getBoolean(\"manual\", false)\n            isVisible = show\n        }\n        // Update the summary of the preferences based on the state\n        updateSummary()\n        // Add state callback\n        service.addStateCallback(stateCallback)\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        // Remove state callback\n        service.removeStateCallback(stateCallback)\n    }\n\n    private fun updateSummary() {\n        val state = service.getState(false)\n        findPreference<Preference>(\"bedtime_mode\")?.apply {\n            val isBedTimeModeEnabled = state.isBedtimeModeEnabled()\n            summary = if (isBedTimeModeEnabled) getString(R.string.on) else getString(R.string.off)\n        }\n        findPreference<Preference>(\"timers\")?.apply {\n            val isAppTimerSet = state.isAppTimerSet()\n            summary = if (isAppTimerSet) getString(R.string.on) else getString(R.string.off)\n        }\n        findPreference<Preference>(\"manual\")?.apply {\n            val isManuallySuspended = state.isSuspendedManually()\n            summary = if (isManuallySuspended) getString(R.string.on) else getString(R.string.off)\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ui/ShowSuspendedAppDetails.kt",
    "content": "package org.eu.droid_ng.wellbeing.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.graphics.drawable.Drawable\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.AppCompatImageView\nimport androidx.appcompat.widget.AppCompatTextView\nimport com.google.android.material.card.MaterialCardView\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.shared.BugUtils.Companion.BUG\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport org.eu.droid_ng.wellbeing.shim.PackageManagerDelegate\n\nclass ShowSuspendedAppDetails : AppCompatActivity() {\n\tprivate var tw: WellbeingService? = null\n\tprivate var pmd: PackageManagerDelegate? = null\n\n\t@SuppressLint(\"SetTextI18n\")\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tval packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)\n\t\tif (packageName == null) {\n\t\t\tToast.makeText(\n\t\t\t\tthis@ShowSuspendedAppDetails,\n\t\t\t\t\"Assertion failure (0xAB): packageName is null. Please report this to the developers!\",\n\t\t\t\tToast.LENGTH_LONG\n\t\t\t).show()\n\t\t\tBUG(\"packageName == null (0xAB)\")\n\t\t\tfinish()\n\t\t\treturn\n\t\t}\n\t\ttw = get()\n\t\tval pm = packageManager\n\t\tpmd = PackageManagerDelegate(pm)\n\n\t\tsetContentView(R.layout.activity_show_suspended_app_details)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\n\t\tval iconView = findViewById<AppCompatImageView>(R.id.appIcon)\n\t\tval nameView = findViewById<AppCompatTextView>(R.id.appName)\n\t\tvar appInfo: ApplicationInfo? = null\n\t\tvar icon: Drawable? = null\n\t\tvar name: CharSequence? = null\n\t\ttry {\n\t\t\tappInfo = tw!!.getApplicationInfo(packageName, false)\n\t\t\ticon = pm.getApplicationIcon(appInfo)\n\t\t\tname = pm.getApplicationLabel(appInfo)\n\t\t} catch (ignored: PackageManager.NameNotFoundException) {\n\t\t}\n\t\tif (appInfo != null && icon != null && name != null) {\n\t\t\ticonView.setImageDrawable(icon)\n\t\t\tnameView.text = name\n\t\t}\n\t\tval reason = tw!!.getAppState(packageName)\n\t\tvar container: MaterialCardView\n\t\tvar hasReason = 0\n\t\tif (reason.isAppTimerExpired() && !reason.isAppTimerBreak()) {\n\t\t\thasReason++\n\t\t\tcontainer = findViewById(R.id.apptimer)\n\t\t\tfindViewById<View>(R.id.takeabreakbtn2).setOnClickListener { v: View? ->\n\t\t\t\ttw!!.takeAppTimerBreakWithDialog(\n\t\t\t\t\tthis@ShowSuspendedAppDetails, true, arrayOf(packageName)\n\t\t\t\t)\n\t\t\t}\n\t\t\tcontainer.visibility = View.VISIBLE\n\t\t}\n\t\tif (reason.isFocusModeEnabled() && !(reason.isOnFocusModeBreakGlobal() || reason.isOnFocusModeBreakPartial())) {\n\t\t\thasReason++\n\t\t\tcontainer = findViewById(R.id.focusMode)\n\t\t\tfindViewById<View>(R.id.takeabreakbtn).setOnClickListener { v: View? ->\n\t\t\t\ttw!!.takeFocusModeBreakWithDialog(\n\t\t\t\t\tthis@ShowSuspendedAppDetails,\n\t\t\t\t\ttrue,\n\t\t\t\t\tif (tw!!.focusModeAllApps) null else arrayOf(packageName)\n\t\t\t\t)\n\t\t\t}\n\t\t\tfindViewById<View>(R.id.disablefocusmode).setOnClickListener { v: View? ->\n\t\t\t\ttw!!.disableFocusMode()\n\t\t\t\tthis@ShowSuspendedAppDetails.finish()\n\t\t\t}\n\t\t\tcontainer.visibility = View.VISIBLE\n\t\t}\n\t\tif (reason.isSuspendedManually()) {\n\t\t\thasReason++\n\t\t\tcontainer = findViewById(R.id.manually)\n\t\t\tfindViewById<View>(R.id.unsuspendbtn2).setOnClickListener { v: View? ->\n\t\t\t\ttw!!.manualUnsuspend(arrayOf(packageName))\n\t\t\t\tthis@ShowSuspendedAppDetails.finish()\n\t\t\t}\n\t\t\tfindViewById<View>(R.id.unsuspendallbtn).setOnClickListener { v: View? ->\n\t\t\t\ttw!!.manualUnsuspend(null)\n\t\t\t\tthis@ShowSuspendedAppDetails.finish()\n\t\t\t}\n\t\t\tcontainer.visibility = View.VISIBLE\n\t\t}\n\t\tif (hasReason < 1 || reason.hasUpdateFailed()) {\n\t\t\tcontainer = findViewById(R.id.unknown)\n\t\t\tfindViewById<View>(R.id.unsuspendbtn).setOnClickListener { v: View? ->\n\t\t\t\tBUG(\"Used unknown unsuspend!!\")\n\t\t\t\tpmd!!.setPackagesSuspended(arrayOf(packageName), false, null, null, null)\n\t\t\t\tthis@ShowSuspendedAppDetails.finish()\n\t\t\t}\n\t\t\tcontainer.visibility = View.VISIBLE\n\t\t}\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/ui/TakeBreakDialogActivity.kt",
    "content": "package org.eu.droid_ng.wellbeing.ui\n\nimport android.os.Bundle\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ArrayAdapter\nimport android.widget.ListView\nimport androidx.appcompat.app.AppCompatActivity\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\n\nclass TakeBreakDialogActivity : AppCompatActivity() {\n\toverride fun onCreate(savedInstanceState: Bundle?) {\n\t\tsuper.onCreate(savedInstanceState)\n\t\tsetContentView(R.layout.take_a_break_activity)\n\t\tsetSupportActionBar(findViewById(R.id.topbar))\n\t\tval actionBar = checkNotNull(supportActionBar)\n\t\tactionBar.setDisplayHomeAsUpEnabled(true)\n\n\t\tval tw = get()\n\t\tval optionsS = WellbeingService.breakTimeOptions\n\t\t\t.map { i -> resources.getQuantityString(R.plurals.break_mins, i, i) }\n\t\t\t.toTypedArray()\n\t\tval a: ArrayAdapter<String> =\n\t\t\tobject : ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, optionsS) {\n\t\t\t\toverride fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n\t\t\t\t\tval v = super.getView(position, convertView, parent)\n\t\t\t\t\tv.setOnClickListener {\n\t\t\t\t\t\ttw.takeFocusModeBreak(WellbeingService.breakTimeOptions[position])\n\t\t\t\t\t\tthis@TakeBreakDialogActivity.finish()\n\t\t\t\t\t}\n\t\t\t\t\treturn v\n\t\t\t\t}\n\t\t\t}\n\t\tval lv = findViewById<ListView>(R.id.listView)\n\t\tlv.adapter = a\n\t}\n\n\toverride fun onSupportNavigateUp(): Boolean {\n\t\tfinish()\n\t\treturn true\n\t}\n}"
  },
  {
    "path": "app/src/main/java/org/eu/droid_ng/wellbeing/widget/ScreenTimeAppWidget.kt",
    "content": "package org.eu.droid_ng.wellbeing.widget\n\nimport android.app.PendingIntent\nimport android.appwidget.AppWidgetManager\nimport android.appwidget.AppWidgetProvider\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.util.Log\nimport android.view.View\nimport android.widget.RemoteViews\nimport org.eu.droid_ng.wellbeing.R\nimport org.eu.droid_ng.wellbeing.lib.Utils.clearUsageStatsCache\nimport org.eu.droid_ng.wellbeing.lib.Utils.getMostUsedPackages\nimport org.eu.droid_ng.wellbeing.lib.Utils.getScreenTime\nimport org.eu.droid_ng.wellbeing.lib.Utils.getTimeUsed\nimport org.eu.droid_ng.wellbeing.lib.WellbeingService.Companion.get\nimport java.time.Duration\n\nclass ScreenTimeAppWidget : AppWidgetProvider() {\n\tprivate var pendingIntent: PendingIntent? = null\n\n\toverride fun onReceive(context: Context, intent: Intent) {\n\t\tsuper.onReceive(context, intent)\n\n\t\tif (\"org.eu.droid_ng.wellbeing.APPWIDGET_UPDATE\" == intent.action) {\n\t\t\tval awm = AppWidgetManager.getInstance(context)\n\t\t\tonUpdate(\n\t\t\t\tcontext,\n\t\t\t\tawm,\n\t\t\t\tawm.getAppWidgetIds(ComponentName(context, ScreenTimeAppWidget::class.java))\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate fun checkInitialize(context: Context) {\n\t\tif (pendingIntent == null) {\n\t\t\tval intent = Intent(\"com.android.settings.action.IA_SETTINGS\")\n\t\t\tintent.setPackage(context.packageName)\n\t\t\tpendingIntent = PendingIntent.getActivity(\n\t\t\t\tcontext, this.hashCode(),\n\t\t\t\tintent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT\n\t\t\t)\n\t\t}\n\t}\n\n\toverride fun onEnabled(context: Context) {\n\t\tcheckInitialize(context)\n\t}\n\n\toverride fun onUpdate(\n\t\tcontext: Context,\n\t\tappWidgetManager: AppWidgetManager,\n\t\tappWidgetIds: IntArray\n\t) {\n\t\tcheckInitialize(context)\n\t\tclearUsageStatsCache(get().usm, context.packageManager, get().pmd, true)\n\n\t\tfor (appWidgetId in appWidgetIds) {\n\t\t\tappWidgetManager.updateAppWidget(\n\t\t\t\tappWidgetId,\n\t\t\t\tupdateLayout(context)\n\t\t\t)\n\t\t}\n\t}\n\n\toverride fun onDeleted(context: Context, appWidgetIds: IntArray) {\n\t}\n\n\toverride fun onDisabled(context: Context) {\n\t}\n\n\tprivate fun updateLayout(\n\t\tcontext: Context\n\t): RemoteViews {\n\t\tval usm = get().usm\n\t\tval remoteViews = RemoteViews(\n\t\t\tcontext.packageName, R.layout.appwidget_screen_time\n\t\t)\n\n\t\tremoteViews.setOnClickPendingIntent(R.id.appwidget_root, pendingIntent)\n\t\tremoteViews.setTextViewText(\n\t\t\tR.id.appwidget_screen_time,\n\t\t\tformatDuration(getScreenTime(usm))\n\t\t)\n\t\tval mostUsedPackages = getMostUsedPackages(usm)\n\t\tfor (i in appViewIds.indices) {\n\t\t\tif (i >= mostUsedPackages.size) {\n\t\t\t\tremoteViews.setViewVisibility(appView3Ids[i], View.GONE)\n\t\t\t\tremoteViews.setViewVisibility(appViewIds[i], View.GONE)\n\t\t\t} else {\n\t\t\t\tremoteViews.setViewVisibility(appViewIds[i], View.VISIBLE)\n\t\t\t\tremoteViews.setViewVisibility(appView3Ids[i], View.VISIBLE)\n\t\t\t\tval packageName = mostUsedPackages[i]\n\t\t\t\tvar packageLabel = packageName\n\t\t\t\ttry {\n\t\t\t\t\tpackageLabel = get()\n\t\t\t\t\t\t.getApplicationLabel(packageName).toString()\n\t\t\t\t} catch (e: PackageManager.NameNotFoundException) {\n\t\t\t\t\tLog.e(\"ScreenTimeAppWidget\", \"Failed to get app label!\")\n\t\t\t\t}\n\n\t\t\t\tremoteViews.setTextViewText(appViewIds[i], packageLabel)\n\t\t\t\tremoteViews.setTextViewText(\n\t\t\t\t\tappView2Ids[i],\n\t\t\t\t\tformatDuration(getTimeUsed(usm, packageName))\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\treturn remoteViews\n\t}\n\n\tcompanion object {\n\t\tprivate val appViewIds = intArrayOf(\n\t\t\tR.id.appwidget_app1_n, R.id.appwidget_app2_n, R.id.appwidget_app3_n\n\t\t)\n\t\tprivate val appView2Ids = intArrayOf(\n\t\t\tR.id.appwidget_app1_t, R.id.appwidget_app2_t, R.id.appwidget_app3_t\n\t\t)\n\t\tprivate val appView3Ids = intArrayOf(\n\t\t\tR.id.appwidget_app1_l, R.id.appwidget_app2_l, R.id.appwidget_app3_l\n\t\t)\n\n\t\tprivate fun formatDuration(duration: Duration): String {\n\t\t\tval hours = duration.toHours()\n\t\t\tvar minutes = duration.toMinutes()\n\t\t\tminutes -= (hours * 60)\n\t\t\treturn if (hours == 0L) {\n\t\t\t\tminutes.toString() + \"m\"\n\t\t\t} else if (minutes == 0L) {\n\t\t\t\thours.toString() + \"h\"\n\t\t\t} else {\n\t\t\t\thours.toString() + \"h \" +\n\t\t\t\t\t\tminutes + \"m\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "app/src/main/privapp-permissions-wellbeing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License\n-->\n\n<!--\n    This XML file declares which signature|privileged permissions should be granted to privileged\n    applications on droid-ng.\n    It allows additional grants on top of privapp-permissions-platform.xml\n-->\n<permissions>\n    <privapp-permissions package=\"org.eu.droid_ng.wellbeing\">\n        <permission name=\"android.permission.ACCESS_AMBIENT_CONTEXT_EVENT\" />\n        <permission name=\"android.permission.ACCESS_INSTANT_APPS\" />\n        <permission name=\"android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS\" />\n        <permission name=\"android.permission.CONTROL_DISPLAY_SATURATION\" />\n        <permission name=\"android.permission.INTERACT_ACROSS_PROFILES\" />\n        <permission name=\"android.permission.LOCATION_HARDWARE\" />\n        <permission name=\"android.permission.MODIFY_PHONE_STATE\" />\n        <permission name=\"android.permission.MODIFY_QUIET_MODE\" />\n        <permission name=\"android.permission.MODIFY_DAY_NIGHT_MODE\" />\n        <permission name=\"android.permission.OBSERVE_APP_USAGE\" />\n        <permission name=\"android.permission.PACKAGE_USAGE_STATS\" />\n        <permission name=\"android.permission.READ_DREAM_STATE\" />\n        <permission name=\"android.permission.READ_WALLPAPER_INTERNAL\" />\n        <permission name=\"android.permission.REAL_GET_TASKS\" />\n        <permission name=\"android.permission.SET_WALLPAPER_COMPONENT\" />\n        <permission name=\"android.permission.START_ACTIVITIES_FROM_BACKGROUND\" />\n        <permission name=\"android.permission.START_TASKS_FROM_RECENTS\" />\n        <permission name=\"android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME\" />\n        <permission name=\"android.permission.SUSPEND_APPS\" />\n        <permission name=\"android.permission.SCHEDULE_EXACT_ALARM\" />\n        <permission name=\"android.permission.WRITE_DREAM_STATE\" />\n\t    <permission name=\"android.permission.WRITE_SECURE_SETTINGS\" />\n        <permission name=\"android.permission.SET_WALLPAPER_DIM_AMOUNT\" />\n        <permission name=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\" />\n    </privapp-permissions>\n    <privapp-permissions package=\"org.eu.droid_ng.wellbeing.framework\">\n        <permission name=\"android.permission.INTERACT_ACROSS_USERS\" />\n        <permission name=\"android.permission.WRITE_SECURE_SETTINGS\" />\n        <permission name=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\" />\n    </privapp-permissions>\n</permissions>\n"
  },
  {
    "path": "app/src/main/res/drawable/appwidget_background.xml",
    "content": "<shape  xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <solid android:color=\"?android:attr/colorBackground\"/>\n    <corners android:bottomRightRadius=\"@dimen/app_widget_background_radius\"\n        android:bottomLeftRadius=\"@dimen/app_widget_background_radius\"\n        android:topRightRadius=\"@dimen/app_widget_background_radius\"\n        android:topLeftRadius=\"@dimen/app_widget_background_radius\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/appwidget_screen_time_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:shape=\"oval\">\n\t<solid android:color=\"@android:color/white\" />\n\t<size\n\t\tandroid:width=\"20dp\"\n\t\tandroid:height=\"20dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/baseline_airplanemode_active_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M22,16v-2l-8.5,-5V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5V9L2,14v2l8.5,-2.5V19L8,20.5L8,22l4,-1l4,1l0,-1.5L13.5,19v-5.5L22,16z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_alarm_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M22,5.72l-4.6,-3.86 -1.29,1.53 4.6,3.86L22,5.72zM7.88,3.39L6.6,1.86 2,5.71l1.29,1.53 4.59,-3.85zM12.5,8L11,8v6l4.75,2.85 0.75,-1.23 -4,-2.37L12.5,8zM12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_arrow_drop_down_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M7,10l5,5 5,-5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_battery_charging_full_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4zM11,20v-5.5H9L13,7v5.5h2L11,20z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_bedtime_24.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector android:height=\"32dip\" android:width=\"32dip\" android:viewportWidth=\"24.0\" android:viewportHeight=\"24.0\" android:tint=\"?android:attr/colorControlNormal\"\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#ffffffff\" android:pathData=\"M7,14c1.66,0 3,-1.34 3,-3S8.66,8 7,8s-3,1.34 -3,3 1.34,3 3,3zM19,7h-8v8L3,15L3,5L1,5v15h2v-3h18v3h2v-9c0,-2.21 -1.79,-4 -4,-4z\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/baseline_cancel_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_delete_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_exit_to_app_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_gradient_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11,9h2v2h-2zM9,11h2v2L9,13zM13,11h2v2h-2zM15,9h2v2h-2zM7,9h2v2L7,11zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM9,18L7,18v-2h2v2zM13,18h-2v-2h2v2zM17,18h-2v-2h2v2zM19,11h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2L9,15v-2L7,13v2L5,15v-2h2v-2L5,11L5,5h14v6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_schedule_24.xml",
    "content": "<vector android:height=\"28dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"28dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/dpicker_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<item android:state_checked=\"false\"\n\t\tandroid:drawable=\"@drawable/dpicker_outline_oval\" />\n\t<item android:state_checked=\"true\"\n\t\tandroid:drawable=\"@drawable/dpicker_shape_oval\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/dpicker_outline_oval.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:shape=\"oval\">\n\t<stroke android:width=\"0.1dp\" android:color=\"?attr/colorPrimary\" />\n\t<size\n\t\tandroid:width=\"20dp\"\n\t\tandroid:height=\"20dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/dpicker_shape_oval.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:shape=\"oval\">\n\t<solid android:color=\"?android:attr/colorPrimary\" />\n\t<size\n\t\tandroid:width=\"20dp\"\n\t\tandroid:height=\"20dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/dpicker_text_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<item android:state_checked=\"false\"\n\t\tandroid:color=\"?android:attr/colorAccent\"/>\n\n\t<item android:state_checked=\"true\"\n\t\tandroid:color=\"?attr/colorOnPrimary\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_access_time_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_app_blocking_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M18,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM15.5,12c0,-1.38 1.12,-2.5 2.5,-2.5 0.42,0 0.8,0.11 1.15,0.29l-3.36,3.36c-0.18,-0.35 -0.29,-0.73 -0.29,-1.15zM18,14.5c-0.42,0 -0.8,-0.11 -1.15,-0.29l3.36,-3.36c0.18,0.35 0.29,0.73 0.29,1.15 0,1.38 -1.12,2.5 -2.5,2.5zM17,18L7,18L7,6h10v1h2L19,3c0,-1.1 -0.9,-2 -2,-2L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2v1z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_bug_report_24.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_dashboard_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_king_bed_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20,10V7c0,-1.1 -0.9,-2 -2,-2H6C4.9,5 4,5.9 4,7v3c-1.1,0 -2,0.9 -2,2v5h1.33L4,19h1l0.67,-2h12.67L19,19h1l0.67,-2H22v-5C22,10.9 21.1,10 20,10zM11,10H6V7h5V10zM18,10h-5V7h5V10z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_person_24.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_person_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_settings_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z\"\n\t    tools:ignore=\"VectorPath\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <group android:scaleX=\"0.7\"\n      android:scaleY=\"0.7\"\n      android:translateX=\"76.8\"\n      android:translateY=\"76.8\">\n    <path\n        android:pathData=\"m291.99,209.97c-23.42,9.16 -35.45,-13.73 -20.5,-32.03 2.36,-2.42 4.37,-4.45 5.57,-5.59 19.96,-19.01 39.64,-27.03 72.37,-27.03 59.5,0 111,48.07 111,111 0,62.93 -49.37,109.4 -108.86,109.4 -43.15,0 -92.81,-20.21 -109.37,-103.41C229.13,196.67 196.45,182.32 164.43,182.32 122.79,182.32 90.43,216.88 90.43,256.32c0,39.61 32.1,74 74,74 19.3,0 42.9,-3.94 57.17,-27.63 14.64,-11.73 38.29,6.27 25.52,27.03 -18.47,26 -54.74,37.6 -82.7,37.6 -62.93,0 -111,-51.5 -111,-111 0,-59.35 48.36,-111 111,-111 52.77,0 90.15,24.78 109.37,101.27 16.78,66.78 34.95,83.59 75.63,83.73 40.58,0.13 74,-32.1 74,-74 0,-41.9 -34.39,-74 -74,-74 -23.14,0 -33.71,4.3 -46.85,16.82 -1.74,1.65 -10.58,10.82 -10.58,10.82z\"\n        android:strokeWidth=\"18.5\"\n        android:fillColor=\"#009102\"\n        android:fillType=\"evenOdd\"/>\n    <path\n        android:pathData=\"m120.69,213.53c0,-5.62 4.56,-10.23 10.19,-10.19L196.51,203.88c5.62,0.05 10.19,4.56 10.19,10.19 0,5.62 -4.56,10.23 -10.19,10.19L130.88,223.72c-5.62,-0.05 -10.19,-4.56 -10.19,-10.19zM212,247.71L106.3,247.71c-5.62,0 -10.19,4.56 -10.19,10.19 0,5.62 4.56,10.19 10.19,10.19L212,268.09c5.62,0 10.19,-4.56 10.19,-10.19 0,-5.62 -4.56,-10.19 -10.19,-10.19zM193.3,289.41 L130.88,289.95c-5.62,0.05 -10.19,4.56 -10.19,10.19 0,5.62 4.56,10.24 10.19,10.19L193.3,309.79c5.62,-0.05 10.19,-4.56 10.19,-10.19 0,-5.62 -4.56,-10.24 -10.19,-10.19z\"\n        android:fillColor=\"#eeab00\"/>\n    <path\n        android:pathData=\"M378.92,304.09 L378.87,274.21 359,254.3 378.87,234.33 378.92,204.5L319.16,204.5l0,29.88l19.92,19.92 -19.92,19.87L319.16,304.09ZM329.12,231.89L329.12,214.46l39.84,0l0,17.43l-19.92,19.92z\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"3.06\"\n        android:fillColor=\"#eeab00\"\n        android:strokeColor=\"#eeab00\"\n        android:strokeLineCap=\"round\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_plus_24.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector android:height=\"24dp\" android:tint=\"?android:attr/colorControlNormal\"\n\tandroid:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n\tandroid:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<path android:fillColor=\"#FF000000\" android:pathData=\"M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_settings.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:tint=\"?android:attr/colorBackground\"\n\tandroid:width=\"24dp\"\n\tandroid:height=\"24dp\"\n\tandroid:viewportWidth=\"24\"\n\tandroid:viewportHeight=\"24\">\n\t<!-- Icon must not be tinted, as it is tinted in settings via manifest -->\n\t<path\n\t\tandroid:fillColor=\"#ffffffff\"\n\t\tandroid:pathData=\"M18,22l-0.01,-6L14,12l3.99,-4.01L18,2H6v6l4,4l-4,3.99V22H18zM8,7.5V4h8v3.5l-4,4L8,7.5z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_badge_24.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"?android:attr/colorControlNormal\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M14,12h4v1.5h-4z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M14,15h4v1.5h-4z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,7h-5V4c0,-1.1 -0.9,-2 -2,-2h-2C9.9,2 9,2.9 9,4v3H4C2.9,7 2,7.9 2,9v11c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V9C22,7.9 21.1,7 20,7zM11,7V4h2v3v2h-2V7zM20,20H4V9h5c0,1.1 0.9,2 2,2h2c1.1,0 2,-0.9 2,-2h5V20z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,13.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11.08,16.18C10.44,15.9 9.74,15.75 9,15.75s-1.44,0.15 -2.08,0.43C6.36,16.42 6,16.96 6,17.57V18h6v-0.43C12,16.96 11.64,16.42 11.08,16.18z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-anydpi/ic_focus_mode.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:width=\"32dp\"\n\tandroid:height=\"32dp\"\n\tandroid:viewportWidth=\"24\"\n\tandroid:viewportHeight=\"24\"\n\tandroid:tint=\"?android:attr/colorControlNormal\">\n\t<group android:scaleX=\"0.92\"\n\t\tandroid:scaleY=\"0.92\"\n\t\tandroid:translateX=\"0.96\"\n\t\tandroid:translateY=\"0.96\">\n\t\t<path\n\t\t\tandroid:fillColor=\"@android:color/white\"\n\t\t\tandroid:pathData=\"M18,22l-0.01,-6L14,12l3.99,-4.01L18,2H6v6l4,4l-4,3.99V22H18zM8,7.5V4h8v3.5l-4,4L8,7.5z\"/>\n\t</group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-anydpi/ic_stat_name.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?android:attr/colorControlNormal\">\n  <group android:scaleX=\"0.92\"\n      android:scaleY=\"0.92\"\n      android:translateX=\"0.96\"\n      android:translateY=\"0.96\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18,22l-0.01,-6L14,12l3.99,-4.01L18,2H6v6l4,4l-4,3.99V22H18zM8,7.5V4h8v3.5l-4,4L8,7.5z\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-anydpi/ic_take_break.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"28dp\"\n    android:height=\"28dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?android:attr/colorControlNormal\">\n  <group android:scaleX=\"0.92\"\n      android:scaleY=\"0.92\"\n      android:translateX=\"0.96\"\n      android:translateY=\"0.96\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14.5,14.2l2.9,1.7 -0.8,1.3L13,15v-5h1.5v4.2zM22,14c0,4.41 -3.59,8 -8,8 -2.02,0 -3.86,-0.76 -5.27,-2L4,20c-1.15,0 -2,-0.85 -2,-2L2,9c0,-1.12 0.89,-1.96 2,-2v-0.5C4,4.01 6.01,2 8.5,2c2.34,0 4.24,1.79 4.46,4.08 0.34,-0.05 0.69,-0.08 1.04,-0.08 4.41,0 8,3.59 8,8zM6,7h5v-0.74C10.88,4.99 9.8,4 8.5,4 7.12,4 6,5.12 6,6.5L6,7zM20,14c0,-3.31 -2.69,-6 -6,-6s-6,2.69 -6,6 2.69,6 6,6 6,-2.69 6,-6z\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_app_timers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".prefs.AppTimers\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<FrameLayout\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/appTimerLoading\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tandroid:layout_marginTop=\"-152dp\"\n\t\t\tandroid:gravity=\"center\"> <!-- -152dp = (-1) * ?attr/collapsingToolbarLayoutLargeSize -->\n\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\" />\n\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<androidx.recyclerview.widget.RecyclerView\n\t\t\tandroid:id=\"@+id/appTimerPkgs\"\n\t\t\tandroid:visibility=\"gone\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tapp:layoutManager=\"LinearLayoutManager\" />\n\n\t</FrameLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_bedtime_mode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\ttools:context=\".prefs.BedtimeMode\">\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.core.widget.NestedScrollView\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\">\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/topsc\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_marginHorizontal=\"15dp\"\n\t\t\t\tandroid:layout_marginVertical=\"5dp\"\n\t\t\t\tapp:cardCornerRadius=\"20dp\"\n\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\">\n\n\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\t\tandroid:orientation=\"vertical\">\n\n\t\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\t\t\tandroid:gravity=\"center\"\n\t\t\t\t\t\tandroid:orientation=\"horizontal\"\n\t\t\t\t\t\tandroid:padding=\"10dp\">\n\n\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"5dp\"\n\t\t\t\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\t\t\t\tandroid:text=\"@string/enable\"\n\t\t\t\t\t\t\tandroid:textAppearance=\"@style/TextAppearance.Material3.TitleLarge\" />\n\n\t\t\t\t\t\t<com.google.android.material.materialswitch.MaterialSwitch\n\t\t\t\t\t\t\tandroid:id=\"@+id/topsw\"\n\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:clickable=\"false\" />\n\t\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\n\t\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\t\tandroid:id=\"@+id/schedule\"\n\t\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:background=\"?android:attr/selectableItemBackground\"\n\t\t\t\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\t\t\t\tandroid:minHeight=\"?android:attr/listPreferredItemHeight\"\n\t\t\t\t\t\tandroid:padding=\"10dp\">\n\n\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"5dip\"\n\t\t\t\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\t\t\t\tandroid:src=\"@drawable/baseline_schedule_24\" />\n\n\t\t\t\t\t\t<RelativeLayout\n\t\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"15dip\"\n\t\t\t\t\t\t\tandroid:layout_marginTop=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginEnd=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginBottom=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_weight=\"1\">\n\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\t\t\t\t\tandroid:fadingEdge=\"horizontal\"\n\t\t\t\t\t\t\t\tandroid:singleLine=\"true\"\n\t\t\t\t\t\t\t\tandroid:text=\"@string/schedule\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_below=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:layout_alignStart=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:maxLines=\"4\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceSmall\"\n\t\t\t\t\t\t\t\tandroid:textColor=\"?android:attr/textColorSecondary\" />\n\t\t\t\t\t\t</RelativeLayout>\n\t\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:orientation=\"horizontal\"\n\t\t\t\tandroid:layout_marginHorizontal=\"5dip\"\n\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/topsc\">\n\n\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\tandroid:id=\"@+id/greyscaleCheckbox\"\n\t\t\t\t\tandroid:clickable=\"true\"\n\t\t\t\t\tandroid:orientation=\"horizontal\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:background=\"?android:attr/selectableItemBackground\"\n\t\t\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\t\t\tandroid:minHeight=\"?android:attr/listPreferredItemHeight\"\n\t\t\t\t\tandroid:padding=\"10dp\"\n\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\t\tandroid:layout_marginStart=\"5dip\"\n\t\t\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\t\t\tapp:srcCompat=\"@drawable/baseline_gradient_24\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:layout_marginStart=\"15dip\"\n\t\t\t\t\t\tandroid:layout_marginTop=\"6dip\"\n\t\t\t\t\t\tandroid:layout_marginEnd=\"6dip\"\n\t\t\t\t\t\tandroid:layout_marginBottom=\"6dip\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\t\t\tandroid:fadingEdge=\"horizontal\"\n\t\t\t\t\t\tandroid:singleLine=\"true\"\n\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceLarge\"\n\t\t\t\t\t\tandroid:text=\"@string/greyscale\" />\n\n\t\t\t\t\t<com.google.android.material.checkbox.MaterialCheckBox\n\t\t\t\t\t\tandroid:id=\"@+id/checkBox2\"\n\t\t\t\t\t\tandroid:layout_width=\"32dp\"\n\t\t\t\t\t\tandroid:layout_height=\"32dp\"\n\t\t\t\t\t\tandroid:layout_weight=\"0\"\n\t\t\t\t\t\tandroid:background=\"?android:attr/listChoiceIndicatorMultiple\"\n\t\t\t\t\t\tandroid:button=\"@null\"\n\t\t\t\t\t\tandroid:clickable=\"false\" />\n\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\tandroid:id=\"@+id/airplaneModeCheckbox\"\n\t\t\t\t\tandroid:clickable=\"true\"\n\t\t\t\t\tandroid:orientation=\"horizontal\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:background=\"?android:attr/selectableItemBackground\"\n\t\t\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\t\t\tandroid:minHeight=\"?android:attr/listPreferredItemHeight\"\n\t\t\t\t\tandroid:padding=\"10dp\"\n\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@id/greyscaleCheckbox\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\t\tandroid:layout_marginStart=\"5dip\"\n\t\t\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\t\t\tapp:srcCompat=\"@drawable/baseline_airplanemode_active_24\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:layout_marginStart=\"15dip\"\n\t\t\t\t\t\tandroid:layout_marginTop=\"6dip\"\n\t\t\t\t\t\tandroid:layout_marginEnd=\"6dip\"\n\t\t\t\t\t\tandroid:layout_marginBottom=\"6dip\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\t\t\tandroid:fadingEdge=\"horizontal\"\n\t\t\t\t\t\tandroid:singleLine=\"true\"\n\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceLarge\"\n\t\t\t\t\t\tandroid:text=\"@string/airplane_mode\" />\n\n\t\t\t\t\t<com.google.android.material.checkbox.MaterialCheckBox\n\t\t\t\t\t\tandroid:id=\"@+id/checkBox3\"\n\t\t\t\t\t\tandroid:layout_width=\"32dp\"\n\t\t\t\t\t\tandroid:layout_height=\"32dp\"\n\t\t\t\t\t\tandroid:layout_weight=\"0\"\n\t\t\t\t\t\tandroid:background=\"?android:attr/listChoiceIndicatorMultiple\"\n\t\t\t\t\t\tandroid:button=\"@null\"\n\t\t\t\t\t\tandroid:clickable=\"false\" />\n\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t</androidx.core.widget.NestedScrollView>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_dashboard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".ui.DashboardActivity\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<FrameLayout\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/dashboardLoading\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tandroid:layout_marginTop=\"-152dp\"\n\t\t\tandroid:gravity=\"center\"> <!-- -152dp = (-1) * ?attr/collapsingToolbarLayoutLargeSize -->\n\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\" />\n\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<androidx.core.widget.NestedScrollView\n\t\t\tandroid:id=\"@+id/dashboardContainer\"\n\t\t\tandroid:visibility=\"gone\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\">\n\n\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\tandroid:orientation=\"vertical\"\n\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\tandroid:layout_width=\"match_parent\">\n\n\t\t\t\t<com.google.android.material.chip.ChipGroup\n\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:layout_margin=\"5dp\"\n\t\t\t\t\tapp:chipSpacingHorizontal=\"5dp\"\n\t\t\t\t\tapp:singleLine=\"true\">\n\n\t\t\t\t\t<com.google.android.material.chip.Chip\n\t\t\t\t\t\tandroid:id=\"@+id/chip_what\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:textColor=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:checkedIconEnabled=\"false\"\n\t\t\t\t\t\tapp:chipIconTint=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:chipStrokeColor=\"?attr/colorSecondary\"\n\t\t\t\t\t\tapp:chipStrokeWidth=\"1dp\"\n\t\t\t\t\t\tapp:closeIcon=\"@drawable/baseline_arrow_drop_down_24\"\n\t\t\t\t\t\tapp:closeIconEnabled=\"true\"\n\t\t\t\t\t\tapp:closeIconTint=\"?attr/colorOnBackground\" />\n\n\t\t\t\t\t<com.google.android.material.chip.Chip\n\t\t\t\t\t\tandroid:id=\"@+id/chip_when\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:textColor=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:checkedIconEnabled=\"false\"\n\t\t\t\t\t\tapp:chipIconTint=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:chipStrokeColor=\"?attr/colorSecondary\"\n\t\t\t\t\t\tapp:chipStrokeWidth=\"1dp\"\n\t\t\t\t\t\tapp:closeIcon=\"@drawable/baseline_arrow_drop_down_24\"\n\t\t\t\t\t\tapp:closeIconEnabled=\"true\"\n\t\t\t\t\t\tapp:closeIconTint=\"?attr/colorOnBackground\" />\n\n\t\t\t\t\t<com.google.android.material.chip.Chip\n\t\t\t\t\t\tandroid:id=\"@+id/chip_start\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:textColor=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:checkedIconEnabled=\"false\"\n\t\t\t\t\t\tapp:chipIconTint=\"?attr/colorOnBackground\"\n\t\t\t\t\t\tapp:chipStrokeColor=\"?attr/colorSecondary\"\n\t\t\t\t\t\tapp:chipStrokeWidth=\"1dp\"\n\t\t\t\t\t\tapp:closeIcon=\"@drawable/baseline_arrow_drop_down_24\"\n\t\t\t\t\t\tapp:closeIconEnabled=\"true\"\n\t\t\t\t\t\tapp:closeIconTint=\"?attr/colorOnBackground\" />\n\n\t\t\t\t</com.google.android.material.chip.ChipGroup>\n\n\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\tandroid:id=\"@+id/noData\"\n\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:textAppearance=\"@style/TextAppearance.AppCompat.Headline\"\n\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\tandroid:text=\"@string/no_data\" />\n\n\t\t\t\t<com.github.mikephil.charting.charts.BarChart\n\t\t\t\t\tandroid:id=\"@+id/chart\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"200dp\" />\n\n\t\t\t\t<com.github.mikephil.charting.charts.PieChart\n\t\t\t\t\tandroid:id=\"@+id/chart2\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"200dp\" />\n\n\t\t\t\t<androidx.recyclerview.widget.RecyclerView\n\t\t\t\t\tandroid:id=\"@+id/dashboardPkgs\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tapp:layoutManager=\"LinearLayoutManager\" />\n\n\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t</androidx.core.widget.NestedScrollView>\n\n\t</FrameLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_focusmode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".prefs.FocusModeActivity\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.core.widget.NestedScrollView\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/focusModeRoot\"\n\t\t\tandroid:orientation=\"vertical\"\n\t\t\tandroid:animateLayoutChanges=\"true\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\">\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/topsc\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_marginHorizontal=\"15dp\"\n\t\t\t\tandroid:layout_marginVertical=\"5dp\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\tapp:cardCornerRadius=\"20dp\">\n\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\t\tandroid:orientation=\"vertical\">\n\t\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\t\t\tandroid:padding=\"10dp\"\n\t\t\t\t\t\tandroid:orientation=\"horizontal\"\n\t\t\t\t\t\tandroid:gravity=\"center\">\n\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"5dp\"\n\t\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:text=\"@string/enable\"\n\t\t\t\t\t\t\tandroid:textAppearance=\"@style/TextAppearance.Material3.TitleLarge\"\n\t\t\t\t\t\t\tandroid:layout_weight=\"1\" />\n\t\t\t\t\t\t<com.google.android.material.materialswitch.MaterialSwitch\n\t\t\t\t\t\t\tandroid:id=\"@+id/topsw\"\n\t\t\t\t\t\t\tandroid:clickable=\"false\"\n\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\" />\n\t\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\n\t\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\t\tandroid:id=\"@+id/schedule\"\n\t\t\t\t\t\tandroid:padding=\"10dp\"\n\t\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:minHeight=\"?android:attr/listPreferredItemHeight\"\n\t\t\t\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\t\t\t\tandroid:background=\"?android:attr/selectableItemBackground\" >\n\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"5dip\"\n\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\t\t\tandroid:src=\"@drawable/baseline_schedule_24\" />\n\t\t\t\t\t\t<RelativeLayout\n\t\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"15dip\"\n\t\t\t\t\t\t\tandroid:layout_marginEnd=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginTop=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginBottom=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_weight=\"1\">\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:singleLine=\"true\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceLarge\"\n\t\t\t\t\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\t\t\t\t\tandroid:text=\"@string/schedule\"\n\t\t\t\t\t\t\t\tandroid:fadingEdge=\"horizontal\" />\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:id=\"@+id/summary\"\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_below=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:layout_alignStart=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceSmall\"\n\t\t\t\t\t\t\t\tandroid:textColor=\"?android:attr/textColorSecondary\"\n\t\t\t\t\t\t\t\tandroid:maxLines=\"4\" />\n\t\t\t\t\t\t</RelativeLayout>\n\t\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\t\t\tandroid:id=\"@+id/takeBreak\"\n\t\t\t\t\t\tandroid:padding=\"10dp\"\n\t\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:minHeight=\"?android:attr/listPreferredItemHeight\"\n\t\t\t\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\t\t\t\tandroid:background=\"?android:attr/selectableItemBackground\" >\n\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"5dip\"\n\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_gravity=\"center\"\n\t\t\t\t\t\t\tandroid:src=\"@drawable/ic_take_break\" />\n\t\t\t\t\t\t<RelativeLayout\n\t\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\tandroid:layout_marginStart=\"15dip\"\n\t\t\t\t\t\t\tandroid:layout_marginEnd=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginTop=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_marginBottom=\"6dip\"\n\t\t\t\t\t\t\tandroid:layout_weight=\"1\">\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:id=\"@+id/title\"\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:singleLine=\"true\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceLarge\"\n\t\t\t\t\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\t\t\t\t\tandroid:text=\"@string/focus_mode_break\"\n\t\t\t\t\t\t\t\tandroid:fadingEdge=\"horizontal\" />\n\t\t\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\t\t\tandroid:layout_below=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:layout_alignStart=\"@android:id/title\"\n\t\t\t\t\t\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceSmall\"\n\t\t\t\t\t\t\t\tandroid:textColor=\"?android:attr/textColorSecondary\"\n\t\t\t\t\t\t\t\tandroid:maxLines=\"4\" />\n\t\t\t\t\t\t</RelativeLayout>\n\t\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:orientation=\"vertical\">\n\n\t\t\t\t<androidx.recyclerview.widget.RecyclerView\n\t\t\t\t\tandroid:id=\"@+id/focusModePkgs\"\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\t\tandroid:layout_marginHorizontal=\"5dip\"\n\t\t\t\t\tapp:layoutManager=\"LinearLayoutManager\" />\n\t\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t</androidx.core.widget.NestedScrollView>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_manual_suspend.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".prefs.ManualSuspendActivity\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:orientation=\"vertical\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\tandroid:id=\"@+id/suspendbtn\"\n\t\t\t\tstyle=\"@style/AppTheme.TonalButton\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\tandroid:text=\"@string/suspend\" />\n\n\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\tandroid:id=\"@+id/desuspendbtn\"\n\t\t\t\tstyle=\"@style/AppTheme.TonalButton\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\tandroid:text=\"@string/unsuspend\" />\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<androidx.recyclerview.widget.RecyclerView\n\t\t\t\tandroid:id=\"@+id/pkgList\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\t\tapp:layoutManager=\"LinearLayoutManager\" />\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_schedule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\ttools:context=\".prefs.ScheduleActivity\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:layout_width=\"match_parent\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.core.widget.NestedScrollView\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/cardHost\"\n\t\t\tandroid:paddingHorizontal=\"20dp\"\n\t\t\tandroid:paddingBottom=\"20dp\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tandroid:orientation=\"vertical\" />\n\n\t</androidx.core.widget.NestedScrollView>\n\n\t<com.google.android.material.floatingactionbutton.FloatingActionButton\n\t\tandroid:id=\"@+id/floating_action_button\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_gravity=\"bottom|end\"\n\t\tandroid:layout_margin=\"16dp\"\n\t\tandroid:contentDescription=\"@string/add_schedule\"\n\t\tapp:srcCompat=\"@drawable/ic_plus_24\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_show_suspended_app_details.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".ui.ShowSuspendedAppDetails\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.core.widget.NestedScrollView\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\"\n\t\t\tandroid:orientation=\"vertical\"\n\t\t\tandroid:padding=\"5dp\">\n\n\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\t\tandroid:id=\"@+id/appIcon\"\n\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:contentDescription=\"@string/app_icon_content_desc\"\n\t\t\t\t\tandroid:src=\"@android:drawable/sym_def_app_icon\"\n\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintHorizontal_bias=\"0.06\"\n\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\tandroid:id=\"@+id/appName\"\n\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\tandroid:text=\"@string/suspended_app_details_app\"\n\t\t\t\t\tandroid:textAppearance=\"@android:style/TextAppearance.Material.Large\"\n\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\tapp:layout_constraintStart_toEndOf=\"@+id/appIcon\"\n\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/focusMode\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_margin=\"5dp\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\tapp:contentPadding=\"10dp\"\n\t\t\t\tapp:contentPaddingBottom=\"0dp\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\ttools:visibility=\"visible\">\n\n\t\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/textView\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:text=\"@string/focus_mode\"\n\t\t\t\t\t\tandroid:textAppearance=\"@android:style/TextAppearance.Material.Large\"\n\t\t\t\t\t\tandroid:textSize=\"24sp\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:drawableStartCompat=\"@drawable/outline_badge_24\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/focusModeDesc\"\n\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/suspended_app_details_focus_mode\"\n\t\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintHorizontal_bias=\"0.0\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/textView\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/takeabreakbtn\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_marginStart=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/focus_mode_break\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:layout_constraintStart_toEndOf=\"@+id/disablefocusmode\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/focusModeDesc\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/disablefocusmode\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/focus_mode_off\"\n\t\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/focusModeDesc\" />\n\n\t\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/unknown\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_margin=\"5dp\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\tapp:contentPadding=\"10dp\"\n\t\t\t\tapp:contentPaddingBottom=\"0dp\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\ttools:visibility=\"visible\">\n\n\t\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/unknownHeader\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/unknown\"\n\t\t\t\t\t\tandroid:textAppearance=\"@android:style/TextAppearance.Material.Large\"\n\t\t\t\t\t\tandroid:textSize=\"24sp\"\n\t\t\t\t\t\tapp:drawableStartCompat=\"@drawable/ic_baseline_bug_report_24\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/unknownDesc\"\n\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/suspended_app_details_unknown\"\n\t\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintHorizontal_bias=\"0.0\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/unknownHeader\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/unsuspendbtn\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/unsuspend\"\n\t\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/unknownDesc\"\n\t\t\t\t\t\ttools:ignore=\"DuplicateSpeakableTextCheck\" />\n\n\t\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/manually\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_margin=\"5dp\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\tapp:contentPadding=\"10dp\"\n\t\t\t\tapp:contentPaddingBottom=\"0dp\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\ttools:visibility=\"visible\">\n\n\t\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/manuallyHeader\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:text=\"@string/manually\"\n\t\t\t\t\t\tandroid:textAppearance=\"@android:style/TextAppearance.Material.Large\"\n\t\t\t\t\t\tandroid:textSize=\"24sp\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:drawableStartCompat=\"@drawable/ic_baseline_person_24\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/manuallyDesc\"\n\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/suspended_app_details_manually\"\n\t\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintHorizontal_bias=\"0.0\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/manuallyHeader\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/unsuspendbtn2\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_marginStart=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/unsuspend\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintStart_toEndOf=\"@+id/unsuspendallbtn\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/manuallyDesc\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/unsuspendallbtn\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:text=\"@string/unsuspend_all\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/manuallyDesc\" />\n\n\t\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t\t<com.google.android.material.card.MaterialCardView\n\t\t\t\tandroid:id=\"@+id/apptimer\"\n\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_margin=\"5dp\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\tapp:contentPadding=\"10dp\"\n\t\t\t\tapp:contentPaddingBottom=\"0dp\"\n\t\t\t\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\t\t\t\ttools:visibility=\"visible\">\n\n\t\t\t\t<androidx.constraintlayout.widget.ConstraintLayout\n\t\t\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\t\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/apptimerHeader\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:text=\"@string/app_timers\"\n\t\t\t\t\t\tandroid:textAppearance=\"@android:style/TextAppearance.Material.Large\"\n\t\t\t\t\t\tandroid:textSize=\"24sp\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:drawableStartCompat=\"@drawable/ic_focus_mode\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toTopOf=\"parent\" />\n\n\t\t\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\t\t\tandroid:id=\"@+id/apptimerDesc\"\n\t\t\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tandroid:text=\"@string/app_timer_exceed\"\n\t\t\t\t\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintHorizontal_bias=\"0.0\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/apptimerHeader\" />\n\n\t\t\t\t\t<com.google.android.material.button.MaterialButton\n\t\t\t\t\t\tandroid:id=\"@+id/takeabreakbtn2\"\n\t\t\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\t\t\tandroid:text=\"@string/focus_mode_break\"\n\t\t\t\t\t\tandroid:layout_margin=\"10dp\"\n\t\t\t\t\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\t\t\t\t\tapp:layout_constraintTop_toBottomOf=\"@+id/apptimerDesc\" />\n\n\t\t\t\t</androidx.constraintlayout.widget.ConstraintLayout>\n\t\t\t</com.google.android.material.card.MaterialCardView>\n\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t</androidx.core.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/appitem.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:id=\"@+id/container\"\n\tandroid:clickable=\"true\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"wrap_content\"\n\tandroid:padding=\"10dp\">\n\n\t<androidx.appcompat.widget.AppCompatImageView\n\t\tandroid:id=\"@+id/appIcon\"\n\t\tandroid:clickable=\"false\"\n\t\tandroid:layout_width=\"@android:dimen/app_icon_size\"\n\t\tandroid:layout_height=\"@android:dimen/app_icon_size\"\n\t\tandroid:contentDescription=\"@string/app_icon_content_desc\"\n\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\tapp:layout_constraintStart_toStartOf=\"parent\"\n\t\tapp:layout_constraintTop_toTopOf=\"parent\"\n\t\tapp:srcCompat=\"@android:drawable/sym_def_app_icon\" />\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_marginStart=\"10dp\"\n\t\tandroid:clickable=\"false\"\n\t\tandroid:orientation=\"vertical\"\n\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\tapp:layout_constraintEnd_toStartOf=\"@+id/frameLayout\"\n\t\tapp:layout_constraintHorizontal_bias=\"0.0\"\n\t\tapp:layout_constraintStart_toEndOf=\"@+id/appIcon\"\n\t\tapp:layout_constraintTop_toTopOf=\"parent\">\n\n\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\tandroid:id=\"@+id/appName2\"\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:clickable=\"false\"\n\t\t\tandroid:text=\"@string/app\"\n\t\t\tandroid:textAppearance=\"@style/TextAppearance.AppCompat.Large\" />\n\n\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\tandroid:id=\"@+id/pkgName\"\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:clickable=\"false\"\n\t\t\tandroid:text=\"@string/pkg_name_example\"\n\t\t\tandroid:textColor=\"#546E7A\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<FrameLayout\n\t\tandroid:id=\"@+id/frameLayout\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tapp:layout_constraintBottom_toBottomOf=\"parent\"\n\t\tapp:layout_constraintEnd_toEndOf=\"parent\"\n\t\tapp:layout_constraintTop_toTopOf=\"parent\">\n\n\t\t<com.google.android.material.checkbox.MaterialCheckBox\n\t\t\tandroid:id=\"@+id/isChecked\"\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:clickable=\"false\"\n\t\t\ttools:ignore=\"TouchTargetSizeCheck\" />\n\t</FrameLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/appwidget_screen_time.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/appwidget_background\"\n    android:theme=\"@style/AppWidgetTheme\"\n    android:id=\"@+id/appwidget_root\"\n    android:paddingTop=\"1dp\"\n    android:paddingStart=\"8dp\"\n    android:paddingEnd=\"4dp\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/screen_time\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/loading\"\n        android:textSize=\"22sp\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Headline\"\n        android:id=\"@+id/appwidget_screen_time\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginBottom=\"8dp\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:layout_marginBottom=\"-7.5dp\"\n        android:elevation=\"2dp\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:id=\"@+id/appwidget_app1_l\"\n            android:layout_width=\"45dp\"\n            android:layout_height=\"45dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:background=\"@drawable/appwidget_screen_time_bg\"\n            android:backgroundTint=\"@color/design_default_color_primary\"\n            android:gravity=\"center\">\n\n            <TextView\n                android:id=\"@+id/appwidget_app1_t\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/sample_app_t\"\n                android:textAlignment=\"center\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"11sp\" />\n        </LinearLayout>\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/sample_app\"\n            android:textSize=\"11sp\"\n            android:id=\"@+id/appwidget_app1_n\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:layout_marginBottom=\"-5dp\"\n        android:elevation=\"1dp\"\n        android:orientation=\"horizontal\">\n        <LinearLayout\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:background=\"@drawable/appwidget_screen_time_bg\"\n            android:backgroundTint=\"@color/design_default_color_secondary\"\n            android:layout_marginStart=\"2.5dp\"\n            android:layout_marginEnd=\"12.5dp\"\n            android:id=\"@+id/appwidget_app2_l\"\n            android:gravity=\"center\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/sample_app_t\"\n                android:textSize=\"11sp\"\n                android:textAlignment=\"center\"\n                android:textColor=\"@android:color/white\"\n                android:id=\"@+id/appwidget_app2_t\" />\n        </LinearLayout>\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/sample_app\"\n            android:textSize=\"11sp\"\n            android:id=\"@+id/appwidget_app2_n\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <LinearLayout\n            android:layout_width=\"35dp\"\n            android:layout_height=\"35dp\"\n            android:background=\"@drawable/appwidget_screen_time_bg\"\n            android:backgroundTint=\"@color/design_default_color_secondary_variant\"\n            android:layout_marginStart=\"5dp\"\n            android:layout_marginEnd=\"15dp\"\n            android:id=\"@+id/appwidget_app3_l\"\n            android:gravity=\"center\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/sample_app_t\"\n                android:textSize=\"11sp\"\n                android:textAlignment=\"center\"\n                android:textColor=\"@android:color/white\"\n                android:id=\"@+id/appwidget_app3_t\" />\n        </LinearLayout>\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/sample_app\"\n            android:textSize=\"11sp\"\n            android:id=\"@+id/appwidget_app3_n\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/dpicker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:orientation=\"horizontal\"\n\tandroid:layout_gravity=\"center\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\">\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay1\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay2\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay3\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay4\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay5\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay6\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_gravity=\"center\"\n\t\tandroid:layout_width=\"0dp\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<androidx.appcompat.widget.AppCompatToggleButton\n\t\t\tandroid:id=\"@+id/dayPickerDay7\"\n\t\t\tandroid:layout_width=\"35dp\"\n\t\t\tandroid:layout_height=\"35dp\"\n\t\t\tandroid:layout_marginLeft=\"3dp\"\n\t\t\tandroid:layout_marginRight=\"3dp\"\n\t\t\tandroid:textColor=\"@drawable/dpicker_text_color\"\n\t\t\tandroid:background=\"@drawable/dpicker_background\" />\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/preference_material_switch.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Derived from https://github.com/androidx/androidx/blob/8cb282cc/preference/preference/res/layout/preference_widget_switch_compat.xml -->\n<com.google.android.material.materialswitch.MaterialSwitch xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@id/switchWidget\"\n\tandroid:layout_width=\"wrap_content\"\n\tandroid:layout_height=\"wrap_content\"\n\tandroid:background=\"@null\"\n\tandroid:clickable=\"false\"\n\tandroid:focusable=\"false\" />"
  },
  {
    "path": "app/src/main/res/layout/schedule_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\tstyle=\"@style/Widget.Material3.CardView.Filled\"\n\tapp:cardCornerRadius=\"20dp\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"wrap_content\">\n\n\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_margin=\"5dp\"\n\t\tandroid:padding=\"10dp\"\n\t\tandroid:gravity=\"center_horizontal\"\n\t\tandroid:orientation=\"vertical\">\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center_vertical|start\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<org.eu.droid_ng.wellbeing.prefs.TimeSettingView\n\t\t\t\tandroid:id=\"@+id/startTime\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:textSize=\"18sp\" />\n\n\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\tandroid:layout_marginStart=\"7dp\"\n\t\t\t\tandroid:textSize=\"30sp\"\n\t\t\t\tandroid:text=\"@string/until\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\" />\n\n\t\t\t<org.eu.droid_ng.wellbeing.prefs.TimeSettingView\n\t\t\t\tandroid:id=\"@+id/endTime\"\n\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_weight=\"1\"\n\t\t\t\tandroid:textSize=\"18sp\" />\n\n\t\t\t<com.google.android.material.materialswitch.MaterialSwitch\n\t\t\t\tandroid:id=\"@+id/enableCheckBox\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"/>\n\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<org.eu.droid_ng.wellbeing.prefs.DayPicker\n\t\t\tandroid:id=\"@+id/dayPicker\"\n\t\t\tandroid:layout_marginVertical=\"10dp\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\" />\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/chargerLayout\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"45dp\"\n\t\t\tandroid:clickable=\"true\"\n\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\tandroid:width=\"10dp\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tapp:srcCompat=\"@drawable/baseline_battery_charging_full_24\" />\n\n\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\tandroid:layout_marginStart=\"10dp\"\n\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:text=\"@string/sched_charging\"\n\t\t\t\tandroid:layout_weight=\"1\" />\n\n\t\t\t<com.google.android.material.checkbox.MaterialCheckBox\n\t\t\t\tandroid:id=\"@+id/chargerCheckBox\"\n\t\t\t\tandroid:clickable=\"false\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\" />\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/alarmLayout\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"45dp\"\n\t\t\tandroid:clickable=\"true\"\n\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<androidx.appcompat.widget.AppCompatImageView\n\t\t\t\tandroid:importantForAccessibility=\"no\"\n\t\t\t\tandroid:width=\"10dp\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tapp:srcCompat=\"@drawable/baseline_alarm_24\" />\n\n\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\tandroid:layout_marginStart=\"10dp\"\n\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:text=\"@string/sched_alarm\"\n\t\t\t\tandroid:layout_weight=\"1\" />\n\n\t\t\t<com.google.android.material.checkbox.MaterialCheckBox\n\t\t\t\tandroid:id=\"@+id/alarmCheckBox\"\n\t\t\t\tandroid:clickable=\"false\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"/>\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\n\t\t<androidx.appcompat.widget.LinearLayoutCompat\n\t\t\tandroid:id=\"@+id/delete\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"45dp\"\n\t\t\tandroid:clickable=\"true\"\n\t\t\tandroid:gravity=\"center_vertical\"\n\t\t\tandroid:orientation=\"horizontal\">\n\n\t\t\t<androidx.appcompat.widget.AppCompatImageButton\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:background=\"@android:color/transparent\"\n\t\t\t\tapp:srcCompat=\"@drawable/baseline_delete_24\"\n\t\t\t\tandroid:width=\"10dp\"\n\t\t\t\tandroid:clickable=\"false\"\n\t\t\t\tandroid:contentDescription=\"@string/delete\" />\n\n\t\t\t<androidx.appcompat.widget.AppCompatTextView\n\t\t\t\tandroid:layout_marginStart=\"10dp\"\n\t\t\t\tandroid:layout_width=\"0dp\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:text=\"@string/delete\"\n\t\t\t\tandroid:layout_weight=\"1\" />\n\t\t</androidx.appcompat.widget.LinearLayoutCompat>\n\t</androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/settings_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".prefs.SettingsActivity\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<androidx.core.widget.NestedScrollView\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tandroid:importantForAccessibility=\"no\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n\t\t<FrameLayout\n\t\t\tandroid:id=\"@+id/settings\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"match_parent\" />\n\n\t</androidx.core.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/take_a_break_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"match_parent\"\n\tandroid:layout_height=\"match_parent\"\n\tandroid:orientation=\"vertical\"\n\ttools:context=\".ui.TakeBreakDialogActivity\">\n\n\t<com.google.android.material.appbar.AppBarLayout\n\t\tandroid:fitsSystemWindows=\"true\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"wrap_content\">\n\n\t\t<com.google.android.material.appbar.CollapsingToolbarLayout\n\t\t\tstyle=\"?attr/collapsingToolbarLayoutLargeSize\"\n\t\t\tapp:expandedTitleTextAppearance=\"?attr/textAppearanceHeadlineLarge\"\n\t\t\tapp:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n\t\t\tandroid:layout_width=\"match_parent\"\n\t\t\tandroid:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\n\n\t\t\t<com.google.android.material.appbar.MaterialToolbar\n\t\t\t\tandroid:id=\"@+id/topbar\"\n\t\t\t\tandroid:elevation=\"0dp\"\n\t\t\t\tapp:layout_collapseMode=\"pin\"\n\t\t\t\tandroid:layout_height=\"?attr/actionBarSize\"\n\t\t\t\tandroid:layout_width=\"match_parent\"/>\n\n\t\t</com.google.android.material.appbar.CollapsingToolbarLayout>\n\n\t</com.google.android.material.appbar.AppBarLayout>\n\n\t<ListView\n\t\tandroid:id=\"@+id/listView\"\n\t\tandroid:layout_width=\"match_parent\"\n\t\tandroid:layout_height=\"match_parent\"\n\t\tapp:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/arrays.xml",
    "content": "<resources>\n\t<string-array name=\"break_entries\">\n\t\t<item>@string/always_ask</item>\n\t\t<item>@string/min_1</item>\n\t\t<item>@string/min_3</item>\n\t\t<item>@string/min_5</item>\n\t\t<item>@string/min_10</item>\n\t\t<item>@string/min_15</item>\n\t</string-array>\n\t<string-array name=\"break_values\">\n\t\t<item>-1</item>\n\t\t<item>1</item>\n\t\t<item>3</item>\n\t\t<item>5</item>\n\t\t<item>10</item>\n\t\t<item>15</item>\n\t</string-array>\n\t<string-array name=\"reminder_entries\">\n\t\t<item>@string/disabled</item>\n\t\t<item>@string/min_1</item>\n\t\t<item>@string/min_3</item>\n\t\t<item>@string/min_5</item>\n\t\t<item>@string/min_10</item>\n\t\t<item>@string/min_15</item>\n\t</string-array>\n\t<string-array name=\"chip_what_entries\">\n\t\t<item>@string/screen_time</item>\n\t\t<item>@string/notifications</item>\n\t\t<item>@string/unlocks</item>\n\t</string-array>\n\t<string-array name=\"chip_when_entries\">\n\t\t<item>@string/when_year</item>\n\t\t<item>@string/when_month</item>\n\t\t<item>@string/when_day</item>\n\t\t<item>@string/when_hour</item>\n\t</string-array>\n\t<string-array name=\"chip_this_entries\">\n\t\t<item>@string/this_year</item>\n\t\t<item>@string/this_month</item>\n\t\t<item>@string/this_day</item>\n\t\t<item>@string/this_hour</item>\n\t</string-array>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"app_widget_background_radius\">16dp</dimen>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#FEFCE9</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\" tools:ignore=\"MissingTranslation\">\n    <!-- App Name -->\n    <string name=\"app_name\" translatable=\"false\">Neo Wellbeing</string>\n\n    <!-- Main Preference -->\n    <string name=\"main_preference_category_one_title\">Wellbeing settings</string>\n    <string name=\"main_preference_category_two_title\">@string/other</string>\n    <string name=\"main_preference_focus_mode_summary\">Tap to set up</string>\n\n    <string name=\"loading\">Loading…</string>\n    <string name=\"setting_desc\">Focus mode, bedtime mode, app timers</string>\n    <string name=\"dialog_title\">App is blocked</string>\n    <string name=\"dialog_message\">Unfortunately, this app is currently not available.</string>\n    <string name=\"dialog_btn_settings\">More details</string>\n    <string name=\"channel_description\">Contains notifications like \\\"Focus mode is enabled\\\"</string>\n    <string name=\"channel_name\">Service notifications</string>\n    <string name=\"channel2_description\">Contains notifications like \\\"The app timer for this app is about to run out\\\"</string>\n    <string name=\"channel2_name\">Reminders</string>\n    <string name=\"app_timer_reminder\">The app timer for %s is about to run out</string>\n    <string name=\"disabled\">Disabled</string>\n    <string name=\"app_icon_content_desc\">Application icon</string>\n    <string name=\"suspended_app_details_app\">App</string>\n    <string name=\"focus_mode\">Focus mode</string>\n    <string name=\"focus_mode_enabled\">Focus mode is enabled</string>\n    <string name=\"suspended_app_details_focus_mode\">Focus mode is currently enabled!</string>\n    <string name=\"notification_focus_mode\">Distracting apps are currently disabled.</string>\n    <string name=\"focus_mode_break\">Take a break</string>\n    <string name=\"unknown\">Unknown</string>\n    <string name=\"suspended_app_details_unknown\">The app is suspended for an unknown reason. This probably is a bug!</string>\n    <string name=\"unsuspend\">Unsuspend</string>\n    <string name=\"suspended_app_details_manually\">The app was manually suspended.</string>\n    <string name=\"manually\">Manual suspension</string>\n    <string name=\"notification_desc\">Wellbeing is suspending some applications.</string>\n    <string name=\"notification_title\">Apps suspended</string>\n    <string name=\"focus_mode_off\">Disable</string>\n    <string name=\"notification_focus_mode_break\">You are taking a break right now!</string>\n    <string name=\"focus_mode_break_end\">End break</string>\n    <string name=\"cancel\">Cancel</string>\n    <string name=\"notification_manual\">Some apps were manually suspended.</string>\n    <string name=\"unsuspend_all\">Unsuspend all</string>\n    <plurals name=\"break_mins\">\n        <item quantity=\"one\">%d minute</item>\n        <item quantity=\"other\">%d minutes</item>\n    </plurals>\n    <string name=\"break_dialog_1\">Use app for 1 minute</string>\n    <string name=\"break_dialog_3\">Use app for 3 minutes</string>\n    <string name=\"break_dialog_5\">Use app for 5 minutes</string>\n    <string name=\"break_dialog_10\">Use app for 10 minutes</string>\n    <string name=\"break_dialog_15\">Use app for 15 minutes</string>\n    <string name=\"min_1\">1 minute</string>\n    <string name=\"min_3\">3 minutes</string>\n    <string name=\"min_5\">5 minutes</string>\n    <string name=\"min_10\">10 minutes</string>\n    <string name=\"min_15\">15 minutes</string>\n    <string name=\"title_activity_settings\">Settings</string>\n    <string name=\"app\">App</string>\n    <string name=\"pkg_name_example\" translatable=\"false\">com.android.app</string>\n    <string name=\"enable\">Enable</string>\n    <string name=\"disable\">Disable</string>\n    <string name=\"focus_mode_pref_dialog\">Default break time (dialog)</string>\n    <string name=\"focus_mode_pref_notification\">Default break time (notification)</string>\n    <string name=\"manually_dialog_desc\">It has less features</string>\n    <string name=\"manually_dialog_title\">Use flow non-interrupting dialog</string>\n    <string name=\"manually_all_off\">Only unsuspend the app you tried to open</string>\n    <string name=\"manually_all_on\">Unsuspend all apps when you are unsuspending one</string>\n    <string name=\"manually_all\">Unsuspend all apps</string>\n    <string name=\"focus_mode_dialog\">%s and other distracting apps are currently disabled.</string>\n    <string name=\"suspend\">Suspend</string>\n    <string name=\"schedule\">Schedule</string>\n    <string name=\"bedtime_mode\">Bedtime mode</string>\n    <string name=\"bedtime_desc\">You should go to sleep now!</string>\n    <string name=\"no_timer\">No timer set</string>\n    <string name=\"app_timers\">App timers</string>\n    <string name=\"screen_time\">Screen time</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"desc_container\">%1$s (used %2$s)</string>\n    <string name=\"app_timer_exceed\">The app timer for this app has elapsed.</string>\n    <string name=\"app_timer_exceed_f\">The app timer for %s has elapsed.</string>\n    <string name=\"about\">About</string>\n    <string name=\"about_1_title\">Neo Wellbeing</string>\n    <string name=\"about_1_desc\">A project by the Neo Applications Collective</string>\n    <string name=\"bug_title\">Open bug viewer</string>\n    <string name=\"bug_desc\">That you found this hidden entry means that you found an bug in the program. Please click here for more details. Thank you for using Neo Wellbeing :)</string>\n    <string name=\"share\">Share</string>\n    <string name=\"copy_to_clipboard\">Copy</string>\n    <string name=\"copied\">Copied to clipboard</string>\n    <string name=\"bug_viewer\">Bug viewer</string>\n    <string name=\"greyscale\">Greyscale</string>\n    <string name=\"airplane_mode\">Airplane mode</string>\n    <string name=\"sched_charging\">Only while charging</string>\n    <string name=\"dpicker_monday\">M</string>\n    <string name=\"dpicker_tuesday\">T</string>\n    <string name=\"dpicker_wednesday\">W</string>\n    <string name=\"dpicker_thursday\">T</string>\n    <string name=\"dpicker_friday\">F</string>\n    <string name=\"dpicker_saturday\">S</string>\n    <string name=\"dpicker_sunday\">S</string>\n    <string name=\"add_schedule\">Add schedule</string>\n    <string name=\"delete\">Delete</string>\n    <string name=\"add_schedule_info\">Nothing here yet, try to add an schedule</string>\n    <string name=\"sched_alarm\">End with alarm</string>\n    <string name=\"sample_app\">Application</string>\n    <string name=\"sample_app_t\">23h 59m</string>\n    <string name=\"until\" translatable=\"false\">-</string>\n    <string name=\"on\">On</string>\n    <string name=\"off\">Off</string>\n    <plurals name=\"app_timer_reminder_title\">\n        <item quantity=\"one\">%d minute left</item>\n        <item quantity=\"other\">%d minutes left</item>\n    </plurals>\n    <string name=\"app_timer_reminder_pref\">Remind when time is running out</string>\n    <string name=\"always_ask\">Always ask</string>\n    <string name=\"whitelist_title\">Whitelist mode</string>\n    <string name=\"blacklist_desc\">Suspend all apps that you selected</string>\n    <string name=\"whitelist_desc\">Suspend all apps except those you selected</string>\n    <string name=\"other\">Other</string>\n    <string name=\"dashboard\">Dashboard</string>\n    <string name=\"notifications\">Notifications</string>\n    <plurals name=\"notifications_count\">\n        <item quantity=\"one\">%d notification</item>\n        <item quantity=\"other\">%d notifications</item>\n    </plurals>\n    <string name=\"unlocks\">Unlocks</string>\n    <string name=\"this_year\">This year</string>\n    <string name=\"this_month\">This month</string>\n    <string name=\"this_day\">Today</string>\n    <string name=\"this_hour\">This hour</string>\n    <string name=\"when_year\">By year</string>\n    <string name=\"when_month\">By month</string>\n    <string name=\"when_day\">By day</string>\n    <string name=\"when_hour\">By hour</string>\n    <string name=\"stat_view_name\">%s - %s</string>\n    <string name=\"total\">Total: %d</string>\n    <string name=\"select_hour\">Select hour</string>\n    <string name=\"select_date\">Select date</string>\n    <string name=\"stat_to_display\">Statistic to display</string>\n    <string name=\"time_dimension_to_display\">Time dimension to display</string>\n    <string name=\"no_data\">No data</string>\n    <string name=\"event_channel_description\">Notifies you when Neo Wellbeing is processing events in the background. Feel free to turn off these notifications.</string>\n    <string name=\"event_channel_name\">Event processing</string>\n    <string name=\"bug2_title\">Open framework bug viewer</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <style name=\"AppTheme\" parent=\"AppTheme.Base\" />\n\n    <style name=\"AppWidgetTheme\" parent=\"AppTheme.Base\" />\n\n    <style name=\"AppTheme.Base\" parent=\"Theme.Material3.DynamicColors.DayNight\">\n        <item name=\"colorPrimaryDark\">@android:color/transparent</item> <!-- Status bar color -->\n        <item name=\"colorPrimaryVariant\">@android:color/transparent</item>\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"alertDialogTheme\">@style/AppTheme.AlertDialog</item>\n        <item name=\"preferenceTheme\">@style/MaterialPreferenceThemeOverlay</item>\n    </style>\n\n    <style name=\"AppTheme.AlertDialog\" parent=\"ThemeOverlay.Material3.MaterialAlertDialog\">\n        <item name=\"dialogCornerRadius\">28dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"android:colorBackground\">?attr/colorSurface</item>\n        <item name=\"android:layout\" tools:ignore=\"PrivateResource\">@layout/m3_alert_dialog</item>\n    </style>\n\n    <style name=\"AppTheme.TonalButton\" parent=\"ThemeOverlay.Material3.Button.TonalButton\" />\n\n    <!-- Custom Preference Theme -->\n    <style name=\"MaterialPreferenceThemeOverlay\" parent=\"PreferenceThemeOverlay\">\n        <item name=\"switchPreferenceCompatStyle\">@style/Preference.SwitchPreferenceCompat</item>\n    </style>\n\n    <!-- Custom Switch Preference Theme -->\n    <style name=\"Preference.SwitchPreferenceCompat\" parent=\"Preference.SwitchPreferenceCompat.Material\">\n        <item name=\"android:widgetLayout\">@layout/preference_material_switch</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fil/strings.xml",
    "content": "<resources>\n\t<string name=\"loading\">Ikinakarga…</string>\n\t<string name=\"setting_desc\">Mode sa pag-focus, mode sa pagtulog, at orasan sa app</string>\n\t<string name=\"dialog_title\">Naharang ang app</string>\n\t<string name=\"dialog_message\">Paumanhin, hindi available sa kasalukuyan ang app na ito.</string>\n\t<string name=\"dialog_btn_settings\">Higit pang detalye</string>\n\t<string name=\"channel_description\">Mga notipikasyon tulad ng \\\"Nakabukas ang mode sa pag-focus\\\"</string>\n\t<string name=\"channel_name\">Mga notipikasyon ng serbisyo</string>\n\t<string name=\"channel2_description\">Mga notipikasyon tulad ng \\\"Mauubos na ang oras para sa app na ito\\\"</string>\n\t<string name=\"channel2_name\">Mga paalala</string>\n\t<string name=\"app_timer_reminder\">Mauubos na ang oras para sa %s</string>\n\t<string name=\"disabled\">Nakasara</string>\n\t<string name=\"app_icon_content_desc\">Icon ng aplikasyon</string>\n\t<string name=\"suspended_app_details_app\">App</string>\n\t<string name=\"focus_mode\">Mode sa pag-focus</string>\n\t<string name=\"focus_mode_enabled\">Binuksan ang mode sa pag-focus</string>\n\t<string name=\"suspended_app_details_focus_mode\">Kasalukuyang nakabukas ang mode sa pag-focus!</string>\n\t<string name=\"notification_focus_mode\">Kasalukuyang hinaharang ang mga nakakaabalang app.</string>\n\t<string name=\"focus_mode_break\">Magpahinga</string>\n\t<string name=\"unknown\">Hindi alam</string>\n\t<string name=\"suspended_app_details_unknown\">Sinuspinde ang app sa hindi malamang dahilan. Maaaring isa itong bug!</string>\n\t<string name=\"unsuspend\">Itigil ang suspensyon</string>\n\t<string name=\"suspended_app_details_manually\">Manu-manong sinuspinde ang app.</string>\n\t<string name=\"manually\">Manu-manong pagsuspinde</string>\n\t<string name=\"notification_desc\">May mga sinususpindeng aplikasyon ang Wellbeing.</string>\n\t<string name=\"notification_title\">Mga suspendidong app</string>\n\t<string name=\"focus_mode_off\">Isara</string>\n\t<string name=\"notification_focus_mode_break\">Kasalukuyan kang nagpapahinga!</string>\n\t<string name=\"focus_mode_break_end\">Tapusin ang pagpapahinga</string>\n\t<string name=\"cancel\">Kanselahin</string>\n\t<string name=\"notification_manual\">Manu-manong sinuspinde ang ilang mga app.</string>\n\t<string name=\"unsuspend_all\">Itigil ang pagsuspinde sa lahat</string>\n\t<plurals name=\"break_mins\">\n\t\t<item quantity=\"one\">%d minuto</item>\n\t\t<item quantity=\"other\">%d (na) minuto</item>\n\t</plurals>\n\t<string name=\"break_dialog_1\">Gamitin ang app nang 1 minuto</string>\n\t<string name=\"break_dialog_3\">Gamitin ang app nang 3 minuto</string>\n\t<string name=\"break_dialog_5\">Gamitin ang app nang 5 minuto</string>\n\t<string name=\"break_dialog_10\">Gamitin ang app nang 10 minuto</string>\n\t<string name=\"break_dialog_15\">Gamitin ang app nang 15 minuto</string>\n\t<string name=\"min_1\">1 minuto</string>\n\t<string name=\"min_3\">3 minuto</string>\n\t<string name=\"min_5\">5 minuto</string>\n\t<string name=\"min_10\">10 minuto</string>\n\t<string name=\"min_15\">15 minuto</string>\n\t<string name=\"title_activity_settings\">Mga Setting</string>\n\t<string name=\"app\">App</string>\n\t<string name=\"enable\">Buksan</string>\n\t<string name=\"disable\">Isara</string>\n\t<string name=\"focus_mode_pref_dialog\">Default na oras sa pahinga (diyalogo)</string>\n\t<string name=\"focus_mode_pref_notification\">Default na oras sa pahinga (notipikasyon)</string>\n\t<string name=\"manually_dialog_desc\">Mas kaunti ang mga feature nito</string>\n\t<string name=\"manually_dialog_title\">Gumamit ng diyalogong hindi nakakaistorbo sa daloy</string>\n\t<string name=\"manually_all_off\">Itigil ang suspensyon ng app lang na gusto mong buksan</string>\n\t<string name=\"manually_all_on\">Itigil ang pagsuspinde sa lahat ng mga app kung itinigil mo ang pagsuspinde sa isa man lang sa kanila</string>\n\t<string name=\"manually_all\">Itigil ang pagsuspinde sa lahat ng mga app</string>\n\t<string name=\"focus_mode_dialog\">Kasalukuyang naka-disable ang %s at iba pang mga nakakaabalang app.</string>\n\t<string name=\"suspend\">Suspindehin</string>\n\t<string name=\"schedule\">Iskedyul</string>\n\t<string name=\"bedtime_mode\">Mode sa pagtulog</string>\n\t<string name=\"bedtime_desc\">Oras na ng tulog mo!</string>\n\t<string name=\"no_timer\">Walang nakatakdang orasan</string>\n\t<string name=\"app_timers\">Orasan sa app</string>\n\t<string name=\"screen_time\">Oras sa screen</string>\n\t<string name=\"ok\">Sige</string>\n\t<string name=\"desc_container\">%1$s (ginamit %2$s)</string>\n\t<string name=\"app_timer_exceed\">Naubos na ang oras para sa app na ito.</string>\n\t<string name=\"app_timer_exceed_f\">Naubos na ang oras para sa %s.</string>\n\t<string name=\"about\">Tungkol</string>\n\t<string name=\"about_1_title\">Neo Wellbeing</string>\n\t<string name=\"about_1_desc\">Isang proyekto ng Neo Applications Collective</string>\n\t<string name=\"bug_title\">Buksan ang pangtingin sa mga bug</string>\n\t<string name=\"bug_desc\">Nahanap mo ang nakatagong entry na ito na nangangahulugang nakadiskubre ka ng bug sa programa. Pumindot dito para sa higit pang detalye. Salamat sa paggamit ng Neo Wellbeing :)</string>\n\t<string name=\"share\">Ibahagi</string>\n\t<string name=\"copy_to_clipboard\">Kopyahin</string>\n\t<string name=\"copied\">Nakopya sa clipboard</string>\n\t<string name=\"bug_viewer\">Pangtingin sa mga bug</string>\n\t<string name=\"greyscale\">Grayscale</string>\n\t<string name=\"airplane_mode\">Mode pang-eroplano</string>\n\t<string name=\"sched_charging\">Kapag nagcha-charge lang</string>\n\t<string name=\"dpicker_monday\">Lu</string>\n\t<string name=\"dpicker_tuesday\">Ma</string>\n\t<string name=\"dpicker_wednesday\">Mi</string>\n\t<string name=\"dpicker_thursday\">Hu</string>\n\t<string name=\"dpicker_friday\">Bi</string>\n\t<string name=\"dpicker_saturday\">Sa</string>\n\t<string name=\"dpicker_sunday\">Li</string>\n\t<string name=\"add_schedule\">Magdagdag ng iskedyul</string>\n\t<string name=\"delete\">Tanggalin</string>\n\t<string name=\"add_schedule_info\">Wala pang nandito, subukang magdagdag ng iskedyul</string>\n\t<string name=\"sched_alarm\">Wakasan nang may alarm</string>\n\t<string name=\"sample_app\">Aplikasyon</string>\n\t<string name=\"sample_app_t\">23o 59m</string>\n\t<string name=\"on\">Bukas</string>\n\t<string name=\"off\">Sarado</string>\n\t<string name=\"app_timer_reminder_pref\">Magpaalala kung paubos na ang oras</string>\n\t<string name=\"always_ask\">Laging magtanong</string>\n\t<string name=\"whitelist_title\">Allowlist mode</string>\n\t<string name=\"blacklist_desc\">Suspindehin lahat ng mga pinili mong app</string>\n\t<string name=\"whitelist_desc\">Suspindehin lahat maliban sa mga pinili mong app</string>\n\t<string name=\"other\">Iba pa</string>\n\t<string name=\"dashboard\">Dashboard</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-sw360dp/values-preference.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <bool name=\"config_materialPreferenceIconSpaceReserved\" tools:ignore=\"MissingDefaultResource,PrivateResource\">\n        false\n    </bool>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v31/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"app_widget_background_radius\">@android:dimen/system_app_widget_background_radius</dimen>\n</resources>"
  },
  {
    "path": "app/src/main/res/xml/appwidget_screen_time.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:minWidth=\"102dp\"\n    android:minHeight=\"102dp\"\n    android:targetCellWidth=\"2\"\n    android:targetCellHeight=\"2\"\n    android:minResizeWidth=\"130dp\"\n    android:minResizeHeight=\"102dp\"\n    android:maxResizeWidth=\"9999dp\"\n    android:maxResizeHeight=\"9999dp\"\n    android:updatePeriodMillis=\"60000\"\n    android:description=\"@string/screen_time\"\n    android:previewLayout=\"@layout/appwidget_screen_time\"\n\tandroid:previewImage=\"@drawable/appwidget_screen_time\"\n    android:initialLayout=\"@layout/appwidget_screen_time\"\n    android:resizeMode=\"horizontal|vertical\"\n    android:widgetCategory=\"home_screen\"\n    tools:targetApi=\"s\">\n</appwidget-provider>"
  },
  {
    "path": "app/src/main/res/xml/backup_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample backup rules file; uncomment and customize as necessary.\n   See https://developer.android.com/guide/topics/data/autobackup\n   for details.\n   Note: This file is ignored for devices older that API 31\n   See https://developer.android.com/about/versions/12/backup-restore\n-->\n<full-backup-content>\n   <include domain=\"sharedpref\" path=\".\" />\n</full-backup-content>"
  },
  {
    "path": "app/src/main/res/xml/data_extraction_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample data extraction rules file; uncomment and customize as necessary.\n   See https://developer.android.com/about/versions/12/backup-restore#xml-changes\n   for details.\n-->\n<data-extraction-rules>\n\t<cloud-backup>\n\t\t<include domain=\"sharedpref\" path=\".\" />\n\t</cloud-backup>\n    <device-transfer>\n\t    <include domain=\"sharedpref\" path=\".\" />\n    </device-transfer>\n</data-extraction-rules>"
  },
  {
    "path": "app/src/main/res/xml/main_preferences.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <PreferenceCategory android:title=\"@string/main_preference_category_one_title\">\n        <Preference\n            android:key=\"dashboard\"\n            android:title=\"@string/dashboard\"\n            app:icon=\"@drawable/ic_baseline_dashboard_24dp\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.ui.DashboardActivity\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n        <Preference\n            android:key=\"focus_mode\"\n            android:title=\"@string/focus_mode\"\n            app:icon=\"@drawable/ic_baseline_person_24dp\"\n            app:summary=\"@string/main_preference_focus_mode_summary\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.prefs.FocusModeActivity\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n        <Preference\n            android:key=\"bedtime_mode\"\n            android:title=\"@string/bedtime_mode\"\n            app:icon=\"@drawable/ic_baseline_king_bed_24dp\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.prefs.BedtimeMode\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n        <Preference\n            android:key=\"timers\"\n            android:title=\"@string/app_timers\"\n            app:icon=\"@drawable/ic_baseline_access_time_24dp\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.prefs.AppTimers\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n        <Preference\n            android:key=\"manual\"\n            android:title=\"@string/manually\"\n            app:icon=\"@drawable/ic_baseline_app_blocking_24\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.prefs.ManualSuspendActivity\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/main_preference_category_two_title\">\n        <Preference\n            android:key=\"settings\"\n            android:title=\"@string/title_activity_settings\"\n            app:icon=\"@drawable/ic_baseline_settings_24dp\">\n            <intent\n                android:targetClass=\"org.eu.droid_ng.wellbeing.prefs.SettingsActivity\"\n                android:targetPackage=\"org.eu.droid_ng.wellbeing\" />\n        </Preference>\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/root_preferences.xml",
    "content": "<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n\t<PreferenceCategory app:title=\"@string/focus_mode\">\n\n\t\t<ListPreference\n\t\t\tapp:defaultValue=\"-1\"\n\t\t\tapp:entries=\"@array/break_entries\"\n\t\t\tapp:entryValues=\"@array/break_values\"\n\t\t\tapp:key=\"focus_dialog\"\n\t\t\tapp:title=\"@string/focus_mode_pref_dialog\"\n\t\t\tapp:useSimpleSummaryProvider=\"true\" />\n\n\t\t<ListPreference\n\t\t\tapp:defaultValue=\"-1\"\n\t\t\tapp:entries=\"@array/break_entries\"\n\t\t\tapp:entryValues=\"@array/break_values\"\n\t\t\tapp:key=\"focus_notification\"\n\t\t\tapp:title=\"@string/focus_mode_pref_notification\"\n\t\t\tapp:useSimpleSummaryProvider=\"true\" />\n\n\t\t<SwitchPreferenceCompat\n\t\t\tapp:key=\"focus_all\"\n\t\t\tapp:summaryOff=\"@string/manually_all_off\"\n\t\t\tapp:summaryOn=\"@string/manually_all_on\"\n\t\t\tapp:title=\"@string/manually_all\" />\n\n\t\t<SwitchPreferenceCompat\n\t\t\tapp:key=\"focus_whitelist\"\n\t\t\tapp:summaryOff=\"@string/blacklist_desc\"\n\t\t\tapp:summaryOn=\"@string/whitelist_desc\"\n\t\t\tapp:title=\"@string/whitelist_title\" />\n\n\t</PreferenceCategory>\n\n\t<PreferenceCategory app:title=\"@string/app_timers\">\n\n\t\t<ListPreference\n\t\t\tapp:defaultValue=\"-1\"\n\t\t\tapp:entries=\"@array/break_entries\"\n\t\t\tapp:entryValues=\"@array/break_values\"\n\t\t\tapp:key=\"app_timer_dialog\"\n\t\t\tapp:title=\"@string/focus_mode_pref_dialog\"\n\t\t\tapp:useSimpleSummaryProvider=\"true\" />\n\n\t\t<ListPreference\n\t\t\tapp:defaultValue=\"-1\"\n\t\t\tapp:entries=\"@array/reminder_entries\"\n\t\t\tapp:entryValues=\"@array/break_values\"\n\t\t\tapp:key=\"app_timer_reminder\"\n\t\t\tapp:title=\"@string/app_timer_reminder_pref\"\n\t\t\tapp:useSimpleSummaryProvider=\"true\" />\n\n\t</PreferenceCategory>\n\n\t<PreferenceCategory app:title=\"@string/manually\">\n\n\t\t<SwitchPreferenceCompat\n\t\t\tapp:key=\"manual\"\n\t\t\tapp:title=\"@string/enable\" />\n\n\t\t<SwitchPreferenceCompat\n\t\t\tapp:key=\"manual_dialog\"\n\t\t\tapp:summary=\"@string/manually_dialog_desc\"\n\t\t\tapp:title=\"@string/manually_dialog_title\" />\n\n\t\t<SwitchPreferenceCompat\n\t\t\tapp:dependency=\"manual_dialog\"\n\t\t\tapp:key=\"manual_all\"\n\t\t\tapp:summaryOff=\"@string/manually_all_off\"\n\t\t\tapp:summaryOn=\"@string/manually_all_on\"\n\t\t\tapp:title=\"@string/manually_all\" />\n\n\t</PreferenceCategory>\n\n\t<PreferenceCategory app:title=\"@string/about\">\n\n\t\t<Preference\n\t\t\tapp:key=\"app_about1\"\n\t\t\tapp:summary=\"@string/about_1_desc\"\n\t\t\tapp:title=\"@string/about_1_title\" />\n\n\t\t<Preference\n\t\t\tapp:key=\"bugs\"\n\t\t\tapp:isPreferenceVisible=\"false\"\n\t\t\tapp:summary=\"@string/bug_desc\"\n\t\t\tapp:title=\"@string/bug_title\" />\n\n\n\t</PreferenceCategory>\n\n\n</PreferenceScreen>"
  },
  {
    "path": "app/update-binary",
    "content": "#!/sbin/sh\n\n#################\n# Initialization\n#################\n\numask 022\n\n# echo before loading util_functions\nui_print() { echo \"$1\"; }\n\nrequire_new_magisk() {\n  ui_print \"*******************************\"\n  ui_print \" Please install Magisk v20.4+! \"\n  ui_print \"*******************************\"\n  exit 1\n}\n\n#########################\n# Load util_functions.sh\n#########################\n\nexport OUTFD=\"$2\"\nexport ZIPFILE=\"$3\"\n\nmount /data 2>/dev/null\n\n[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk\n. /data/adb/magisk/util_functions.sh\n[ \"$MAGISK_VER_CODE\" -lt 20400 ] && require_new_magisk\n\ninstall_module\nexit 0\n"
  },
  {
    "path": "build.gradle.kts",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nplugins {\n\tval agpVersion = \"8.6.0-rc01\"\n\tid(\"com.android.application\") version agpVersion apply false\n\tid(\"com.android.library\") version agpVersion apply false\n\tval kotlinVersion = \"2.0.20\"\n\tid(\"org.jetbrains.kotlin.android\")  version kotlinVersion apply false\n\tid(\"com.google.devtools.ksp\") version \"$kotlinVersion-1.0.24\" apply false\n}\n\ntasks.withType(JavaCompile::class.java) {\n\toptions.compilerArgs.add(\"-Xlint:all\")\n}\n\nval dir = rootProject.layout.buildDirectory.get().asFile\ntasks.register(\"clean\", type = Delete::class) {\n\tdelete(dir)\n}"
  },
  {
    "path": "framework/.gitignore",
    "content": "/build"
  },
  {
    "path": "framework/build.gradle.kts",
    "content": "plugins {\n    id(\"com.android.application\")\n    id(\"org.jetbrains.kotlin.android\")\n}\n\nandroid {\n    namespace = \"org.eu.droid_ng.wellbeing.framework\"\n    compileSdk = 35\n\n    defaultConfig {\n        applicationId = \"org.eu.droid_ng.wellbeing.framework\"\n        minSdk = 29\n        targetSdk = 35\n        versionCode = 33\n        versionName = \"13.0\"\n    }\n\n    signingConfigs {\n        register(\"release\") {\n            if (project.hasProperty(\"RELEASE_KEY_ALIAS\")) {\n                storeFile = file(project.properties[\"RELEASE_STORE_FILE\"].toString())\n                storePassword = project.properties[\"RELEASE_STORE_PASSWORD\"].toString()\n                keyAlias = project.properties[\"RELEASE_KEY_ALIAS\"].toString()\n                keyPassword = project.properties[\"RELEASE_KEY_PASSWORD\"].toString()\n            }\n        }\n    }\n\n    buildTypes {\n        release {\n            isMinifyEnabled = true\n            setProguardFiles(listOf(getDefaultProguardFile(\"proguard-android-optimize.txt\"), \"proguard-rules.pro\"))\n            if (project.hasProperty(\"RELEASE_KEY_ALIAS\")) {\n                signingConfig = signingConfigs.getByName(\"release\")\n            } else {\n                logger.warn(\"Using debug signing configs!\")\n                signingConfig = signingConfigs.getByName(\"debug\")\n            }\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility = JavaVersion.VERSION_17\n        targetCompatibility = JavaVersion.VERSION_17\n    }\n\n    kotlin {\n        jvmToolchain(17)\n    }\n}\n\ndependencies {\n    implementation(project(\":shared\"))\n}"
  },
  {
    "path": "framework/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n-dontobfuscate"
  },
  {
    "path": "framework/src/main/Android.bp",
    "content": "android_app {\n    name: \"NeoWellbeingFramework\",\n    defaults: [\"platform_app_defaults\"],\n    static_libs: [\n        \"androidx.room_room-runtime\",\n        \"NeoWellbeing-shared\",\n    ],\n    plugins: [\"androidx.room_room-compiler-plugin\"],\n\n    resource_dirs: [\"res\"],\n\n    srcs: [\n        \"java/**/*.java\",\n        \"java/**/*.kt\",\n    ],\n\n    platform_apis: true,\n    privileged: true,\n    certificate: \"platform\",\n}\n"
  },
  {
    "path": "framework/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <permission\n        android:name=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\"\n        android:protectionLevel=\"signature|privileged\" />\n    <uses-permission\n        android:name=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\" />\n\n    <uses-permission\n        android:name=\"android.permission.INTERACT_ACROSS_USERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_SECURE_SETTINGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n\n    <queries>\n        <package android:name=\"org.eu.droid_ng.wellbeing\" />\n    </queries>\n\n    <application\n        android:label=\"@string/app_name\"\n        android:name=\".Framework\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@android:style/Theme.DeviceDefault.DayNight\"\n        android:icon=\"@android:drawable/sym_def_app_icon\"\n        android:testOnly=\"false\"\n        android:persistent=\"true\">\n        <service android:name=\".WellbeingFrameworkService\"\n            android:permission=\"org.eu.droid_ng.wellbeing.framework.permission.BIND\"\n            android:exported=\"true\"\n            android:enabled=\"true\">\n            <intent-filter>\n                <action android:name=\"org.eu.droid_ng.wellbeing.framework.FRAMEWORK_SERVICE\" />\n            </intent-filter>\n        </service>\n        <receiver\n            android:name=\".WellbeingBootReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n    </application>\n\n</manifest>"
  },
  {
    "path": "framework/src/main/java/org/eu/droid_ng/wellbeing/framework/Framework.kt",
    "content": "package org.eu.droid_ng.wellbeing.framework\n\nimport android.app.Application\nimport android.util.Log\nimport org.eu.droid_ng.wellbeing.shared.BugUtils\n\nclass Framework : Application() {\n\tcompanion object {\n\t\tprivate const val TAG = \"WellbeingFramework\"\n\t\tprivate lateinit var application: Framework\n\n\t\tfun setService(service: WellbeingFrameworkServiceImpl?) {\n\t\t\treturn application.setServiceInternal(service)\n\t\t}\n\n\t\tfun getService(): WellbeingFrameworkServiceImpl? {\n\t\t\treturn application.getServiceInternal()\n\t\t}\n\t}\n\tprivate var service: WellbeingFrameworkServiceImpl? = null\n\n\tinit {\n\t\t// While it's... quite bad if we get uncaught exceptions, it's even worse if we crash.\n\t\t// If Android can't keep us alive, the device gets thrown into a boot loop.\n\t\t// This is also why this app should be kept as simple as possible.\n\t\tThread.setDefaultUncaughtExceptionHandler { _, e ->\n\t\t\tLog.e(TAG, Log.getStackTraceString(e))\n\t\t\tBugUtils.get()?.onBugAdded(e, System.currentTimeMillis())\n\t\t}\n\t}\n\n\toverride fun onCreate() {\n\t\tsuper.onCreate()\n\t\tapplication = this\n\t\tBugUtils.maybeInit(this)\n\t\tThread {\n\t\t\t// maybe it'll be useful in the future\n\t\t\tval prefs = getSharedPreferences(\"framework\", 0)\n\t\t\tif (prefs.getInt(\"version\", 0) != WellbeingFrameworkServiceImpl.VERSION_CODE) {\n\t\t\t\tprefs.edit().putInt(\"version\", WellbeingFrameworkServiceImpl.VERSION_CODE).apply()\n\t\t\t}\n\t\t\t// == temp migration code start ==\n\t\t\ttry {\n\t\t\t\tfilesDir.listFiles()?.forEach { it.deleteRecursively() }\n\t\t\t} catch (e: Exception) {\n\t\t\t\tLog.e(TAG, Log.getStackTraceString(e))\n\t\t\t}\n\t\t\t// == temp migration code end ==\n\t\t}.start()\n\t}\n\n\tprivate fun getServiceInternal(): WellbeingFrameworkServiceImpl? {\n\t\treturn service\n\t}\n\n\tprivate fun setServiceInternal(service: WellbeingFrameworkServiceImpl?) {\n\t\tthis.service = service\n\t}\n}"
  },
  {
    "path": "framework/src/main/java/org/eu/droid_ng/wellbeing/framework/WellbeingBootReceiver.kt",
    "content": "package org.eu.droid_ng.wellbeing.framework\n\nimport android.app.admin.DevicePolicyManager\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\n\nclass WellbeingBootReceiver : BroadcastReceiver() {\n\toverride fun onReceive(context: Context, intent: Intent?) {\n\t\tif (intent?.action != \"android.intent.action.BOOT_COMPLETED\")\n\t\t\treturn\n\t\tif (!isInWorkProfile(context))\n\t\t\tcontext.startService(Intent(context, WellbeingFrameworkService::class.java))\n\t}\n\n\tprivate fun isInWorkProfile(context: Context): Boolean {\n\t\tval devicePolicyManager =\n\t\t\tcontext.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager\n\t\tval activeAdmins = devicePolicyManager.activeAdmins\n\t\tif (activeAdmins != null) {\n\t\t\tfor (admin in activeAdmins) {\n\t\t\t\tif (devicePolicyManager.isProfileOwnerApp(admin.packageName))\n\t\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n}"
  },
  {
    "path": "framework/src/main/java/org/eu/droid_ng/wellbeing/framework/WellbeingFrameworkService.kt",
    "content": "package org.eu.droid_ng.wellbeing.framework\n\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.os.IBinder\n\nclass WellbeingFrameworkService : Service() {\n\toverride fun onBind(intent: Intent): IBinder? {\n\t\treturn if (\"org.eu.droid_ng.wellbeing.framework.FRAMEWORK_SERVICE\" == intent.action)\n\t\t\tFramework.getService()\n\t\telse\n\t\t\tnull\n\t}\n\n\toverride fun onCreate() {\n\t\tsuper.onCreate()\n\t\tif (Framework.getService() == null)\n\t\t\tFramework.setService(WellbeingFrameworkServiceImpl(this))\n\t\tval ws = Framework.getService()!!\n\t\tws.bgThread.start()\n\t\tws.start()\n\t}\n\n\toverride fun onDestroy() {\n\t\tval ws = Framework.getService()\n\t\tws?.stop()\n\t\tws?.bgThread?.quitSafely()\n\t\tws?.bgThread?.join()\n\t\tsuper.onDestroy()\n\t}\n\n\toverride fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n\t\treturn START_STICKY\n\t}\n\n\tabstract class BaseWellbeingFrameworkService(protected val context: Context) :\n\t\tIWellbeingFrameworkService.Stub() {\n\t\tcompanion object {\n\t\t\t@JvmStatic protected val TAG = \"WellbeingFrameworkService\"\n\t\t}\n\n\t\tinternal val bgThread = HandlerThread(TAG)\n\t\tprotected val bgHandler by lazy { Handler(bgThread.looper\n\t\t\t?: throw IllegalStateException(\"used bgHandler before start() was called\")) }\n\n\t\tabstract fun start()\n\t\tabstract fun stop()\n\t}\n}"
  },
  {
    "path": "framework/src/main/java/org/eu/droid_ng/wellbeing/framework/WellbeingFrameworkServiceImpl.kt",
    "content": "package org.eu.droid_ng.wellbeing.framework\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.RemoteException\nimport android.provider.Settings\nimport org.eu.droid_ng.wellbeing.shared.BugUtils\nimport org.eu.droid_ng.wellbeing.shim.UserHandlerShim\n\nclass WellbeingFrameworkServiceImpl(context: Context) :\n\tWellbeingFrameworkService.BaseWellbeingFrameworkService(context) {\n\n\tcompanion object {\n\t\tconst val VERSION_CODE = 3\n\t}\n\n\toverride fun start() {\n\t\t// do nothing\n\t}\n\n\toverride fun stop() {\n\t\t// do nothing\n\t}\n\n\t// since 1\n\t@Throws(RemoteException::class)\n\toverride fun versionCode(): Int {\n\t\treturn VERSION_CODE\n\t}\n\n\t// since 1\n\t@Throws(RemoteException::class)\n\toverride fun setAirplaneMode(value: Boolean) {\n\t\tbgHandler.post {\n\t\t\tSettings.Global.putInt(\n\t\t\t\tcontext.contentResolver,\n\t\t\t\tSettings.Global.AIRPLANE_MODE_ON, if (value) 1 else 0\n\t\t\t)\n\t\t\tcontext.sendBroadcastAsUser(\n\t\t\t\tIntent(Intent.ACTION_AIRPLANE_MODE_CHANGED)\n\t\t\t\t\t.putExtra(\"state\", value), UserHandlerShim.ALL\n\t\t\t)\n\t\t}\n\t}\n\n\t// only in 2\n\t@Throws(RemoteException::class)\n\toverride fun onNotificationPosted(packageName: String) {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// only in 2\n\t@Throws(RemoteException::class)\n\toverride fun getEventCount(type: String, dimension: Int, from: Long, to: Long): Long {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// only in 2\n\t@Throws(RemoteException::class)\n\toverride fun getTypesForPrefix(type: String, dimension: Int, from: Long, to: Long): Map<out Any?, Any?> {\n\t\tthrow IllegalArgumentException(\"no longer supported\")\n\t}\n\n\t// since 3\n\toverride fun getBugs(): MutableMap<Any?, Any?> {\n\t\treturn BugUtils.get()?.getBugs()?.toMutableMap() ?: mutableMapOf()\n\t}\n}"
  },
  {
    "path": "framework/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\" translatable=\"false\">Neo Wellbeing Framework</string>\n</resources>"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionSha256Sum=a4b4158601f8636cdeeab09bd76afb640030bb5b144aafe261a5e8af027dc612\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.8-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\norg.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n# Enables namespacing of each library's R class so that its R class includes only the\n# resources declared in the library itself and none from the library's dependencies,\n# thereby reducing the size of the R class for that library\nandroid.nonTransitiveRClass=true\n# Generate compile-time only R class for app modules\nandroid.enableAppCompileTimeRClass=true\n# Only keep the single relevant constructor for types mentioned in XML files\n# instead of using a parameter wildcard which keeps them all\nandroid.useMinimalKeepRules=true\n# Enable resource optimizations for release build\nandroid.enableResourceOptimizations=true\n# Disable Jetifier as we don't use legacy libraries\nandroid.enableJetifier=false\n# Gradle\norg.gradle.caching=true\norg.gradle.configureondemand=true\norg.gradle.configuration-cache=true"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd \"${APP_HOME:-./}\" > /dev/null && pwd -P ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle.kts",
    "content": "@file:Suppress(\"UnstableApiUsage\")\n\npluginManagement {\n\trepositories {\n\t\tgradlePluginPortal()\n\t\tgoogle()\n\t\tmavenCentral()\n\t}\n}\n\ndependencyResolutionManagement {\n\trepositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)\n\trepositories {\n\t\tgoogle()\n\t\tmavenCentral()\n\t\tmaven(\"https://jitpack.io\")\n\t}\n}\n\nrootProject.name = \"NeoWellbeing\"\ninclude(\":shared\", \":framework\", \":app\")"
  },
  {
    "path": "shared/.gitignore",
    "content": "/build"
  },
  {
    "path": "shared/build.gradle.kts",
    "content": "plugins {\n\tid(\"com.android.library\")\n\tid(\"org.jetbrains.kotlin.android\")\n}\n\nandroid {\n\tnamespace = \"org.eu.droid_ng.wellbeing.shared\"\n\tcompileSdk = 35\n\n\tdefaultConfig {\n\t\tminSdk = 29\n\t\tlint {\n\t\t\ttargetSdk = 35\n\t\t}\n\n\t\tconsumerProguardFiles(\"consumer-rules.pro\")\n\t}\n\n\tbuildFeatures {\n\t\taidl = true\n\t}\n\n\tsourceSets {\n\t\tgetByName(\"main\") {\n\t\t\tjava.srcDir(\"src/main/java_magisk\")\n\t\t\tkotlin.srcDir(\"src/main/java_magisk\")\n\t\t}\n\t}\n\n\tcompileOptions {\n\t\tsourceCompatibility = JavaVersion.VERSION_17\n\t\ttargetCompatibility = JavaVersion.VERSION_17\n\t}\n\n\tkotlin {\n\t\tjvmToolchain(17)\n\t}\n}\n\ndependencies {\n\timplementation(\"androidx.annotation:annotation:1.8.2\")\n\t// For gradle builds only\n\timplementation(\"org.lsposed.hiddenapibypass:hiddenapibypass:4.3\")\n}"
  },
  {
    "path": "shared/consumer-rules.pro",
    "content": ""
  },
  {
    "path": "shared/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n-dontobfuscate"
  },
  {
    "path": "shared/src/main/Android.bp",
    "content": "android_library {\n    name: \"NeoWellbeing-shared\",\n    resource_dirs: [\"res\"],\n\n    static_libs: [\n        \"androidx.annotation_annotation\",\n        \"androidx.room_room-runtime\",\n    ],\n    plugins: [\"androidx.room_room-compiler-plugin\"],\n\n    srcs: [\n        \"java/**/*.java\",\n        \"java/**/*.kt\",\n        \"aidl/**/*.aidl\",\n        \"java_real/**/*.java\",\n    ],\n\n    platform_apis: true,\n}\n"
  },
  {
    "path": "shared/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest>\n</manifest>"
  },
  {
    "path": "shared/src/main/aidl/org/eu/droid_ng/wellbeing/framework/IWellbeingFrameworkService.aidl",
    "content": "// IWellbeingFrameworkService.aidl\npackage org.eu.droid_ng.wellbeing.framework;\n\n// Declare any non-default types here with import statements\n\n@JavaDefault\ninterface IWellbeingFrameworkService {\n    // since 1\n    int versionCode() = 0;\n    void setAirplaneMode(boolean value) = 1;\n\n    // only in 2\n    void onNotificationPosted(String packageName) = 2;\n    long getEventCount(String type, int dimension, long from, long to) = 3;\n    Map getTypesForPrefix(String prefix, int dimension, long from, long to) = 4;\n\n    // since 3\n    Map getBugs() = 5;\n}"
  },
  {
    "path": "shared/src/main/java/org/eu/droid_ng/wellbeing/shared/BugUtils.kt",
    "content": "package org.eu.droid_ng.wellbeing.shared\n\nimport android.content.Context\nimport android.util.ArrayMap\nimport android.util.Log\nimport android.util.SparseArray\nimport android.util.SparseLongArray\nimport java.io.File\nimport java.nio.charset.Charset\nimport java.time.Instant\nimport java.time.LocalDateTime\nimport java.time.ZoneId\nimport java.time.format.DateTimeFormatter\n\nclass BugUtils(private val bugFolder: File, private val pkg: String) {\n\tcompanion object {\n\t\tprivate var utils: BugUtils? = null\n\n\t\tfun maybeInit(context: Context) {\n\t\t\tif (utils == null) {\n\t\t\t\tval f = File(context.cacheDir, \"bugutils\")\n\t\t\t\tf.mkdirs()\n\t\t\t\tutils = BugUtils(f, context.packageName)\n\t\t\t}\n\t\t}\n\n\t\t@Suppress(\"FunctionName\")\n\t\tfun BUG(message: String) {\n\t\t\tif (utils != null) {\n\t\t\t\tutils?.onBugAdded(RuntimeException(message), System.currentTimeMillis())\n\t\t\t\tLog.e(\"Wellbeing:BugUtils\", \"BUG \\\"$message\\\"\")\n\t\t\t} else {\n\t\t\t\tLog.e(\"Wellbeing:BugUtils\", \"had to drop BUG \\\"$message\\\"\")\n\t\t\t}\n\t\t}\n\n\t\tfun get(): BugUtils? {\n\t\t\treturn utils\n\t\t}\n\n\t\tfun formatDateForRender(epochMillis: Long): String {\n\t\t\treturn DateTimeFormatter.ofPattern(\"yyyy/MM/dd HH:mm:ss\").format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()))\n\t\t}\n\t}\n\n\tprivate fun cleanup() {\n\t\tbugFolder.list()?.let {\n\t\t\tval l = it.asList().sorted()\n\t\t\tif (l.size > 20) {\n\t\t\t\tl.subList(0, l.size - 21).forEach { name ->\n\t\t\t\t\tFile(bugFolder, name).delete()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfun onBugAdded(message: Throwable, date: Long) {\n\t\tval l = \"$pkg\\n${Log.getStackTraceString(message)}\"\n\t\tval o = File(bugFolder, date.toString()).outputStream()\n\t\to.write(l.toByteArray(Charset.defaultCharset()))\n\t\to.close()\n\t\tcleanup()\n\t}\n\n\tfun hasBugs(): Boolean {\n\t\treturn (bugFolder.list()?.size ?: 0) > 0\n\t}\n\n\tfun getBugs(): Map<Long, String> {\n\t\tval m = hashMapOf<Long, String>()\n\t\tbugFolder.list()?.let {\n\t\t\tval l = it.asList().sorted()\n\t\t\tl.forEach { date ->\n\t\t\t\tval content = File(bugFolder, date).readText(Charset.defaultCharset())\n\t\t\t\tm[date.toLong()] = content\n\t\t\t}\n\t\t}\n\t\treturn m\n\t}\n}"
  },
  {
    "path": "shared/src/main/java_magisk/org/eu/droid_ng/wellbeing/shim/PackageManagerDelegate.java",
    "content": "package org.eu.droid_ng.wellbeing.shim;\n\nimport android.annotation.SuppressLint;\nimport android.app.PendingIntent;\nimport android.app.usage.UsageStatsManager;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.PersistableBundle;\nimport android.util.Log;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport org.lsposed.hiddenapibypass.HiddenApiBypass;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\n/** @noinspection ALL*/ /* both PackageManager stub for building in Android Studio for UI stuff\n* and reflective delegate for magisk module, only used in debug builds.\n*\n* Note: The class must not fail or crash if a reference is missing.\n* */\n@SuppressLint(\"PrivateApi\")\n@SuppressWarnings({\"unused\", \"JavaReflectionMemberAccess\", \"ConstantConditions\"})\npublic class PackageManagerDelegate {\n\tprivate static boolean success;\n\tprivate static Method realSuspendDialogInfoBuilderBuild;\n\tprivate static Method setPackagesSuspended;\n\tprivate static Method getUnsuspendablePackages;\n\tprivate static Constructor<?> realSuspendDialogInfoCst;\n\tprivate static Constructor<?> realSuspendDialogInfoBuilderCst;\n\tprivate static Method getIconResId;\n\tprivate static Method setIconResId;\n\tprivate static Method getTitleResId;\n\tprivate static Method setTitleResId;\n\tprivate static Method getDialogMessageResId;\n\tprivate static Method setDialogMessageResId;\n\tprivate static Method getDialogMessage;\n\tprivate static Method setDialogMessage;\n\tprivate static Method getNeutralButtonTextResId;\n\tprivate static Method setNeutralButtonTextResId;\n\tprivate static Method getNeutralButtonAction;\n\tprivate static Method setNeutralButtonAction;\n\n\tprivate static Method usmCall;\n\tprivate static Method usmCall2;\n\tprivate static Method usmCalla;\n\tprivate static Method usmCalla2;\n\tprivate static Class<?> realDisplayColorManager;\n\n\tstatic {\n\t\tHiddenApiBypass.addHiddenApiExemptions(\"\"); // Help in some cases.\n\t\ttry {\n\t\t\trealDisplayColorManager = Class.forName(\"android.hardware.display.ColorDisplayManager\");\n\t\t\tClass<?> realUsageStatsManager = Class.forName(\"android.app.usage.UsageStatsManager\");\n\t\t\tusmCall = realUsageStatsManager.getMethod(\"registerAppUsageObserver\", int.class, String[].class, long.class, TimeUnit.class, PendingIntent.class);\n\t\t\tusmCall2 = realUsageStatsManager.getMethod(\"registerAppUsageLimitObserver\", int.class, String[].class, Duration.class, Duration.class, PendingIntent.class);\n\t\t\tusmCalla = realUsageStatsManager.getMethod(\"unregisterAppUsageObserver\", int.class);\n\t\t\tusmCalla2 = realUsageStatsManager.getMethod(\"unregisterAppUsageLimitObserver\", int.class);\n\n\n\t\t\tClass<?> realSuspendDialogInfo = Class.forName(\"android.content.pm.SuspendDialogInfo\");\n\t\t\tClass<?> realSuspendDialogInfoBuilder = Class.forName(\"android.content.pm.SuspendDialogInfo$Builder\");\n\t\t\tsetPackagesSuspended = PackageManager.class.getDeclaredMethod(\"setPackagesSuspended\", String[].class,\n\t\t\t\t\tboolean.class, PersistableBundle.class, PersistableBundle.class, realSuspendDialogInfo);\n\t\t\tgetUnsuspendablePackages = PackageManager.class.getDeclaredMethod(\"getUnsuspendablePackages\", String[].class);\n\t\t\ttry {\n\t\t\t\trealSuspendDialogInfoBuilderBuild =\n\t\t\t\t\t\trealSuspendDialogInfoBuilder.getMethod(\"build\");\n\t\t\t\tif (realSuspendDialogInfoBuilderBuild.getReturnType() != realSuspendDialogInfo) {\n\t\t\t\t\trealSuspendDialogInfoBuilderBuild = null;\n\t\t\t\t}\n\t\t\t} catch (ReflectiveOperationException e) {\n\t\t\t\trealSuspendDialogInfoBuilderBuild = null;\n\t\t\t}\n\t\t\tif (realSuspendDialogInfoBuilderBuild == null) {\n\t\t\t\trealSuspendDialogInfoCst =\n\t\t\t\t\t\trealSuspendDialogInfo.getConstructor(realSuspendDialogInfoBuilder);\n\t\t\t}\n\t\t\trealSuspendDialogInfoBuilderCst =\n\t\t\t\t\trealSuspendDialogInfoBuilder.getConstructor();\n\t\t\tgetIconResId = realSuspendDialogInfo.getMethod(\"getIconResId\");\n\t\t\tsetIconResId = realSuspendDialogInfoBuilder.getMethod(\"setIcon\", int.class);\n\t\t\tgetTitleResId = realSuspendDialogInfo.getMethod(\"getTitleResId\");\n\t\t\tsetTitleResId = realSuspendDialogInfoBuilder.getMethod(\"setTitle\", int.class);\n\t\t\tgetDialogMessageResId = realSuspendDialogInfo.getMethod(\"getDialogMessageResId\");\n\t\t\tsetDialogMessageResId = realSuspendDialogInfoBuilder.getMethod(\"setMessage\", int.class);\n\t\t\tgetDialogMessage = realSuspendDialogInfo.getMethod(\"getDialogMessage\");\n\t\t\tsetDialogMessage = realSuspendDialogInfoBuilder.getMethod(\"setMessage\", String.class);\n\t\t\tgetNeutralButtonTextResId = realSuspendDialogInfo.getMethod(\"getNeutralButtonTextResId\");\n\t\t\tsetNeutralButtonTextResId = realSuspendDialogInfoBuilder.getMethod(\"setNeutralButtonText\", int.class);\n\t\t\ttry {\n\t\t\t\tgetNeutralButtonAction = realSuspendDialogInfo.getMethod(\"getNeutralButtonAction\");\n\t\t\t\tsetNeutralButtonAction = realSuspendDialogInfoBuilder.getMethod(\"setNeutralButtonAction\", int.class);\n\t\t\t} catch (ReflectiveOperationException e) {\n\t\t\t\tgetNeutralButtonAction = null;\n\t\t\t\tsetNeutralButtonAction = null;\n\t\t\t}\n\t\t\tsuccess = true;\n\t\t} catch (ReflectiveOperationException e) {\n\t\t\tLog.e(\"PackageManagerDelegate\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\tsuccess = false;\n\t\t}\n\t}\n\n\tpublic static void registerAppUsageObserver(UsageStatsManager m, int observerId, @NonNull String[] observedEntities,\n\t                                            long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {\n\t\ttry {\n\t\t\tusmCall.invoke(m, observerId, observedEntities, timeLimit, timeUnit, callbackIntent);\n\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\tLog.e(\"UsageStatsManager\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t}\n\t}\n\n\tpublic static void registerAppUsageLimitObserver(UsageStatsManager m, int observerId, @NonNull String[] observedEntities,\n\t                                                 Duration timeLimit, Duration timeUsed, @NonNull PendingIntent callbackIntent) {\n\t\ttry {\n\t\t\tusmCall2.invoke(m, observerId, observedEntities, timeLimit, timeUsed, callbackIntent);\n\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\tLog.e(\"UsageStatsManager\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t}\n\t}\n\n\tpublic static void unregisterAppUsageObserver(UsageStatsManager m, int observerId) {\n\t\ttry {\n\t\t\tusmCalla.invoke(m, observerId);\n\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\tLog.e(\"UsageStatsManager\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t}\n\t}\n\n\tpublic static void unregisterAppUsageLimitObserver(UsageStatsManager m, int observerId) {\n\t\ttry {\n\t\t\tusmCalla2.invoke(m, observerId);\n\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\tLog.e(\"UsageStatsManager\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t}\n\t}\n\n\t/** @noinspection BooleanMethodIsAlwaysInverted*/ /* Does not belong here, but for one class im not creating a new delegate */\n\tpublic interface IColorDisplayManager {\n\t\t/**\n\t\t * Returns whether the device has a wide color gamut display.\n\t\t */\n\t\tboolean isDeviceColorManaged();\n\n\t\t/**\n\t\t * Set the level of color saturation to apply to the display.\n\t\t *\n\t\t * @param saturationLevel 0-100 (inclusive), where 100 is full saturation\n\t\t * @return whether the saturation level change was applied successfully\n\t\t */\n\t\tboolean setSaturationLevel(@IntRange(from = 0, to = 100) int saturationLevel);\n\n\t\t/**\n\t\t * Set the level of color saturation to apply to a specific app.\n\t\t *\n\t\t * @param packageName the package name of the app whose windows should be desaturated\n\t\t * @param saturationLevel 0-100 (inclusive), where 100 is full saturation\n\t\t * @return whether the saturation level change was applied successfully\n\t\t */\n\t\tboolean setAppSaturationLevel(@NonNull String packageName,\n\t\t                                     @IntRange(from = 0, to = 100) int saturationLevel);\n\n\t\t/**\n\t\t * Returns {@code true} if Night Display is supported by the device.\n\t\t */\n\t\tboolean isNightDisplayAvailable(Context context);\n\n\t\t/**\n\t\t * Returns {@code true} if display white balance is supported by the device.\n\t\t */\n\t\tboolean isDisplayWhiteBalanceAvailable(Context context);\n\t}\n\n\t@NonNull\n\tpublic static IColorDisplayManager getColorDisplayManager(Context ctx) {\n\t\tObject cdm;\n\t\tMethod isDeviceColorManaged, setSaturationLevel, setAppSaturationLevel, isNightDisplayAvailable, isDisplayWhiteBalanceAvailable;\n\t\ttry {\n\t\t\tcdm = ctx.getSystemService(realDisplayColorManager);\n\t\t\tisDeviceColorManaged = realDisplayColorManager.getDeclaredMethod(\"isDeviceColorManaged\");\n\t\t\tsetSaturationLevel = realDisplayColorManager.getDeclaredMethod(\"setSaturationLevel\", int.class);\n\t\t\tsetAppSaturationLevel = realDisplayColorManager.getDeclaredMethod(\"setAppSaturationLevel\", String.class, int.class);\n\t\t\tisNightDisplayAvailable = realDisplayColorManager.getDeclaredMethod(\"isNightDisplayAvailable\", Context.class);\n\t\t\tisDisplayWhiteBalanceAvailable = realDisplayColorManager.getDeclaredMethod(\"isDisplayWhiteBalanceAvailable\", Context.class);\n\t\t} catch (Exception e) {\n\t\t\tLog.e(\"PackageManagerDelegate\", // Log why it's crashing\n\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\treturn new IColorDisplayManager() { // Return stub then.\n\t\t\t\t@Override public boolean isDeviceColorManaged() { return false; }\n\t\t\t\t@Override public boolean setSaturationLevel(int saturationLevel) { return false; }\n\t\t\t\t@Override public boolean setAppSaturationLevel(@NonNull String packageName, int saturationLevel) { return false; }\n\t\t\t\t@Override public boolean isNightDisplayAvailable(Context context) { return false; }\n\t\t\t\t@Override public boolean isDisplayWhiteBalanceAvailable(Context context) { return false; }\n\t\t\t};\n\t\t}\n\t\treturn new IColorDisplayManager() {\n\t\t\t@Override\n\t\t\tpublic boolean isDeviceColorManaged() {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Boolean) isDeviceColorManaged.invoke(cdm);\n\t\t\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\t\t\tLog.e(\"IColorDisplayManager\", // Log why it's crashing\n\t\t\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean setSaturationLevel(int saturationLevel) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Boolean) setSaturationLevel.invoke(cdm, saturationLevel);\n\t\t\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\t\t\tLog.e(\"IColorDisplayManager\", // Log why it's crashing\n\t\t\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean setAppSaturationLevel(@NonNull String packageName, int saturationLevel) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Boolean) setAppSaturationLevel.invoke(cdm, packageName, saturationLevel);\n\t\t\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\t\t\tLog.e(\"IColorDisplayManager\", // Log why it's crashing\n\t\t\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isNightDisplayAvailable(Context context) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Boolean) isNightDisplayAvailable.invoke(null, context);\n\t\t\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\t\t\tLog.e(\"IColorDisplayManager\", // Log why it's crashing\n\t\t\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isDisplayWhiteBalanceAvailable(Context context) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Boolean) isDisplayWhiteBalanceAvailable.invoke(null, context);\n\t\t\t\t} catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {\n\t\t\t\t\tLog.e(\"IColorDisplayManager\", // Log why it's crashing\n\t\t\t\t\t\t\t\"This would not occur if the app was built-in into the ROM:\", e);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate final PackageManager pm;\n\n\tpublic PackageManagerDelegate(PackageManager pm) {\n\t\tthis.pm = pm;\n\t}\n\n\tpublic String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspend, @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo) {\n\t\tif (success && (dialogInfo == null || dialogInfo.real != null)) {\n\t\t\ttry {\n\t\t\t\treturn (String[]) setPackagesSuspended.invoke(this.pm, packageNames, suspend, appExtras,\n\t\t\t\t\t\tlauncherExtras, dialogInfo == null ? null : dialogInfo.real);\n\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t}\n\n\t\t/* stub */\n\t\treturn new String[]{};\n\t}\n\n\tpublic String[] getUnsuspendablePackages(String[] packageNames) {\n\t\tif (success) {\n\t\t\ttry {\n\t\t\t\treturn (String[]) getUnsuspendablePackages.invoke(this.pm, (Object) packageNames);\n\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t}\n\n\t\t/* stub */\n\t\treturn new String[]{};\n\t}\n\n\tpublic static class SuspendDialogInfo {\n\t\tObject real; // Instance used by reflection\n\t\t/**\n\t\t * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that\n\t\t * starts the Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS activity.\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t */\n\t\tpublic static final int BUTTON_ACTION_MORE_DETAILS = 0;\n\n\t\t/**\n\t\t * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that\n\t\t * unsuspends the app that the user was trying to launch and continues with the launch. The\n\t\t * system also sends the broadcast\n\t\t * Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY to the suspending app\n\t\t * when this happens.\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t * see ACTION_PACKAGE_UNSUSPENDED_MANUALLY\n\t\t */\n\t\tpublic static final int BUTTON_ACTION_UNSUSPEND = 1;\n\n\t\t/**\n\t\t * Button actions to specify what happens when the user taps on the neutral button.\n\t\t * To be used with {@link Builder#setNeutralButtonAction(int)}.\n\t\t *\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t */\n\t\t@IntDef(flag = true, value = {\n\t\t\t\tBUTTON_ACTION_MORE_DETAILS,\n\t\t\t\tBUTTON_ACTION_UNSUSPEND\n\t\t})\n\t\t@Retention(RetentionPolicy.SOURCE)\n\t\tpublic @interface ButtonAction {\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the icon to be used with the dialog\n\t\t */\n\t\t@DrawableRes\n\t\tpublic int getIconResId() {\n\t\t\tif (success && real != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Integer) getIconResId.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the title to be used with the dialog\n\t\t */\n\t\t@StringRes\n\t\tpublic int getTitleResId() {\n\t\t\tif (success && real != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Integer) getTitleResId.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the text to be shown in the dialog's body\n\t\t */\n\t\t@StringRes\n\t\tpublic int getDialogMessageResId() {\n\t\t\tif (success && real != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Integer) getDialogMessageResId.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\t/**\n\t\t * @return the text to be shown in the dialog's body. Returns {@code null} if {@link\n\t\t * #getDialogMessageResId()} returns a valid resource id\n\t\t */\n\t\t@Nullable\n\t\tpublic String getDialogMessage() {\n\t\t\tif (success && real != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (String) getDialogMessage.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\t/**\n\t\t * @return the text to be shown\n\t\t */\n\t\t@StringRes\n\t\tpublic int getNeutralButtonTextResId() {\n\t\t\tif (success && real != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Integer) getNeutralButtonTextResId.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\t/**\n\t\t * @return The {@link ButtonAction} that happens on tapping this button\n\t\t */\n\t\t@ButtonAction\n\t\tpublic int getNeutralButtonAction() {\n\t\t\tif (success && real != null && getNeutralButtonAction != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn (Integer) getNeutralButtonAction.invoke(real);\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tSuspendDialogInfo(Builder b) {\n\t\t\tif (success && b != null && b.realB != null) {\n\t\t\t\ttry {\n\t\t\t\t\tif (realSuspendDialogInfoBuilderBuild != null) {\n\t\t\t\t\t\tthis.real = realSuspendDialogInfoBuilderBuild.invoke(b.realB);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.real = realSuspendDialogInfoCst.newInstance(b.realB);\n\t\t\t\t\t}\n\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Builder to build a {@link SuspendDialogInfo} object.\n\t\t */\n\t\tpublic static final class Builder {\n\t\t\tObject realB; // Instance used by reflection\n\n\t\t\tpublic Builder() {\n\t\t\t\tif (success) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.realB = realSuspendDialogInfoBuilderCst.newInstance();\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/**\n\t\t\t * Set the resource id of the icon to be used. If not provided, no icon will be shown.\n\t\t\t *\n\t\t\t * @param resId The resource id of the icon.\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setIcon(@DrawableRes int resId) {\n\t\t\t\tif (success && realB != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetIconResId.invoke(realB, resId);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of the title text to be displayed. If this is not provided, the\n\t\t\t * system will use a default title.\n\t\t\t *\n\t\t\t * @param resId The resource id of the title.\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setTitle(@StringRes int resId) {\n\t\t\t\tif (success && realB != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetTitleResId.invoke(realB, resId);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the text to show in the body of the dialog. Ignored if a resource id is set via\n\t\t\t * {@link #setMessage(int)}.\n\t\t\t * <p>\n\t\t\t * The system will use String#format(Locale, String, Object...) to\n\t\t\t * insert the suspended app name into the message, so an example format string could be\n\t\t\t * {@code \"The app %1$s is currently suspended\"}. This is optional - if the string passed in\n\t\t\t * {@code message} does not accept an argument, it will be used as is.\n\t\t\t *\n\t\t\t * @param message The dialog message.\n\t\t\t * @return this builder object.\n\t\t\t * @see #setMessage(int)\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setMessage(@NonNull String message) {\n\t\t\t\tif (success && realB != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetDialogMessage.invoke(realB, message);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of the dialog message to be shown. If no dialog message is provided\n\t\t\t * via either this method or {@link #setMessage(String)}, the system will use a default\n\t\t\t * message.\n\t\t\t * <p>\n\t\t\t * The system will use {@link android.content.res.Resources#getString(int, Object...)\n\t\t\t * getString} to insert the suspended app name into the message, so an example format string\n\t\t\t * could be {@code \"The app %1$s is currently suspended\"}. This is optional - if the string\n\t\t\t * referred to by {@code resId} does not accept an argument, it will be used as is.\n\t\t\t *\n\t\t\t * @param resId The resource id of the dialog message.\n\t\t\t * @return this builder object.\n\t\t\t * @see #setMessage(String)\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setMessage(@StringRes int resId) {\n\t\t\t\tif (success && realB != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetDialogMessageResId.invoke(realB, resId);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of text to be shown on the neutral button. Tapping this button would\n\t\t\t * perform the {@link ButtonAction action} specified through\n\t\t\t * {@link #setNeutralButtonAction(int)}. If this is not provided, the system will use a\n\t\t\t * default text.\n\t\t\t *\n\t\t\t * @param resId The resource id of the button text\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setNeutralButtonText(@StringRes int resId) {\n\t\t\t\tif (success && realB != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetNeutralButtonTextResId.invoke(realB, resId);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the action expected to happen on neutral button tap. Defaults to\n\t\t\t * {@link #BUTTON_ACTION_MORE_DETAILS} if this is not provided.\n\t\t\t *\n\t\t\t * @param buttonAction Either {@link #BUTTON_ACTION_MORE_DETAILS} or\n\t\t\t *                     {@link #BUTTON_ACTION_UNSUSPEND}.\n\t\t\t * @return this builder object\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setNeutralButtonAction(@ButtonAction int buttonAction) {\n\t\t\t\tif (success && realB != null && setNeutralButtonAction != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsetNeutralButtonAction.invoke(realB, buttonAction);\n\t\t\t\t\t} catch (ReflectiveOperationException ignored) {}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Build the final object based on given inputs.\n\t\t\t *\n\t\t\t * @return The {@link SuspendDialogInfo} object built using this builder.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic SuspendDialogInfo build() {\n\t\t\t\treturn new SuspendDialogInfo(this);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static boolean canSuspend() {\n\t\treturn success;\n\t}\n\n\tpublic static boolean canSetNeutralButtonAction() {\n\t\treturn success && setNeutralButtonAction != null;\n\t}\n}"
  },
  {
    "path": "shared/src/main/java_magisk/org/eu/droid_ng/wellbeing/shim/UserHandlerShim.java",
    "content": "package org.eu.droid_ng.wellbeing.shim;\n\nimport android.os.Process;\nimport android.os.UserHandle;\n\n@SuppressWarnings(\"JavaReflectionMemberAccess\")\npublic class UserHandlerShim {\n    public static final UserHandle ALL;\n\n    static {\n        UserHandle UserHandler_ALL;\n        try {\n            UserHandler_ALL = (UserHandle) UserHandle.class\n                    .getDeclaredField(\"ALL\").get(null);\n        } catch (Exception ignored) {\n            UserHandler_ALL = UserHandle.getUserHandleForUid(Process.myUid());\n        }\n        ALL = UserHandler_ALL;\n    }\n}\n"
  },
  {
    "path": "shared/src/main/java_real/org/eu/droid_ng/wellbeing/shim/PackageManagerDelegate.java",
    "content": "package org.eu.droid_ng.wellbeing.shim;\n\nimport android.content.pm.PackageManager;\nimport android.hardware.display.ColorDisplayManager;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.PersistableBundle;\nimport android.app.PendingIntent;\nimport android.app.usage.UsageStatsManager;\nimport android.content.Context;\nimport android.os.PersistableBundle;\nimport android.util.Log;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\n/* This file contains all references to private API. Private API will not be used elsewhere\n* This class is only used when doing full systems builds, so assume system implement required APIs\n* */\npublic class PackageManagerDelegate {\n\n\tpublic static void registerAppUsageObserver(UsageStatsManager m, int observerId, @NonNull String[] observedEntities,\n\t                                            long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {\n\t\tm.registerAppUsageObserver(observerId, observedEntities, timeLimit, timeUnit, callbackIntent);\n\t}\n\n\tpublic static void registerAppUsageLimitObserver(UsageStatsManager m, int observerId, @NonNull String[] observedEntities,\n\t                                            Duration timeLimit, Duration timeUsed, @NonNull PendingIntent callbackIntent) {\n\t\tm.registerAppUsageLimitObserver(observerId, observedEntities, timeLimit, timeUsed, callbackIntent);\n\t}\n\n\tpublic static void unregisterAppUsageObserver(UsageStatsManager m, int observerId) {\n\t\tm.unregisterAppUsageObserver(observerId);\n\t}\n\n\tpublic static void unregisterAppUsageLimitObserver(UsageStatsManager m, int observerId) {\n\t\tm.unregisterAppUsageLimitObserver(observerId);\n\t}\n\n\t/* Does not belong here, but for one class im not creating a new delegate */\n\tpublic interface IColorDisplayManager {\n\t\t/**\n\t\t * Returns whether the device has a wide color gamut display.\n\t\t */\n\t\tpublic boolean isDeviceColorManaged();\n\n\t\t/**\n\t\t * Set the level of color saturation to apply to the display.\n\t\t *\n\t\t * @param saturationLevel 0-100 (inclusive), where 100 is full saturation\n\t\t * @return whether the saturation level change was applied successfully\n\t\t */\n\t\tpublic boolean setSaturationLevel(@IntRange(from = 0, to = 100) int saturationLevel);\n\n\t\t/**\n\t\t * Set the level of color saturation to apply to a specific app.\n\t\t *\n\t\t * @param packageName the package name of the app whose windows should be desaturated\n\t\t * @param saturationLevel 0-100 (inclusive), where 100 is full saturation\n\t\t * @return whether the saturation level change was applied successfully\n\t\t */\n\t\tpublic boolean setAppSaturationLevel(@NonNull String packageName,\n\t\t                              @IntRange(from = 0, to = 100) int saturationLevel);\n\n\t\t/**\n\t\t * Returns {@code true} if Night Display is supported by the device.\n\t\t */\n\t\tpublic boolean isNightDisplayAvailable(Context context);\n\n\t\t/**\n\t\t * Returns {@code true} if display white balance is supported by the device.\n\t\t */\n\t\tpublic boolean isDisplayWhiteBalanceAvailable(Context context);\n\t}\n\n\tpublic IColorDisplayManager getColorDisplayManager(Context ctx) {\n\t\tColorDisplayManager cdm = ctx.getSystemService(ColorDisplayManager.class);\n\t\treturn new IColorDisplayManager() {\n\t\t\t@Override\n\t\t\tpublic boolean isDeviceColorManaged() {\n\t\t\t\treturn cdm.isDeviceColorManaged();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean setSaturationLevel(int saturationLevel) {\n\t\t\t\treturn cdm.setSaturationLevel(saturationLevel);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean setAppSaturationLevel(String packageName, int saturationLevel) {\n\t\t\t\treturn cdm.setAppSaturationLevel(packageName, saturationLevel);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isNightDisplayAvailable(Context context) {\n\t\t\t\treturn ColorDisplayManager.isNightDisplayAvailable(context);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isDisplayWhiteBalanceAvailable(Context context) {\n\t\t\t\treturn ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate final PackageManager pm;\n\n\tpublic PackageManagerDelegate(PackageManager pm) {\n\t\tthis.pm = pm;\n\t}\n\n\tpublic String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspend, @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo) {\n\t\treturn pm.setPackagesSuspended(packageNames, suspend, appExtras, launcherExtras, dialogInfo == null ? null : dialogInfo.real);\n\t}\n\n\tpublic String[] getUnsuspendablePackages(String[] packageNames) {\n\t\treturn pm.getUnsuspendablePackages(packageNames);\n\t}\n\n\tpublic static class SuspendDialogInfo {\n\t\tandroid.content.pm.SuspendDialogInfo real;\n\n\t\t/**\n\t\t * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that\n\t\t * starts the Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS activity.\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t */\n\t\tpublic static final int BUTTON_ACTION_MORE_DETAILS = 0;\n\n\t\t/**\n\t\t * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that\n\t\t * unsuspends the app that the user was trying to launch and continues with the launch. The\n\t\t * system also sends the broadcast\n\t\t * Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY to the suspending app\n\t\t * when this happens.\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t * see ACTION_PACKAGE_UNSUSPENDED_MANUALLY\n\t\t */\n\t\tpublic static final int BUTTON_ACTION_UNSUSPEND = 1;\n\n\t\t/**\n\t\t * Button actions to specify what happens when the user taps on the neutral button.\n\t\t * To be used with {@link Builder#setNeutralButtonAction(int)}.\n\t\t *\n\t\t * @hide\n\t\t * @see Builder#setNeutralButtonAction(int)\n\t\t */\n\t\t@IntDef(flag = true, value = {\n\t\t\t\tBUTTON_ACTION_MORE_DETAILS,\n\t\t\t\tBUTTON_ACTION_UNSUSPEND\n\t\t})\n\t\t@Retention(RetentionPolicy.SOURCE)\n\t\tpublic @interface ButtonAction {\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the icon to be used with the dialog\n\t\t * @hide\n\t\t */\n\t\t@DrawableRes\n\t\tpublic int getIconResId() {\n\t\t\treturn real.getIconResId();\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the title to be used with the dialog\n\t\t * @hide\n\t\t */\n\t\t@StringRes\n\t\tpublic int getTitleResId() {\n\t\t\treturn real.getTitleResId();\n\t\t}\n\n\t\t/**\n\t\t * @return the resource id of the text to be shown in the dialog's body\n\t\t * @hide\n\t\t */\n\t\t@StringRes\n\t\tpublic int getDialogMessageResId() {\n\t\t\treturn real.getDialogMessageResId();\n\t\t}\n\n\t\t/**\n\t\t * @return the text to be shown in the dialog's body. Returns {@code null} if {@link\n\t\t * #getDialogMessageResId()} returns a valid resource id\n\t\t * @hide\n\t\t */\n\t\t@Nullable\n\t\tpublic String getDialogMessage() {\n\t\t\treturn real.getDialogMessage();\n\t\t}\n\n\t\t/**\n\t\t * @return the text to be shown\n\t\t * @hide\n\t\t */\n\t\t@StringRes\n\t\tpublic int getNeutralButtonTextResId() {\n\t\t\treturn real.getNeutralButtonTextResId();\n\t\t}\n\n\t\t/**\n\t\t * @return The {@link ButtonAction} that happens on tapping this button\n\t\t */\n\t\t@ButtonAction\n\t\tpublic int getNeutralButtonAction() {\n\t\t\treturn real.getNeutralButtonAction();\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn real.hashCode();\n\t\t}\n\n\t\tpublic SuspendDialogInfo(Builder b) {\n\t\t\treal = b.realb.build();\n\t\t}\n\n\t\tprivate SuspendDialogInfo(android.content.pm.SuspendDialogInfo r) {\n\t\t\treal = r;\n\t\t}\n\n\t\t/**\n\t\t * Builder to build a {@link SuspendDialogInfo} object.\n\t\t */\n\t\tpublic static final class Builder {\n\t\t\tpublic android.content.pm.SuspendDialogInfo.Builder realb = new android.content.pm.SuspendDialogInfo.Builder();\n\t\t\t/**\n\t\t\t * Set the resource id of the icon to be used. If not provided, no icon will be shown.\n\t\t\t *\n\t\t\t * @param resId The resource id of the icon.\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setIcon(@DrawableRes int resId) {\n\t\t\t\trealb.setIcon(resId);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of the title text to be displayed. If this is not provided, the\n\t\t\t * system will use a default title.\n\t\t\t *\n\t\t\t * @param resId The resource id of the title.\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setTitle(@StringRes int resId) {\n\t\t\t\trealb.setTitle(resId);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the text to show in the body of the dialog. Ignored if a resource id is set via\n\t\t\t * {@link #setMessage(int)}.\n\t\t\t * <p>\n\t\t\t * The system will use String#format(Locale, String, Object...) to\n\t\t\t * insert the suspended app name into the message, so an example format string could be\n\t\t\t * {@code \"The app %1$s is currently suspended\"}. This is optional - if the string passed in\n\t\t\t * {@code message} does not accept an argument, it will be used as is.\n\t\t\t *\n\t\t\t * @param message The dialog message.\n\t\t\t * @return this builder object.\n\t\t\t * @see #setMessage(int)\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setMessage(@NonNull String message) {\n\t\t\t\trealb.setMessage(message);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of the dialog message to be shown. If no dialog message is provided\n\t\t\t * via either this method or {@link #setMessage(String)}, the system will use a default\n\t\t\t * message.\n\t\t\t * <p>\n\t\t\t * The system will use {@link android.content.res.Resources#getString(int, Object...)\n\t\t\t * getString} to insert the suspended app name into the message, so an example format string\n\t\t\t * could be {@code \"The app %1$s is currently suspended\"}. This is optional - if the string\n\t\t\t * referred to by {@code resId} does not accept an argument, it will be used as is.\n\t\t\t *\n\t\t\t * @param resId The resource id of the dialog message.\n\t\t\t * @return this builder object.\n\t\t\t * @see #setMessage(String)\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setMessage(@StringRes int resId) {\n\t\t\t\trealb.setMessage(resId);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the resource id of text to be shown on the neutral button. Tapping this button would\n\t\t\t * perform the {@link ButtonAction action} specified through\n\t\t\t * {@link #setNeutralButtonAction(int)}. If this is not provided, the system will use a\n\t\t\t * default text.\n\t\t\t *\n\t\t\t * @param resId The resource id of the button text\n\t\t\t * @return this builder object.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setNeutralButtonText(@StringRes int resId) {\n\t\t\t\trealb.setNeutralButtonText(resId);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Set the action expected to happen on neutral button tap. Defaults to\n\t\t\t * {@link #BUTTON_ACTION_MORE_DETAILS} if this is not provided.\n\t\t\t *\n\t\t\t * @param buttonAction Either {@link #BUTTON_ACTION_MORE_DETAILS} or\n\t\t\t *                     {@link #BUTTON_ACTION_UNSUSPEND}.\n\t\t\t * @return this builder object\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic Builder setNeutralButtonAction(@ButtonAction int buttonAction) {\n\t\t\t\trealb.setNeutralButtonAction(buttonAction);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Build the final object based on given inputs.\n\t\t\t *\n\t\t\t * @return The {@link SuspendDialogInfo} object built using this builder.\n\t\t\t */\n\t\t\t@NonNull\n\t\t\tpublic SuspendDialogInfo build() {\n\t\t\t\treturn new SuspendDialogInfo(this);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static boolean canSuspend() {\n\t\treturn true;\n\t}\n\n\tpublic static boolean canSetNeutralButtonAction() {\n\t\treturn true;\n\t}\n}"
  },
  {
    "path": "shared/src/main/java_real/org/eu/droid_ng/wellbeing/shim/UserHandlerShim.java",
    "content": "package org.eu.droid_ng.wellbeing.shim;\n\nimport android.os.UserHandle;\n\npublic class UserHandlerShim {\n    public static final UserHandle ALL = UserHandle.ALL;\n}\n"
  }
]