[
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n#local\n/local.properties\n.idea/\n/.idea/*\n.idea/misc.xml\n.idea/vcs.xml\n*.idea*\n*manifest-merger-debug-report.txt\n*manifest-merger-release-report.txt\n*.ds_store\n*.DS_Store\n*.swp\n"
  },
  {
    "path": "DexDrip.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/classes/main\" />\n    <output-test url=\"file://$MODULE_DIR$/build/classes/test\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/resources\" type=\"java-test-resource\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\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 GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  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\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions 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 convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU 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\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\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\nstate 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 3 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\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program 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, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "xDrip\n=======\n##### ** Please note this is __NOT__ a product created by or backed by Dexcom, you can check them out [here](http://dexcom.com/) **\n\n#### Wirelessly with a Dexcom Share Receiver -- or -- Wireless xDrip bridge (No receiver!)\n\n#### Click here for the [Main Project Page](http://stephenblackwasalreadytaken.github.io/xDrip/)\n\n\n#### Access your Glucose levels from anywhere!\nxDrip is ready to upload your glucose data to any [Nightscout](http://nightscout.github.io/) server for remote monitoring on just about any internet connected device!!\n\n\n#### Want to learn more?? \nJump on over to the [Wiki](https://github.com/StephenBlackWasAlreadyTaken/xDrip/wiki) for instructions and downloads!!\n\n\n#### Stay Up to Date!\nFollow me on twitter `@StephenIsTaken`, I will let everyone know when updates happen that you should definitely download! Updates will be rolling out fairly frequently as there is lots to do!!!\n\n\n#### Want to help out?\nAWESOME, let me know, put up some PRS, lets make it awesome!\n\n\n#### Awesome Contributors:\n(in no particular order, because they are all awesome)\n* [@tzachi-dar](https://github.com/tzachi-dar) \n* [@jstevensog](https://github.com/jstevensog) \n* [@bhandfast](https://github.com/bhandfast) \n* [@LorelaiL](https://github.com/LorelaiL)\n* [@syntaxerr66](https://github.com/syntaxerr66)\n* [@saercnap](https://github.com/saercnap) \n* [@ktind](https://github.com/ktind)\n* [Ly](http://youtu.be/YuxCUeJ9xAU)\n* [Kev](http://circles-of-blue.winchcombe.org/)\n* [NightScout](https://github.com/nightscout)\n* Whoever else is supporting this and helping people out!!\n\n***\n\n<a href=\"http://i.imgur.com/7b18gLs.jpg\"><img src=\"http://i.imgur.com/7b18gLs.jpg\" align=\"center\" width=\"600\" ></a>\n\n<a href=\"http://imgur.com/lFwKzRr.jpg\"><img src=\"http://imgur.com/lFwKzRr.jpg\" align=\"center\" width=\"600\" ></a>\n\n***\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/app.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":app\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"xDrip-Experimental\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":app\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"SELECTED_TEST_ARTIFACT\" value=\"_android_test_\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <option name=\"SOURCE_GEN_TASK_NAME\" value=\"generateDebugSources\" />\n        <option name=\"ASSEMBLE_TEST_TASK_NAME\" value=\"assembleDebugAndroidTest\" />\n        <option name=\"COMPILE_JAVA_TEST_TASK_NAME\" value=\"compileDebugAndroidTestSources\" />\n        <option name=\"TEST_SOURCE_GEN_TASK_NAME\" value=\"generateDebugAndroidTestSources\" />\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"file://$MODULE_DIR$/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <output-test url=\"file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jacoco\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/javaResources\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/libs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/manifests\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/ndk\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/pre-dexed\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/proguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 21 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"android-support-v4\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"ActiveAndroid\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"okio-1.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"okhttp-2.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"crashlytics-2.2.3\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"answers-1.1.2\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"rxjava-1.0.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"retrofit-1.9.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"acra-4.5.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"beta-1.1.2\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"gson-2.3.1\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"mongo-java-driver-2.10.1\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"usb-serial-for-android-v010\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"pebblekit-2.6.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"fabric-1.3.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"hellocharts-library-1.1\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "app/build.gradle",
    "content": "buildscript {\n    repositories {\n        maven { url 'https://maven.fabric.io/public' }\n    }\n\n    dependencies {\n        classpath 'io.fabric.tools:gradle:1.+'\n    }\n}\napply plugin: 'com.android.application'\napply plugin: 'io.fabric'\n\nrepositories {\n    maven { url 'https://maven.fabric.io/public' }\n}\n\n\nandroid {\n    compileSdkVersion 21\n    buildToolsVersion \"20.0.0\"\n\n    defaultConfig {\n        applicationId \"com.eveningoutpost.dexdrip\"\n        minSdkVersion 19\n        targetSdkVersion 21\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    testCompile 'com.squareup.okhttp:mockwebserver:2.2.0'\n    compile 'com.squareup.okhttp:okhttp:2.2.0'\n    compile 'com.google.code.gson:gson:2.3'\n    compile 'org.mongodb:mongo-java-driver:2.10.1'\n    compile 'com.squareup.retrofit:retrofit:1.9.0'\n    compile 'com.getpebble:pebblekit:2.6.0@aar'\n    compile 'io.reactivex:rxjava:1.0.0'\n    compile 'ch.acra:acra:4.5.0'\n    compile('com.crashlytics.sdk.android:crashlytics:2.2.3@aar') {\n        transitive = true;\n    }\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/stephenblack/adt-bundle-mac-x86_64-20140702 2/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "app/src/androidTest/java/com/eveningoutpost/dexdrip/ApplicationTest.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\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    package=\"com.eveningoutpost.dexdrip\" >\n\n    <permission android:name=\"com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE\" />\n\n    <uses-feature\n        android:name=\"android.hardware.bluetooth_le\"\n        android:required=\"true\" />\n    <uses-feature android:name=\"android.hardware.usb.host\" />\n\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n    <uses-permission android:name=\"android.permission.BATTERY_STATS\" />\n    <uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.\" />\n\n    <application\n        android:name=\".xdrip\"\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:theme=\"@style/AppTheme\" >\n        <meta-data\n            android:name=\"AA_DB_NAME\"\n            android:value=\"DexDrip.db\" />\n        <meta-data\n            android:name=\"AA_DB_VERSION\"\n            android:value=\"27\" />\n\n        <provider\n            android:name=\"com.activeandroid.content.ContentProvider\"\n            android:authorities=\"com.example\"\n            android:exported=\"false\" />\n\n        <activity\n            android:name=\".Home\"\n            android:label=\"@string/app_name\"\n            android:launchMode=\"singleInstance\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".BluetoothScan\"\n            android:label=\"@string/title_activity_bluetooth_scan\" >\n        </activity>\n\n        <service\n            android:name=\".Services.DexCollectionService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" >\n        </service>\n\n        <activity\n            android:name=\".Tables.BgReadingTable\"\n            android:label=\"Bg Readings Table\" >\n        </activity>\n        <activity\n            android:name=\".Tables.SensorDataTable\"\n            android:label=\"Sensor Table\" >\n        </activity>\n        <activity\n            android:name=\".AddCalibration\"\n            android:label=\"@string/title_activity_add_calibration\" >\n        </activity>\n        <activity\n            android:name=\".StartNewSensor\"\n            android:label=\"@string/title_activity_start_new_sensor\" >\n        </activity>\n        <activity\n            android:name=\".StopSensor\"\n            android:label=\"@string/title_activity_stop_sensor\" >\n        </activity>\n\n        <receiver android:name=\".AutoStart\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\".Tables.CalibrationDataTable\"\n            android:label=\"@string/title_activity_calibration_data_table\" >\n        </activity>\n\n        <service\n            android:name=\".Services.SyncService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" >\n        </service>\n        <service\n            android:name=\".ImportedLibraries.dexcom.SyncingService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" >\n        </service>\n\n        <activity\n            android:name=\".FakeNumbers\"\n            android:label=\"@string/title_activity_fake_numbers\" >\n        </activity>\n        <activity\n            android:name=\".DoubleCalibrationActivity\"\n            android:label=\"@string/title_activity_double_calibration\" >\n        </activity>\n        <activity\n            android:name=\".CalibrationOverride\"\n            android:label=\"@string/title_activity_calibration_override\" >\n        </activity>\n        <activity\n            android:name=\".CalibrationGraph\"\n            android:label=\"@string/title_activity_calibration_graph\" >\n        </activity>\n        <activity\n            android:name=\".SettingsActivity\"\n            android:label=\"Settings\" >\n        </activity>\n        <activity\n            android:name=\".LicenseAgreementActivity\"\n            android:label=\"@string/title_activity_license_agreement\" >\n        </activity>\n        <activity\n            android:name=\".CalibrationCheckInActivity\"\n            android:label=\"@string/title_activity_calibration_check_in\" >\n        </activity>\n        <activity\n            android:name=\".UsbConnectedActivity\"\n            android:label=\"@string/title_activity_usb_connected\" >\n            <intent-filter>\n                <action android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\"\n                android:resource=\"@xml/device_filter\" />\n        </activity>\n\n        <service\n            android:name=\".Services.DexShareCollectionService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" >\n        </service>\n\n        <activity\n            android:name=\".ShareTest\"\n            android:label=\"@string/title_activity_share_test\" >\n        </activity>\n        <activity\n            android:name=\".SystemStatus\"\n            android:label=\"@string/title_activity_system_status\" >\n        </activity>\n        <activity\n            android:name=\".utils.Preferences\"\n            android:label=\"@string/title_activity_preferences\" >\n        </activity>\n\n        <receiver android:name=\".xDripWidget\" >\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/x_drip_widget_info\" />\n        </receiver>\n\n        <service\n            android:name=\".widgetUpdateService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" >\n        </service>\n        <meta-data\n            android:name=\"io.fabric.ApiKey\"\n            android:value=\"193dbc121e25e5f3e71bb98164ec074378e339df\" />\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/assets/migrations/10.sql",
    "content": "ALTER TABLE Notifications ADD COLUMN calibration_alert BOOLEAN;\nALTER TABLE Notifications ADD COLUMN double_calibration_alert BOOLEAN;\nALTER TABLE Notifications ADD COLUMN extra_calibration_alert BOOLEAN;"
  },
  {
    "path": "app/src/main/assets/migrations/16.sql",
    "content": "ALTER TABLE CalibrationSendQueue ADD COLUMN mongo_success BOOLEAN;\nALTER TABLE BgSendQueue ADD COLUMN mongo_success BOOLEAN;\n"
  },
  {
    "path": "app/src/main/assets/migrations/17.sql",
    "content": "ALTER TABLE Calibration ADD COLUMN possible_bad BOOLEAN;\n"
  },
  {
    "path": "app/src/main/assets/migrations/18.sql",
    "content": "ALTER TABLE Calibration ADD COLUMN first_decay REAL;\nALTER TABLE Calibration ADD COLUMN second_decay REAL;\nALTER TABLE Calibration ADD COLUMN first_slope REAL;\nALTER TABLE Calibration ADD COLUMN second_slope REAL;\n"
  },
  {
    "path": "app/src/main/assets/migrations/19.sql",
    "content": "ALTER TABLE Calibration ADD COLUMN first_intercept REAL;\nALTER TABLE Calibration ADD COLUMN second_intercept REAL;\nALTER TABLE Calibration ADD COLUMN first_scale REAL;\nALTER TABLE Calibration ADD COLUMN second_scale REAL;\n\n"
  },
  {
    "path": "app/src/main/assets/migrations/20.sql",
    "content": "ALTER TABLE Calibration ADD COLUMN check_in BOOLEAN;\n"
  },
  {
    "path": "app/src/main/assets/migrations/21.sql",
    "content": "ALTER TABLE ActiveBluetoothDevice ADD COLUMN connected BOOLEAN;\n"
  },
  {
    "path": "app/src/main/assets/migrations/23.sql",
    "content": "ALTER TABLE BgReadings ADD COLUMN raw_calculated REAL;\n"
  },
  {
    "path": "app/src/main/assets/migrations/24.sql",
    "content": "ALTER TABLE BgReadings ADD COLUMN hide_slope BOOLEAN;\n"
  },
  {
    "path": "app/src/main/assets/migrations/25.sql",
    "content": "ALTER TABLE BgReadings ADD COLUMN noise TEXT;\n"
  },
  {
    "path": "app/src/main/assets/migrations/26.sql",
    "content": "ALTER TABLE BgReadings ADD COLUMN filtered_data REAL DEFAULT 0;\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/AddCalibration.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\n\npublic class AddCalibration extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    Button button;\n    private String menu_name = \"Add Calibration\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            Intent intent = new Intent(this, Home.class);\n            startActivity(intent);\n            finish();\n        }\n        setContentView(R.layout.activity_add_calibration);\n        addListenerOnButton();\n    }\n\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button) findViewById(R.id.save_calibration_button);\n\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n\n                if (Sensor.isActive()) {\n                    EditText value = (EditText) findViewById(R.id.bg_value);\n                    String string_value = value.getText().toString();\n                    if (!TextUtils.isEmpty(string_value)){\n                        double calValue = Double.parseDouble(string_value);\n\n\n                        Calibration calibration = Calibration.create(calValue, getApplicationContext());\n\n                        Intent tableIntent = new Intent(v.getContext(), Home.class);\n                        startActivity(tableIntent);\n                        finish();\n                    } else {\n                        value.setError(\"Calibration Can Not be blank\");\n                    }\n                } else {\n                    Log.w(\"CALERROR\", \"ERROR\");\n                }\n            }\n        });\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/AutoStart.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\n/**\n * Created by stephenblack on 11/3/14.\n */\npublic class AutoStart extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        Log.w(\"DexDrip\", \"Service auto starter, starting!\");\n        CollectionServiceStarter.newStart(context);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/BluetoothScan.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.annotation.TargetApi;\nimport android.app.ListActivity;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.widget.DrawerLayout;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Services.DexCollectionService;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\nimport java.util.ArrayList;\n\n@TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)\npublic class BluetoothScan extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Scan for BT\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    private final static String TAG = BluetoothScan.class.getSimpleName();\n    private static final long SCAN_PERIOD = 10000;\n    private boolean is_scanning;\n    private boolean has_bluetooth;\n\n    private Handler mHandler;\n    private LeDeviceListAdapter mLeDeviceListAdapter;\n\n    private ArrayList<BluetoothDevice> found_devices;\n    private BluetoothAdapter bluetooth_adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_bluetooth_scan);\n\n        ListView lv = (ListView)findViewById(android.R.id.list);\n\n        final BluetoothManager bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n\n        bluetooth_adapter = bluetooth_manager.getAdapter();\n        mHandler = new Handler();\n\n        if (bluetooth_adapter == null) {\n            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_LONG).show();\n            has_bluetooth = false;\n            finish();\n            return;\n        } else {\n            has_bluetooth = true;\n        }\n        if(bluetooth_manager == null) {\n            Toast.makeText(this, \"This device does not seem to support bluetooth\", Toast.LENGTH_LONG).show();\n        } else {\n            if(!bluetooth_manager.getAdapter().isEnabled()) {\n                Toast.makeText(this, \"Bluetooth is turned off on this device currently\", Toast.LENGTH_LONG).show();\n            } else {\n                if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){\n                    Toast.makeText(this, \"The android version of this device is not compatible with Bluetooth Low Energy\", Toast.LENGTH_LONG).show();\n                }\n            }\n        }\n        mLeDeviceListAdapter = new LeDeviceListAdapter();\n        setListAdapter(mLeDeviceListAdapter);\n\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        scanLeDevice(false);\n        mLeDeviceListAdapter.clear();\n    }\n\n    @Override\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_bluetooth_scan, menu);\n        if (!is_scanning) {\n            menu.findItem(R.id.menu_stop).setVisible(false);\n            menu.findItem(R.id.menu_scan).setVisible(true);\n        } else {\n            menu.findItem(R.id.menu_stop).setVisible(true);\n            menu.findItem(R.id.menu_scan).setVisible(false);\n        }\n        return true;\n    }\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_scan:\n                scanLeDevice(true);\n                BluetoothManager bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n                Toast.makeText(this, \"Scanning\", Toast.LENGTH_LONG).show();\n                if(bluetooth_manager == null) {\n                    Toast.makeText(this, \"This device does not seem to support bluetooth\", Toast.LENGTH_LONG).show();\n                } else {\n                    if(!bluetooth_manager.getAdapter().isEnabled()) {\n                        Toast.makeText(this, \"Bluetooth is turned off on this device currently\", Toast.LENGTH_LONG).show();\n                    } else {\n                        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){\n                            Toast.makeText(this, \"The android version of this device is not compatible with Bluetooth Low Energy\", Toast.LENGTH_LONG).show();\n                        }\n                    }\n                }\n                return true;\n//            case R.id.menu_stop:\n//                Intent tableIntent = new Intent(this, RawDataTable.class);\n//                startActivity(tableIntent);\n//                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    private void scanLeDevice(final boolean enable) {\n        if (enable) {\n            // Stops scanning after a pre-defined scan period.\n            mHandler.postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    is_scanning = false;\n                    bluetooth_adapter.stopLeScan(mLeScanCallback);\n                    invalidateOptionsMenu();\n                }\n            }, SCAN_PERIOD);\n\n            is_scanning = true;\n            bluetooth_adapter.startLeScan(mLeScanCallback);\n        } else {\n            is_scanning = false;\n            bluetooth_adapter.stopLeScan(mLeScanCallback);\n        }\n        invalidateOptionsMenu();\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        Log.d(TAG, \"Item Clicked\");\n        final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);\n        if (device == null) return;\n        Toast.makeText(this, R.string.connecting_to_device, Toast.LENGTH_LONG).show();\n\n        ActiveBluetoothDevice btDevice = new Select().from(ActiveBluetoothDevice.class)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n        if (btDevice == null) {\n            ActiveBluetoothDevice newBtDevice = new ActiveBluetoothDevice();\n            newBtDevice.name = device.getName();\n            newBtDevice.address = device.getAddress();\n            newBtDevice.save();\n        } else {\n            btDevice.name = device.getName();\n            btDevice.address = device.getAddress();\n            btDevice.save();\n        }\n\n        if (is_scanning) {\n            bluetooth_adapter.stopLeScan(mLeScanCallback);\n            is_scanning = false;\n        }\n        Intent intent = new Intent(this, Home.class);\n        CollectionServiceStarter.newStart(getApplicationContext());\n        startActivity(intent);\n        finish();\n    }\n\n    private class LeDeviceListAdapter extends BaseAdapter {\n        private ArrayList<BluetoothDevice> mLeDevices;\n        private LayoutInflater mInflator;\n\n        public LeDeviceListAdapter() {\n            super();\n            mLeDevices = new ArrayList<BluetoothDevice>();\n            mInflator = BluetoothScan.this.getLayoutInflater();\n        }\n\n        public void addDevice(BluetoothDevice device) {\n            if(!mLeDevices.contains(device)) {\n                mLeDevices.add(device);\n            }\n        }\n\n        public BluetoothDevice getDevice(int position) {\n            return mLeDevices.get(position);\n        }\n\n        public void clear() {\n            mLeDevices.clear();\n        }\n\n        @Override\n        public int getCount() {\n            return mLeDevices.size();\n        }\n\n        @Override\n        public Object getItem(int i) {\n            return mLeDevices.get(i);\n        }\n\n        @Override\n        public long getItemId(int i) {\n            return i;\n        }\n\n        @Override\n        public View getView(int i, View view, ViewGroup viewGroup) {\n            ViewHolder viewHolder;\n            // General ListView optimization code.\n            if (view == null) {\n                view = mInflator.inflate(R.layout.listitem_device, null);\n                viewHolder = new ViewHolder();\n                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);\n                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);\n                view.setTag(viewHolder);\n            } else {\n                viewHolder = (ViewHolder) view.getTag();\n            }\n\n            BluetoothDevice device = mLeDevices.get(i);\n            final String deviceName = device.getName();\n            if (deviceName != null && deviceName.length() > 0)\n                viewHolder.deviceName.setText(deviceName);\n            else\n                viewHolder.deviceName.setText(R.string.unknown_device);\n            viewHolder.deviceAddress.setText(device.getAddress());\n\n            return view;\n        }\n    }\n\n\n\n    private BluetoothAdapter.LeScanCallback mLeScanCallback =\n            new BluetoothAdapter.LeScanCallback() {\n\n                @Override\n                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {\n                    runOnUiThread(new Runnable() {\n                        @Override\n                        public void run() {\n                            mLeDeviceListAdapter.addDevice(device);\n                            mLeDeviceListAdapter.notifyDataSetChanged();\n                        }\n                    });\n                }\n            };\n\n    static class ViewHolder {\n        TextView deviceName;\n        TextView deviceAddress;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/CalibrationCheckInActivity.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.Home;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.SyncingService;\nimport com.eveningoutpost.dexdrip.R;\nimport com.eveningoutpost.dexdrip.Sensor;\n\npublic class CalibrationCheckInActivity extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Check in calibration\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    Button button;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_calibration_check_in);\n        addListenerOnButton();\n    }\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button) findViewById(R.id.check_in_calibrations);\n\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n\n                if (Sensor.isActive()) {\n                    SyncingService.startActionCalibrationCheckin(getApplicationContext());\n                    Toast.makeText(getApplicationContext(), \"Checked in all calibrations\", Toast.LENGTH_LONG).show();\n                    Intent tableIntent = new Intent(v.getContext(), Home.class);\n                    startActivity(tableIntent);\n                    finish();\n                } else {\n                    Log.w(\"CANNOT CALIBRATE WITHOUT CURRENT SENSOR\", \"ERROR\");\n                }\n            }\n        });\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/CalibrationGraph.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport com.eveningoutpost.dexdrip.Models.Calibration;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lecho.lib.hellocharts.model.Axis;\nimport lecho.lib.hellocharts.model.Line;\nimport lecho.lib.hellocharts.model.LineChartData;\nimport lecho.lib.hellocharts.model.PointValue;\nimport lecho.lib.hellocharts.util.Utils;\nimport lecho.lib.hellocharts.view.LineChartView;\n\n\npublic class CalibrationGraph extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Calibration Graph\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    private LineChartView chart;\n    private LineChartData data;\n    public double  start_x = 50;\n    public double  end_x = 300;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_calibration_graph);\n    }\n    @Override\n    protected void onResume(){\n        super.onResume();\n\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n\n        setupCharts();\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n\n    public void setupCharts() {\n        chart = (LineChartView) findViewById(R.id.chart);\n        List<Calibration> calibrations = Calibration.allForSensor();\n        List<PointValue> values = new ArrayList<PointValue>();\n        for (Calibration calibration : calibrations) {\n            values.add(new PointValue((float)calibration.estimate_raw_at_time_of_calibration, (float)calibration.bg));\n        }\n\n        Line line = new Line(values);\n        line.setColor(Utils.COLOR_BLUE);\n        line.setHasLines(false);\n        line.setPointRadius(2);\n        line.setHasPoints(true);\n\n        Calibration calibration = Calibration.last();\n        List<PointValue> lineValues = new ArrayList<PointValue>();\n        if(calibration != null) {\n            lineValues.add(new PointValue((float) start_x, (float) (start_x * calibration.slope + calibration.intercept)));\n            lineValues.add(new PointValue((float) end_x, (float) (end_x * calibration.slope + calibration.intercept)));\n        }\n        Line calibrationLine = new Line(lineValues);\n        calibrationLine.setColor(Utils.COLOR_RED);\n        calibrationLine.setHasLines(true);\n        calibrationLine.setHasPoints(false);\n        Axis axisX = new Axis();\n        Axis axisY = new Axis().setHasLines(true);\n        axisX.setName(\"Raw Value\");\n        axisY.setName(\"BG\");\n\n         List<Line> lines = new ArrayList<Line>();\n        lines.add(line);\n        lines.add(calibrationLine);\n\n        data = new LineChartData(lines);\n        data.setAxisXBottom(axisX);\n        data.setAxisYLeft(axisY);\n        chart.setLineChartData(data);\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/CalibrationOverride.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\n\npublic class CalibrationOverride extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n        Button button;\n    private String menu_name = \"Override Calibration\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            Intent intent = new Intent(this, Home.class);\n            startActivity(intent);\n            finish();\n        }\n        setContentView(R.layout.activity_calibration_override);\n        addListenerOnButton();\n    }\n\n    @Override\n    protected void onResume(){\n                super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n            }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void addListenerOnButton() {\n            button = (Button) findViewById(R.id.save_calibration_button);\n\n            button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                if (Sensor.isActive()) {\n                    EditText value = (EditText) findViewById(R.id.bg_value);\n                    String string_value = value.getText().toString();\n                    if (!TextUtils.isEmpty(string_value)){\n                        double calValue = Double.parseDouble(string_value);\n\n                        Calibration last_calibration = Calibration.last();\n                        last_calibration.sensor_confidence = 0;\n                        last_calibration.slope_confidence = 0;\n                        last_calibration.save();\n                        Calibration.create(calValue, getApplicationContext());\n\n                         Intent tableIntent = new Intent(v.getContext(), Home.class);\n                         startActivity(tableIntent);\n                         finish();\n                    } else {\n                        value.setError(\"Calibration Can Not be blank\");\n                    }\n                } else {\n                    Log.w(\"CANNOT CALIBRATE WITHOUT CURRENT SENSOR\", \"ERROR\");\n                }\n            }\n        });\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/DoubleCalibrationActivity.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\n\npublic class DoubleCalibrationActivity  extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    Button button;\n    private String menu_name = \"Add Double Calibration\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            Intent intent = new Intent(this, Home.class);\n            startActivity(intent);\n            finish();\n        }\n        setContentView(R.layout.activity_double_calibration);\n        addListenerOnButton();\n    }\n\n    @Override\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button) findViewById(R.id.save_calibration_button);\n\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n\n                if (Sensor.isActive()) {\n                    EditText value_1 = (EditText) findViewById(R.id.bg_value_1);\n                    EditText value_2 = (EditText) findViewById(R.id.bg_value_2);\n                    String string_value_1 = value_1.getText().toString();\n                    String string_value_2 = value_2.getText().toString();\n\n                    if (!TextUtils.isEmpty(string_value_1)){\n                        if(!TextUtils.isEmpty(string_value_2)) {\n                            double calValue_1 = Double.parseDouble(string_value_1);\n                            double calValue_2 = Double.parseDouble(string_value_2);\n                            Calibration.initialCalibration(calValue_1, calValue_2, getApplicationContext());\n                            Intent tableIntent = new Intent(v.getContext(), Home.class);\n                            startActivity(tableIntent);\n                            finish();\n                        } else {\n                            value_2.setError(\"Calibration Can Not be blank\");\n                        }\n                    } else {\n                        value_1.setError(\"Calibration Can Not be blank\");\n                    }\n                } else {\n                    Log.w(\"DoubleCalibration\", \"ERROR\");\n                }\n            }\n        });\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/FakeNumbers.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport java.util.Date;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.DatePicker;\nimport android.widget.EditText;\nimport android.widget.TimePicker;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\n\n\npublic class FakeNumbers extends Activity {\n    public Button button;\n    public DatePicker dp;\n    public TimePicker tp;\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_fake_numbers);\n\n        button = (Button)findViewById(R.id.log);\n        addListenerOnButton();\n\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button)findViewById(R.id.log);\n\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                EditText value = (EditText) findViewById(R.id.bg_value);\n                int intValue = Integer.parseInt(value.getText().toString());\n\n                BgReading bgReading = BgReading.create(intValue * 1000, getApplicationContext(), new Date().getTime());\n                Intent intent = new Intent(getApplicationContext(), Home.class);\n                startActivity(intent);\n                finish();\n            }\n\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Home.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.app.NotificationManager;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Services.WixelReader;\nimport com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.Intents;\nimport com.eveningoutpost.dexdrip.UtilityModels.Notifications;\nimport com.eveningoutpost.dexdrip.utils.DatabaseUtil;\nimport com.eveningoutpost.dexdrip.utils.ShareNotification;\n\n\nimport java.io.File;\nimport java.text.DecimalFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport lecho.lib.hellocharts.ViewportChangeListener;\nimport lecho.lib.hellocharts.gesture.ZoomType;\nimport lecho.lib.hellocharts.model.Viewport;\nimport lecho.lib.hellocharts.view.LineChartView;\nimport lecho.lib.hellocharts.view.PreviewLineChartView;\n\n\npublic class Home extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"xDrip\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    private LineChartView chart;\n    private PreviewLineChartView previewChart;\n    SharedPreferences prefs;\n    Viewport tempViewport = new Viewport();\n    Viewport holdViewport = new Viewport();\n    public float left;\n    public float right;\n    public float top;\n    public float bottom;\n    public boolean updateStuff;\n    public boolean updatingPreviewViewport = false;\n    public boolean updatingChartViewport = false;\n    boolean isBTWixel;\n    boolean isBTShare;\n    boolean isWifiWixel;\n\n    public BgGraphBuilder bgGraphBuilder;\n    BroadcastReceiver _broadcastReceiver;\n    BroadcastReceiver newDataReceiver;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(getApplicationContext());\n        collectionServiceStarter.start(getApplicationContext());\n        PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, false);\n        PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, false);\n        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        checkEula();\n        setContentView(R.layout.activity_home);\n    }\n\n    public void checkEula() {\n        boolean IUnderstand = prefs.getBoolean(\"I_understand\", false);\n        if (!IUnderstand) {\n            Intent intent = new Intent(getApplicationContext(), LicenseAgreementActivity.class);\n            startActivity(intent);\n            finish();\n        }\n    }\n\n    @Override\n    protected void onResume(){\n        super.onResume();\n        checkEula();\n        _broadcastReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context ctx, Intent intent) {\n                if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {\n                    updateCurrentBgInfo();\n                }\n            }\n        };\n        newDataReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context ctx, Intent intent) {\n                holdViewport.set(0, 0, 0, 0);\n                setupCharts();\n                updateCurrentBgInfo();\n            }\n        };\n        registerReceiver(_broadcastReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));\n        registerReceiver(newDataReceiver, new IntentFilter(Intents.ACTION_NEW_BG_ESTIMATE_NO_DATA));\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n        holdViewport.set(0, 0, 0, 0);\n        setupCharts();\n        updateCurrentBgInfo();\n    }\n\n    public void setupCharts() {\n        bgGraphBuilder = new BgGraphBuilder(this);\n        updateStuff = false;\n        chart = (LineChartView) findViewById(R.id.chart);\n        chart.setZoomType(ZoomType.HORIZONTAL);\n\n        previewChart = (PreviewLineChartView) findViewById(R.id.chart_preview);\n        previewChart.setZoomType(ZoomType.HORIZONTAL);\n\n        chart.setLineChartData(bgGraphBuilder.lineData());\n        previewChart.setLineChartData(bgGraphBuilder.previewLineData());\n        updateStuff = true;\n\n        previewChart.setViewportCalculationEnabled(true);\n        chart.setViewportCalculationEnabled(true);\n        previewChart.setViewportChangeListener(new ViewportListener());\n        chart.setViewportChangeListener(new ChartViewPortListener());\n        setViewport();\n    }\n\n    private class ChartViewPortListener implements ViewportChangeListener {\n        @Override\n        public void onViewportChanged(Viewport newViewport) {\n            if (!updatingPreviewViewport) {\n                updatingChartViewport = true;\n                previewChart.setZoomType(ZoomType.HORIZONTAL);\n                previewChart.setCurrentViewport(newViewport, false);\n                updatingChartViewport = false;\n            }\n        }\n    }\n\n    private class ViewportListener implements ViewportChangeListener {\n        @Override\n        public void onViewportChanged(Viewport newViewport) {\n            if (!updatingChartViewport) {\n                updatingPreviewViewport = true;\n                chart.setZoomType(ZoomType.HORIZONTAL);\n                chart.setCurrentViewport(newViewport, false);\n                tempViewport = newViewport;\n                updatingPreviewViewport = false;\n            }\n            if (updateStuff == true) {\n                holdViewport.set(newViewport.left, newViewport.top, newViewport.right, newViewport.bottom);\n            }\n        }\n\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void setViewport() {\n        if (tempViewport.left == 0.0 || holdViewport.left == 0.0 || holdViewport.right  >= (new Date().getTime())) {\n            previewChart.setCurrentViewport(bgGraphBuilder.advanceViewport(chart, previewChart), false);\n        } else {\n            previewChart.setCurrentViewport(holdViewport, false);\n        }\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        if (_broadcastReceiver != null) {\n            unregisterReceiver(_broadcastReceiver);\n        }\n        if(newDataReceiver != null) {\n            unregisterReceiver(newDataReceiver);\n        }\n    }\n\n    public void updateCurrentBgInfo() {\n        final TextView currentBgValueText = (TextView) findViewById(R.id.currentBgValueRealTime);\n        final TextView notificationText = (TextView)findViewById(R.id.notices);\n        notificationText.setText(\"\");\n        isBTWixel = CollectionServiceStarter.isBTWixel(getApplicationContext());\n        isBTShare = CollectionServiceStarter.isBTShare(getApplicationContext());\n        isWifiWixel = CollectionServiceStarter.isWifiWixel(getApplicationContext());\n        if(isBTShare) {\n            if((android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)) {\n                notificationText.setText(\"Unfortunately your android version does not support Bluetooth Low Energy\");\n            } else {\n                String receiverSn = prefs.getString(\"share_key\", \"SM00000000\").toUpperCase();\n                if (receiverSn.compareTo(\"SM00000000\") == 0 || receiverSn.length() == 0) {\n                    notificationText.setText(\"Please set your Dex Receiver Serial Number in App Settings\");\n                } else {\n                    if (receiverSn.length() < 10) {\n                        notificationText.setText(\"Double Check Dex Receiver Serial Number, should be 10 characters, don't forget the letters\");\n                    } else {\n                        if (ActiveBluetoothDevice.first() == null) {\n                            notificationText.setText(\"Now pair with your Dexcom Share\");\n                        } else {\n                            if (!Sensor.isActive()) {\n                                notificationText.setText(\"Now choose start your sensor in your settings\");\n                            } else {\n                                displayCurrentInfo();\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        if(isBTWixel) {\n            if ((android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)) {\n                notificationText.setText(\"Unfortunately your android version does not support Bluetooth Low Energy\");\n            } else {\n                if (ActiveBluetoothDevice.first() == null) {\n                    notificationText.setText(\"First pair with your BT device!\");\n                } else {\n                    if (Sensor.isActive() && (Sensor.currentSensor().started_at + (60000 * 60 * 2)) < new Date().getTime()) {\n                        if (BgReading.latest(2).size() > 1) {\n                            List<Calibration> calibrations = Calibration.latest(2);\n                            if (calibrations.size() > 1) {\n                                if (calibrations.get(0).possible_bad != null && calibrations.get(0).possible_bad == true && calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad != true) {\n                                    notificationText.setText(\"Possible bad calibration slope, please have a glass of water, wash hands, then recalibrate in a few!\");\n                                }\n                                displayCurrentInfo();\n                            } else {\n                                notificationText.setText(\"Please enter two calibrations to get started!\");\n                            }\n                        } else {\n                            if(BgReading.latestUnCalculated(2).size() < 2) {\n                                notificationText.setText(\"Please wait, need 2 readings from transmitter first.\");\n                            } else {\n                                List<Calibration> calibrations = Calibration.latest(2);\n                                if (calibrations.size() < 2) {\n                                    notificationText.setText(\"Please enter two calibrations to get started!\");\n                                }\n                            }\n                        }\n                    } else if (Sensor.isActive() && ((Sensor.currentSensor().started_at + (60000 * 60 * 2))) >= new Date().getTime()) {\n                        double waitTime = ((Sensor.currentSensor().started_at + (60000 * 60 * 2)) - (new Date().getTime())) / (60000);\n                        notificationText.setText(\"Please wait while sensor warms up! (\" + String.format(\"%.2f\", waitTime) + \" minutes)\");\n                    } else {\n                        notificationText.setText(\"Now start your sensor\");\n                    }\n                }\n            }\n        }\n        if(isWifiWixel) {\n            if (!WixelReader.IsConfigured(getApplicationContext())) {\n                notificationText.setText(\"First configure your wifi wixel reader ip addresses\");\n            } else {\n                if (Sensor.isActive() && (Sensor.currentSensor().started_at + (60000 * 60 * 2)) < new Date().getTime()) {\n                    if (BgReading.latest(2).size() > 1) {\n                        List<Calibration> calibrations = Calibration.latest(2);\n                        if (calibrations.size() > 1) {\n                            if (calibrations.get(0).possible_bad != null && calibrations.get(0).possible_bad == true && calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad != true) {\n                                notificationText.setText(\"Possible bad calibration slope, please have a glass of water, wash hands, then recalibrate in a few!\");\n                            }\n                            displayCurrentInfo();\n                        } else {\n                            notificationText.setText(\"Please enter two calibrations to get started!\");\n                        }\n                    } else {\n                        notificationText.setText(\"Please wait, need 2 readings from transmitter first.\");\n                    }\n                } else if (Sensor.isActive() && ((Sensor.currentSensor().started_at + (60000 * 60 * 2))) >= new Date().getTime()) {\n                    double waitTime = ((Sensor.currentSensor().started_at + (60000 * 60 * 2)) - (new Date().getTime())) / (60000);\n                    notificationText.setText(\"Please wait while sensor warms up! (\" + String.format(\"%.2f\", waitTime) + \" minutes)\");\n                } else {\n                    notificationText.setText(\"Now start your sensor\");\n                }\n            }\n        }\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n\n    public void displayCurrentInfo() {\n        DecimalFormat df = new DecimalFormat(\"#\");\n        df.setMaximumFractionDigits(0);\n\n        final TextView currentBgValueText = (TextView)findViewById(R.id.currentBgValueRealTime);\n        final TextView notificationText = (TextView)findViewById(R.id.notices);\n        if ((currentBgValueText.getPaintFlags() & Paint.STRIKE_THRU_TEXT_FLAG) > 0) {\n            currentBgValueText.setPaintFlags(currentBgValueText.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));\n        }\n        BgReading lastBgreading = BgReading.lastNoSenssor();\n        boolean predictive = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean(\"predictive_bg\", false);\n        if(isBTShare) { predictive = false; }\n        if (lastBgreading != null) {\n            double estimate = 0;\n            if ((new Date().getTime()) - (60000 * 11) - lastBgreading.timestamp > 0) {\n                notificationText.setText(\"Signal Missed\");\n                if(!predictive){\n                    estimate=lastBgreading.calculated_value;\n                } else {\n                    estimate = BgReading.estimated_bg(lastBgreading.timestamp + (6000 * 7));\n                }\n                currentBgValueText.setText(bgGraphBuilder.unitized_string(estimate));\n                currentBgValueText.setPaintFlags(currentBgValueText.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);\n            } else {\n                if(!predictive){\n                    estimate=lastBgreading.calculated_value;\n                    String stringEstimate = bgGraphBuilder.unitized_string(estimate);\n                    String slope_arrow = BgReading.slopeArrow((lastBgreading.calculated_value_slope * 60000));\n                    if(lastBgreading.hide_slope) {\n                        slope_arrow = \"\";\n                    }\n                    currentBgValueText.setText( stringEstimate + \" \" + slope_arrow);\n                } else {\n                    estimate = BgReading.activePrediction();\n                    String stringEstimate = bgGraphBuilder.unitized_string(estimate);\n                    currentBgValueText.setText( stringEstimate + \" \" + BgReading.slopeArrow());\n                }\n            }\n            if(bgGraphBuilder.unitized(estimate) <= bgGraphBuilder.lowMark) {\n                currentBgValueText.setTextColor(Color.parseColor(\"#C30909\"));\n            } else if(bgGraphBuilder.unitized(estimate) >= bgGraphBuilder.highMark) {\n                currentBgValueText.setTextColor(Color.parseColor(\"#FFBB33\"));\n            } else {\n                currentBgValueText.setTextColor(Color.WHITE);\n            }\n        }\n    setupCharts();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_home, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (item.getItemId() == R.id.action_export_database) {\n            new AsyncTask<Void, Void, String>() {\n                @Override\n                protected String doInBackground(Void... params) {\n                    return DatabaseUtil.saveSql(getBaseContext());\n                }\n\n                @Override\n                protected void onPostExecute(String filename) {\n                    super.onPostExecute(filename);\n\n                    final Context ctx = getApplicationContext();\n\n                    Toast.makeText(ctx, \"Export stored at \" + filename, Toast.LENGTH_SHORT).show();\n\n                    final NotificationCompat.Builder n = new NotificationCompat.Builder(ctx);\n                    n.setContentTitle(\"Export complete\");\n                    n.setContentText(\"Ready to be sent.\");\n                    n.setAutoCancel(true);\n                    n.setSmallIcon(R.drawable.ic_action_communication_invert_colors_on);\n                    ShareNotification.viewOrShare(\"application/octet-stream\", Uri.fromFile(new File(filename)), n, ctx);\n\n                    final NotificationManager manager = (NotificationManager) ctx.getSystemService(Service.NOTIFICATION_SERVICE);\n                    manager.notify(Notifications.exportCompleteNotificationId, n.build());\n                }\n            }.execute();\n\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/CRC16.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class CRC16 {\n    public static byte[] calculate(byte[] buff, int start, int end) {\n        int crcShort = 0;\n        for (int i = start; i < end; i++) {\n            crcShort = ((crcShort  >>> 8) | (crcShort  << 8) )& 0xffff;\n            crcShort ^= (buff[i] & 0xff);\n            crcShort ^= ((crcShort & 0xff) >> 4);\n            crcShort ^= (crcShort << 12) & 0xffff;\n            crcShort ^= ((crcShort & 0xFF) << 5) & 0xffff;\n        }\n        crcShort &= 0xffff;\n        return new byte[] {(byte) (crcShort & 0xff), (byte) ((crcShort >> 8) & 0xff)};\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/CRCFailRuntimeException.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class CRCFailRuntimeException extends RuntimeException {\n    public CRCFailRuntimeException(String message){\n        super(message);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/Constants.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class Constants {\n\n    public final static int NULL = 0;\n    public final static int ACK = 1;\n    public final static int NAK = 2;\n    public final static int INVALID_COMMAND = 3;\n    public final static int INVALID_PARAM = 4;\n    public final static int INCOMPLETE_PACKET_RECEIVED = 5;\n    public final static int RECEIVER_ERROR = 6;\n    public final static int INVALID_MODE = 7;\n    public final static int PING = 10;\n    public final static int READ_FIRMWARE_HEADER = 11;\n    public final static int READ_DATABASE_PARTITION_INFO = 15;\n    public final static int READ_DATABASE_PAGE_RANGE = 16;\n    public final static int READ_DATABASE_PAGES = 17;\n    public final static int READ_DATABASE_PAGE_HEADER = 18;\n    public final static int READ_TRANSMITTER_ID = 25;\n    public final static int WRITE_TRANSMITTER_ID = 26;\n    public final static int READ_LANGUAGE = 27;\n    public final static int WRITE_LANGUAGE = 28;\n    public final static int READ_DISPLAY_TIME_OFFSET = 29;\n    public final static int WRITE_DISPLAY_TIME_OFFSET = 30;\n    public final static int READ_RTC = 31;\n    public final static int RESET_RECEIVER = 32;\n    public final static int READ_BATTERY_LEVEL = 33;\n    public final static int READ_SYSTEM_TIME = 34;\n    public final static int READ_SYSTEM_TIME_OFFSET = 35;\n    public final static int WRITE_SYSTEM_TIME = 36;\n    public final static int READ_GLUCOSE_UNIT = 37;\n    public final static int WRITE_GLUCOSE_UNIT = 38;\n    public final static int READ_BLINDED_MODE = 39;\n    public final static int WRITE_BLINDED_MODE = 40;\n    public final static int READ_CLOCK_MODE = 41;\n    public final static int WRITE_CLOCK_MODE = 42;\n    public final static int READ_DEVICE_MODE = 43;\n    public final static int ERASE_DATABASE = 45;\n    public final static int SHUTDOWN_RECEIVER = 46;\n    public final static int WRITE_PC_PARAMETERS = 47;\n    public final static int READ_BATTERY_STATE = 48;\n    public final static int READ_HARDWARE_BOARD_ID = 49;\n    public final static int READ_FIRMWARE_SETTINGS = 54;\n    public final static int READ_ENABLE_SETUP_WIZARD_FLAG = 55;\n    public final static int READ_SETUP_WIZARD_STATE = 57;\n    public final static int MAX_COMMAND = 59;\n    public final static int MAX_POSSIBLE_COMMAND = 255;\n    public final static int EGV_VALUE_MASK = 1023;\n    public final static int EGV_DISPLAY_ONLY_MASK = 32768;\n    public final static int EGV_TREND_ARROW_MASK = 15;\n    public final static int EGV_NOISE_MASK = 112;\n    public final static float MG_DL_TO_MMOL_L = 0.05556f;\n    public final static int CRC_LEN = 2;\n\n    public enum BATTERY_STATES {\n        NONE,\n        CHARGING,\n        NOT_CHARGING,\n        NTC_FAULT,\n        BAD_BATTERY\n    }\n\n    public enum RECORD_TYPES {\n        MANUFACTURING_DATA,\n        FIRMWARE_PARAMETER_DATA,\n        PC_SOFTWARE_PARAMETER,\n        SENSOR_DATA,\n        EGV_DATA,\n        CAL_SET,\n        DEVIATION,\n        INSERTION_TIME,\n        RECEIVER_LOG_DATA,\n        RECEIVER_ERROR_DATA,\n        METER_DATA,\n        USER_EVENT_DATA,\n        USER_SETTING_DATA,\n        MAX_VALUE\n    }\n\n    public enum TREND_ARROW_VALUES {\n        NONE(0),\n        DOUBLE_UP(1,\"\\u21C8\", \"DoubleUp\"),\n        SINGLE_UP(2,\"\\u2191\", \"SingleUp\"),\n        UP_45(3,\"\\u2197\", \"FortyFiveUp\"),\n        FLAT(4,\"\\u2192\", \"Flat\"),\n        DOWN_45(5,\"\\u2198\", \"FortyFiveDown\"),\n        SINGLE_DOWN(6,\"\\u2193\", \"SingleDown\"),\n        DOUBLE_DOWN(7,\"\\u21CA\", \"DoubleDown\"),\n        NOT_COMPUTABLE(8, \"\", \"NOT_COMPUTABLE\"),\n        OUT_OF_RANGE(9, \"\", \"OUT_OF_RANGE\");\n\n        private String arrowSymbol;\n        private String trendName;\n        private int myID;\n\n        TREND_ARROW_VALUES(int id, String a, String t) {\n            myID=id;\n            arrowSymbol = a;\n            trendName = t;\n        }\n\n        TREND_ARROW_VALUES(int id) {\n            this(id,null, null);\n        }\n\n        public String Symbol() {\n            if (arrowSymbol == null) {\n                return \"\\u2194\";\n            } else {\n                return arrowSymbol;\n            }\n        }\n\n        public String friendlyTrendName() {\n            if (trendName == null) {\n                return this.name().replace(\"_\", \" \");\n            } else {\n                return this.trendName;\n            }\n        }\n\n        public int getID(){\n            return myID;\n        }\n\n    }\n\n    public enum SPECIALBGVALUES_MGDL {\n        NONE(\"??0\", 0),\n        SENSORNOTACTIVE(\"?SN\", 1),\n        MINIMALLYEGVAB(\"??2\", 2),\n        NOANTENNA(\"?NA\", 3),\n        SENSOROUTOFCAL(\"?NC\", 5),\n        COUNTSAB(\"?CD\", 6),\n        ABSOLUTEAB(\"?AD\", 9),\n        POWERAB(\"???\", 10),\n        RFBADSTATUS(\"?RF\", 12);\n\n\n        private String name;\n        private int val;\n        private SPECIALBGVALUES_MGDL(String s, int i){\n            name=s;\n            val=i;\n        }\n\n        public int getValue(){\n            return val;\n        }\n\n        public String toString(){\n            return name;\n        }\n\n        public static SPECIALBGVALUES_MGDL getEGVSpecialValue(int val){\n            for (SPECIALBGVALUES_MGDL e: values()){\n                if (e.getValue()==val)\n                    return e;\n            }\n            return null;\n        }\n\n        public static boolean isSpecialValue(int val){\n            for (SPECIALBGVALUES_MGDL e: values()){\n                if (e.getValue()==val)\n                    return true;\n            }\n            return false;\n        }\n\n    }\n\n    public enum InsertionState {\n        NONE,\n        REMOVED,\n        EXPIRED,\n        RESIDUAL_DEVIATION,\n        COUNTS_DEVIATION,\n        SECOND_SESSION,\n        OFF_TIME_LOSS,\n        STARTED,\n        BAD_TRANSMITTER,\n        MANUFACTURING_MODE,\n        MAX_VALUE\n    }\n\n    public enum NOISE {\n        NOISE_NONE(0),\n        CLEAN(1),\n        LIGHT(2),\n        MEDIUM(3),\n        HEAVY(4),\n        NOT_COMPUTED(5),\n        MAX(6);\n\n        private final int value;\n\n        private NOISE(int value) {\n            this.value = value;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/PacketBuilder.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport android.util.Log;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class PacketBuilder {\n    public static final int MAX_PAYLOAD = 1584;\n    public static final int MIN_LEN = 6;\n    public static final int MAX_LEN = MAX_PAYLOAD + MIN_LEN;\n    public static final byte SOF = 0x01;\n    public static final int OFFSET_SOF = 0;\n    public static final int OFFSET_LENGTH = 1;\n    public static final int OFFSET_NULL = 2;\n    public static final byte NULL = 0x00;\n    public static final int OFFSET_CMD = 3;\n    public static final int OFFSET_PAYLOAD = 4;\n    public static final int CRC_LEN = 2;\n    public static final int HEADER_LEN = 4;\n    public ArrayList<Byte> packet;\n    public int command;\n    public ArrayList<Byte> payload;\n\n    public PacketBuilder(int command) {\n        this.command = command;\n    }\n\n    public PacketBuilder(int command, ArrayList<Byte> payload) {\n        this.command = command;\n        this.payload = payload;\n    }\n\n    public byte[] compose() {\n        packet = new ArrayList<Byte>();\n        packet.add(OFFSET_SOF, SOF);\n        packet.add(OFFSET_LENGTH, getLength());\n        packet.add(OFFSET_NULL, NULL);\n        packet.add(OFFSET_CMD, (byte) command);\n        if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }\n        byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());\n        this.packet.add(crc16[0]);\n        this.packet.add(crc16[1]);\n        Log.d(\"ShareTest\", \"About to start adding to Byte, size: \" + this.packet.size());\n        return this.toBytes();\n    }\n\n    public List<byte[]> composeList() {\n        packet = new ArrayList<Byte>();\n        packet.add(OFFSET_SOF, SOF);\n        packet.add(OFFSET_LENGTH, getLength());\n        packet.add(OFFSET_NULL, NULL);\n        packet.add(OFFSET_CMD, (byte) command);\n        if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }\n        byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());\n        this.packet.add(crc16[0]);\n        this.packet.add(crc16[1]);\n        Log.d(\"ShareTest\", \"About to start adding to ByteList, size: \" + this.packet.size());\n        return this.toBytesList();\n    }\n\n    private byte getLength() {\n        int packetSize = payload == null ? MIN_LEN : payload.size() + CRC_LEN + HEADER_LEN;\n\n        if (packetSize > MAX_LEN) {\n            throw new IndexOutOfBoundsException(packetSize + \" bytes, but packet must between \"\n                    + MIN_LEN + \" and \" + MAX_LEN + \" bytes.\");\n        }\n\n        return (byte) packetSize;\n    }\n\n    public byte[] toBytes() {\n        byte[] b = new byte[this.packet.size()];\n        for (int i = 0; i < this.packet.size(); i++) {\n            b[i] = this.packet.get(i).byteValue();\n        }\n        return b;\n    }\n\n    public List<byte[]> toBytesList() {\n        List<byte[]> byteMessages = new ArrayList<byte[]>();\n        double totalPacketSize = packet.size();\n        int messages =(int) Math.ceil(totalPacketSize/18);\n        for(int m = 0; m < messages; m++) {\n            int thisPacketSize;\n            if (m == messages - 1) {\n                thisPacketSize = ((this.packet.size()+2) % 18);\n            } else {\n                thisPacketSize = (20);\n            }\n            int offset = m * 18;\n            Log.d(\"ShareTest\", \"This packet size: \" + thisPacketSize);\n            byte[] b = new byte[thisPacketSize];\n            b[0] = (byte) (m + 1);\n            b[1] = (byte) (messages);\n            for (int i = 2; i < thisPacketSize; i++) {\n                b[i] = packet.get(offset + i - 2).byteValue();\n            }\n            byteMessages.add(b);\n        }\n        return byteMessages;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadData.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbEndpoint;\nimport android.hardware.usb.UsbInterface;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.CdcAcmSerialDriver;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialPort;\n\nimport org.w3c.dom.Element;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\n\npublic class ReadData {\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\n    private static final String TAG = ReadData.class.getSimpleName();\n    private static final int IO_TIMEOUT = 3000;\n    private static final int MIN_LEN = 256;\n    private UsbSerialDriver mSerialDevice;\n    protected final Object mReadBufferLock = new Object();\n    private UsbDeviceConnection mConnection;\n    private UsbDevice mDevice;\n\n    public ReadData(){}\n    public ReadData(UsbSerialDriver device) {\n        mSerialDevice = device;\n    }\n    public ReadData(UsbSerialDriver device, UsbDeviceConnection connection, UsbDevice usbDevice) {\n        mSerialDevice = device;\n        mConnection = connection;\n        mDevice = usbDevice;\n        try {\n      mSerialDevice.getPorts().get(0).open(connection);\n        } catch(IOException e) {\n            Log.w(\"FAILED WHILE\", \"trying to open\");\n        }\n//        }\n    }\n\n    public EGVRecord[] getRecentEGVs() {\n        int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        return readDataBasePage(recordType, endPage);\n    }\n\n    public EGVRecord[] getRecentEGVsPages(int numOfRecentPages) {\n        if (numOfRecentPages < 1) {\n            throw new IllegalArgumentException(\"Number of pages must be greater than 1.\");\n        }\n        Log.d(TAG, \"Reading EGV page range...\");\n        int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        Log.d(TAG, \"Reading \" + numOfRecentPages + \" EGV page(s)...\");\n        numOfRecentPages = numOfRecentPages - 1;\n        EGVRecord[] allPages = new EGVRecord[0];\n        for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {\n            int nextPage = endPage - i;\n            Log.d(TAG, \"Reading #\" + i + \" EGV pages (page number \" + nextPage + \")\");\n            EGVRecord[] ithEGVRecordPage = readDataBasePage(recordType, nextPage);\n            EGVRecord[] result = Arrays.copyOf(allPages, allPages.length + ithEGVRecordPage.length);\n            System.arraycopy(ithEGVRecordPage, 0, result, allPages.length, ithEGVRecordPage.length);\n            allPages = result;\n        }\n        Log.d(TAG, \"Read complete of EGV pages.\");\n        return allPages;\n    }\n\n    public long getTimeSinceEGVRecord(EGVRecord egvRecord) {\n        return readSystemTime() - egvRecord.getSystemTimeSeconds();\n    }\n\n    public MeterRecord[] getRecentMeterRecords() {\n        Log.d(TAG, \"Reading Meter page...\");\n        int recordType = Constants.RECORD_TYPES.METER_DATA.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        return readDataBasePage(recordType, endPage);\n    }\n\n    public SensorRecord[] getRecentSensorRecords(int numOfRecentPages) {\n        if (numOfRecentPages < 1) {\n            throw new IllegalArgumentException(\"Number of pages must be greater than 1.\");\n        }\n        Log.d(TAG, \"Reading Sensor page range...\");\n        int recordType = Constants.RECORD_TYPES.SENSOR_DATA.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        Log.d(TAG, \"Reading \" + numOfRecentPages + \" Sensor page(s)...\");\n        numOfRecentPages = numOfRecentPages - 1;\n        SensorRecord[] allPages = new SensorRecord[0];\n        for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {\n            int nextPage = endPage - i;\n            Log.d(TAG, \"Reading #\" + i + \" Sensor pages (page number \" + nextPage + \")\");\n            SensorRecord[] ithSensorRecordPage = readDataBasePage(recordType, nextPage);\n            SensorRecord[] result = Arrays.copyOf(allPages, allPages.length + ithSensorRecordPage.length);\n            System.arraycopy(ithSensorRecordPage, 0, result, allPages.length, ithSensorRecordPage.length);\n            allPages = result;\n        }\n        Log.d(TAG, \"Read complete of Sensor pages.\");\n        return allPages;\n    }\n\n    public CalRecord[] getRecentCalRecords() {\n        Log.d(TAG, \"Reading Cal Records page range...\");\n        int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        Log.d(TAG, \"Reading Cal Records page...\");\n        return readDataBasePage(recordType, endPage);\n    }\n    public byte[] getRecentCalRecordsTest() {\n        Log.d(TAG, \"Reading Cal Records page range...\");\n        int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();\n        int endPage = readDataBasePageRange(recordType);\n        Log.d(TAG, \"Reading Cal Records page...\");\n        return readDataBasePageTest(recordType, endPage);\n    }\n\n    public boolean ping() {\n        writeCommand(Constants.PING);\n        return read(MIN_LEN).getCommand() == Constants.ACK;\n    }\n\n    public int readBatteryLevel() {\n        Log.d(TAG, \"Reading battery level...\");\n        writeCommand(Constants.READ_BATTERY_LEVEL);\n        byte[] readData = read(MIN_LEN).getData();\n        return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt();\n    }\n\n    public String readSerialNumber() {\n        int PAGE_OFFSET = 0;\n        byte[] readData = readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), PAGE_OFFSET);\n        Element md = ParsePage(readData, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());\n        return md.getAttribute(\"SerialNumber\");\n    }\n\n    public Date readDisplayTime() {\n        return Utils.receiverTimeToDate(readSystemTime() + readDisplayTimeOffset());\n    }\n\n    public long readSystemTime() {\n        Log.d(TAG, \"Reading system time...\");\n        writeCommand(Constants.READ_SYSTEM_TIME);\n        byte[] readData = read(MIN_LEN).getData();\n        return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;\n    }\n\n    public int readDisplayTimeOffset() {\n        Log.d(TAG, \"Reading display time offset...\");\n        writeCommand(Constants.READ_DISPLAY_TIME_OFFSET);\n        byte[] readData = read(MIN_LEN).getData();\n        return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;\n    }\n\n    private int readDataBasePageRange(int recordType) {\n        ArrayList<Byte> payload = new ArrayList<Byte>();\n        Log.d(TAG, \"adding Payload\");\n        payload.add((byte) recordType);\n        Log.d(TAG, \"Sending write command\");\n        writeCommand(Constants.READ_DATABASE_PAGE_RANGE, payload);\n        Log.d(TAG, \"About to call getdata\");\n        byte[] readData = read(MIN_LEN).getData();\n        Log.d(TAG, \"Going to return\");\n        return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt(4);\n    }\n\n    private <T> T readDataBasePage(int recordType, int page) {\n        byte numOfPages = 1;\n        if (page < 0){\n            throw new IllegalArgumentException(\"Invalid page requested:\" + page);\n        }\n        ArrayList<Byte> payload = new ArrayList<Byte>();\n        payload.add((byte) recordType);\n        byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();\n        payload.add(pageInt[3]);\n        payload.add(pageInt[2]);\n        payload.add(pageInt[1]);\n        payload.add(pageInt[0]);\n        payload.add(numOfPages);\n        writeCommand(Constants.READ_DATABASE_PAGES, payload);\n        byte[] readData = read(2122).getData();\n        return ParsePage(readData, recordType);\n    }\n    private byte[] readDataBasePageTest(int recordType, int page) {\n        byte numOfPages = 1;\n        if (page < 0){\n            throw new IllegalArgumentException(\"Invalid page requested:\" + page);\n        }\n        ArrayList<Byte> payload = new ArrayList<Byte>();\n        payload.add((byte) recordType);\n        byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();\n        payload.add(pageInt[3]);\n        payload.add(pageInt[2]);\n        payload.add(pageInt[1]);\n        payload.add(pageInt[0]);\n        payload.add(numOfPages);\n        return writeCommandTest(Constants.READ_DATABASE_PAGES, payload);\n    }\n\n    private void writeCommand(int command, ArrayList<Byte> payload) {\n        byte[] packet = new PacketBuilder(command, payload).compose();\n        if (mSerialDevice != null) {\n            try {\n//                UsbInterface mDataInterface = mDevice.getInterface(1);\n//                UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);\n//                mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);\n                  mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);\n            } catch (Exception e) {\n                Log.e(TAG, \"Unable to write to serial device.\", e);\n            }\n        }\n    }\n    private byte[] writeCommandTest(int command, ArrayList<Byte> payload) {\n        byte[] packet = new PacketBuilder(command, payload).compose();\n        return packet;\n    }\n    private void writeCommand(int command) {\n        byte[] packet = new PacketBuilder(command).compose();\n        if (mSerialDevice != null) {\n            try {\n//                UsbInterface mDataInterface = mDevice.getInterface(1);\n//                UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);\n//                mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);\n                mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);\n            } catch (Exception e) {\n                Log.e(TAG, \"Unable to write to serial device.\", e);\n            }\n        }\n    }\n\n    private ReadPacket read(int numOfBytes) {\n        byte[] readData = new byte[numOfBytes];\n        int len = 0;\n        try {\n//            UsbInterface mDataInterface = mDevice.getInterface(1);\n//            UsbEndpoint mReadEndpoint = mDataInterface.getEndpoint(1);\n//            byte[] mReadBuffer;\n//            mReadBuffer = new byte[16 * 1024];\n//\n//            int readAmt = Math.min(readData.length, mReadBuffer.length);\n//            synchronized (mReadBufferLock) {\n//\n//\n//                Log.d(TAG, \"Read about to call bulk transfer.\");\n//                if (len < 0) {\n//                    // This sucks: we get -1 on timeout, not 0 as preferred.\n//                    // We *should* use UsbRequest, except it has a bug/api oversight\n//                    // where there is no way to determine the number of bytes read\n//                    // in response :\\ -- http://b.android.com/28023\n//                    if (IO_TIMEOUT == Integer.MAX_VALUE) {\n//                        // Hack: Special case \"~infinite timeout\" as an error.\n//                        len = -1;\n//                    }\n//                    len = 0;\n//                }\n//\n////              System.arraycopy(mReadBuffer, 0, readData, 0, readAmt);\n//            }\n//            len = mConnection.bulkTransfer(mReadEndpoint, readData, readAmt, IO_TIMEOUT);\n\n            len = mSerialDevice.getPorts().get(0).read(readData, IO_TIMEOUT);\n\n            Log.d(TAG, \"Read \" + len + \" byte(s) complete.\");\n\n            // Add a 100ms delay for when multiple write/reads are occurring in series\n            Thread.sleep(100);\n\n            // TODO: this debug code to print data of the read, should be removed after\n            // finding the source of the reading issue\n            String bytes = \"\";\n            int readAmount = len;\n            for (int i = 0; i < readAmount; i++) bytes += String.format(\"%02x\", readData[i]) + \" \";\n            Log.d(TAG, \"Read data: \" + bytes);\n            ////////////////////////////////////////////////////////////////////////////////////////\n\n        } catch (Exception e) {\n            Log.e(TAG, \"Unable to read from serial device.\", e);\n        }\n        byte[] data = Arrays.copyOfRange(readData, 0, len);\n        return new ReadPacket(data);\n    }\n\n    private <T> T ParsePage(byte[] data, int recordType) {\n        int HEADER_LEN = 28;\n        PageHeader pageHeader=new PageHeader(data);\n        int NUM_REC_OFFSET = 4;\n        int numRec = data[NUM_REC_OFFSET];\n        int rec_len;\n\n        switch (Constants.RECORD_TYPES.values()[recordType]) {\n            case MANUFACTURING_DATA:\n                GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));\n                return (T) xmlRecord;\n            case SENSOR_DATA:\n                rec_len = 20;\n                SensorRecord[] sensorRecords = new SensorRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                return (T) sensorRecords;\n            case EGV_DATA:\n                rec_len = 13;\n                EGVRecord[] egvRecords = new EGVRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                return (T) egvRecords;\n            case METER_DATA:\n                rec_len = 16;\n                MeterRecord[] meterRecords = new MeterRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                return (T) meterRecords;\n            case CAL_SET:\n                rec_len = 249;\n                if (pageHeader.getRevision()<=2) {\n                    rec_len = 148;\n                }\n                CalRecord[] calRecords = new CalRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                return (T) calRecords;\n            default:\n                // Throw error \"Database record not supported\"\n                break;\n        }\n\n        return (T) null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadDataShare.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattService;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;\nimport com.eveningoutpost.dexdrip.Services.DexCollectionService;\nimport com.eveningoutpost.dexdrip.Services.DexShareCollectionService;\nimport com.eveningoutpost.dexdrip.ShareTest;\n\nimport org.w3c.dom.Element;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class ReadDataShare {\n    byte[] accumulatedResponse;\n    private ShareTest mShareTest;\n    private DexShareCollectionService mCollectionService;\n\n    public ReadDataShare(ShareTest aShareTest){\n        mShareTest = aShareTest;\n    }\n    public ReadDataShare(DexShareCollectionService collectionService){\n        mCollectionService = collectionService;\n    }\n\n    public void getRecentEGVs(final Action1<EGVRecord[]> recordListener) {\n        final int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();\n        final Action1<byte[]> fullPageListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }\n        };\n        Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {\n            @Override\n            public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }\n        };\n        readDataBasePageRange(recordType, databasePageRangeCaller);\n    }\n\n    public void getRecentMeterRecords(final Action1<MeterRecord[]> recordListener) {\n        final int recordType = Constants.RECORD_TYPES.METER_DATA.ordinal();\n        final Action1<byte[]> fullPageListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }\n        };\n        Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {\n            @Override\n            public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }\n        };\n        readDataBasePageRange(recordType, databasePageRangeCaller);\n    }\n\n    public void getRecentCalRecords(final Action1<CalRecord[]> recordListener) {\n        final int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();\n        final Action1<byte[]> fullPageListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }\n        };\n        Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {\n            @Override\n            public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }\n        };\n        readDataBasePageRange(recordType, databasePageRangeCaller);\n    }\n\n\n    public void getRecentSensorRecords(final Action1<SensorRecord[]> recordListener) {\n        final int recordType = Constants.RECORD_TYPES.SENSOR_DATA.ordinal();\n        final Action1<byte[]> fullPageListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }\n        };\n        Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {\n            @Override\n            public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }\n        };\n        readDataBasePageRange(recordType, databasePageRangeCaller);\n    }\n\n    public void getTimeSinceEGVRecord(final EGVRecord egvRecord, final Action1<Long> timeSinceEgvRecord) {\n        Action1<Long> tempSystemTimeListener = new Action1<Long>() {\n            @Override\n            public void call(Long s) { Observable.just(s - egvRecord.getSystemTimeSeconds()).subscribe(timeSinceEgvRecord); }\n        };\n        readSystemTime(tempSystemTimeListener);\n    }\n\n    public void ping(final Action1<Boolean> pingListener) {\n        Action1<byte[]> pingReader = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { Observable.just(read(0, s).getCommand() == Constants.ACK).subscribe(pingListener); }\n        };\n        writeCommand(Constants.PING, pingReader);\n    }\n\n    public void readBatteryLevel(final Action1<Integer> batteryLevelListener) {\n        Action1<byte[]> batteryLevelReader = new Action1<byte[]>() {\n            @Override //TODO: find out if this should be wrapped in read(s).getData();\n            public void call(byte[] s) { Observable.just(ByteBuffer.wrap(s).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(batteryLevelListener); }\n        };\n        writeCommand(Constants.READ_BATTERY_LEVEL, batteryLevelReader);\n    }\n\n    public void readSerialNumber(final Action1<String> serialNumberListener) {\n        final Action1<byte[]> manufacturingDataListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) {\n                Element el = ParsePage(s, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());\n                Observable.just(el.getAttribute(\"SerialNumber\")).subscribe(serialNumberListener);\n            }\n        };\n        readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), 0, manufacturingDataListener);\n    }\n\n    public void readDisplayTime(final Action1<Date> displayTimeListener) {\n        Action1<Long> tempSystemTimeListener = new Action1<Long>() {\n            @Override\n            public void call(Long s) {\n                final long systemTime = s;\n                Action1<Long> tempSystemTimeListener = new Action1<Long>() {\n                    @Override\n                    public void call(Long s) {\n                        Date dateDisplayTime = Utils.receiverTimeToDate(systemTime + s);\n                        Observable.just(dateDisplayTime).subscribe(displayTimeListener); }\n                };\n                readDisplayTimeOffset(tempSystemTimeListener);\n            }\n        };\n        readSystemTime(tempSystemTimeListener);\n    }\n\n    public void readSystemTime(final Action1<Long> systemTimeListener) {\n        Action1<byte[]> systemTimeReader = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) {\n                Observable.just(Utils.receiverTimeToDate(ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).getTime()).subscribe(systemTimeListener);\n            }\n        };\n        writeCommand(Constants.READ_SYSTEM_TIME, systemTimeReader);\n    }\n\n    public void readDisplayTimeOffset(final Action1<Long> displayTimeOffsetListener) {\n        Action1<byte[]> displayTimeOffsetReader = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) { Observable.just((long) ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(displayTimeOffsetListener); }\n        };\n        writeCommand(Constants.READ_DISPLAY_TIME_OFFSET, displayTimeOffsetReader);\n    }\n\n    private void readDataBasePageRange(int recordType, final Action1<Integer> databasePageRangeCaller) {\n        ArrayList<Byte> payload = new ArrayList<Byte>();\n        payload.add((byte) recordType);\n        final Action1<byte[]> databasePageRangeListener = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) {\n                Observable.just(ByteBuffer.wrap(new ReadPacket(s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(4)).subscribe(databasePageRangeCaller);\n            }\n        };\n        writeCommand(Constants.READ_DATABASE_PAGE_RANGE, payload, databasePageRangeListener);\n    }\n\n    private <T> T readDataBasePage(final int recordType, int page, final Action1<byte[]> fullPageListener) {\n        byte numOfPages = 1;\n        if (page < 0){ throw new IllegalArgumentException(\"Invalid page requested:\" + page); }\n        ArrayList<Byte> payload = new ArrayList<Byte>();\n        payload.add((byte) recordType);\n        byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();\n        payload.add(pageInt[3]);\n        payload.add(pageInt[2]);\n        payload.add(pageInt[1]);\n        payload.add(pageInt[0]);\n        payload.add(numOfPages);\n        accumulatedResponse = null;\n        final Action1<byte[]> databasePageReader = new Action1<byte[]>() {\n            @Override\n            public void call(byte[] s) {\n                Log.d(\"ShareTest\", \"Database Page Reader received SIZE: \" + s.length);\n                byte[] temp = s;\n                if (accumulatedResponse == null) {\n                    accumulatedResponse = s;\n                } else {\n                    try {\n                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n                        outputStream.write(accumulatedResponse);\n                        outputStream.write(temp);\n                        accumulatedResponse = outputStream.toByteArray();\n                        Log.d(\"ShareTest\", \"Combined Response length: \" + accumulatedResponse.length);\n                    } catch (Exception e) { e.printStackTrace(); }\n                }\n                if (temp.length < 20) { Observable.just(accumulatedResponse).subscribe(fullPageListener).unsubscribe(); }\n            }\n        };\n        writeCommand(Constants.READ_DATABASE_PAGES, payload, databasePageReader);\n        return null;\n    }\n\n    private void writeCommand(int command, ArrayList<Byte> payload, Action1<byte[]> responseListener) {\n        List<byte[]> packets = new PacketBuilder(command, payload).composeList();\n        if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }\n        else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }\n    }\n\n    private void writeCommand(int command, Action1<byte[]> responseListener) {\n        List<byte[]> packets = new PacketBuilder(command).composeList();\n        if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }\n        else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }\n    }\n\n    private ReadPacket read(int numOfBytes, byte[] readPacket) {\n        return new ReadPacket(Arrays.copyOfRange(readPacket, 0, readPacket.length));\n    }\n\n    private <T> T ParsePage(byte[] data, int recordType) { return ParsePage(data, recordType, null); }\n    private <T> T ParsePage(byte[] data, int recordType, Action1<T> parsedPageReceiver) {\n        int HEADER_LEN = 28;\n        PageHeader pageHeader=new PageHeader(data);\n        int NUM_REC_OFFSET = 4;\n        int numRec = data[NUM_REC_OFFSET];\n        int rec_len;\n\n        switch (Constants.RECORD_TYPES.values()[recordType]) {\n            case MANUFACTURING_DATA:\n                GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));\n                if(parsedPageReceiver != null) {\n                    Observable.just((T) xmlRecord).subscribe(parsedPageReceiver);\n                } else {\n                    return (T) xmlRecord;\n                }\n                break;\n            case SENSOR_DATA:\n                rec_len = 20;\n                SensorRecord[] sensorRecords = new SensorRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                if(parsedPageReceiver != null) {\n                    Observable.just((T) sensorRecords).subscribe(parsedPageReceiver);\n                } else {\n                    return (T) sensorRecords;\n                }\n                break;\n            case EGV_DATA:\n                rec_len = 13;\n                EGVRecord[] egvRecords = new EGVRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                if(parsedPageReceiver != null) {\n                    Observable.just((T) egvRecords).subscribe(parsedPageReceiver);\n                } else {\n                    return (T) egvRecords;\n                }\n                break;\n            case METER_DATA:\n                rec_len = 16;\n                MeterRecord[] meterRecords = new MeterRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                if(parsedPageReceiver != null) {\n                    Observable.just((T) meterRecords).subscribe(parsedPageReceiver);\n                } else {\n                    return (T) meterRecords;\n                }\n                break;\n            case CAL_SET:\n                rec_len = 249;\n                if (pageHeader.getRevision()<=2) { rec_len = 148; }\n                CalRecord[] calRecords = new CalRecord[numRec];\n                for (int i = 0; i < numRec; i++) {\n                    int startIdx = HEADER_LEN + rec_len * i;\n                    calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));\n                }\n                if(parsedPageReceiver != null) {\n                    Observable.just((T) calRecords).subscribe(parsedPageReceiver);\n                } else {\n                    return (T) calRecords;\n                }\n                break;\n            default:\n                break;\n        }\n        Observable.just((T) null).subscribe(parsedPageReceiver);\n        return (T) null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadPacket.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport java.util.Arrays;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\n\npublic class ReadPacket {\n    private int command;\n    private byte[] data;\n    private byte[] crc_calc;\n    private byte[] crc;\n    private int OFFSET_CMD = 3;\n    private int OFFSET_DATA = 4;\n    private int CRC_LEN = 2;\n\n    public ReadPacket(byte[] readPacket) {\n        this.command = readPacket[OFFSET_CMD];\n        this.data = Arrays.copyOfRange(readPacket, OFFSET_DATA, readPacket.length - CRC_LEN);\n        this.crc = Arrays.copyOfRange(readPacket, readPacket.length - CRC_LEN, readPacket.length);\n        this.crc_calc=CRC16.calculate(readPacket, 0, readPacket.length - 2);\n        if (!Arrays.equals(this.crc, this.crc_calc)) {\n            throw new CRCFailRuntimeException(\"CRC check failed: \" + Utils.bytesToHex(this.crc) + \" vs \" + Utils.bytesToHex(this.crc_calc));\n        }\n    }\n\n    public int getCommand() {\n        return command;\n    }\n\n    public byte[] getData() {\n        return data;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/SyncingService.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport android.app.IntentService;\nimport android.bluetooth.BluetoothClass;\nimport android.content.Intent;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbManager;\nimport android.os.PowerManager;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.CdcAcmSerialDriver;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.ProbeTable;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialProber;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\n\nimport org.json.JSONArray;\n\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\n\n/**\n * An {@link IntentService} subclass for handling asynchronous CGM Receiver downloads and cloud uploads\n * requests in a service on a separate handler thread.\n */\npublic class SyncingService extends IntentService {\n\n    // Action for intent\n    private static final String ACTION_SYNC = \"com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.action.SYNC\";\n    private static final String ACTION_CALIBRATION_CHECKIN = \"com.eveningoutpost.dexdrip.CalibrationCheckInActivity\";\n\n    // Parameters for intent\n    private static final String SYNC_PERIOD = \"com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.extra.SYNC_PERIOD\";\n\n    // Response to broadcast to activity\n    public static final String RESPONSE_SGV = \"mySGV\";\n    public static final String RESPONSE_TREND = \"myTrend\";\n    public static final String RESPONSE_TIMESTAMP = \"myTimestamp\";\n    public static final String RESPONSE_NEXT_UPLOAD_TIME = \"myUploadTime\";\n    public static final String RESPONSE_UPLOAD_STATUS = \"myUploadStatus\";\n    public static final String RESPONSE_DISPLAY_TIME = \"myDisplayTime\";\n    public static final String RESPONSE_JSON = \"myJSON\";\n    public static final String RESPONSE_BAT = \"myBatLvl\";\n\n    private final String TAG = SyncingService.class.getSimpleName();\n    private Context mContext;\n    private UsbManager mUsbManager;\n    private UsbSerialDriver mSerialDevice;\n    private UsbDevice dexcom;\n    private UsbDeviceConnection mConnection;\n\n    // Constants\n    private final int TIME_SYNC_OFFSET = 10000;\n    public static final int MIN_SYNC_PAGES = 2;\n    public static final int GAP_SYNC_PAGES = 20;\n\n\n    /**\n     * Starts this service to perform action Single Sync with the given parameters. If\n     * the service is already performing a task this action will be queued.\n     *\n     * @see IntentService\n     */\n    public static void startActionSingleSync(Context context, int numOfPages) {\n        Intent intent = new Intent(context, SyncingService.class);\n        intent.setAction(ACTION_SYNC);\n        intent.putExtra(SYNC_PERIOD, numOfPages);\n        context.startService(intent);\n    }\n    public static void startActionCalibrationCheckin(Context context) {\n        Intent intent = new Intent(context, SyncingService.class);\n        intent.setAction(ACTION_CALIBRATION_CHECKIN);\n        context.startService(intent);\n    }\n    public SyncingService() {\n        super(\"SyncingService\");\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        mContext = getApplicationContext();\n        if (intent != null) {\n            final String action = intent.getAction();\n            if (ACTION_SYNC.equals(action)) {\n                final int param1 = intent.getIntExtra(SYNC_PERIOD, 1);\n                handleActionSync(param1);\n            } else if (ACTION_CALIBRATION_CHECKIN.equals(action)) {\n                Log.w(\"CALIBRATION-CHECK-IN: \", \"Beginning check in process\");\n                performCalibrationCheckin();\n            }\n        }\n    }\n\n    /**\n     * Handle action Sync in the provided background thread with the provided\n     * parameters.\n     */\n    private void performCalibrationCheckin(){\n        PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);\n        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"NSDownload\");\n        wl.acquire();\n        Log.w(\"CALIBRATION-CHECK-IN: \", \"Wake Lock Acquired\");\n        if (acquireSerialDevice()) {\n            try {\n                ReadData readData = new ReadData(mSerialDevice, mConnection, dexcom);\n\n//                ReadData readData = new ReadData(mSerialDevice);\n                CalRecord[] calRecords = readData.getRecentCalRecords();\n                Log.w(\"CALIBRATION-CHECK-IN: \", \"Found \"+ calRecords.length + \" Records!\");\n                save_most_recent_cal_record(calRecords);\n\n            } catch (Exception e) {\n                Log.wtf(\"Unhandled exception caught\", e);\n            } finally {\n                // Close serial\n                try {\n                    mSerialDevice.getPorts().get(0).close();\n                } catch (IOException e) {\n                    Log.e(TAG, \"Unable to close\", e);\n                }\n\n            }\n        } else {\n            Log.w(\"CALIBRATION-CHECK-IN: \", \"Failed to acquire serial device\");\n        }\n    }\n\n    private void handleActionSync(int numOfPages) {\n        boolean broadcastSent = false;\n\n        PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);\n        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"NSDownload\");\n        wl.acquire();\n\n        if (acquireSerialDevice()) {\n            try {\n\n                ReadData readData = new ReadData(mSerialDevice);\n                // TODO: need to check if numOfPages if valid on ReadData side\n                EGVRecord[] recentRecords = readData.getRecentEGVsPages(numOfPages);\n                MeterRecord[] meterRecords = readData.getRecentMeterRecords();\n                // TODO: need to check if numOfPages if valid on ReadData side\n                SensorRecord[] sensorRecords = readData.getRecentSensorRecords(numOfPages);\n                GlucoseDataSet[] glucoseDataSets = Utils.mergeGlucoseDataRecords(recentRecords, sensorRecords);\n\n                // FIXME: This is a workaround for the new Dexcom AP which seems to have a new format\n                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n                CalRecord[] calRecords = new CalRecord[1];\n                if (prefs.getBoolean(\"cloud_cal_data\", false)) {\n                    calRecords = readData.getRecentCalRecords();\n                }\n\n                long timeSinceLastRecord = readData.getTimeSinceEGVRecord(recentRecords[recentRecords.length - 1]);\n                // TODO: determine if the logic here is correct. I suspect it assumes the last record was less than 5\n                // minutes ago. If a reading is skipped and the device is plugged in then nextUploadTime will be\n                // set to a negative number. This situation will eventually correct itself.\n                long nextUploadTime = (1000 * 60 * 5) - (timeSinceLastRecord * (1000));\n                long displayTime = readData.readDisplayTime().getTime();\n                // FIXME: Device seems to flake out on battery level reads. Removing for now.\n//                int batLevel = readData.readBatteryLevel();\n                int batLevel = 100;\n\n                // convert into json for d3 plot\n                JSONArray array = new JSONArray();\n                for (int i = 0; i < recentRecords.length; i++) array.put(recentRecords[i].toJSON());\n\n                EGVRecord recentEGV = recentRecords[recentRecords.length - 1];\n//                broadcastSGVToUI(recentEGV, uploadStatus, nextUploadTime + TIME_SYNC_OFFSET,\n//                                 displayTime, array ,batLevel);\n                broadcastSent=true;\n            } catch (ArrayIndexOutOfBoundsException e) {\n                Log.wtf(\"Unable to read from the dexcom, maybe it will work next time\", e);\n            } catch (NegativeArraySizeException e) {\n                Log.wtf(\"Negative array exception from receiver\", e);\n            } catch (IndexOutOfBoundsException e) {\n                Log.wtf(\"IndexOutOfBounds exception from receiver\", e);\n            } catch (CRCFailRuntimeException e){\n                // FIXME: may consider localizing this catch at a lower level (like ReadData) so that\n                // if the CRC check fails on one type of record we can capture the values if it\n                // doesn't fail on other types of records. This means we'd need to broadcast back\n                // partial results to the UI. Adding it to a lower level could make the ReadData class\n                // more difficult to maintain - needs discussion.\n                Log.wtf(\"CRC failed\", e);\n            } catch (Exception e) {\n                Log.wtf(\"Unhandled exception caught\", e);\n            } finally {\n                // Close serial\n                try {\n                    mSerialDevice.getPorts().get(0).close();\n                } catch (IOException e) {\n\n                    Log.e(TAG, \"Unable to close\", e);\n                }\n\n            }\n        }\n//        if (!broadcastSent) broadcastSGVToUI();\n\n        wl.release();\n    }\n\n    private void save_most_recent_cal_record(CalRecord[] calRecords) {\n        int size = calRecords.length;\n        Calibration.create(calRecords,getApplicationContext(), false, 0);\n    }\n\n    private boolean acquireSerialDevice() {\n        UsbDevice found_device = findDexcom();\n\n        if(mUsbManager == null) {\n            Log.w(\"CALIBRATION-CHECK-IN: \", \"USB manager is null\");\n        }\n\n\n        if( mUsbManager.hasPermission(dexcom)) {                                           // the system is allowing us to poke around this device\n\n            ProbeTable customTable = new ProbeTable();                                           // From the USB library...\n            customTable.addProduct(0x22A3, 0x0047, CdcAcmSerialDriver.class);       // ...Specify the Vendor ID and Product ID\n\n            UsbSerialProber prober = new UsbSerialProber(customTable);                      // Probe the device with the custom values\n            List<UsbSerialDriver> drivers = prober.findAllDrivers(mUsbManager);            // let's go through the list\n            Iterator<UsbSerialDriver> foo = drivers.iterator();                                                                                                  // Invalid Return code\n            while (foo.hasNext()) {                                                         // let's loop through\n                UsbSerialDriver driver = foo.next();                                        // set fooDriver to the next available driver\n                if (driver != null) {\n                    UsbDeviceConnection connection = mUsbManager.openDevice(driver.getDevice());\n                    if (connection != null) {\n                        mSerialDevice = driver;\n\n                        mConnection = connection;\n                        Log.w(\"CALIBRATION-CHECK-IN: \", \"CONNECTEDDDD!!\");\n                        return true;\n                    }\n                } else {\n                    Log.w(\"CALIBRATION-CHECK-IN: \", \"Driver was no good\");\n                }\n            }\n            Log.w(\"CALIBRATION-CHECK-IN: \", \"No usable drivers found\");\n        } else {\n            Log.w(\"CALIBRATION-CHECK-IN: \", \"You dont have permissions for that dexcom!!\");\n        }\n        return false;\n    }\n\n    static public boolean isG4Connected(Context c){\n        UsbManager manager = (UsbManager) c.getSystemService(Context.USB_SERVICE);\n        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();\n        Log.w(\"USB DEVICES = \", deviceList.toString());\n        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();\n        Log.w(\"USB DEVICES = \", String.valueOf(deviceList.size()));\n\n        while(deviceIterator.hasNext()){\n            UsbDevice device = deviceIterator.next();\n            if (device.getVendorId() == 8867 && device.getProductId() == 71\n                    && device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0\n                    && device.getDeviceProtocol() == 0){\n                Log.w(\"CALIBRATION-CHECK-IN: \", \"Dexcom Found!\");\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public UsbDevice findDexcom() {\n        Log.w(\"CALIBRATION-CHECK-IN: \", \"Searching for dexcom\");\n        mUsbManager = (UsbManager) getApplicationContext().getSystemService(Context.USB_SERVICE);\n        Log.w(\"USB MANAGER = \", mUsbManager.toString());\n        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();\n        Log.w(\"USB DEVICES = \", deviceList.toString());\n        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();\n        Log.w(\"USB DEVICES = \", String.valueOf(deviceList.size()));\n\n        while(deviceIterator.hasNext()){\n            UsbDevice device = deviceIterator.next();\n            if (device.getVendorId() == 8867 && device.getProductId() == 71\n                    && device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0\n                    && device.getDeviceProtocol() == 0){\n                dexcom = device;\n                Log.w(\"CALIBRATION-CHECK-IN: \", \"Dexcom Found!\");\n                return device;\n            } else {\n                Log.w(\"CALIBRATION-CHECK-IN: \", \"that was not a dexcom (I dont think)\");\n            }\n        }\n        return null;\n    }\n\n    private void broadcastSGVToUI(EGVRecord egvRecord, boolean uploadStatus,\n                                  long nextUploadTime, long displayTime,\n                                  JSONArray json, int batLvl) {\n        Log.d(TAG, \"Current EGV: \" + egvRecord.getBGValue());\n        Intent broadcastIntent = new Intent();\n//        broadcastIntent.setAction(MainActivity.CGMStatusReceiver.PROCESS_RESPONSE);\n        broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);\n        broadcastIntent.putExtra(RESPONSE_SGV, egvRecord.getBGValue());\n        broadcastIntent.putExtra(RESPONSE_TREND, egvRecord.getTrend().getID());\n        broadcastIntent.putExtra(RESPONSE_TIMESTAMP, egvRecord.getDisplayTime().getTime());\n        broadcastIntent.putExtra(RESPONSE_NEXT_UPLOAD_TIME, nextUploadTime);\n        broadcastIntent.putExtra(RESPONSE_UPLOAD_STATUS, uploadStatus);\n        broadcastIntent.putExtra(RESPONSE_DISPLAY_TIME, displayTime);\n        if (json!=null)\n            broadcastIntent.putExtra(RESPONSE_JSON, json.toString());\n        broadcastIntent.putExtra(RESPONSE_BAT, batLvl);\n        sendBroadcast(broadcastIntent);\n    }\n\n    private void broadcastSGVToUI() {\n        EGVRecord record=new EGVRecord(-1, Constants.TREND_ARROW_VALUES.NONE,new Date(),new Date());\n        broadcastSGVToUI(record,false, (long) (1000 * 60 * 5) + TIME_SYNC_OFFSET, new Date().getTime(), null, 0);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/Utils.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\n\nimport java.util.Date;\nimport java.util.TimeZone;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class Utils {\n\n    public static Date receiverTimeToDate(long delta) {\n        int currentTZOffset = TimeZone.getDefault().getRawOffset();\n        long epochMS = 1230768000000L;  // Jan 01, 2009 00:00 in UTC\n        long milliseconds = epochMS - currentTZOffset;\n        long timeAdd = milliseconds + (1000L * delta);\n        TimeZone tz = TimeZone.getDefault();\n        if (tz.inDaylightTime(new Date())) timeAdd = timeAdd - (1000 * 60 * 60);\n        return new Date(timeAdd);\n    }\n\n    public static String getTimeString(long timeDeltaMS) {\n        long minutes = (timeDeltaMS / 1000) / 60;\n        long hours = minutes / 60;\n        long days = hours / 24;\n        long weeks = days / 7;\n        minutes= minutes - hours * 60;\n        hours = hours - days * 24;\n        days= days - weeks * 7;\n\n        String timeAgoString = \"\";\n        if (weeks > 0) {\n            timeAgoString += weeks + \" weeks \";\n        }\n        if (days > 0) {\n            timeAgoString += days + \" days \";\n        }\n        if (hours > 0) {\n            timeAgoString += hours + \" hours \";\n        }\n        if (minutes >= 0) {\n            timeAgoString += minutes + \" min \";\n        }\n\n        return (timeAgoString.equals(\"\") ? \"--\" : timeAgoString + \"ago\");\n    }\n\n    public static GlucoseDataSet[] mergeGlucoseDataRecords(EGVRecord[] egvRecords,\n                                                           SensorRecord[] sensorRecords) {\n        int egvLength = egvRecords.length;\n        int sensorLength = sensorRecords.length;\n        int smallerLength = egvLength < sensorLength ? egvLength : sensorLength;\n        GlucoseDataSet[] glucoseDataSets = new GlucoseDataSet[smallerLength];\n        for (int i = 1; i <= smallerLength; i++) {\n            glucoseDataSets[smallerLength - i] = new GlucoseDataSet(egvRecords[egvLength - i], sensorRecords[sensorLength - i]);\n        }\n        return glucoseDataSets;\n    }\n\n    public static String bytesToHex(byte[] bytes) {\n        char[] hexArray = \"0123456789ABCDEF\".toCharArray();\n        char[] hexChars = new char[bytes.length * 3];\n        for ( int j = 0; j < bytes.length; j++ ) {\n            int v = bytes[j] & 0xFF;\n            hexChars[j * 3] = hexArray[v >>> 4];\n            hexChars[j * 3 + 1] = hexArray[v & 0x0F];\n            hexChars[j * 3 + 2] = \" \".toCharArray()[0];\n        }\n        return new String(hexChars);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/CalRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class CalRecord extends GenericTimestampRecord {\n    private static final String TAG = CalRecord.class.getSimpleName();\n    private double slope;\n    private double intercept;\n    private double scale;\n    private int[] unk = new int[3];\n    private double decay;\n    private int  numRecords;\n    private CalSubrecord[] calSubrecords = new CalSubrecord[12];\n    private int SUB_LEN = 17;\n\n    public CalRecord(byte[] packet) {\n        super(packet);\n        slope = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(8);\n        intercept = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(16);\n        scale = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(24);\n        unk[0] = packet[32];\n        unk[1] = packet[33];\n        unk[2] = packet[34];\n        decay = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(35);\n        numRecords = packet[43];\n        long displayTimeOffset = (getDisplayTime().getTime() - getSystemTime().getTime()) / (1000);\n        int start = 44;\n        for (int i = 0; i < numRecords; i++) {\n            Log.d(\"CalDebug\",\"Loop #\"+i);\n            byte[] temp = new byte[SUB_LEN];\n            System.arraycopy(packet, start, temp, 0, temp.length);\n            calSubrecords[i] = new CalSubrecord(temp, displayTimeOffset);\n            start += SUB_LEN;\n        }\n\n        Log.d(\"ShareTest\", \"slope: \" + slope + \" intercept: \" + intercept);\n    }\n\n    public double getSlope() {\n        return slope;\n    }\n\n    public double getIntercept() {\n        return intercept;\n    }\n\n    public double getScale() {\n        return scale;\n    }\n\n    public int[] getUnk() {\n        return unk;\n    }\n\n    public double getDecay() {\n        return decay;\n    }\n\n    public int getNumRecords() {\n        return numRecords;\n    }\n\n    public CalSubrecord[] getCalSubrecords() {\n        return calSubrecords;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/CalSubrecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Date;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class CalSubrecord {\n    private static final String TAG = CalSubrecord.class.getSimpleName();\n    private Date dateEntered;\n    private int calBGL;\n    private int calRaw;\n    private Date dateApplied;\n    private byte unk;\n\n    public CalSubrecord(byte[] packet, long displayTimeOffset) {\n        int delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt();\n        dateEntered = Utils.receiverTimeToDate(delta + displayTimeOffset);\n        calBGL = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4);\n        calRaw = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(8);\n        delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(12);\n        dateApplied = Utils.receiverTimeToDate(delta + displayTimeOffset);\n        unk = packet[16];\n    }\n\n    public Date getDateEntered() {\n        return dateEntered;\n    }\n\n    public int getCalBGL() {\n        return calBGL;\n    }\n\n    public int getCalRaw() {\n        return calRaw;\n    }\n\n    public Date getDateApplied() {\n        return dateApplied;\n    }\n\n    public byte getUnk() {\n        return unk;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/EGVRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.Serializable;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Arrays;\nimport java.util.Date;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class EGVRecord extends GenericTimestampRecord {\n\n    private int bGValue;\n    private int noise;\n    private Constants.TREND_ARROW_VALUES trend;\n\n    public EGVRecord(byte[] packet) {\n        // system_time (UInt), display_time (UInt), glucose (UShort), trend_arrow (Byte), crc (UShort))\n        super(packet);\n        bGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8) & Constants.EGV_VALUE_MASK;\n        byte trendAndNoise = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).get(10);\n        int trendValue = trendAndNoise & Constants.EGV_TREND_ARROW_MASK;\n        byte noiseValue = (byte) ((trendAndNoise & Constants.EGV_NOISE_MASK) >> 4);\n        trend = Constants.TREND_ARROW_VALUES.values()[trendValue];\n        noise = noiseValue;\n    }\n\n    public EGVRecord(int bGValue,Constants.TREND_ARROW_VALUES trend,Date displayTime, Date systemTime){\n        super(displayTime, systemTime);\n        this.bGValue=bGValue;\n        this.trend=trend;\n    }\n\n    public String noiseValue() { return String.valueOf(noise); }\n    public int getBGValue() {\n        return bGValue;\n    }\n\n    public Constants.TREND_ARROW_VALUES getTrend() {\n        return trend;\n    }\n\n    public JSONObject toJSON() {\n        JSONObject obj = new JSONObject();\n        try {\n            obj.put(\"sgv\", getBGValue());\n            obj.put(\"date\", getDisplayTimeSeconds());\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GenericTimestampRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Date;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class GenericTimestampRecord {\n\n    protected final int OFFSET_SYS_TIME = 0;\n    protected final int OFFSET_DISPLAY_TIME = 4;\n    protected Date systemTime;\n    protected int systemTimeSeconds;\n    protected Date displayTime;\n\n    public GenericTimestampRecord(byte[] packet) {\n        systemTimeSeconds = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_SYS_TIME);\n        systemTime = Utils.receiverTimeToDate(systemTimeSeconds);\n        int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_DISPLAY_TIME);\n        displayTime = Utils.receiverTimeToDate(dt);\n    }\n\n    public GenericTimestampRecord(Date displayTime, Date systemTime){\n        this.displayTime=displayTime;\n        this.systemTime=systemTime;\n    }\n\n    public Date getSystemTime() {\n        return systemTime;\n    }\n\n    public int getSystemTimeSeconds() {\n        return systemTimeSeconds;\n    }\n\n    public Date getDisplayTime() {\n        return displayTime;\n    }\n    public long getDisplayTimeSeconds() {\n        return displayTime.getTime();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GenericXMLRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.xml.sax.InputSource;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport java.io.Serializable;\nimport java.io.StringReader;\nimport java.util.Arrays;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class GenericXMLRecord extends GenericTimestampRecord {\n    int XML_START = 8;\n    int XML_END = 241;\n\n    private final String TAG = GenericXMLRecord.class.getSimpleName();\n\n    private Element xmlElement;\n\n    public GenericXMLRecord(byte[] packet) {\n        super(packet);\n        Document document;\n        // TODO: it would be best if we could just remove /x00 characters and read till end\n        String xml = new String(Arrays.copyOfRange(packet, XML_START, XML_END));\n        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n        DocumentBuilder builder;\n        try\n        {\n            builder = factory.newDocumentBuilder();\n            document = builder.parse(new InputSource(new StringReader(xml)));\n            xmlElement = document.getDocumentElement();\n        } catch (Exception e) {\n            Log.e(TAG, \"Unable to build xml element\", e);\n        }\n    }\n\n    // example: String sn = getXmlElement().getAttribute(\"SerialNumber\");\n    public Element getXmlElement() {\n        return xmlElement;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GlucoseDataSet.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;\n\nimport java.util.Date;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class GlucoseDataSet {\n\n    private Date systemTime;\n    private Date displayTime;\n    private int bGValue;\n    private Constants.TREND_ARROW_VALUES trend;\n    private long unfiltered;\n    private long filtered;\n    private int rssi;\n\n    public GlucoseDataSet(EGVRecord egvRecord, SensorRecord sensorRecord) {\n        // TODO check times match between record\n        systemTime = egvRecord.getSystemTime();\n        displayTime = egvRecord.getDisplayTime();\n        bGValue = egvRecord.getBGValue();\n        trend = egvRecord.getTrend();\n        unfiltered = sensorRecord.getUnfiltered();\n        filtered = sensorRecord.getFiltered();\n        rssi = sensorRecord.getRSSI();\n    }\n\n    public Date getSystemTime() {\n        return systemTime;\n    }\n\n    public Date getDisplayTime() {\n        return displayTime;\n    }\n\n    public int getBGValue() {\n        return bGValue;\n    }\n\n    public Constants.TREND_ARROW_VALUES getTrend() {\n        return trend;\n    }\n\n    public String getTrendSymbol() {\n        return trend.Symbol();\n    }\n\n    public long getUnfiltered() {\n        return unfiltered;\n    }\n\n    public long getFiltered() {\n        return filtered;\n    }\n\n    public int getRssi() {\n        return rssi;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/MeterRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class MeterRecord extends GenericTimestampRecord {\n\n    private int meterBG;\n    private int meterTime;\n\n    public MeterRecord(byte[] packet) {\n        super(packet);\n        meterBG = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8);\n        meterTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(10);\n    }\n\n    public int getMeterBG() {\n        return meterBG;\n    }\n\n    public int getMeterTime() {\n        return meterTime;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/PageHeader.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRC16;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRCFailRuntimeException;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Arrays;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class PageHeader {\n    protected final int HEADER_SIZE=28;\n    protected final int FIRSTRECORDINDEX_OFFSET=0;\n    protected final int NUMRECS_OFFSET=4;\n    protected final int RECTYPE_OFFSET=8;\n    protected final int REV_OFFSET=9;\n    protected final int PAGENUMBER_OFFSET=10;\n    protected final int RESERVED2_OFFSET=14;\n    protected final int RESERVED3_OFFSET=18;\n    protected final int RESERVED4_OFFSET=22;\n\n    protected int firstRecordIndex;\n    protected int numOfRecords;\n    protected Constants.RECORD_TYPES recordType;\n    protected byte revision;\n    protected int pageNumber;\n    protected int reserved2;\n    protected int reserved3;\n    protected int reserved4;\n    protected byte[] crc=new byte[2];\n\n\n    public PageHeader(byte[] packet) {\n        Log.d(\"ShareTest\", \"Header Packet Data Length: \" + packet.length);\n\n        firstRecordIndex = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(FIRSTRECORDINDEX_OFFSET);\n        numOfRecords = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(NUMRECS_OFFSET);\n        recordType = Constants.RECORD_TYPES.values()[packet[RECTYPE_OFFSET]];\n        revision = packet[REV_OFFSET];\n        pageNumber = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(PAGENUMBER_OFFSET);\n        reserved2 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED2_OFFSET);\n        reserved3 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED3_OFFSET);\n        reserved4 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED4_OFFSET);\n        System.arraycopy(packet,HEADER_SIZE-Constants.CRC_LEN,crc,0,Constants.CRC_LEN);\n        byte[] crc_calc = CRC16.calculate(packet,0,HEADER_SIZE - Constants.CRC_LEN);\n        if (!Arrays.equals(this.crc, crc_calc)) {\n            throw new CRCFailRuntimeException(\"CRC check failed: \" + Utils.bytesToHex(this.crc) + \" vs \" + Utils.bytesToHex(crc_calc));\n        }\n    }\n\n    public byte getRevision() {\n        return revision;\n    }\n\n    public Constants.RECORD_TYPES getRecordType() {\n        return recordType;\n    }\n\n    public int getFirstRecordIndex() {\n        return firstRecordIndex;\n    }\n\n    public int getNumOfRecords() {\n        return numOfRecords;\n    }\n\n    public int getPageNumber() {\n        return pageNumber;\n    }\n\n    public int getReserved2() {\n        return reserved2;\n    }\n\n    public int getReserved3() {\n        return reserved3;\n    }\n\n    public int getReserved4() {\n        return reserved4;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/SensorRecord.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;\n\nimport android.util.Log;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\n// This code and this particular library are from the NightScout android uploader\n// Check them out here: https://github.com/nightscout/android-uploader\n// Some of this code may have been modified for use in this project\n\npublic class SensorRecord extends GenericTimestampRecord {\n\n    private int unfiltered;\n    private int filtered;\n    private int rssi;\n    private int OFFSET_UNFILTERED = 8;\n    private int OFFSET_FILTERED = 12;\n    private int OFFSET_RSSI = 16;\n\n    public SensorRecord(byte[] packet) {\n        super(packet);\n        unfiltered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_UNFILTERED);\n        filtered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_FILTERED);\n        rssi = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(OFFSET_RSSI);\n        Log.d(\"ShareTest\", \"filtered: \" + filtered + \" unfiltered: \" + unfiltered);\n    }\n\n    public long getUnfiltered() {\n        return unfiltered;\n    }\n\n    public long getFiltered() {\n        return filtered;\n    }\n\n    public int getRSSI() {\n        return rssi;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/BuildInfo.java",
    "content": "package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial;\n\n/**\n * Static container of information about this library.\n */\npublic final class BuildInfo {\n\n    /**\n     * The current version of this library. Values are of the form\n     * \"major.minor.micro[-suffix]\". A suffix of \"-pre\" indicates a pre-release\n     * of the version preceeding it.\n     */\n    public static final String VERSION = \"0.2.0-pre\";\n\n    private BuildInfo() {\n        throw new IllegalStateException(\"Non-instantiable class.\");\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/CdcAcmSerialDriver.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbConstants;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbEndpoint;\nimport android.hardware.usb.UsbInterface;\nimport android.hardware.usb.UsbRequest;\nimport android.os.Build;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * USB CDC/ACM serial driver implementation.\n *\n * @author mike wakerly (opensource@hoho.com)\n * @see <a\n *      href=\"http://www.usb.org/developers/devclass_docs/usbcdc11.pdf\">Universal\n *      Serial Bus Class Definitions for Communication Devices, v1.1</a>\n */\npublic class CdcAcmSerialDriver implements UsbSerialDriver {\n\n    private final String TAG = CdcAcmSerialDriver.class.getSimpleName();\n\n    private final UsbDevice mDevice;\n    private final UsbSerialPort mPort;\n\n    public CdcAcmSerialDriver(UsbDevice device) {\n        mDevice = device;\n        mPort = new CdcAcmSerialPort(device, 0);\n    }\n\n    @Override\n    public UsbDevice getDevice() {\n        return mDevice;\n    }\n\n    @Override\n    public List<UsbSerialPort> getPorts() {\n        return Collections.singletonList(mPort);\n    }\n\n    class CdcAcmSerialPort extends CommonUsbSerialPort {\n\n        private final boolean mEnableAsyncReads;\n        private UsbInterface mControlInterface;\n        private UsbInterface mDataInterface;\n\n        private UsbEndpoint mControlEndpoint;\n        private UsbEndpoint mReadEndpoint;\n        private UsbEndpoint mWriteEndpoint;\n\n        private boolean mRts = false;\n        private boolean mDtr = false;\n\n        private static final int USB_RECIP_INTERFACE = 0x01;\n        private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;\n\n        private static final int SET_LINE_CODING = 0x20;  // USB CDC 1.1 section 6.2\n        private static final int GET_LINE_CODING = 0x21;\n        private static final int SET_CONTROL_LINE_STATE = 0x22;\n        private static final int SEND_BREAK = 0x23;\n\n        public CdcAcmSerialPort(UsbDevice device, int portNumber) {\n            super(device, portNumber);\n            mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);\n        }\n\n        @Override\n        public UsbSerialDriver getDriver() {\n            return CdcAcmSerialDriver.this;\n        }\n\n        @Override\n        public void open(UsbDeviceConnection connection) throws IOException {\n            if (mConnection != null && false) {\n                throw new IOException(\"Already open\");\n            }\n\n            mConnection = connection;\n            boolean opened = false;\n            try {\n                Log.d(TAG, \"claiming interfaces, count=\" + mDevice.getInterfaceCount());\n                mControlInterface = mDevice.getInterface(0);\n                Log.d(TAG, \"Control iface=\" + mControlInterface);\n                // class should be USB_CLASS_COMM\n\n                if (!mConnection.claimInterface(mControlInterface, true)) {\n                    throw new IOException(\"Could not claim control interface.\");\n                }\n                mControlEndpoint = mControlInterface.getEndpoint(0);\n                Log.d(TAG, \"Control endpoint direction: \" + mControlEndpoint.getDirection());\n\n                Log.d(TAG, \"Claiming data interface.\");\n                mDataInterface = mDevice.getInterface(1);\n                Log.d(TAG, \"data iface=\" + mDataInterface);\n                // class should be USB_CLASS_CDC_DATA\n\n                if (!mConnection.claimInterface(mDataInterface, true)) {\n                    throw new IOException(\"Could not claim data interface.\");\n                }\n                mReadEndpoint = mDataInterface.getEndpoint(1);\n                Log.d(TAG, \"Read endpoint direction: \" + mReadEndpoint.getDirection());\n                mWriteEndpoint = mDataInterface.getEndpoint(0);\n                Log.d(TAG, \"Write endpoint direction: \" + mWriteEndpoint.getDirection());\n                if (mEnableAsyncReads) {\n                  Log.d(TAG, \"Async reads enabled\");\n                } else {\n                  Log.d(TAG, \"Async reads disabled.\");\n                }\n                opened = true;\n            } finally {\n                if (!opened) {\n                    mConnection = null;\n                }\n            }\n        }\n\n        private int sendAcmControlMessage(int request, int value, byte[] buf) {\n            return mConnection.controlTransfer(\n                    USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (mConnection == null) {\n                throw new IOException(\"Already closed\");\n            }\n            mConnection.close();\n            mConnection = null;\n        }\n\n        @Override\n        public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {return 0;}\n\n        @Override\n        public int read(byte[] dest, int timeoutMillis) throws IOException {\n            if (mEnableAsyncReads) {\n              final UsbRequest request = new UsbRequest();\n              try {\n                request.initialize(mConnection, mReadEndpoint);\n                final ByteBuffer buf = ByteBuffer.wrap(dest);\n                if (!request.queue(buf, dest.length)) {\n                  throw new IOException(\"Error queueing request.\");\n                }\n\n                final UsbRequest response = mConnection.requestWait();\n                if (response == null) {\n                  throw new IOException(\"Null response\");\n                }\n\n                final int nread = buf.position();\n                if (nread > 0) {\n                  //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));\n                  return nread;\n                } else {\n                  return 0;\n                }\n              } finally {\n                request.close();\n              }\n            }\n\n            final int numBytesRead;\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,\n                        timeoutMillis);\n                if (numBytesRead < 0) {\n                    // This sucks: we get -1 on timeout, not 0 as preferred.\n                    // We *should* use UsbRequest, except it has a bug/api oversight\n                    // where there is no way to determine the number of bytes read\n                    // in response :\\ -- http://b.android.com/28023\n                    if (timeoutMillis == Integer.MAX_VALUE) {\n                        // Hack: Special case \"~infinite timeout\" as an error.\n                        return -1;\n                    }\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n            }\n            return numBytesRead;\n        }\n\n        @Override\n        public int write(byte[] src, int timeoutMillis) throws IOException {\n            // TODO(mikey): Nearly identical to FtdiSerial write. Refactor.\n            int offset = 0;\n\n            while (offset < src.length) {\n                final int writeLength;\n                final int amtWritten;\n\n                synchronized (mWriteBufferLock) {\n                    final byte[] writeBuffer;\n\n                    writeLength = Math.min(src.length - offset, mWriteBuffer.length);\n                    if (offset == 0) {\n                        writeBuffer = src;\n                    } else {\n                        // bulkTransfer does not support offsets, make a copy.\n                        System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);\n                        writeBuffer = mWriteBuffer;\n                    }\n\n                    amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,\n                            timeoutMillis);\n                }\n                if (amtWritten <= 0) {\n                    throw new IOException(\"Error writing \" + writeLength\n                            + \" bytes at offset \" + offset + \" length=\" + src.length);\n                }\n\n                Log.d(TAG, \"Wrote amt=\" + amtWritten + \" attempted=\" + writeLength);\n                offset += amtWritten;\n            }\n            return offset;\n        }\n\n        @Override\n        public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {\n            byte stopBitsByte;\n            switch (stopBits) {\n                case STOPBITS_1: stopBitsByte = 0; break;\n                case STOPBITS_1_5: stopBitsByte = 1; break;\n                case STOPBITS_2: stopBitsByte = 2; break;\n                default: throw new IllegalArgumentException(\"Bad value for stopBits: \" + stopBits);\n            }\n\n            byte parityBitesByte;\n            switch (parity) {\n                case PARITY_NONE: parityBitesByte = 0; break;\n                case PARITY_ODD: parityBitesByte = 1; break;\n                case PARITY_EVEN: parityBitesByte = 2; break;\n                case PARITY_MARK: parityBitesByte = 3; break;\n                case PARITY_SPACE: parityBitesByte = 4; break;\n                default: throw new IllegalArgumentException(\"Bad value for parity: \" + parity);\n            }\n\n            byte[] msg = {\n                    (byte) ( baudRate & 0xff),\n                    (byte) ((baudRate >> 8 ) & 0xff),\n                    (byte) ((baudRate >> 16) & 0xff),\n                    (byte) ((baudRate >> 24) & 0xff),\n                    stopBitsByte,\n                    parityBitesByte,\n                    (byte) dataBits};\n            sendAcmControlMessage(SET_LINE_CODING, 0, msg);\n        }\n\n        @Override\n        public boolean getCD() throws IOException {\n            return false;  // TODO\n        }\n\n        @Override\n        public boolean getCTS() throws IOException {\n            return false;  // TODO\n        }\n\n        @Override\n        public boolean getDSR() throws IOException {\n            return false;  // TODO\n        }\n\n        @Override\n        public boolean getDTR() throws IOException {\n            return mDtr;\n        }\n\n        @Override\n        public void setDTR(boolean value) throws IOException {\n            mDtr = value;\n            setDtrRts();\n        }\n\n        @Override\n        public boolean getRI() throws IOException {\n            return false;  // TODO\n        }\n\n        @Override\n        public boolean getRTS() throws IOException {\n            return mRts;\n        }\n\n        @Override\n        public void setRTS(boolean value) throws IOException {\n            mRts = value;\n            setDtrRts();\n        }\n\n        private void setDtrRts() {\n            int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);\n            sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);\n        }\n\n    }\n\n    public static Map<Integer, int[]> getSupportedDevices() {\n        final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),\n                new int[] {\n                        UsbId.ARDUINO_UNO,\n                        UsbId.ARDUINO_UNO_R3,\n                        UsbId.ARDUINO_MEGA_2560,\n                        UsbId.ARDUINO_MEGA_2560_R3,\n                        UsbId.ARDUINO_SERIAL_ADAPTER,\n                        UsbId.ARDUINO_SERIAL_ADAPTER_R3,\n                        UsbId.ARDUINO_MEGA_ADK,\n                        UsbId.ARDUINO_MEGA_ADK_R3,\n                        UsbId.ARDUINO_LEONARDO,\n                });\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),\n                new int[] {\n                    UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,\n                });\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),\n                new int[] {\n                    UsbId.ATMEL_LUFA_CDC_DEMO_APP,\n                });\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),\n                new int[] {\n                    UsbId.LEAFLABS_MAPLE,\n                });\n        return supportedDevices;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/CommonUsbSerialPort.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\n\nimport java.io.IOException;\n\n/**\n * A base class shared by several driver implementations.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\nabstract class CommonUsbSerialPort implements UsbSerialPort {\n\n    public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024;\n    public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;\n\n    protected final UsbDevice mDevice;\n    protected final int mPortNumber;\n\n    // non-null when open()\n    protected UsbDeviceConnection mConnection = null;\n\n    protected final Object mReadBufferLock = new Object();\n    protected final Object mWriteBufferLock = new Object();\n\n    /** Internal read buffer.  Guarded by {@link #mReadBufferLock}. */\n    protected byte[] mReadBuffer;\n\n    /** Internal write buffer.  Guarded by {@link #mWriteBufferLock}. */\n    protected byte[] mWriteBuffer;\n\n    public CommonUsbSerialPort(UsbDevice device, int portNumber) {\n        mDevice = device;\n        mPortNumber = portNumber;\n\n        mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];\n        mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"<%s device_name=%s device_id=%s port_number=%s>\",\n                getClass().getSimpleName(), mDevice.getDeviceName(),\n                mDevice.getDeviceId(), mPortNumber);\n    }\n\n    /**\n     * Returns the currently-bound USB device.\n     *\n     * @return the device\n     */\n    public final UsbDevice getDevice() {\n        return mDevice;\n    }\n\n    @Override\n    public int getPortNumber() {\n        return mPortNumber;\n    }\n\n    /**\n     * Returns the device serial number\n     *  @return serial number\n     */\n    @Override\n    public String getSerial() {\n        return mConnection.getSerial();\n    }\n\n    /**\n     * Sets the size of the internal buffer used to exchange data with the USB\n     * stack for read operations.  Most users should not need to change this.\n     *\n     * @param bufferSize the size in bytes\n     */\n    public final void setReadBufferSize(int bufferSize) {\n        synchronized (mReadBufferLock) {\n            if (bufferSize == mReadBuffer.length) {\n                return;\n            }\n            mReadBuffer = new byte[bufferSize];\n        }\n    }\n\n    /**\n     * Sets the size of the internal buffer used to exchange data with the USB\n     * stack for write operations.  Most users should not need to change this.\n     *\n     * @param bufferSize the size in bytes\n     */\n    public final void setWriteBufferSize(int bufferSize) {\n        synchronized (mWriteBufferLock) {\n            if (bufferSize == mWriteBuffer.length) {\n                return;\n            }\n            mWriteBuffer = new byte[bufferSize];\n        }\n    }\n\n    @Override\n    public abstract void open(UsbDeviceConnection connection) throws IOException;\n\n    @Override\n    public abstract void close() throws IOException;\n\n    @Override\n    public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException;\n\n    @Override\n    public abstract int write(final byte[] src, final int timeoutMillis) throws IOException;\n\n    @Override\n    public abstract void setParameters(\n            int baudRate, int dataBits, int stopBits, int parity) throws IOException;\n\n    @Override\n    public abstract boolean getCD() throws IOException;\n\n    @Override\n    public abstract boolean getCTS() throws IOException;\n\n    @Override\n    public abstract boolean getDSR() throws IOException;\n\n    @Override\n    public abstract boolean getDTR() throws IOException;\n\n    @Override\n    public abstract void setDTR(boolean value) throws IOException;\n\n    @Override\n    public abstract boolean getRI() throws IOException;\n\n    @Override\n    public abstract boolean getRTS() throws IOException;\n\n    @Override\n    public abstract void setRTS(boolean value) throws IOException;\n\n    @Override\n    public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException {\n        return !flushReadBuffers && !flushWriteBuffers;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/Cp21xxSerialDriver.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbConstants;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbEndpoint;\nimport android.hardware.usb.UsbInterface;\nimport android.hardware.usb.UsbRequest;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class Cp21xxSerialDriver implements UsbSerialDriver {\n\n    private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();\n\n    private final UsbDevice mDevice;\n    private final UsbSerialPort mPort;\n\n    public Cp21xxSerialDriver(UsbDevice device) {\n        mDevice = device;\n        mPort = new Cp21xxSerialPort(mDevice, 0);\n    }\n\n    @Override\n    public UsbDevice getDevice() {\n        return mDevice;\n    }\n\n    @Override\n    public List<UsbSerialPort> getPorts() {\n        return Collections.singletonList(mPort);\n    }\n\n    public class Cp21xxSerialPort extends CommonUsbSerialPort {\n\n        private static final int DEFAULT_BAUD_RATE = 9600;\n\n        private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;\n\n        /*\n         * Configuration Request Types\n         */\n        private static final int REQTYPE_HOST_TO_DEVICE = 0x41;\n\n        /*\n         * Configuration Request Codes\n         */\n        private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;\n        private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01;\n        private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;\n        private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;\n        private static final int SILABSER_SET_BAUDRATE = 0x1E;\n        private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;\n\n       private static final int FLUSH_READ_CODE = 0x0a;\n       private static final int FLUSH_WRITE_CODE = 0x05;\n\n        /*\n         * SILABSER_IFC_ENABLE_REQUEST_CODE\n         */\n        private static final int UART_ENABLE = 0x0001;\n        private static final int UART_DISABLE = 0x0000;\n\n        /*\n         * SILABSER_SET_BAUDDIV_REQUEST_CODE\n         */\n        private static final int BAUD_RATE_GEN_FREQ = 0x384000;\n\n        /*\n         * SILABSER_SET_MHS_REQUEST_CODE\n         */\n        private static final int MCR_DTR = 0x0001;\n        private static final int MCR_RTS = 0x0002;\n        private static final int MCR_ALL = 0x0003;\n\n        private static final int CONTROL_WRITE_DTR = 0x0100;\n        private static final int CONTROL_WRITE_RTS = 0x0200;\n\n        private UsbEndpoint mReadEndpoint;\n        private UsbEndpoint mWriteEndpoint;\n\n        public Cp21xxSerialPort(UsbDevice device, int portNumber) {\n            super(device, portNumber);\n        }\n\n        @Override\n        public UsbSerialDriver getDriver() {\n            return Cp21xxSerialDriver.this;\n        }\n\n        private int setConfigSingle(int request, int value) {\n            return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,\n                    0, null, 0, USB_WRITE_TIMEOUT_MILLIS);\n        }\n\n        @Override\n        public void open(UsbDeviceConnection connection) throws IOException {\n            if (mConnection != null) {\n                throw new IOException(\"Already opened.\");\n            }\n\n            mConnection = connection;\n            boolean opened = false;\n            try {\n                for (int i = 0; i < mDevice.getInterfaceCount(); i++) {\n                    UsbInterface usbIface = mDevice.getInterface(i);\n                    if (mConnection.claimInterface(usbIface, true)) {\n                        Log.d(TAG, \"claimInterface \" + i + \" SUCCESS\");\n                    } else {\n                        Log.d(TAG, \"claimInterface \" + i + \" FAIL\");\n                    }\n                }\n\n                UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);\n                for (int i = 0; i < dataIface.getEndpointCount(); i++) {\n                    UsbEndpoint ep = dataIface.getEndpoint(i);\n                    if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {\n                        if (ep.getDirection() == UsbConstants.USB_DIR_IN) {\n                            mReadEndpoint = ep;\n                        } else {\n                            mWriteEndpoint = ep;\n                        }\n                    }\n                }\n\n                setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);\n                setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS);\n                setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE);\n    //            setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY);\n                opened = true;\n            } finally {\n                if (!opened) {\n                    try {\n                        close();\n                    } catch (IOException e) {\n                        // Ignore IOExceptions during close()\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (mConnection == null) {\n                throw new IOException(\"Already closed\");\n            }\n            try {\n                setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);\n                mConnection.close();\n            } finally {\n                mConnection = null;\n            }\n        }\n\n        @Override\n        public int read(byte[] dest, int timeoutMillis) throws IOException {\n            final int numBytesRead;\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,\n                        timeoutMillis);\n                if (numBytesRead < 0) {\n                    // This sucks: we get -1 on timeout, not 0 as preferred.\n                    // We *should* use UsbRequest, except it has a bug/api oversight\n                    // where there is no way to determine the number of bytes read\n                    // in response :\\ -- http://b.android.com/28023\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n            }\n            return numBytesRead;\n        }\n\n        @Override\n        public int write(byte[] src, int timeoutMillis) throws IOException {\n            int offset = 0;\n\n            while (offset < src.length) {\n                final int writeLength;\n                final int amtWritten;\n\n                synchronized (mWriteBufferLock) {\n                    final byte[] writeBuffer;\n\n                    writeLength = Math.min(src.length - offset, mWriteBuffer.length);\n                    if (offset == 0) {\n                        writeBuffer = src;\n                    } else {\n                        // bulkTransfer does not support offsets, make a copy.\n                        System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);\n                        writeBuffer = mWriteBuffer;\n                    }\n\n                    amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,\n                            timeoutMillis);\n                }\n                if (amtWritten <= 0) {\n                    throw new IOException(\"Error writing \" + writeLength\n                            + \" bytes at offset \" + offset + \" length=\" + src.length);\n                }\n\n                Log.d(TAG, \"Wrote amt=\" + amtWritten + \" attempted=\" + writeLength);\n                offset += amtWritten;\n            }\n            return offset;\n        }\n        @Override\n        public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {\n            if (false) {\n                final UsbRequest request = new UsbRequest();\n                try {\n                    request.initialize(connection, mReadEndpoint);\n                    final ByteBuffer buf = ByteBuffer.wrap(dest);\n                    if (!request.queue(buf, dest.length)) {\n                        throw new IOException(\"Error queueing request.\");\n                    }\n\n                    final UsbRequest response = connection.requestWait();\n                    if (response == null) {\n                        throw new IOException(\"Null response\");\n                    }\n\n                    final int nread = buf.position();\n                    if (nread > 0) {\n                        //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));\n                        return nread;\n                    } else {\n                        return 0;\n                    }\n                } finally {\n                    request.close();\n                }\n            }\n\n            final int numBytesRead;\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                numBytesRead = connection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,\n                        timeoutMillis);\n                if (numBytesRead < 0) {\n                    // This sucks: we get -1 on timeout, not 0 as preferred.\n                    // We *should* use UsbRequest, except it has a bug/api oversight\n                    // where there is no way to determine the number of bytes read\n                    // in response :\\ -- http://b.android.com/28023\n                    if (timeoutMillis == Integer.MAX_VALUE) {\n                        // Hack: Special case \"~infinite timeout\" as an error.\n                        return -1;\n                    }\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n            }\n            return numBytesRead;\n        }\n        private void setBaudRate(int baudRate) throws IOException {\n            byte[] data = new byte[] {\n                    (byte) ( baudRate & 0xff),\n                    (byte) ((baudRate >> 8 ) & 0xff),\n                    (byte) ((baudRate >> 16) & 0xff),\n                    (byte) ((baudRate >> 24) & 0xff)\n            };\n            int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,\n                    0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS);\n            if (ret < 0) {\n                throw new IOException(\"Error setting baud rate.\");\n            }\n        }\n\n        @Override\n        public void setParameters(int baudRate, int dataBits, int stopBits, int parity)\n                throws IOException {\n            setBaudRate(baudRate);\n\n            int configDataBits = 0;\n            switch (dataBits) {\n                case DATABITS_5:\n                    configDataBits |= 0x0500;\n                    break;\n                case DATABITS_6:\n                    configDataBits |= 0x0600;\n                    break;\n                case DATABITS_7:\n                    configDataBits |= 0x0700;\n                    break;\n                case DATABITS_8:\n                    configDataBits |= 0x0800;\n                    break;\n                default:\n                    configDataBits |= 0x0800;\n                    break;\n            }\n\n            switch (parity) {\n                case PARITY_ODD:\n                    configDataBits |= 0x0010;\n                    break;\n                case PARITY_EVEN:\n                    configDataBits |= 0x0020;\n                    break;\n            }\n\n            switch (stopBits) {\n                case STOPBITS_1:\n                    configDataBits |= 0;\n                    break;\n                case STOPBITS_2:\n                    configDataBits |= 2;\n                    break;\n            }\n            setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);\n        }\n\n        @Override\n        public boolean getCD() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getCTS() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getDSR() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getDTR() throws IOException {\n            return true;\n        }\n\n        @Override\n        public void setDTR(boolean value) throws IOException {\n        }\n\n        @Override\n        public boolean getRI() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getRTS() throws IOException {\n            return true;\n        }\n\n        @Override\n        public void setRTS(boolean value) throws IOException {\n        }\n\n        @Override\n        public boolean purgeHwBuffers(boolean purgeReadBuffers,\n                boolean purgeWriteBuffers) throws IOException {\n            int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)\n                    | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);\n\n            if (value != 0) {\n                setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);\n            }\n\n            return true;\n        }\n\n    }\n\n    public static Map<Integer, int[]> getSupportedDevices() {\n        final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS),\n                new int[] {\n            UsbId.SILABS_CP2102,\n            UsbId.SILABS_CP2105,\n            UsbId.SILABS_CP2108,\n            UsbId.SILABS_CP2110\n        });\n        return supportedDevices;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/FtdiSerialDriver.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbConstants;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbEndpoint;\nimport android.hardware.usb.UsbRequest;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util.HexDump;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices\n * <p>\n * This driver is based on <a\n * href=\"http://www.intra2net.com/en/developer/libftdi\">libftdi</a>, and is\n * copyright and subject to the following terms:\n *\n * <pre>\n *   Copyright (C) 2003 by Intra2net AG\n *\n *   This program is free software; you can redistribute it and/or modify\n *   it under the terms of the GNU Lesser General Public License\n *   version 2.1 as published by the Free Software Foundation;\n *\n *   opensource@intra2net.com\n *   http://www.intra2net.com/en/developer/libftdi\n * </pre>\n *\n * </p>\n * <p>\n * Some FTDI devices have not been tested; see later listing of supported and\n * unsupported devices. Devices listed as \"supported\" support the following\n * features:\n * <ul>\n * <li>Read and write of serial data (see\n * {@link CommonUsbSerialPort#read(byte[], int)} and\n * {@link CommonUsbSerialPort#write(byte[], int)}.</li>\n * <li>Setting serial line parameters (see\n * {@link CommonUsbSerialPort#setParameters(int, int, int, int)}.</li>\n * </ul>\n * </p>\n * <p>\n * Supported and tested devices:\n * <ul>\n * <li>{@value DeviceType#TYPE_R}</li>\n * </ul>\n * </p>\n * <p>\n * Unsupported but possibly working devices (please contact the author with\n * feedback or patches):\n * <ul>\n * <li>{@value DeviceType#TYPE_2232C}</li>\n * <li>{@value DeviceType#TYPE_2232H}</li>\n * <li>{@value DeviceType#TYPE_4232H}</li>\n * <li>{@value DeviceType#TYPE_AM}</li>\n * <li>{@value DeviceType#TYPE_BM}</li>\n * </ul>\n * </p>\n *\n * @author mike wakerly (opensource@hoho.com)\n * @see <a href=\"https://github.com/mik3y/usb-serial-for-android\">USB Serial\n *      for Android project page</a>\n * @see <a href=\"http://www.ftdichip.com/\">FTDI Homepage</a>\n * @see <a href=\"http://www.intra2net.com/en/developer/libftdi\">libftdi</a>\n */\npublic class FtdiSerialDriver implements UsbSerialDriver {\n\n    private final UsbDevice mDevice;\n    private final UsbSerialPort mPort;\n\n    /**\n     * FTDI chip types.\n     */\n    private static enum DeviceType {\n        TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H;\n    }\n\n    public FtdiSerialDriver(UsbDevice device) {\n        mDevice = device;\n        mPort = new FtdiSerialPort(mDevice, 0);\n    }\n    @Override\n    public UsbDevice getDevice() {\n        return mDevice;\n    }\n\n    @Override\n    public List<UsbSerialPort> getPorts() {\n        return Collections.singletonList(mPort);\n    }\n\n    private class FtdiSerialPort extends CommonUsbSerialPort {\n\n        public static final int USB_TYPE_STANDARD = 0x00 << 5;\n        public static final int USB_TYPE_CLASS = 0x00 << 5;\n        public static final int USB_TYPE_VENDOR = 0x00 << 5;\n        public static final int USB_TYPE_RESERVED = 0x00 << 5;\n\n        public static final int USB_RECIP_DEVICE = 0x00;\n        public static final int USB_RECIP_INTERFACE = 0x01;\n        public static final int USB_RECIP_ENDPOINT = 0x02;\n        public static final int USB_RECIP_OTHER = 0x03;\n\n        public static final int USB_ENDPOINT_IN = 0x80;\n        public static final int USB_ENDPOINT_OUT = 0x00;\n\n        public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;\n        public static final int USB_READ_TIMEOUT_MILLIS = 5000;\n\n        // From ftdi.h\n        /**\n         * Reset the port.\n         */\n        private static final int SIO_RESET_REQUEST = 0;\n\n        /**\n         * Set the modem control register.\n         */\n        private static final int SIO_MODEM_CTRL_REQUEST = 1;\n\n        /**\n         * Set flow control register.\n         */\n        private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;\n\n        /**\n         * Set baud rate.\n         */\n        private static final int SIO_SET_BAUD_RATE_REQUEST = 3;\n\n        /**\n         * Set the data characteristics of the port.\n         */\n        private static final int SIO_SET_DATA_REQUEST = 4;\n\n        private static final int SIO_RESET_SIO = 0;\n        private static final int SIO_RESET_PURGE_RX = 1;\n        private static final int SIO_RESET_PURGE_TX = 2;\n\n        public static final int FTDI_DEVICE_OUT_REQTYPE =\n                UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;\n\n        public static final int FTDI_DEVICE_IN_REQTYPE =\n                UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;\n\n        /**\n         * Length of the modem status header, transmitted with every read.\n         */\n        private static final int MODEM_STATUS_HEADER_LENGTH = 2;\n\n        private final String TAG = FtdiSerialDriver.class.getSimpleName();\n\n        private DeviceType mType;\n\n        private int mInterface = 0; /* INTERFACE_ANY */\n\n        private int mMaxPacketSize = 64; // TODO(mikey): detect\n\n        /**\n         * Due to http://b.android.com/28023 , we cannot use UsbRequest async reads\n         * since it gives no indication of number of bytes read. Set this to\n         * {@code true} on platforms where it is fixed.\n         */\n        private static final boolean ENABLE_ASYNC_READS = false;\n\n        public FtdiSerialPort(UsbDevice device, int portNumber) {\n            super(device, portNumber);\n        }\n\n        @Override\n        public UsbSerialDriver getDriver() {\n            return FtdiSerialDriver.this;\n        }\n\n        /**\n         * Filter FTDI status bytes from buffer\n         * @param src The source buffer (which contains status bytes)\n         * @param dest The destination buffer to write the status bytes into (can be src)\n         * @param totalBytesRead Number of bytes read to src\n         * @param maxPacketSize The USB endpoint max packet size\n         * @return The number of payload bytes\n         */\n        private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {\n            final int packetsCount = totalBytesRead / maxPacketSize + (totalBytesRead % maxPacketSize == 0 ? 0 : 1);\n            for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {\n                final int count = (packetIdx == (packetsCount - 1))\n                        ? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH\n                        : maxPacketSize - MODEM_STATUS_HEADER_LENGTH;\n                if (count > 0) {\n                    System.arraycopy(src,\n                            packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH,\n                            dest,\n                            packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH),\n                            count);\n                }\n            }\n\n          return totalBytesRead - (packetsCount * 2);\n        }\n        public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {\n            if (false) {\n                final UsbRequest request = new UsbRequest();\n                try {\n                    request.initialize(connection, null);\n                    final ByteBuffer buf = ByteBuffer.wrap(dest);\n                    if (!request.queue(buf, dest.length)) {\n                        throw new IOException(\"Error queueing request.\");\n                    }\n\n                    final UsbRequest response = connection.requestWait();\n                    if (response == null) {\n                        throw new IOException(\"Null response\");\n                    }\n\n                    final int nread = buf.position();\n                    if (nread > 0) {\n                        //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));\n                        return nread;\n                    } else {\n                        return 0;\n                    }\n                } finally {\n                    request.close();\n                }\n            }\n\n            final int numBytesRead;\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                numBytesRead = connection.bulkTransfer(null, mReadBuffer, readAmt,\n                        timeoutMillis);\n                if (numBytesRead < 0) {\n                    // This sucks: we get -1 on timeout, not 0 as preferred.\n                    // We *should* use UsbRequest, except it has a bug/api oversight\n                    // where there is no way to determine the number of bytes read\n                    // in response :\\ -- http://b.android.com/28023\n                    if (timeoutMillis == Integer.MAX_VALUE) {\n                        // Hack: Special case \"~infinite timeout\" as an error.\n                        return -1;\n                    }\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n            }\n            return numBytesRead;\n        }\n        public void reset() throws IOException {\n            int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,\n                    SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);\n            if (result != 0) {\n                throw new IOException(\"Reset failed: result=\" + result);\n            }\n\n            // TODO(mikey): autodetect.\n            mType = DeviceType.TYPE_R;\n        }\n\n        @Override\n        public void open(UsbDeviceConnection connection) throws IOException {\n            if (mConnection != null) {\n                throw new IOException(\"Already open\");\n            }\n            mConnection = connection;\n\n            boolean opened = false;\n            try {\n                for (int i = 0; i < mDevice.getInterfaceCount(); i++) {\n                    if (connection.claimInterface(mDevice.getInterface(i), true)) {\n                        Log.d(TAG, \"claimInterface \" + i + \" SUCCESS\");\n                    } else {\n                        throw new IOException(\"Error claiming interface \" + i);\n                    }\n                }\n                reset();\n                opened = true;\n            } finally {\n                if (!opened) {\n                    close();\n                    mConnection = null;\n                }\n            }\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (mConnection == null) {\n                throw new IOException(\"Already closed\");\n            }\n            try {\n                mConnection.close();\n            } finally {\n                mConnection = null;\n            }\n        }\n\n        @Override\n        public int read(byte[] dest, int timeoutMillis) throws IOException {\n            final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);\n\n            if (ENABLE_ASYNC_READS) {\n                final int readAmt;\n                synchronized (mReadBufferLock) {\n                    // mReadBuffer is only used for maximum read size.\n                    readAmt = Math.min(dest.length, mReadBuffer.length);\n                }\n\n                final UsbRequest request = new UsbRequest();\n                request.initialize(mConnection, endpoint);\n\n                final ByteBuffer buf = ByteBuffer.wrap(dest);\n                if (!request.queue(buf, readAmt)) {\n                    throw new IOException(\"Error queueing request.\");\n                }\n\n                final UsbRequest response = mConnection.requestWait();\n                if (response == null) {\n                    throw new IOException(\"Null response\");\n                }\n\n                final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;\n                if (payloadBytesRead > 0) {\n                    Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));\n                    return payloadBytesRead;\n                } else {\n                    return 0;\n                }\n            } else {\n                final int totalBytesRead;\n\n                synchronized (mReadBufferLock) {\n                    final int readAmt = Math.min(dest.length, mReadBuffer.length);\n                    totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,\n                            readAmt, timeoutMillis);\n\n                    if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {\n                        throw new IOException(\"Expected at least \" + MODEM_STATUS_HEADER_LENGTH + \" bytes\");\n                    }\n\n                    return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());\n                }\n            }\n        }\n\n        @Override\n        public int write(byte[] src, int timeoutMillis) throws IOException {\n            final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);\n            int offset = 0;\n\n            while (offset < src.length) {\n                final int writeLength;\n                final int amtWritten;\n\n                synchronized (mWriteBufferLock) {\n                    final byte[] writeBuffer;\n\n                    writeLength = Math.min(src.length - offset, mWriteBuffer.length);\n                    if (offset == 0) {\n                        writeBuffer = src;\n                    } else {\n                        // bulkTransfer does not support offsets, make a copy.\n                        System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);\n                        writeBuffer = mWriteBuffer;\n                    }\n\n                    amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,\n                            timeoutMillis);\n                }\n\n                if (amtWritten <= 0) {\n                    throw new IOException(\"Error writing \" + writeLength\n                            + \" bytes at offset \" + offset + \" length=\" + src.length);\n                }\n\n                Log.d(TAG, \"Wrote amtWritten=\" + amtWritten + \" attempted=\" + writeLength);\n                offset += amtWritten;\n            }\n            return offset;\n        }\n\n        private int setBaudRate(int baudRate) throws IOException {\n            long[] vals = convertBaudrate(baudRate);\n            long actualBaudrate = vals[0];\n            long index = vals[1];\n            long value = vals[2];\n            int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,\n                    SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index,\n                    null, 0, USB_WRITE_TIMEOUT_MILLIS);\n            if (result != 0) {\n                throw new IOException(\"Setting baudrate failed: result=\" + result);\n            }\n            return (int) actualBaudrate;\n        }\n\n        @Override\n        public void setParameters(int baudRate, int dataBits, int stopBits, int parity)\n                throws IOException {\n            setBaudRate(baudRate);\n\n            int config = dataBits;\n\n            switch (parity) {\n                case PARITY_NONE:\n                    config |= (0x00 << 8);\n                    break;\n                case PARITY_ODD:\n                    config |= (0x01 << 8);\n                    break;\n                case PARITY_EVEN:\n                    config |= (0x02 << 8);\n                    break;\n                case PARITY_MARK:\n                    config |= (0x03 << 8);\n                    break;\n                case PARITY_SPACE:\n                    config |= (0x04 << 8);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown parity value: \" + parity);\n            }\n\n            switch (stopBits) {\n                case STOPBITS_1:\n                    config |= (0x00 << 11);\n                    break;\n                case STOPBITS_1_5:\n                    config |= (0x01 << 11);\n                    break;\n                case STOPBITS_2:\n                    config |= (0x02 << 11);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown stopBits value: \" + stopBits);\n            }\n\n            int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,\n                    SIO_SET_DATA_REQUEST, config, 0 /* index */,\n                    null, 0, USB_WRITE_TIMEOUT_MILLIS);\n            if (result != 0) {\n                throw new IOException(\"Setting parameters failed: result=\" + result);\n            }\n        }\n\n        private long[] convertBaudrate(int baudrate) {\n            // TODO(mikey): Braindead transcription of libfti method.  Clean up,\n            // using more idiomatic Java where possible.\n            int divisor = 24000000 / baudrate;\n            int bestDivisor = 0;\n            int bestBaud = 0;\n            int bestBaudDiff = 0;\n            int fracCode[] = {\n                    0, 3, 2, 4, 1, 5, 6, 7\n            };\n\n            for (int i = 0; i < 2; i++) {\n                int tryDivisor = divisor + i;\n                int baudEstimate;\n                int baudDiff;\n\n                if (tryDivisor <= 8) {\n                    // Round up to minimum supported divisor\n                    tryDivisor = 8;\n                } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) {\n                    // BM doesn't support divisors 9 through 11 inclusive\n                    tryDivisor = 12;\n                } else if (divisor < 16) {\n                    // AM doesn't support divisors 9 through 15 inclusive\n                    tryDivisor = 16;\n                } else {\n                    if (mType == DeviceType.TYPE_AM) {\n                        // TODO\n                    } else {\n                        if (tryDivisor > 0x1FFFF) {\n                            // Round down to maximum supported divisor value (for\n                            // BM)\n                            tryDivisor = 0x1FFFF;\n                        }\n                    }\n                }\n\n                // Get estimated baud rate (to nearest integer)\n                baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor;\n\n                // Get absolute difference from requested baud rate\n                if (baudEstimate < baudrate) {\n                    baudDiff = baudrate - baudEstimate;\n                } else {\n                    baudDiff = baudEstimate - baudrate;\n                }\n\n                if (i == 0 || baudDiff < bestBaudDiff) {\n                    // Closest to requested baud rate so far\n                    bestDivisor = tryDivisor;\n                    bestBaud = baudEstimate;\n                    bestBaudDiff = baudDiff;\n                    if (baudDiff == 0) {\n                        // Spot on! No point trying\n                        break;\n                    }\n                }\n            }\n\n            // Encode the best divisor value\n            long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14);\n            // Deal with special cases for encoded value\n            if (encodedDivisor == 1) {\n                encodedDivisor = 0; // 3000000 baud\n            } else if (encodedDivisor == 0x4001) {\n                encodedDivisor = 1; // 2000000 baud (BM only)\n            }\n\n            // Split into \"value\" and \"index\" values\n            long value = encodedDivisor & 0xFFFF;\n            long index;\n            if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H\n                    || mType == DeviceType.TYPE_4232H) {\n                index = (encodedDivisor >> 8) & 0xffff;\n                index &= 0xFF00;\n                index |= 0 /* TODO mIndex */;\n            } else {\n                index = (encodedDivisor >> 16) & 0xffff;\n            }\n\n            // Return the nearest baud rate\n            return new long[] {\n                    bestBaud, index, value\n            };\n        }\n\n        @Override\n        public boolean getCD() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getCTS() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getDSR() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getDTR() throws IOException {\n            return false;\n        }\n\n        @Override\n        public void setDTR(boolean value) throws IOException {\n        }\n\n        @Override\n        public boolean getRI() throws IOException {\n            return false;\n        }\n\n        @Override\n        public boolean getRTS() throws IOException {\n            return false;\n        }\n\n        @Override\n        public void setRTS(boolean value) throws IOException {\n        }\n\n        @Override\n        public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {\n            if (purgeReadBuffers) {\n                int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,\n                        SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);\n                if (result != 0) {\n                    throw new IOException(\"Flushing RX failed: result=\" + result);\n                }\n            }\n\n            if (purgeWriteBuffers) {\n                int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,\n                        SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);\n                if (result != 0) {\n                    throw new IOException(\"Flushing RX failed: result=\" + result);\n                }\n            }\n            return true;\n        }\n    }\n\n    public static Map<Integer, int[]> getSupportedDevices() {\n        final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),\n                new int[] {\n                    UsbId.FTDI_FT232R,\n                    UsbId.FTDI_FT231X,\n                });\n        return supportedDevices;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/ProbeTable.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.util.Pair;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Maps (vendor id, product id) pairs to the corresponding serial driver.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic class ProbeTable {\n\n    private final Map<Pair<Integer, Integer>, Class<? extends UsbSerialDriver>> mProbeTable =\n            new LinkedHashMap<Pair<Integer,Integer>, Class<? extends UsbSerialDriver>>();\n\n    /**\n     * Adds or updates a (vendor, product) pair in the table.\n     *\n     * @param vendorId the USB vendor id\n     * @param productId the USB product id\n     * @param driverClass the driver class responsible for this pair\n     * @return {@code this}, for chaining\n     */\n    public ProbeTable addProduct(int vendorId, int productId,\n            Class<? extends UsbSerialDriver> driverClass) {\n        mProbeTable.put(Pair.create(vendorId, productId), driverClass);\n        return this;\n    }\n\n    /**\n     * Internal method to add all supported products from\n     * {@code getSupportedProducts} static method.\n     *\n     * @param driverClass\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    ProbeTable addDriver(Class<? extends UsbSerialDriver> driverClass) {\n        final Method method;\n\n        try {\n            method = driverClass.getMethod(\"getSupportedDevices\");\n        } catch (SecurityException e) {\n            throw new RuntimeException(e);\n        } catch (NoSuchMethodException e) {\n            throw new RuntimeException(e);\n        }\n\n        final Map<Integer, int[]> devices;\n        try {\n            devices = (Map<Integer, int[]>) method.invoke(null);\n        } catch (IllegalArgumentException e) {\n            throw new RuntimeException(e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        } catch (InvocationTargetException e) {\n            throw new RuntimeException(e);\n        }\n\n        for (Map.Entry<Integer, int[]> entry : devices.entrySet()) {\n            final int vendorId = entry.getKey().intValue();\n            for (int productId : entry.getValue()) {\n                addProduct(vendorId, productId, driverClass);\n            }\n        }\n\n        return this;\n    }\n\n    /**\n     * Returns the driver for the given (vendor, product) pair, or {@code null}\n     * if no match.\n     *\n     * @param vendorId the USB vendor id\n     * @param productId the USB product id\n     * @return the driver class matching this pair, or {@code null}\n     */\n    public Class<? extends UsbSerialDriver> findDriver(int vendorId, int productId) {\n        final Pair<Integer, Integer> pair = Pair.create(vendorId, productId);\n        return mProbeTable.get(pair);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/ProlificSerialDriver.java",
    "content": "/* This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\n/*\n * Ported to usb-serial-for-android\n * by Felix Hädicke <felixhaedicke@web.de>\n *\n * Based on the pyprolific driver written\n * by Emmanuel Blot <emmanuel.blot@free.fr>\n * See https://github.com/eblot/pyftdi\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbConstants;\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbEndpoint;\nimport android.hardware.usb.UsbInterface;\nimport android.hardware.usb.UsbRequest;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ProlificSerialDriver implements UsbSerialDriver {\n\n    private final String TAG = ProlificSerialDriver.class.getSimpleName();\n\n    private final UsbDevice mDevice;\n    private final UsbSerialPort mPort;\n\n    public ProlificSerialDriver(UsbDevice device) {\n        mDevice = device;\n        mPort = new ProlificSerialPort(mDevice, 0);\n    }\n\n    @Override\n    public List<UsbSerialPort> getPorts() {\n        return Collections.singletonList(mPort);\n    }\n\n    @Override\n    public UsbDevice getDevice() {\n        return mDevice;\n    }\n\n    class ProlificSerialPort extends CommonUsbSerialPort {\n\n        private static final int USB_READ_TIMEOUT_MILLIS = 1000;\n        private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;\n\n        private static final int USB_RECIP_INTERFACE = 0x01;\n\n        private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;\n        private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;\n\n        private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT\n                | UsbConstants.USB_TYPE_VENDOR;\n\n        private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN\n                | UsbConstants.USB_TYPE_VENDOR;\n\n        private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT\n                | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;\n\n        private static final int WRITE_ENDPOINT = 0x02;\n        private static final int READ_ENDPOINT = 0x83;\n        private static final int INTERRUPT_ENDPOINT = 0x81;\n\n        private static final int FLUSH_RX_REQUEST = 0x08;\n        private static final int FLUSH_TX_REQUEST = 0x09;\n\n        private static final int SET_LINE_REQUEST = 0x20;\n        private static final int SET_CONTROL_REQUEST = 0x22;\n\n        private static final int CONTROL_DTR = 0x01;\n        private static final int CONTROL_RTS = 0x02;\n\n        private static final int STATUS_FLAG_CD = 0x01;\n        private static final int STATUS_FLAG_DSR = 0x02;\n        private static final int STATUS_FLAG_RI = 0x08;\n        private static final int STATUS_FLAG_CTS = 0x80;\n\n        private static final int STATUS_BUFFER_SIZE = 10;\n        private static final int STATUS_BYTE_IDX = 8;\n\n        private static final int DEVICE_TYPE_HX = 0;\n        private static final int DEVICE_TYPE_0 = 1;\n        private static final int DEVICE_TYPE_1 = 2;\n\n        private int mDeviceType = DEVICE_TYPE_HX;\n\n        private UsbEndpoint mReadEndpoint;\n        private UsbEndpoint mWriteEndpoint;\n        private UsbEndpoint mInterruptEndpoint;\n\n        private int mControlLinesValue = 0;\n\n        private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;\n\n        private int mStatus = 0;\n        private volatile Thread mReadStatusThread = null;\n        private final Object mReadStatusThreadLock = new Object();\n        boolean mStopReadStatusThread = false;\n        private IOException mReadStatusException = null;\n\n\n        public ProlificSerialPort(UsbDevice device, int portNumber) {\n            super(device, portNumber);\n        }\n\n        @Override\n        public UsbSerialDriver getDriver() {\n            return ProlificSerialDriver.this;\n        }\n\n        private final byte[] inControlTransfer(int requestType, int request,\n                int value, int index, int length) throws IOException {\n            byte[] buffer = new byte[length];\n            int result = mConnection.controlTransfer(requestType, request, value,\n                    index, buffer, length, USB_READ_TIMEOUT_MILLIS);\n            if (result != length) {\n                throw new IOException(\n                        String.format(\"ControlTransfer with value 0x%x failed: %d\",\n                                value, result));\n            }\n            return buffer;\n        }\n\n        private final void outControlTransfer(int requestType, int request,\n                int value, int index, byte[] data) throws IOException {\n            int length = (data == null) ? 0 : data.length;\n            int result = mConnection.controlTransfer(requestType, request, value,\n                    index, data, length, USB_WRITE_TIMEOUT_MILLIS);\n            if (result != length) {\n                throw new IOException(\n                        String.format(\"ControlTransfer with value 0x%x failed: %d\",\n                                value, result));\n            }\n        }\n        public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {\n            if (false) {\n                final UsbRequest request = new UsbRequest();\n                try {\n                    request.initialize(connection, mReadEndpoint);\n                    final ByteBuffer buf = ByteBuffer.wrap(dest);\n                    if (!request.queue(buf, dest.length)) {\n                        throw new IOException(\"Error queueing request.\");\n                    }\n\n                    final UsbRequest response = connection.requestWait();\n                    if (response == null) {\n                        throw new IOException(\"Null response\");\n                    }\n\n                    final int nread = buf.position();\n                    if (nread > 0) {\n                        //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));\n                        return nread;\n                    } else {\n                        return 0;\n                    }\n                } finally {\n                    request.close();\n                }\n            }\n\n            final int numBytesRead;\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                numBytesRead = connection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,\n                        timeoutMillis);\n                if (numBytesRead < 0) {\n                    // This sucks: we get -1 on timeout, not 0 as preferred.\n                    // We *should* use UsbRequest, except it has a bug/api oversight\n                    // where there is no way to determine the number of bytes read\n                    // in response :\\ -- http://b.android.com/28023\n                    if (timeoutMillis == Integer.MAX_VALUE) {\n                        // Hack: Special case \"~infinite timeout\" as an error.\n                        return -1;\n                    }\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n            }\n            return numBytesRead;\n        }\n        private final byte[] vendorIn(int value, int index, int length)\n                throws IOException {\n            return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE,\n                    PROLIFIC_VENDOR_READ_REQUEST, value, index, length);\n        }\n\n        private final void vendorOut(int value, int index, byte[] data)\n                throws IOException {\n            outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE,\n                    PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);\n        }\n\n        private void resetDevice() throws IOException {\n            purgeHwBuffers(true, true);\n        }\n\n        private final void ctrlOut(int request, int value, int index, byte[] data)\n                throws IOException {\n            outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index,\n                    data);\n        }\n\n        private void doBlackMagic() throws IOException {\n            vendorIn(0x8484, 0, 1);\n            vendorOut(0x0404, 0, null);\n            vendorIn(0x8484, 0, 1);\n            vendorIn(0x8383, 0, 1);\n            vendorIn(0x8484, 0, 1);\n            vendorOut(0x0404, 1, null);\n            vendorIn(0x8484, 0, 1);\n            vendorIn(0x8383, 0, 1);\n            vendorOut(0, 1, null);\n            vendorOut(1, 0, null);\n            vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null);\n        }\n\n        private void setControlLines(int newControlLinesValue) throws IOException {\n            ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null);\n            mControlLinesValue = newControlLinesValue;\n        }\n\n        private final void readStatusThreadFunction() {\n            try {\n                while (!mStopReadStatusThread) {\n                    byte[] buffer = new byte[STATUS_BUFFER_SIZE];\n                    int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint,\n                            buffer,\n                            STATUS_BUFFER_SIZE,\n                            500);\n                    if (readBytesCount > 0) {\n                        if (readBytesCount == STATUS_BUFFER_SIZE) {\n                            mStatus = buffer[STATUS_BYTE_IDX] & 0xff;\n                        } else {\n                            throw new IOException(\n                                    String.format(\"Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d\",\n                                            STATUS_BUFFER_SIZE,\n                                            readBytesCount));\n                        }\n                    }\n                }\n            } catch (IOException e) {\n                mReadStatusException = e;\n            }\n        }\n\n        private final int getStatus() throws IOException {\n            if ((mReadStatusThread == null) && (mReadStatusException == null)) {\n                synchronized (mReadStatusThreadLock) {\n                    if (mReadStatusThread == null) {\n                        byte[] buffer = new byte[STATUS_BUFFER_SIZE];\n                        int readBytes = mConnection.bulkTransfer(mInterruptEndpoint,\n                                buffer,\n                                STATUS_BUFFER_SIZE,\n                                100);\n                        if (readBytes != STATUS_BUFFER_SIZE) {\n                            Log.w(TAG, \"Could not read initial CTS / DSR / CD / RI status\");\n                        } else {\n                            mStatus = buffer[STATUS_BYTE_IDX] & 0xff;\n                        }\n\n                        mReadStatusThread = new Thread(new Runnable() {\n                            @Override\n                            public void run() {\n                                readStatusThreadFunction();\n                            }\n                        });\n                        mReadStatusThread.setDaemon(true);\n                        mReadStatusThread.start();\n                    }\n                }\n            }\n\n            /* throw and clear an exception which occured in the status read thread */\n            IOException readStatusException = mReadStatusException;\n            if (mReadStatusException != null) {\n                mReadStatusException = null;\n                throw readStatusException;\n            }\n\n            return mStatus;\n        }\n\n        private final boolean testStatusFlag(int flag) throws IOException {\n            return ((getStatus() & flag) == flag);\n        }\n\n        @Override\n        public void open(UsbDeviceConnection connection) throws IOException {\n            if (mConnection != null) {\n                throw new IOException(\"Already open\");\n            }\n\n            UsbInterface usbInterface = mDevice.getInterface(0);\n\n            if (!connection.claimInterface(usbInterface, true)) {\n                throw new IOException(\"Error claiming Prolific interface 0\");\n            }\n\n            mConnection = connection;\n            boolean opened = false;\n            try {\n                for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {\n                    UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i);\n\n                    switch (currentEndpoint.getAddress()) {\n                    case READ_ENDPOINT:\n                        mReadEndpoint = currentEndpoint;\n                        break;\n\n                    case WRITE_ENDPOINT:\n                        mWriteEndpoint = currentEndpoint;\n                        break;\n\n                    case INTERRUPT_ENDPOINT:\n                        mInterruptEndpoint = currentEndpoint;\n                        break;\n                    }\n                }\n\n                if (mDevice.getDeviceClass() == 0x02) {\n                    mDeviceType = DEVICE_TYPE_0;\n                } else {\n                    try {\n                        Method getRawDescriptorsMethod\n                            = mConnection.getClass().getMethod(\"getRawDescriptors\");\n                        byte[] rawDescriptors\n                            = (byte[]) getRawDescriptorsMethod.invoke(mConnection);\n                        byte maxPacketSize0 = rawDescriptors[7];\n                        if (maxPacketSize0 == 64) {\n                            mDeviceType = DEVICE_TYPE_HX;\n                        } else if ((mDevice.getDeviceClass() == 0x00)\n                                || (mDevice.getDeviceClass() == 0xff)) {\n                            mDeviceType = DEVICE_TYPE_1;\n                        } else {\n                          Log.w(TAG, \"Could not detect PL2303 subtype, \"\n                              + \"Assuming that it is a HX device\");\n                          mDeviceType = DEVICE_TYPE_HX;\n                        }\n                    } catch (NoSuchMethodException e) {\n                        Log.w(TAG, \"Method UsbDeviceConnection.getRawDescriptors, \"\n                                + \"required for PL2303 subtype detection, not \"\n                                + \"available! Assuming that it is a HX device\");\n                        mDeviceType = DEVICE_TYPE_HX;\n                    } catch (Exception e) {\n                        Log.e(TAG, \"An unexpected exception occured while trying \"\n                                + \"to detect PL2303 subtype\", e);\n                    }\n                }\n\n                setControlLines(mControlLinesValue);\n                resetDevice();\n\n                doBlackMagic();\n                opened = true;\n            } finally {\n                if (!opened) {\n                    mConnection = null;\n                    connection.releaseInterface(usbInterface);\n                }\n            }\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (mConnection == null) {\n                throw new IOException(\"Already closed\");\n            }\n            try {\n                mStopReadStatusThread = true;\n                synchronized (mReadStatusThreadLock) {\n                    if (mReadStatusThread != null) {\n                        try {\n                            mReadStatusThread.join();\n                        } catch (Exception e) {\n                            Log.w(TAG, \"An error occured while waiting for status read thread\", e);\n                        }\n                    }\n                }\n                resetDevice();\n            } finally {\n                try {\n                    mConnection.releaseInterface(mDevice.getInterface(0));\n                } finally {\n                    mConnection = null;\n                }\n            }\n        }\n\n        @Override\n        public int read(byte[] dest, int timeoutMillis) throws IOException {\n            synchronized (mReadBufferLock) {\n                int readAmt = Math.min(dest.length, mReadBuffer.length);\n                int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,\n                        readAmt, timeoutMillis);\n                if (numBytesRead < 0) {\n                    return 0;\n                }\n                System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);\n                return numBytesRead;\n            }\n        }\n\n        @Override\n        public int write(byte[] src, int timeoutMillis) throws IOException {\n            int offset = 0;\n\n            while (offset < src.length) {\n                final int writeLength;\n                final int amtWritten;\n\n                synchronized (mWriteBufferLock) {\n                    final byte[] writeBuffer;\n\n                    writeLength = Math.min(src.length - offset, mWriteBuffer.length);\n                    if (offset == 0) {\n                        writeBuffer = src;\n                    } else {\n                        // bulkTransfer does not support offsets, make a copy.\n                        System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);\n                        writeBuffer = mWriteBuffer;\n                    }\n\n                    amtWritten = mConnection.bulkTransfer(mWriteEndpoint,\n                            writeBuffer, writeLength, timeoutMillis);\n                }\n\n                if (amtWritten <= 0) {\n                    throw new IOException(\"Error writing \" + writeLength\n                            + \" bytes at offset \" + offset + \" length=\"\n                            + src.length);\n                }\n\n                offset += amtWritten;\n            }\n            return offset;\n        }\n\n        @Override\n        public void setParameters(int baudRate, int dataBits, int stopBits,\n                int parity) throws IOException {\n            if ((mBaudRate == baudRate) && (mDataBits == dataBits)\n                    && (mStopBits == stopBits) && (mParity == parity)) {\n                // Make sure no action is performed if there is nothing to change\n                return;\n            }\n\n            byte[] lineRequestData = new byte[7];\n\n            lineRequestData[0] = (byte) (baudRate & 0xff);\n            lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff);\n            lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff);\n            lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff);\n\n            switch (stopBits) {\n            case STOPBITS_1:\n                lineRequestData[4] = 0;\n                break;\n\n            case STOPBITS_1_5:\n                lineRequestData[4] = 1;\n                break;\n\n            case STOPBITS_2:\n                lineRequestData[4] = 2;\n                break;\n\n            default:\n                throw new IllegalArgumentException(\"Unknown stopBits value: \" + stopBits);\n            }\n\n            switch (parity) {\n            case PARITY_NONE:\n                lineRequestData[5] = 0;\n                break;\n\n            case PARITY_ODD:\n                lineRequestData[5] = 1;\n                break;\n\n            case PARITY_MARK:\n                lineRequestData[5] = 3;\n                break;\n\n            case PARITY_SPACE:\n                lineRequestData[5] = 4;\n                break;\n\n            default:\n                throw new IllegalArgumentException(\"Unknown parity value: \" + parity);\n            }\n\n            lineRequestData[6] = (byte) dataBits;\n\n            ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData);\n\n            resetDevice();\n\n            mBaudRate = baudRate;\n            mDataBits = dataBits;\n            mStopBits = stopBits;\n            mParity = parity;\n        }\n\n        @Override\n        public boolean getCD() throws IOException {\n            return testStatusFlag(STATUS_FLAG_CD);\n        }\n\n        @Override\n        public boolean getCTS() throws IOException {\n            return testStatusFlag(STATUS_FLAG_CTS);\n        }\n\n        @Override\n        public boolean getDSR() throws IOException {\n            return testStatusFlag(STATUS_FLAG_DSR);\n        }\n\n        @Override\n        public boolean getDTR() throws IOException {\n            return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR);\n        }\n\n        @Override\n        public void setDTR(boolean value) throws IOException {\n            int newControlLinesValue;\n            if (value) {\n                newControlLinesValue = mControlLinesValue | CONTROL_DTR;\n            } else {\n                newControlLinesValue = mControlLinesValue & ~CONTROL_DTR;\n            }\n            setControlLines(newControlLinesValue);\n        }\n\n        @Override\n        public boolean getRI() throws IOException {\n            return testStatusFlag(STATUS_FLAG_RI);\n        }\n\n        @Override\n        public boolean getRTS() throws IOException {\n            return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS);\n        }\n\n        @Override\n        public void setRTS(boolean value) throws IOException {\n            int newControlLinesValue;\n            if (value) {\n                newControlLinesValue = mControlLinesValue | CONTROL_RTS;\n            } else {\n                newControlLinesValue = mControlLinesValue & ~CONTROL_RTS;\n            }\n            setControlLines(newControlLinesValue);\n        }\n\n        @Override\n        public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {\n            if (purgeReadBuffers) {\n                vendorOut(FLUSH_RX_REQUEST, 0, null);\n            }\n\n            if (purgeWriteBuffers) {\n                vendorOut(FLUSH_TX_REQUEST, 0, null);\n            }\n\n            return purgeReadBuffers || purgeWriteBuffers;\n        }\n    }\n\n    public static Map<Integer, int[]> getSupportedDevices() {\n        final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();\n        supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),\n                new int[] { UsbId.PROLIFIC_PL2303, });\n        return supportedDevices;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbId.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\n/**\n * Registry of USB vendor/product ID constants.\n *\n * Culled from various sources; see\n * <a href=\"http://www.linux-usb.org/usb.ids\">usb.ids</a> for one listing.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic final class UsbId {\n\n    public static final int VENDOR_FTDI = 0x0403;\n    public static final int FTDI_FT232R = 0x6001;\n    public static final int FTDI_FT231X = 0x6015;\n\n    public static final int VENDOR_ATMEL = 0x03EB;\n    public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;\n\n    public static final int VENDOR_ARDUINO = 0x2341;\n    public static final int ARDUINO_UNO = 0x0001;\n    public static final int ARDUINO_MEGA_2560 = 0x0010;\n    public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;\n    public static final int ARDUINO_MEGA_ADK = 0x003f;\n    public static final int ARDUINO_MEGA_2560_R3 = 0x0042;\n    public static final int ARDUINO_UNO_R3 = 0x0043;\n    public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;\n    public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;\n    public static final int ARDUINO_LEONARDO = 0x8036;\n\n    public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;\n    public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;\n\n    public static final int VENDOR_LEAFLABS = 0x1eaf;\n    public static final int LEAFLABS_MAPLE = 0x0004;\n\n    public static final int VENDOR_SILABS = 0x10c4;\n    public static final int SILABS_CP2102 = 0xea60;\n    public static final int SILABS_CP2105 = 0xea70;\n    public static final int SILABS_CP2108 = 0xea71;\n    public static final int SILABS_CP2110 = 0xea80;\n\n    public static final int VENDOR_PROLIFIC = 0x067b;\n    public static final int PROLIFIC_PL2303 = 0x2303;\n\n    private UsbId() {\n        throw new IllegalAccessError(\"Non-instantiable class.\");\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialDriver.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbDevice;\n\nimport java.util.List;\n\n/**\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic interface UsbSerialDriver {\n\n    /**\n     * Returns the raw {@link UsbDevice} backing this port.\n     *\n     * @return the device\n     */\n    public UsbDevice getDevice();\n\n    /**\n     * Returns all available ports for this device. This list must have at least\n     * one entry.\n     *\n     * @return the ports\n     */\n    public List<UsbSerialPort> getPorts();\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialPort.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbDeviceConnection;\nimport android.hardware.usb.UsbManager;\n\nimport java.io.IOException;\n\n/**\n * Interface for a single serial port.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic interface UsbSerialPort {\n\n    /** 5 data bits. */\n    public static final int DATABITS_5 = 5;\n\n    /** 6 data bits. */\n    public static final int DATABITS_6 = 6;\n\n    /** 7 data bits. */\n    public static final int DATABITS_7 = 7;\n\n    /** 8 data bits. */\n    public static final int DATABITS_8 = 8;\n\n    /** No flow control. */\n    public static final int FLOWCONTROL_NONE = 0;\n\n    /** RTS/CTS input flow control. */\n    public static final int FLOWCONTROL_RTSCTS_IN = 1;\n\n    /** RTS/CTS output flow control. */\n    public static final int FLOWCONTROL_RTSCTS_OUT = 2;\n\n    /** XON/XOFF input flow control. */\n    public static final int FLOWCONTROL_XONXOFF_IN = 4;\n\n    /** XON/XOFF output flow control. */\n    public static final int FLOWCONTROL_XONXOFF_OUT = 8;\n\n    /** No parity. */\n    public static final int PARITY_NONE = 0;\n\n    /** Odd parity. */\n    public static final int PARITY_ODD = 1;\n\n    /** Even parity. */\n    public static final int PARITY_EVEN = 2;\n\n    /** Mark parity. */\n    public static final int PARITY_MARK = 3;\n\n    /** Space parity. */\n    public static final int PARITY_SPACE = 4;\n\n    /** 1 stop bit. */\n    public static final int STOPBITS_1 = 1;\n\n    /** 1.5 stop bits. */\n    public static final int STOPBITS_1_5 = 3;\n\n    /** 2 stop bits. */\n    public static final int STOPBITS_2 = 2;\n\n    public UsbSerialDriver getDriver();\n\n    /**\n     * Port number within driver.\n     */\n    public int getPortNumber();\n\n    /**\n     * The serial number of the underlying UsbDeviceConnection, or {@code null}.\n     */\n    public String getSerial();\n\n    /**\n     * Opens and initializes the port. Upon success, caller must ensure that\n     * {@link #close()} is eventually called.\n     *\n     * @param connection an open device connection, acquired with\n     *            {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)}\n     * @throws IOException on error opening or initializing the port.\n     */\n    public void open(UsbDeviceConnection connection) throws IOException;\n\n    /**\n     * Closes the port.\n     *\n     * @throws IOException on error closing the port.\n     */\n    public void close() throws IOException;\n\n    /**\n     * Reads as many bytes as possible into the destination buffer.\n     *\n     * @param dest the destination byte buffer\n     * @param timeoutMillis the timeout for reading\n     * @return the actual number of bytes read\n     * @throws IOException if an error occurred during reading\n     */\n    public int read(final byte[] dest, final int timeoutMillis) throws IOException;\n    public int read(final byte[] dest, final int timeoutMillis, final UsbDeviceConnection connection) throws IOException;\n\n    /**\n     * Writes as many bytes as possible from the source buffer.\n     *\n     * @param src the source byte buffer\n     * @param timeoutMillis the timeout for writing\n     * @return the actual number of bytes written\n     * @throws IOException if an error occurred during writing\n     */\n    public int write(final byte[] src, final int timeoutMillis) throws IOException;\n\n    /**\n     * Sets various serial port parameters.\n     *\n     * @param baudRate baud rate as an integer, for example {@code 115200}.\n     * @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},\n     *            {@link #DATABITS_7}, or {@link #DATABITS_8}.\n     * @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or\n     *            {@link #STOPBITS_2}.\n     * @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},\n     *            {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or\n     *            {@link #PARITY_SPACE}.\n     * @throws IOException on error setting the port parameters\n     */\n    public void setParameters(\n            int baudRate, int dataBits, int stopBits, int parity) throws IOException;\n\n    /**\n     * Gets the CD (Carrier Detect) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getCD() throws IOException;\n\n    /**\n     * Gets the CTS (Clear To Send) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getCTS() throws IOException;\n\n    /**\n     * Gets the DSR (Data Set Ready) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getDSR() throws IOException;\n\n    /**\n     * Gets the DTR (Data Terminal Ready) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getDTR() throws IOException;\n\n    /**\n     * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if\n     * supported.\n     *\n     * @param value the value to set\n     * @throws IOException if an error occurred during writing\n     */\n    public void setDTR(boolean value) throws IOException;\n\n    /**\n     * Gets the RI (Ring Indicator) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getRI() throws IOException;\n\n    /**\n     * Gets the RTS (Request To Send) bit from the underlying UART.\n     *\n     * @return the current state, or {@code false} if not supported.\n     * @throws IOException if an error occurred during reading\n     */\n    public boolean getRTS() throws IOException;\n\n    /**\n     * Sets the RTS (Request To Send) bit on the underlying UART, if\n     * supported.\n     *\n     * @param value the value to set\n     * @throws IOException if an error occurred during writing\n     */\n    public void setRTS(boolean value) throws IOException;\n\n    /**\n     * Flush non-transmitted output data and / or non-read input data\n     * @param flushRX {@code true} to flush non-transmitted output data\n     * @param flushTX {@code true} to flush non-read input data\n     * @return {@code true} if the operation was successful, or\n     * {@code false} if the operation is not supported by the driver or device\n     * @throws IOException if an error occurred during flush\n     */\n    public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException;\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialProber.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\nimport android.hardware.usb.UsbDevice;\nimport android.hardware.usb.UsbManager;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic class UsbSerialProber {\n\n    private final ProbeTable mProbeTable;\n\n    public UsbSerialProber(ProbeTable probeTable) {\n        mProbeTable = probeTable;\n    }\n\n    public static UsbSerialProber getDefaultProber() {\n        return new UsbSerialProber(getDefaultProbeTable());\n    }\n\n    public static ProbeTable getDefaultProbeTable() {\n        final ProbeTable probeTable = new ProbeTable();\n        probeTable.addDriver(CdcAcmSerialDriver.class);\n        probeTable.addDriver(Cp21xxSerialDriver.class);\n        probeTable.addDriver(FtdiSerialDriver.class);\n        probeTable.addDriver(ProlificSerialDriver.class);\n        return probeTable;\n    }\n\n    /**\n     * Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}\n     * from the currently-attached {@link UsbDevice} hierarchy. This method does\n     * not require permission from the Android USB system, since it does not\n     * open any of the devices.\n     *\n     * @param usbManager\n     * @return a list, possibly empty, of all compatible drivers\n     */\n    public List<UsbSerialDriver> findAllDrivers(final UsbManager usbManager) {\n        final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();\n\n        for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {\n            final UsbSerialDriver driver = probeDevice(usbDevice);\n            if (driver != null) {\n                result.add(driver);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Probes a single device for a compatible driver.\n     *\n     * @param usbDevice the usb device to probe\n     * @return a new {@link UsbSerialDriver} compatible with this device, or\n     *         {@code null} if none available.\n     */\n    public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {\n        final int vendorId = usbDevice.getVendorId();\n        final int productId = usbDevice.getProductId();\n\n        final Class<? extends UsbSerialDriver> driverClass =\n                mProbeTable.findDriver(vendorId, productId);\n        if (driverClass != null) {\n            final UsbSerialDriver driver;\n            try {\n                final Constructor<? extends UsbSerialDriver> ctor =\n                        driverClass.getConstructor(UsbDevice.class);\n                driver = ctor.newInstance(usbDevice);\n            } catch (NoSuchMethodException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalArgumentException e) {\n                throw new RuntimeException(e);\n            } catch (InstantiationException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(e);\n            } catch (InvocationTargetException e) {\n                throw new RuntimeException(e);\n            }\n            return driver;\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialRuntimeException.java",
    "content": "/*\n * Copyright 2011 Google Inc.\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;\n\n/**\n * Generic unchecked exception for the usbserial package.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\n@SuppressWarnings(\"serial\")\npublic class UsbSerialRuntimeException extends RuntimeException {\n\n    public UsbSerialRuntimeException() {\n        super();\n    }\n\n    public UsbSerialRuntimeException(String detailMessage, Throwable throwable) {\n        super(detailMessage, throwable);\n    }\n\n    public UsbSerialRuntimeException(String detailMessage) {\n        super(detailMessage);\n    }\n\n    public UsbSerialRuntimeException(Throwable throwable) {\n        super(throwable);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/util/HexDump.java",
    "content": "/*\n * Copyright (C) 2006 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\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util;\n\n/**\n * Clone of Android's HexDump class, for use in debugging. Cosmetic changes\n * only.\n */\npublic class HexDump {\n    private final static char[] HEX_DIGITS = {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'\n    };\n\n    public static String dumpHexString(byte[] array) {\n        return dumpHexString(array, 0, array.length);\n    }\n\n    public static String dumpHexString(byte[] array, int offset, int length) {\n        StringBuilder result = new StringBuilder();\n\n        byte[] line = new byte[16];\n        int lineIndex = 0;\n\n        result.append(\"\\n0x\");\n        result.append(toHexString(offset));\n\n        for (int i = offset; i < offset + length; i++) {\n            if (lineIndex == 16) {\n                result.append(\" \");\n\n                for (int j = 0; j < 16; j++) {\n                    if (line[j] > ' ' && line[j] < '~') {\n                        result.append(new String(line, j, 1));\n                    } else {\n                        result.append(\".\");\n                    }\n                }\n\n                result.append(\"\\n0x\");\n                result.append(toHexString(i));\n                lineIndex = 0;\n            }\n\n            byte b = array[i];\n            result.append(\" \");\n            result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);\n            result.append(HEX_DIGITS[b & 0x0F]);\n\n            line[lineIndex++] = b;\n        }\n\n        if (lineIndex != 16) {\n            int count = (16 - lineIndex) * 3;\n            count++;\n            for (int i = 0; i < count; i++) {\n                result.append(\" \");\n            }\n\n            for (int i = 0; i < lineIndex; i++) {\n                if (line[i] > ' ' && line[i] < '~') {\n                    result.append(new String(line, i, 1));\n                } else {\n                    result.append(\".\");\n                }\n            }\n        }\n\n        return result.toString();\n    }\n\n    public static String toHexString(byte b) {\n        return toHexString(toByteArray(b));\n    }\n\n    public static String toHexString(byte[] array) {\n        return toHexString(array, 0, array.length);\n    }\n\n    public static String toHexString(byte[] array, int offset, int length) {\n        char[] buf = new char[length * 2];\n\n        int bufIndex = 0;\n        for (int i = offset; i < offset + length; i++) {\n            byte b = array[i];\n            buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];\n            buf[bufIndex++] = HEX_DIGITS[b & 0x0F];\n        }\n\n        return new String(buf);\n    }\n\n    public static String toHexString(int i) {\n        return toHexString(toByteArray(i));\n    }\n\n    public static String toHexString(short i) {\n        return toHexString(toByteArray(i));\n    }\n\n    public static byte[] toByteArray(byte b) {\n        byte[] array = new byte[1];\n        array[0] = b;\n        return array;\n    }\n\n    public static byte[] toByteArray(int i) {\n        byte[] array = new byte[4];\n\n        array[3] = (byte) (i & 0xFF);\n        array[2] = (byte) ((i >> 8) & 0xFF);\n        array[1] = (byte) ((i >> 16) & 0xFF);\n        array[0] = (byte) ((i >> 24) & 0xFF);\n\n        return array;\n    }\n\n    public static byte[] toByteArray(short i) {\n        byte[] array = new byte[2];\n\n        array[1] = (byte) (i & 0xFF);\n        array[0] = (byte) ((i >> 8) & 0xFF);\n\n        return array;\n    }\n\n    private static int toByte(char c) {\n        if (c >= '0' && c <= '9')\n            return (c - '0');\n        if (c >= 'A' && c <= 'F')\n            return (c - 'A' + 10);\n        if (c >= 'a' && c <= 'f')\n            return (c - 'a' + 10);\n\n        throw new RuntimeException(\"Invalid hex char '\" + c + \"'\");\n    }\n\n    public static byte[] hexStringToByteArray(String hexString) {\n        int length = hexString.length();\n        byte[] buffer = new byte[length / 2];\n\n        for (int i = 0; i < length; i += 2) {\n            buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString\n                    .charAt(i + 1)));\n        }\n\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/util/SerialInputOutputManager.java",
    "content": "/* Copyright 2011-2013 Google Inc.\n * Copyright 2013 mike wakerly <opensource@hoho.com>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library 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 GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Project home page: https://github.com/mik3y/usb-serial-for-android\n */\n\npackage com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util;\n\nimport android.hardware.usb.UsbRequest;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialPort;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\n/**\n * Utility class which services a {@link UsbSerialPort} in its {@link #run()}\n * method.\n *\n * @author mike wakerly (opensource@hoho.com)\n */\npublic class SerialInputOutputManager implements Runnable {\n\n    private static final String TAG = SerialInputOutputManager.class.getSimpleName();\n    private static final boolean DEBUG = true;\n\n    private static final int READ_WAIT_MILLIS = 200;\n    private static final int BUFSIZ = 4096;\n\n    private final UsbSerialPort mDriver;\n\n    private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);\n\n    // Synchronized by 'mWriteBuffer'\n    private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);\n\n    private enum State {\n        STOPPED,\n        RUNNING,\n        STOPPING\n    }\n\n    // Synchronized by 'this'\n    private State mState = State.STOPPED;\n\n    // Synchronized by 'this'\n    private Listener mListener;\n\n    public interface Listener {\n        /**\n         * Called when new incoming data is available.\n         */\n        public void onNewData(byte[] data);\n\n        /**\n         * Called when {@link SerialInputOutputManager#run()} aborts due to an\n         * error.\n         */\n        public void onRunError(Exception e);\n    }\n\n    /**\n     * Creates a new instance with no listener.\n     */\n    public SerialInputOutputManager(UsbSerialPort driver) {\n        this(driver, null);\n    }\n\n    /**\n     * Creates a new instance with the provided listener.\n     */\n    public SerialInputOutputManager(UsbSerialPort driver, Listener listener) {\n        mDriver = driver;\n        mListener = listener;\n    }\n\n    public synchronized void setListener(Listener listener) {\n        mListener = listener;\n    }\n\n    public synchronized Listener getListener() {\n        return mListener;\n    }\n\n    public void writeAsync(byte[] data) {\n        synchronized (mWriteBuffer) {\n            mWriteBuffer.put(data);\n        }\n    }\n\n    public synchronized void stop() {\n        if (getState() == State.RUNNING) {\n            Log.i(TAG, \"Stop requested\");\n            mState = State.STOPPING;\n        }\n    }\n\n    private synchronized State getState() {\n        return mState;\n    }\n\n    /**\n     * Continuously services the read and write buffers until {@link #stop()} is\n     * called, or until a driver exception is raised.\n     *\n     * NOTE(mikey): Uses inefficient read/write-with-timeout.\n     * TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)}\n     */\n    @Override\n    public void run() {\n        synchronized (this) {\n            if (getState() != State.STOPPED) {\n                throw new IllegalStateException(\"Already running.\");\n            }\n            mState = State.RUNNING;\n        }\n\n        Log.i(TAG, \"Running ..\");\n        try {\n            while (true) {\n                if (getState() != State.RUNNING) {\n                    Log.i(TAG, \"Stopping mState=\" + getState());\n                    break;\n                }\n                step();\n            }\n        } catch (Exception e) {\n            Log.w(TAG, \"Run ending due to exception: \" + e.getMessage(), e);\n            final Listener listener = getListener();\n            if (listener != null) {\n              listener.onRunError(e);\n            }\n        } finally {\n            synchronized (this) {\n                mState = State.STOPPED;\n                Log.i(TAG, \"Stopped.\");\n            }\n        }\n    }\n\n    private void step() throws IOException {\n        // Handle incoming data.\n        int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS);\n        if (len > 0) {\n            if (DEBUG) Log.d(TAG, \"Read data len=\" + len);\n            final Listener listener = getListener();\n            if (listener != null) {\n                final byte[] data = new byte[len];\n                mReadBuffer.get(data, 0, len);\n                listener.onNewData(data);\n            }\n            mReadBuffer.clear();\n        }\n\n        // Handle outgoing data.\n        byte[] outBuff = null;\n        synchronized (mWriteBuffer) {\n            len = mWriteBuffer.position();\n            if (len > 0) {\n                outBuff = new byte[len];\n                mWriteBuffer.rewind();\n                mWriteBuffer.get(outBuff, 0, len);\n                mWriteBuffer.clear();\n            }\n        }\n        if (outBuff != null) {\n            if (DEBUG) {\n                Log.d(TAG, \"Writing data len=\" + len);\n            }\n            mDriver.write(outBuff, READ_WAIT_MILLIS);\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/BgReadingInterface.java",
    "content": "package com.eveningoutpost.dexdrip.Interfaces;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\n\nimport retrofit.Callback;\nimport retrofit.http.Body;\nimport retrofit.http.POST;\nimport retrofit.http.PUT;\nimport retrofit.http.Path;\n\n/**\n * Created by stephenblack on 11/6/14.\n */\npublic interface BgReadingInterface {\n\n    @POST(\"/api/v1/users/{user_uuid}/BgReadings/new\")\n    void createReading(@Path(\"user_uuid\") String user_uuid, @Body BgReading bgReading, Callback callback);\n\n    @PUT(\"/api/v1/users/{user_uuid}/BgReading/{bgReading_uuid}\")\n    void updateReading(@Path(\"user_uuid\") String user_uuid, @Path(\"bgReading_uuid\") String uuid, @Body BgReading bgReading, Callback callback);\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/CalibrationInterface.java",
    "content": "package com.eveningoutpost.dexdrip.Interfaces;\n\nimport com.eveningoutpost.dexdrip.Models.Calibration;\n\nimport retrofit.Callback;\nimport retrofit.http.Body;\nimport retrofit.http.POST;\nimport retrofit.http.Path;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\npublic interface CalibrationInterface {\n\n    @POST(\"/api/v1/users/{user_uuid}/calibrations/new\")\n    void createCalibration(@Path(\"user_uuid\") String user_uuid, @Body Calibration calibration, Callback callback);\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/SensorInterface.java",
    "content": "package com.eveningoutpost.dexdrip.Interfaces;\n\nimport com.eveningoutpost.dexdrip.Sensor;\n\nimport retrofit.Callback;\nimport retrofit.http.Body;\nimport retrofit.http.POST;\nimport retrofit.http.Path;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\npublic interface SensorInterface {\n\n    @POST(\"/api/v1/users/{user_uuid}/sensors/new\")\n    void createSensor(@Path(\"user_uuid\") String user_uuid, @Body Sensor sensor, Callback callback);\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/UserInterface.java",
    "content": "package com.eveningoutpost.dexdrip.Interfaces;\n\nimport com.eveningoutpost.dexdrip.Models.User;\n\nimport retrofit.Callback;\nimport retrofit.http.Body;\nimport retrofit.http.POST;\n\n/**\n * Created by stephenblack on 11/10/14.\n */\npublic interface UserInterface {\n\n    @POST(\"/api/v1/sessions/new\")\n    void authenticate(@Body User user, Callback callback);\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/LicenseAgreementActivity.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\n\n\npublic class LicenseAgreementActivity extends Activity {\n    boolean IUnderstand;\n    CheckBox agreeCheckBox;\n    Button saveButton;\n    SharedPreferences prefs;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        IUnderstand = prefs.getBoolean(\"I_understand\", false);\n        setContentView(R.layout.activity_license_agreement);\n        agreeCheckBox = (CheckBox)findViewById(R.id.agreeCheckBox);\n        agreeCheckBox.setChecked(IUnderstand);\n        saveButton = (Button)findViewById(R.id.saveButton);\n        addListenerOnButton();\n    }\n\n    public void addListenerOnButton() {\n        saveButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n\n                prefs.edit().putBoolean(\"I_understand\", agreeCheckBox.isChecked()).apply();\n\n                Intent intent = new Intent(getApplicationContext(), Home.class);\n                startActivity(intent);\n                finish();\n            }\n\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/ActiveBluetoothDevice.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.provider.BaseColumns;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\n\n/**\n * Created by stephenblack on 11/3/14.\n */\n@Table(name = \"ActiveBluetoothDevice\", id = BaseColumns._ID)\npublic class ActiveBluetoothDevice extends Model {\n    @Column(name = \"name\")\n    public String name;\n\n    @Column(name = \"address\")\n    public String address;\n\n    @Column(name = \"connected\")\n    public boolean connected;\n\n    public static ActiveBluetoothDevice first() {\n        return new Select()\n                .from(ActiveBluetoothDevice.class)\n                .orderBy(\"_ID asc\")\n                .executeSingle();\n    }\n\n    public static void forget() {\n        ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();\n        if (activeBluetoothDevice != null) {\n            activeBluetoothDevice.delete();\n        }\n    }\n\n    public static void connected() {\n        ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();\n        if(activeBluetoothDevice != null) {\n            activeBluetoothDevice.connected = true;\n            activeBluetoothDevice.save();\n        }\n    }\n\n    public static void disconnected() {\n        ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();\n        if(activeBluetoothDevice != null) {\n            activeBluetoothDevice.connected = false;\n            activeBluetoothDevice.save();\n        }\n    }\n\n    public static boolean is_connected() {\n        ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();\n        if(activeBluetoothDevice != null) {\n            return activeBluetoothDevice.connected;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalSubrecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.Services.DexShareCollectionService;\nimport com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;\nimport com.eveningoutpost.dexdrip.UtilityModels.Constants;\nimport com.eveningoutpost.dexdrip.UtilityModels.Notifications;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.annotations.Expose;\nimport com.google.gson.internal.bind.DateTypeAdapter;\n\nimport java.text.DecimalFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.UUID;\n\n@Table(name = \"BgReadings\", id = BaseColumns._ID)\npublic class BgReading extends Model {\n    private final static String TAG = BgReading.class.getSimpleName();\n    //TODO: Have these as adjustable settings!!\n    public final static double BESTOFFSET = (60000 * 0); // Assume readings are about x minutes off from actual!\n\n    @Column(name = \"sensor\", index = true)\n    public Sensor sensor;\n\n    @Column(name = \"calibration\", index = true)\n    public Calibration calibration;\n\n    @Expose\n    @Column(name = \"timestamp\", index = true)\n    public long timestamp;\n\n    @Expose\n    @Column(name = \"time_since_sensor_started\")\n    public double time_since_sensor_started;\n\n    @Expose\n    @Column(name = \"raw_data\")\n    public double raw_data;\n\n    @Expose\n    @Column(name = \"filtered_data\")\n    public double filtered_data;\n\n    @Expose\n    @Column(name = \"age_adjusted_raw_value\")\n    public double age_adjusted_raw_value;\n\n    @Expose\n    @Column(name = \"calibration_flag\")\n    public boolean calibration_flag;\n\n    @Expose\n    @Column(name = \"calculated_value\")\n    public double calculated_value;\n\n    @Expose\n    @Column(name = \"calculated_value_slope\")\n    public double calculated_value_slope;\n\n    @Expose\n    @Column(name = \"a\")\n    public double a;\n\n    @Expose\n    @Column(name = \"b\")\n    public double b;\n\n    @Expose\n    @Column(name = \"c\")\n    public double c;\n\n    @Expose\n    @Column(name = \"ra\")\n    public double ra;\n\n    @Expose\n    @Column(name = \"rb\")\n    public double rb;\n\n    @Expose\n    @Column(name = \"rc\")\n    public double rc;\n    @Expose\n    @Column(name = \"uuid\", index = true)\n    public String uuid;\n\n    @Expose\n    @Column(name = \"calibration_uuid\")\n    public String calibration_uuid;\n\n    @Expose\n    @Column(name = \"sensor_uuid\", index = true)\n    public String sensor_uuid;\n\n    @Column(name = \"snyced\")\n    public boolean synced;\n\n    @Column(name = \"raw_calculated\")\n    public double raw_calculated;\n\n    @Column(name = \"hide_slope\")\n    public boolean hide_slope;\n\n    @Column(name = \"noise\")\n    public String noise;\n\n    public double calculated_value_mmol() {\n        return mmolConvert(calculated_value);\n    }\n\n    public double mmolConvert(double mgdl) {\n        return mgdl * Constants.MGDL_TO_MMOLL;\n    }\n\n    public String displayValue(Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String unit = prefs.getString(\"units\", \"mgdl\");\n        DecimalFormat df = new DecimalFormat(\"#\");\n        df.setMaximumFractionDigits(0);\n\n        if (calculated_value >= 400) {\n            return \"HIGH\";\n        } else if (calculated_value >= 40) {\n            if(unit.compareTo(\"mgdl\") == 0) {\n                df.setMaximumFractionDigits(0);\n                return df.format(calculated_value);\n            } else {\n                df.setMaximumFractionDigits(1);\n                return df.format(calculated_value_mmol());\n            }\n        } else {\n            return \"LOW\";\n        }\n    }\n\n    public static double activeSlope() {\n        BgReading bgReading = BgReading.lastNoSenssor();\n        double slope = (2 * bgReading.a * (new Date().getTime() + BESTOFFSET)) + bgReading.b;\n        Log.w(TAG, \"ESTIMATE SLOPE\" + slope);\n        return slope;\n    }\n\n    public static double activePrediction() {\n        BgReading bgReading = BgReading.lastNoSenssor();\n        if (bgReading != null) {\n            double currentTime = new Date().getTime();\n            if (currentTime >=  bgReading.timestamp + (60000 * 7)) { currentTime = bgReading.timestamp + (60000 * 7); }\n            double time = currentTime + BESTOFFSET;\n            return ((bgReading.a * time * time) + (bgReading.b * time) + bgReading.c);\n        }\n        return 0;\n    }\n\n    //*******CLASS METHODS***********//\n    public static void create(EGVRecord[] egvRecords, long addativeOffset, Context context) {\n        for(EGVRecord egvRecord : egvRecords) { BgReading.create(egvRecord, addativeOffset, context); }\n    }\n\n    public static void create(SensorRecord[] sensorRecords, long addativeOffset, Context context) {\n        for(SensorRecord sensorRecord : sensorRecords) { BgReading.create(sensorRecord, addativeOffset, context); }\n    }\n\n    public static void create(SensorRecord sensorRecord, long addativeOffset, Context context) {\n        Log.w(TAG, \"gonna make some sensor records: \" + sensorRecord.getUnfiltered());\n        if(BgReading.is_new(sensorRecord, addativeOffset)) {\n            BgReading bgReading = new BgReading();\n            Sensor sensor = Sensor.currentSensor();\n            Calibration calibration = Calibration.getForTimestamp(sensorRecord.getSystemTime().getTime() + addativeOffset);\n            if(sensor != null && calibration != null) {\n                bgReading.sensor = sensor;\n                bgReading.sensor_uuid = sensor.uuid;\n                bgReading.calibration = calibration;\n                bgReading.calibration_uuid = calibration.uuid;\n                bgReading.raw_data = (sensorRecord.getUnfiltered() / 1000);\n                bgReading.filtered_data = (sensorRecord.getFiltered() / 1000);\n                bgReading.timestamp = sensorRecord.getSystemTime().getTime() + addativeOffset;\n                if(bgReading.timestamp > new Date().getTime()) { return; }\n                bgReading.uuid = UUID.randomUUID().toString();\n                bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;\n                bgReading.synced = false;\n                bgReading.calculateAgeAdjustedRawValue();\n                bgReading.save();\n            }\n        }\n    }\n\n    public static void create(EGVRecord egvRecord, long addativeOffset, Context context) {\n        BgReading bgReading = BgReading.getForTimestamp(egvRecord.getSystemTime().getTime() + addativeOffset);\n        Log.w(TAG, \"Looking for BG reading to tag this thing to: \" + egvRecord.getBGValue());\n        if(bgReading != null) {\n            bgReading.calculated_value = egvRecord.getBGValue();\n            if (egvRecord.getBGValue() <= 13) {\n                Calibration calibration = bgReading.calibration;\n                double firstAdjSlope = calibration.first_slope + (calibration.first_decay * (Math.ceil(new Date().getTime() - calibration.timestamp)/(1000 * 60 * 10)));\n                double calSlope = (calibration.first_scale / firstAdjSlope)*1000;\n                double calIntercept = ((calibration.first_scale * calibration.first_intercept) / firstAdjSlope)*-1;\n                bgReading.raw_calculated = (((calSlope * bgReading.raw_data) + calIntercept) - 5);\n                bgReading.noise = egvRecord.noiseValue();\n            }\n            Log.w(TAG, \"NEW VALUE CALCULATED AT: \" + bgReading.calculated_value);\n            bgReading.calculated_value_slope = bgReading.slopefromName(egvRecord.getTrend().friendlyTrendName());\n            if(egvRecord.getTrend().friendlyTrendName().compareTo(\"NOT_COMPUTABLE\") == 0 || egvRecord.getTrend().friendlyTrendName().compareTo(\"OUT_OF_RANGE\") == 0) {\n                bgReading.hide_slope = true;\n            }\n            bgReading.save();\n            bgReading.find_new_curve();\n            bgReading.find_new_raw_curve();\n            Notifications.notificationSetter(context);\n            BgSendQueue.addToQueue(bgReading, \"create\", context);\n        }\n    }\n\n    public static BgReading getForTimestamp(double timestamp) {\n        Sensor sensor = Sensor.currentSensor();\n        if(sensor != null) {\n            BgReading bgReading = new Select()\n                    .from(BgReading.class)\n                    .where(\"Sensor = ? \", sensor.getId())\n                    .where(\"timestamp <= ?\",  (timestamp + (60*1000))) // 1 minute padding (should never be that far off, but why not)\n                    .where(\"calculated_value = 0\")\n                    .where(\"raw_calculated = 0\")\n                    .orderBy(\"timestamp desc\")\n                    .executeSingle();\n            if(bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3*60*1000)) { //cool, so was it actually within 4 minutes of that bg reading?\n                Log.w(TAG, \"Found a BG timestamp match\");\n                return bgReading;\n            }\n        }\n        Log.w(TAG, \"No luck finding a BG timestamp match\");\n        return null;\n    }\n\n    public static boolean is_new(SensorRecord sensorRecord, long addativeOffset) {\n        double timestamp = sensorRecord.getSystemTime().getTime() + addativeOffset;\n        Sensor sensor = Sensor.currentSensor();\n        if(sensor != null) {\n            BgReading bgReading = new Select()\n                    .from(BgReading.class)\n                    .where(\"Sensor = ? \", sensor.getId())\n                    .where(\"timestamp <= ?\",  (timestamp + (60*1000))) // 1 minute padding (should never be that far off, but why not)\n                    .orderBy(\"timestamp desc\")\n                    .executeSingle();\n            if(bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3*60*1000)) { //cool, so was it actually within 4 minutes of that bg reading?\n                Log.w(TAG, \"Old Reading\");\n                return false;\n            }\n        }\n        Log.w(TAG, \"New Reading\");\n        return true;\n    }\n\n    public static BgReading create(double raw_data, Context context, Long timestamp) {\n        BgReading bgReading = new BgReading();\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor != null) {\n            Calibration calibration = Calibration.last();\n            if (calibration == null) {\n                bgReading.sensor = sensor;\n                bgReading.sensor_uuid = sensor.uuid;\n                bgReading.raw_data = (raw_data / 1000);\n                bgReading.filtered_data = (raw_data / 1000);\n                bgReading.timestamp = timestamp;\n                bgReading.uuid = UUID.randomUUID().toString();\n                bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;\n                bgReading.synced = false;\n                bgReading.calibration_flag = false;\n\n                bgReading.calculateAgeAdjustedRawValue();\n\n                bgReading.save();\n                bgReading.perform_calculations();\n            } else {\n\n                bgReading.sensor = sensor;\n                bgReading.sensor_uuid = sensor.uuid;\n                bgReading.calibration = calibration;\n                bgReading.calibration_uuid = calibration.uuid;\n                bgReading.raw_data = (raw_data/1000);\n                bgReading.filtered_data = (raw_data/1000);\n                bgReading.timestamp = timestamp;\n                bgReading.uuid = UUID.randomUUID().toString();\n                bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;\n                bgReading.synced = false;\n\n                bgReading.calculateAgeAdjustedRawValue();\n\n                if(calibration.check_in) {\n                    double firstAdjSlope = calibration.first_slope + (calibration.first_decay * (Math.ceil(new Date().getTime() - calibration.timestamp)/(1000 * 60 * 10)));\n                    double calSlope = (calibration.first_scale / firstAdjSlope)*1000;\n                    double calIntercept = ((calibration.first_scale * calibration.first_intercept) / firstAdjSlope)*-1;\n                    bgReading.calculated_value = (((calSlope * bgReading.raw_data) + calIntercept) - 5);\n\n                } else {\n                    BgReading lastBgReading = BgReading.last();\n                    if (lastBgReading != null && lastBgReading.calibration != null) {\n                        if (lastBgReading.calibration_flag == true && ((lastBgReading.timestamp + (60000 * 20)) > bgReading.timestamp) && ((lastBgReading.calibration.timestamp + (60000 * 20)) > bgReading.timestamp)) {\n                            lastBgReading.calibration.rawValueOverride(BgReading.weightedAverageRaw(lastBgReading.timestamp, bgReading.timestamp, lastBgReading.calibration.timestamp, lastBgReading.age_adjusted_raw_value, bgReading.age_adjusted_raw_value), context);\n                        }\n                    }\n                    bgReading.calculated_value = ((calibration.slope * bgReading.age_adjusted_raw_value) + calibration.intercept);\n                }\n\n                bgReading.calculated_value = Math.min(400, Math.max(40, bgReading.calculated_value));\n                Log.w(TAG, \"NEW VALUE CALCULATED AT: \" + bgReading.calculated_value);\n\n                bgReading.save();\n                bgReading.perform_calculations();\n                Notifications.notificationSetter(context);\n                BgSendQueue.addToQueue(bgReading, \"create\", context);\n            }\n        }\n        Log.w(\"BG GSON: \",bgReading.toS());\n\n        return bgReading;\n    }\n\n    public static String slopeArrow() {\n        double slope = (float) (BgReading.activeSlope() * 60000);\n        return slopeArrow(slope);\n    }\n\n    public static String slopeArrow(double slope) {\n        String arrow;\n        if (slope <= (-3.5)) {\n            arrow = \"\\u21ca\";\n        } else if (slope <= (-2)) {\n            arrow = \"\\u2193\";\n        } else if (slope <= (-1)) {\n            arrow = \"\\u2198\";\n        } else if (slope <= (1)) {\n            arrow = \"\\u2192\";\n        } else if (slope <= (2)) {\n            arrow = \"\\u2197\";\n        } else if (slope <= (3.5)) {\n            arrow = \"\\u2191\";\n        } else {\n            arrow = \"\\u21c8\";\n        }\n        return arrow;\n    }\n\n    public String slopeName() {\n        double slope_by_minute = calculated_value_slope * 60000;\n        String arrow = \"NONE\";\n        if (slope_by_minute <= (-3.5)) {\n            arrow = \"DoubleDown\";\n        } else if (slope_by_minute <= (-2)) {\n            arrow = \"SingleDown\";\n        } else if (slope_by_minute <= (-1)) {\n            arrow = \"FortyFiveDown\";\n        } else if (slope_by_minute <= (1)) {\n            arrow = \"Flat\";\n        } else if (slope_by_minute <= (2)) {\n            arrow = \"FortyFiveUp\";\n        } else if (slope_by_minute <= (3.5)) {\n            arrow = \"SingleUp\";\n        } else if (slope_by_minute <= (40)) {\n            arrow = \"DoubleUp\";\n        }\n        if(hide_slope) {\n            arrow = \"9\";\n        }\n        return arrow;\n    }\n\n    public double slopefromName(String slope_name) {\n        double slope_by_minute = 0;\n        if (slope_name.compareTo(\"DoubleDown\") == 0) {\n            slope_by_minute = -3.5;\n        } else if (slope_name.compareTo(\"SingleDown\") == 0) {\n            slope_by_minute = -2;\n        } else if (slope_name.compareTo(\"FortyFiveDown\") == 0) {\n            slope_by_minute = -1;\n        } else if (slope_name.compareTo(\"Flat\") == 0) {\n            slope_by_minute = 0;\n        } else if (slope_name.compareTo(\"FortyFiveUp\") == 0) {\n            slope_by_minute = 2;\n        } else if (slope_name.compareTo(\"SingleUp\") == 0) {\n            slope_by_minute = 2;\n        } else if (slope_name.compareTo(\"DoubleUp\") == 0) {\n            slope_by_minute = 4;\n        } else if (slope_name.compareTo(\"NOT_COMPUTABLE\") == 0 || slope_name.compareTo(\"OUT_OF_RANGE\") == 0) {\n            slope_by_minute = 0;\n        }\n        return slope_by_minute /60000;\n    }\n\n    public static BgReading last() {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor != null) {\n            return new Select()\n                    .from(BgReading.class)\n                    .where(\"Sensor = ? \", sensor.getId())\n                    .where(\"calculated_value != 0\")\n                    .where(\"raw_data != 0\")\n                    .orderBy(\"timestamp desc\")\n                    .executeSingle();\n        }\n        return null;\n    }\n    public static List<BgReading> latest_by_size(int number) {\n        Sensor sensor = Sensor.currentSensor();\n        return new Select()\n                .from(BgReading.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .limit(number)\n                .execute();\n    }\n\n    public static BgReading lastNoSenssor() {\n        return new Select()\n                .from(BgReading.class)\n                .where(\"calculated_value != 0\")\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .executeSingle();\n    }\n\n    public static List<BgReading> latest(int number) {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(BgReading.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"calculated_value != 0\")\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .limit(number)\n                .execute();\n    }\n\n    public static List<BgReading> latestUnCalculated(int number) {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(BgReading.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .limit(number)\n                .execute();\n    }\n\n    public static List<BgReading> latestForGraph(int number, double startTime) {\n        DecimalFormat df = new DecimalFormat(\"#\");\n        df.setMaximumFractionDigits(1);\n        return new Select()\n                .from(BgReading.class)\n                .where(\"timestamp >= \" + df.format(startTime))\n                .where(\"calculated_value != 0\")\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .limit(number)\n                .execute();\n    }\n\n    public static List<BgReading> last30Minutes() {\n        double timestamp = (new Date().getTime()) - (60000 * 30);\n        return new Select()\n                .from(BgReading.class)\n                .where(\"timestamp >= \" + timestamp)\n                .where(\"calculated_value != 0\")\n                .where(\"raw_data != 0\")\n                .orderBy(\"timestamp desc\")\n                .execute();\n    }\n\n    public static double estimated_bg(double timestamp) {\n        timestamp = timestamp + BESTOFFSET;\n        BgReading latest = BgReading.last();\n        if (latest == null) {\n            return 0;\n        } else {\n            return (latest.a * timestamp * timestamp) + (latest.b * timestamp) + latest.c;\n        }\n    }\n\n    public static double estimated_raw_bg(double timestamp) {\n        timestamp = timestamp + BESTOFFSET;\n        double estimate;\n        BgReading latest = BgReading.last();\n        if (latest == null) {\n            Log.w(TAG, \"No data yet, assume perfect!\");\n            estimate = 160;\n        } else {\n            estimate = (latest.ra * timestamp * timestamp) + (latest.rb * timestamp) + latest.rc;\n        }\n        Log.w(TAG, \"ESTIMATE RAW BG\" + estimate);\n        return estimate;\n    }\n\n    //*******INSTANCE METHODS***********//\n    public void perform_calculations() {\n        find_new_curve();\n        find_new_raw_curve();\n        find_slope();\n    }\n\n    public void find_slope() {\n        List<BgReading> last_2 = BgReading.latest(2);\n        if (last_2.size() == 2) {\n            BgReading second_latest = last_2.get(1);\n            double y1 = calculated_value;\n            double x1 = timestamp;\n            double y2 = second_latest.calculated_value;\n            double x2 = second_latest.timestamp;\n            if(y1 == y2) {\n                calculated_value_slope = 0;\n            } else {\n                calculated_value_slope = (y2 - y1)/(x2 - x1);\n            }\n            save();\n        } else if (last_2.size() == 1) {\n            calculated_value_slope = 0;\n            save();\n        } else {\n            Log.w(TAG, \"NO BG? COULDNT FIND SLOPE!\");\n        }\n    }\n\n    public void find_new_curve() {\n        List<BgReading> last_3 = BgReading.latest(3);\n        if (last_3.size() == 3) {\n            BgReading second_latest = last_3.get(1);\n            BgReading third_latest = last_3.get(2);\n\n            double y3 = calculated_value;\n            double x3 = timestamp;\n            double y2 = second_latest.calculated_value;\n            double x2 = second_latest.timestamp;\n            double y1 = third_latest.calculated_value;\n            double x1 = third_latest.timestamp;\n\n            a = y1/((x1-x2)*(x1-x3))+y2/((x2-x1)*(x2-x3))+y3/((x3-x1)*(x3-x2));\n            b = (-y1*(x2+x3)/((x1-x2)*(x1-x3))-y2*(x1+x3)/((x2-x1)*(x2-x3))-y3*(x1+x2)/((x3-x1)*(x3-x2)));\n            c = (y1*x2*x3/((x1-x2)*(x1-x3))+y2*x1*x3/((x2-x1)*(x2-x3))+y3*x1*x2/((x3-x1)*(x3-x2)));\n\n            Log.w(TAG, \"BG PARABOLIC RATES: \"+a+\"x^2 + \"+b+\"x + \"+c);\n\n            save();\n        } else if (last_3.size() == 2) {\n\n            Log.w(TAG, \"Not enough data to calculate parabolic rates - assume Linear\");\n                BgReading latest = last_3.get(0);\n                BgReading second_latest = last_3.get(1);\n\n                double y2 = latest.calculated_value;\n                double x2 = timestamp;\n                double y1 = second_latest.calculated_value;\n                double x1 = second_latest.timestamp;\n\n                if(y1 == y2) {\n                    b = 0;\n                } else {\n                    b = (y2 - y1)/(x2 - x1);\n                }\n                a = 0;\n                c = -1 * ((latest.b * x1) - y1);\n\n            Log.w(TAG, \"\"+latest.a+\"x^2 + \"+latest.b+\"x + \"+latest.c);\n                save();\n            } else {\n            Log.w(TAG, \"Not enough data to calculate parabolic rates - assume static data\");\n            a = 0;\n            b = 0;\n            c = calculated_value;\n\n            Log.w(TAG, \"\"+a+\"x^2 + \"+b+\"x + \"+c);\n            save();\n        }\n    }\n\n    public void calculateAgeAdjustedRawValue(){\n        double adjust_for = (86400000 * 1.9) - time_since_sensor_started;\n        if (adjust_for > 0) {\n            age_adjusted_raw_value = (((.45) * (adjust_for / (86400000 * 1.9))) * raw_data) + raw_data;\n            Log.w(\"RAW VALUE ADJUSTMENT: \", \"FROM:\" + raw_data + \" TO: \" + age_adjusted_raw_value);\n        } else {\n            age_adjusted_raw_value = raw_data;\n        }\n    }\n\n    public void find_new_raw_curve() {\n        List<BgReading> last_3 = BgReading.latest(3);\n        if (last_3.size() == 3) {\n            BgReading second_latest = last_3.get(1);\n            BgReading third_latest = last_3.get(2);\n\n            double y3 = age_adjusted_raw_value;\n            double x3 = timestamp;\n            double y2 = second_latest.age_adjusted_raw_value;\n            double x2 = second_latest.timestamp;\n            double y1 = third_latest.age_adjusted_raw_value;\n            double x1 = third_latest.timestamp;\n\n            ra = y1/((x1-x2)*(x1-x3))+y2/((x2-x1)*(x2-x3))+y3/((x3-x1)*(x3-x2));\n            rb = (-y1*(x2+x3)/((x1-x2)*(x1-x3))-y2*(x1+x3)/((x2-x1)*(x2-x3))-y3*(x1+x2)/((x3-x1)*(x3-x2)));\n            rc = (y1*x2*x3/((x1-x2)*(x1-x3))+y2*x1*x3/((x2-x1)*(x2-x3))+y3*x1*x2/((x3-x1)*(x3-x2)));\n\n            Log.w(TAG, \"RAW PARABOLIC RATES: \"+ra+\"x^2 + \"+rb+\"x + \"+rc);\n            save();\n        } else if (last_3.size() == 2) {\n            BgReading latest = last_3.get(0);\n            BgReading second_latest = last_3.get(1);\n\n            double y2 = latest.age_adjusted_raw_value;\n            double x2 = timestamp;\n            double y1 = second_latest.age_adjusted_raw_value;\n            double x1 = second_latest.timestamp;\n            if(y1 == y2) {\n                rb = 0;\n            } else {\n                rb = (y2 - y1)/(x2 - x1);\n            }\n            ra = 0;\n            rc = -1 * ((latest.rb * x1) - y1);\n\n            Log.w(TAG, \"Not enough data to calculate parabolic rates - assume Linear data\");\n\n            Log.w(TAG, \"RAW PARABOLIC RATES: \"+ra+\"x^2 + \"+rb+\"x + \"+rc);\n            save();\n        } else {\n            Log.w(TAG, \"Not enough data to calculate parabolic rates - assume static data\");\n            BgReading latest_entry = BgReading.lastNoSenssor();\n            ra = 0;\n            rb = 0;\n            rc = latest_entry.age_adjusted_raw_value;\n\n            save();\n        }\n    }\n    public static double weightedAverageRaw(double timeA, double timeB, double calibrationTime, double rawA, double rawB) {\n        double relativeSlope = (rawB -  rawA)/(timeB - timeA);\n        double relativeIntercept = rawA - (relativeSlope * timeA);\n        return ((relativeSlope * calibrationTime) + relativeIntercept);\n    }\n\n    public String toS() {\n        Gson gson = new GsonBuilder()\n                .excludeFieldsWithoutExposeAnnotation()\n                .registerTypeAdapter(Date.class, new DateTypeAdapter())\n                .serializeSpecialFloatingPointValues()\n                .create();\n        return gson.toJson(this);\n    }\n\n    public String noiseValue() {\n        if(noise == null || noise.compareTo(\"\") == 0) {\n            return \"1\";\n        } else {\n            return String.valueOf(noise);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalSubrecord;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;\nimport com.eveningoutpost.dexdrip.UtilityModels.CalibrationSendQueue;\nimport com.eveningoutpost.dexdrip.UtilityModels.Constants;\nimport com.eveningoutpost.dexdrip.UtilityModels.Notifications;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.annotations.Expose;\nimport com.google.gson.internal.bind.DateTypeAdapter;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.UUID;\n\n/**\n * Created by stephenblack on 10/29/14.\n */\n@Table(name = \"Calibration\", id = BaseColumns._ID)\npublic class Calibration extends Model {\n    private final static String TAG = Calibration.class.getSimpleName();\n\n    @Expose\n    @Column(name = \"timestamp\", index = true)\n    public double timestamp;\n\n    @Expose\n    @Column(name = \"sensor_age_at_time_of_estimation\")\n    public double sensor_age_at_time_of_estimation;\n\n    @Column(name = \"sensor\", index = true)\n    public Sensor sensor;\n\n    @Expose\n    @Column(name = \"bg\")\n    public double bg;\n\n    @Expose\n    @Column(name = \"raw_value\")\n    public double raw_value;\n//\n//    @Expose\n//    @Column(name = \"filtered_value\")\n//    public double filtered_value;\n\n    @Expose\n    @Column(name = \"adjusted_raw_value\")\n    public double adjusted_raw_value;\n\n    @Expose\n    @Column(name = \"sensor_confidence\")\n    public double sensor_confidence;\n\n    @Expose\n    @Column(name = \"slope_confidence\")\n    public double slope_confidence;\n\n    @Expose\n    @Column(name = \"raw_timestamp\")\n    public double raw_timestamp;\n\n    @Expose\n    @Column(name = \"slope\")\n    public double slope;\n\n    @Expose\n    @Column(name = \"intercept\")\n    public double intercept;\n\n    @Expose\n    @Column(name = \"distance_from_estimate\")\n    public double distance_from_estimate;\n\n    @Expose\n    @Column(name = \"estimate_raw_at_time_of_calibration\")\n    public double estimate_raw_at_time_of_calibration;\n\n    @Expose\n    @Column(name = \"estimate_bg_at_time_of_calibration\")\n    public double estimate_bg_at_time_of_calibration;\n\n    @Expose\n    @Column(name = \"uuid\", index = true)\n    public String uuid;\n\n    @Expose\n    @Column(name = \"sensor_uuid\", index = true)\n    public String sensor_uuid;\n\n    @Expose\n    @Column(name = \"possible_bad\")\n    public Boolean possible_bad;\n\n    @Expose\n    @Column(name = \"check_in\")\n    public boolean check_in;\n\n    @Expose\n    @Column(name = \"first_decay\")\n    public double first_decay;\n\n    @Expose\n    @Column(name = \"second_decay\")\n    public double second_decay;\n\n    @Expose\n    @Column(name = \"first_slope\")\n    public double first_slope;\n\n    @Expose\n    @Column(name = \"second_slope\")\n    public double second_slope;\n\n    @Expose\n    @Column(name = \"first_intercept\")\n    public double first_intercept;\n\n    @Expose\n    @Column(name = \"second_intercept\")\n    public double second_intercept;\n\n    @Expose\n    @Column(name = \"first_scale\")\n    public double first_scale;\n\n    @Expose\n    @Column(name = \"second_scale\")\n    public double second_scale;\n\n    public static void initialCalibration(double bg1, double bg2, Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String unit = prefs.getString(\"units\", \"mgdl\");\n\n        if(unit.compareTo(\"mgdl\") != 0 ) {\n            bg1 = bg1 * Constants.MMOLL_TO_MGDL;\n            bg2 = bg2 * Constants.MMOLL_TO_MGDL;\n        }\n        clear_all_existing_calibrations();\n\n        Calibration higherCalibration = new Calibration();\n        Calibration lowerCalibration = new Calibration();\n        Sensor sensor = Sensor.currentSensor();\n        List<BgReading> bgReadings = BgReading.latest_by_size(2);\n        BgReading bgReading1 = bgReadings.get(0);\n        BgReading bgReading2 = bgReadings.get(1);\n        BgReading highBgReading;\n        BgReading lowBgReading;\n        double higher_bg = Math.max(bg1, bg2);\n        double lower_bg = Math.min(bg1, bg2);\n\n        if (bgReading1.raw_data > bgReading2.raw_data) {\n            highBgReading = bgReading1;\n            lowBgReading = bgReading2;\n        } else {\n            highBgReading = bgReading2;\n            lowBgReading = bgReading1;\n        }\n\n        higherCalibration.bg = higher_bg;\n        higherCalibration.slope = 1;\n        higherCalibration.intercept = higher_bg;\n        higherCalibration.sensor = sensor;\n        higherCalibration.estimate_raw_at_time_of_calibration = highBgReading.age_adjusted_raw_value;\n        higherCalibration.adjusted_raw_value = highBgReading.age_adjusted_raw_value;\n        higherCalibration.raw_value = highBgReading.raw_data;\n        higherCalibration.raw_timestamp = highBgReading.timestamp;\n        higherCalibration.save();\n\n        highBgReading.calculated_value = higher_bg;\n        highBgReading.calibration_flag = true;\n        highBgReading.calibration = higherCalibration;\n        highBgReading.save();\n        higherCalibration.save();\n\n        lowerCalibration.bg = lower_bg;\n        lowerCalibration.slope = 1;\n        lowerCalibration.intercept = lower_bg;\n        lowerCalibration.sensor = sensor;\n        lowerCalibration.estimate_raw_at_time_of_calibration = lowBgReading.age_adjusted_raw_value;\n        lowerCalibration.adjusted_raw_value = lowBgReading.age_adjusted_raw_value;\n        lowerCalibration.raw_value = lowBgReading.raw_data;\n        lowerCalibration.raw_timestamp = lowBgReading.timestamp;\n        lowerCalibration.save();\n\n        lowBgReading.calculated_value = lower_bg;\n        lowBgReading.calibration_flag = true;\n        lowBgReading.calibration = lowerCalibration;\n        lowBgReading.save();\n        lowerCalibration.save();\n\n        highBgReading.find_new_curve();\n        highBgReading.find_new_raw_curve();\n        lowBgReading.find_new_curve();\n        lowBgReading.find_new_raw_curve();\n\n        List<Calibration> calibrations = new ArrayList<Calibration>();\n        calibrations.add(lowerCalibration);\n        calibrations.add(higherCalibration);\n\n        for(Calibration calibration : calibrations) {\n            calibration.timestamp = new Date().getTime();\n            calibration.sensor_uuid = sensor.uuid;\n            calibration.slope_confidence = .5;\n            calibration.distance_from_estimate = 0;\n            calibration.check_in = false;\n            calibration.sensor_confidence = ((-0.0018 * calibration.bg * calibration.bg) + (0.6657 * calibration.bg) + 36.7505) / 100;\n\n            calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;\n            calibration.uuid = UUID.randomUUID().toString();\n            calibration.save();\n\n            calculate_w_l_s();\n            CalibrationSendQueue.addToQueue(calibration, context);\n        }\n        adjustRecentBgReadings(5);\n        CalibrationRequest.createOffset(lowerCalibration.bg, 35);\n        Notifications.notificationSetter(context);\n    }\n\n    //Create Calibration Checkin\n    public static void create(CalRecord[] calRecords, long addativeOffset, Context context) { create(calRecords, context, false, addativeOffset); }\n    public static void create(CalRecord[] calRecords, Context context) { create(calRecords, context, false, 0); }\n    public static void create(CalRecord[] calRecords, Context context, boolean override, long addativeOffset) {\n        //TODO: Change calibration.last and other queries to order calibrations by timestamp rather than ID\n        Log.w(\"CALIBRATION-CHECK-IN: \", \"Creating Calibration Record\");\n        Sensor sensor = Sensor.currentSensor();\n        CalRecord firstCalRecord = calRecords[0];\n        CalRecord secondCalRecord = calRecords[0];\n//        CalRecord secondCalRecord = calRecords[calRecords.length - 1];\n        //TODO: Figgure out how the ratio between the two is determined\n        double calSlope = ((secondCalRecord.getScale() / secondCalRecord.getSlope()) + (3 * firstCalRecord.getScale() / firstCalRecord.getSlope())) * 250;\n\n        double calIntercept = (((secondCalRecord.getScale() * secondCalRecord.getIntercept()) / secondCalRecord.getSlope()) + ((3 * firstCalRecord.getScale() * firstCalRecord.getIntercept()) / firstCalRecord.getSlope())) / -4;\n        if (sensor != null) {\n            for(int i = 0; i < firstCalRecord.getCalSubrecords().length - 1; i++) {\n                if (((firstCalRecord.getCalSubrecords()[i] != null && Calibration.is_new(firstCalRecord.getCalSubrecords()[i], addativeOffset))) || (i == 0 && override)) {\n                    CalSubrecord calSubrecord = firstCalRecord.getCalSubrecords()[i];\n\n                    Calibration calibration = new Calibration();\n                    calibration.bg = calSubrecord.getCalBGL();\n                    calibration.timestamp = calSubrecord.getDateEntered().getTime() + addativeOffset;\n                    if (calibration.timestamp > new Date().getTime()) {\n                        Log.e(TAG, \"ERROR - Calibration timestamp is from the future, wont save!\");\n                        return;\n                    }\n                    calibration.raw_value = calSubrecord.getCalRaw() / 1000;\n                    calibration.slope = calSlope;\n                    calibration.intercept = calIntercept;\n\n                    calibration.sensor_confidence = ((-0.0018 * calibration.bg * calibration.bg) + (0.6657 * calibration.bg) + 36.7505) / 100;\n                    if (calibration.sensor_confidence <= 0) {\n                        calibration.sensor_confidence = 0;\n                    }\n                    calibration.slope_confidence = 0.8; //TODO: query backwards to find this value near the timestamp\n                    calibration.estimate_raw_at_time_of_calibration = calSubrecord.getCalRaw() / 1000;\n                    calibration.sensor = sensor;\n                    calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;\n                    calibration.uuid = UUID.randomUUID().toString();\n                    calibration.sensor_uuid = sensor.uuid;\n                    calibration.check_in = true;\n\n                    calibration.first_decay = firstCalRecord.getDecay();\n                    calibration.second_decay = secondCalRecord.getDecay();\n                    calibration.first_slope = firstCalRecord.getSlope();\n                    calibration.second_slope = secondCalRecord.getSlope();\n                    calibration.first_scale = firstCalRecord.getScale();\n                    calibration.second_scale = secondCalRecord.getScale();\n                    calibration.first_intercept = firstCalRecord.getIntercept();\n                    calibration.second_intercept = secondCalRecord.getIntercept();\n\n                    calibration.save();\n                    CalibrationSendQueue.addToQueue(calibration, context);\n                    Calibration.requestCalibrationIfRangeTooNarrow();\n                }\n            }\n            if(firstCalRecord.getCalSubrecords()[0] != null && firstCalRecord.getCalSubrecords()[2] == null) {\n                if(Calibration.latest(2).size() == 1) {\n                    Calibration.create(calRecords, context, true, 0);\n                }\n            }\n            Notifications.notificationSetter(context);\n        }\n    }\n\n    public static boolean is_new(CalSubrecord calSubrecord, long addativeOffset) {\n        Sensor sensor = Sensor.currentSensor();\n        Calibration calibration = new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"timestamp <= ?\", calSubrecord.getDateEntered().getTime() + addativeOffset + (1000 * 60 * 2))\n                .orderBy(\"timestamp desc\")\n                .executeSingle();\n        if(calibration != null && Math.abs(calibration.timestamp - (calSubrecord.getDateEntered().getTime() + addativeOffset)) < (4*60*1000)) {\n            Log.d(\"CAL CHECK IN \", \"Already have that calibration!\");\n            return false;\n        } else {\n            Log.d(\"CAL CHECK IN \", \"Looks like a new calibration!\");\n            return true;\n        }\n    }\n    public static Calibration getForTimestamp(double timestamp) {\n        Sensor sensor = Sensor.currentSensor();\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .where(\"timestamp < ?\", timestamp)\n                .orderBy(\"timestamp desc\")\n                .executeSingle();\n    }\n\n    public static Calibration create(double bg, Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String unit = prefs.getString(\"units\", \"mgdl\");\n\n        if(unit.compareTo(\"mgdl\") != 0 ) {\n            bg = bg * Constants.MMOLL_TO_MGDL;\n        }\n\n        CalibrationRequest.clearAll();\n        Calibration calibration = new Calibration();\n        Sensor sensor = Sensor.currentSensor();\n\n        if (sensor != null) {\n            BgReading bgReading = BgReading.last();\n            if (bgReading != null) {\n                calibration.sensor = sensor;\n                calibration.bg = bg;\n                calibration.check_in = false;\n                calibration.timestamp = new Date().getTime();\n                calibration.raw_value = bgReading.raw_data;\n                calibration.adjusted_raw_value = bgReading.age_adjusted_raw_value;\n                calibration.sensor_uuid = sensor.uuid;\n                calibration.slope_confidence = Math.min(Math.max(((4 - Math.abs((bgReading.calculated_value_slope) * 60000))/4), 0), 1);\n\n                double estimated_raw_bg = BgReading.estimated_raw_bg(new Date().getTime());\n                calibration.raw_timestamp = bgReading.timestamp;\n                if (Math.abs(estimated_raw_bg - bgReading.age_adjusted_raw_value) > 20) {\n                    calibration.estimate_raw_at_time_of_calibration = bgReading.age_adjusted_raw_value;\n                } else {\n                    calibration.estimate_raw_at_time_of_calibration = estimated_raw_bg;\n                }\n                calibration.distance_from_estimate = Math.abs(calibration.bg - bgReading.calculated_value);\n                calibration.sensor_confidence = Math.max(((-0.0018 * bg * bg) + (0.6657 * bg) + 36.7505) / 100, 0);\n                calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;\n                calibration.uuid = UUID.randomUUID().toString();\n                calibration.save();\n\n                bgReading.calibration = calibration;\n                bgReading.calibration_flag = true;\n                bgReading.save();\n                BgSendQueue.addToQueue(bgReading, \"update\", context);\n\n                calculate_w_l_s();\n                adjustRecentBgReadings();\n                CalibrationSendQueue.addToQueue(calibration, context);\n                Notifications.notificationSetter(context);\n                Calibration.requestCalibrationIfRangeTooNarrow();\n            }\n        } else {\n            Log.w(\"CALIBRATION\", \"No sensor, cant save!\");\n        }\n        return Calibration.last();\n    }\n\n    public static List<Calibration> allForSensorInLastFiveDays() {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .where(\"timestamp > ?\", (new Date().getTime() - (60000 * 60 * 24 * 5)))\n                .orderBy(\"timestamp desc\")\n                .execute();\n    }\n\n    public static void calculate_w_l_s() {\n        if (Sensor.isActive()) {\n            double l = 0;\n            double m = 0;\n            double n = 0;\n            double p = 0;\n            double q = 0;\n            double w;\n            List<Calibration> calibrations = allForSensorInLastFourDays(); //5 days was a bit much, dropped this to 4\n            if (calibrations.size() == 1) {\n                Calibration calibration = Calibration.last();\n                calibration.slope = 1;\n                calibration.intercept = calibration.bg - (calibration.raw_value * calibration.slope);\n                calibration.save();\n            } else {\n                for (Calibration calibration : calibrations) {\n                    w = calibration.calculateWeight();\n                    l += (w);\n                    m += (w * calibration.estimate_raw_at_time_of_calibration);\n                    n += (w * calibration.estimate_raw_at_time_of_calibration * calibration.estimate_raw_at_time_of_calibration);\n                    p += (w * calibration.bg);\n                    q += (w * calibration.estimate_raw_at_time_of_calibration * calibration.bg);\n                }\n\n                Calibration last_calibration = Calibration.last();\n                w = (last_calibration.calculateWeight() * (calibrations.size() * 0.14));\n                l += (w);\n                m += (w * last_calibration.estimate_raw_at_time_of_calibration);\n                n += (w * last_calibration.estimate_raw_at_time_of_calibration * last_calibration.estimate_raw_at_time_of_calibration);\n                p += (w * last_calibration.bg);\n                q += (w * last_calibration.estimate_raw_at_time_of_calibration * last_calibration.bg);\n\n                double d = (l * n) - (m * m);\n                Calibration calibration = Calibration.last();\n                calibration.intercept = ((n * p) - (m * q)) / d;\n                calibration.slope = ((l * q) - (m * p)) / d;\n                if ((calibrations.size() == 2 && calibration.slope < 0.95) || (calibration.slope < 0.85)) { // I have not seen a case where a value below 7.5 proved to be accurate but we should keep an eye on this\n                    calibration.slope = calibration.slopeOOBHandler(0);\n                    if(calibrations.size() > 2) { calibration.possible_bad = true; }\n                    calibration.intercept = calibration.bg - (calibration.estimate_raw_at_time_of_calibration * calibration.slope);\n                    CalibrationRequest.createOffset(calibration.bg, 25);\n                }\n                if ((calibrations.size() == 2 && calibration.slope > 1.3) || (calibration.slope > 1.4)) {\n                    calibration.slope = calibration.slopeOOBHandler(1);\n                    if(calibrations.size() > 2) { calibration.possible_bad = true; }\n                    calibration.intercept = calibration.bg - (calibration.estimate_raw_at_time_of_calibration * calibration.slope);\n                    CalibrationRequest.createOffset(calibration.bg, 25);\n                }\n                Log.d(TAG, \"Calculated Calibration Slope: \" + calibration.slope);\n                Log.d(TAG, \"Calculated Calibration intercept: \" + calibration.intercept);\n                calibration.save();\n            }\n        } else {\n            Log.w(TAG, \"NO Current active sensor found!!\");\n        }\n    }\n\n    private double slopeOOBHandler(int status) {\n    // If the last slope was reasonable and reasonably close, use that, otherwise use a slope that may be a little steep, but its best to play it safe when uncertain\n        List<Calibration> calibrations = Calibration.latest(3);\n        Calibration thisCalibration = calibrations.get(0);\n        if(status == 0) {\n            if (calibrations.size() == 3) {\n                if ((Math.abs(thisCalibration.bg - thisCalibration.estimate_bg_at_time_of_calibration) < 30) && (calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad == true)) {\n                    return calibrations.get(1).slope;\n                } else {\n                    return Math.max(((-0.048) * (thisCalibration.sensor_age_at_time_of_estimation / (60000 * 60 * 24))) + 1.1, 1.08);\n                }\n            } else if (calibrations.size() == 2) {\n                return Math.max(((-0.048) * (thisCalibration.sensor_age_at_time_of_estimation / (60000 * 60 * 24))) + 1.1, 1.15);\n            }\n            return 1;\n        } else {\n            if (calibrations.size() == 3) {\n                if ((Math.abs(thisCalibration.bg - thisCalibration.estimate_bg_at_time_of_calibration) < 30) && (calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad == true)) {\n                    return calibrations.get(1).slope;\n                } else {\n                    return 1.3;\n                }\n            } else if (calibrations.size() == 2) {\n                return 1.2;\n            }\n        }\n        return 1;\n    }\n\n    private static List<Calibration> calibrations_for_sensor(Sensor sensor) {\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ?\", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .orderBy(\"timestamp desc\")\n                .execute();\n    }\n\n    private double calculateWeight() {\n        double firstTimeStarted =   Calibration.first().sensor_age_at_time_of_estimation;\n        double lastTimeStarted =   Calibration.last().sensor_age_at_time_of_estimation;\n        double time_percentage = Math.min(((sensor_age_at_time_of_estimation - firstTimeStarted) / (lastTimeStarted - firstTimeStarted)) / (.85), 1);\n        time_percentage = (time_percentage + .01);\n        Log.w(TAG, \"CALIBRATIONS TIME PERCENTAGE WEIGHT: \" + time_percentage);\n        return Math.max((((((slope_confidence + sensor_confidence) * (time_percentage))) / 2) * 100), 1);\n    }\n    public static void adjustRecentBgReadings() {// This just adjust the last 30 bg readings transition from one calibration point to the next\n        adjustRecentBgReadings(30);\n    }\n    public static void adjustRecentBgReadings(int adjustCount) {\n        //TODO: add some handling around calibration overrides as they come out looking a bit funky\n        List<Calibration> calibrations = Calibration.latest(3);\n        List<BgReading> bgReadings = BgReading.latestUnCalculated(adjustCount);\n        if (calibrations.size() == 3) {\n            int denom = bgReadings.size();\n            Calibration latestCalibration = calibrations.get(0);\n            int i = 0;\n            for (BgReading bgReading : bgReadings) {\n                double oldYValue = bgReading.calculated_value;\n                double newYvalue = (bgReading.age_adjusted_raw_value * latestCalibration.slope) + latestCalibration.intercept;\n                bgReading.calculated_value = ((newYvalue * (denom - i)) + (oldYValue * ( i ))) / denom;\n                bgReading.save();\n                i += 1;\n            }\n        } else if (calibrations.size() == 2) {\n            Calibration latestCalibration = calibrations.get(0);\n            for (BgReading bgReading : bgReadings) {\n                double newYvalue = (bgReading.age_adjusted_raw_value * latestCalibration.slope) + latestCalibration.intercept;\n                bgReading.calculated_value = newYvalue;\n                bgReading.save();\n\n            }\n        }\n        bgReadings.get(0).find_new_raw_curve();\n        bgReadings.get(0).find_new_curve();\n    }\n\n    public void rawValueOverride(double rawValue, Context context) {\n        estimate_raw_at_time_of_calibration = rawValue;\n        save();\n        calculate_w_l_s();\n        CalibrationSendQueue.addToQueue(this, context);\n    }\n\n    public static void requestCalibrationIfRangeTooNarrow() {\n        double max = Calibration.max_recent();\n        double min = Calibration.min_recent();\n        if ((max - min) < 55) {\n            double avg = ((min + max) / 2);\n            double dist = max - avg;\n            CalibrationRequest.createOffset(avg, dist + 20);\n        }\n    }\n\n    public static void clear_all_existing_calibrations() {\n        CalibrationRequest.clearAll();\n        List<Calibration> pastCalibrations = Calibration.allForSensor();\n        if (pastCalibrations != null) {\n            for(Calibration calibration : pastCalibrations){\n                calibration.slope_confidence = 0;\n                calibration.sensor_confidence = 0;\n                calibration.save();\n            }\n        }\n\n    }\n\n    public String toS() {\n        Gson gson = new GsonBuilder()\n                .excludeFieldsWithoutExposeAnnotation()\n                .registerTypeAdapter(Date.class, new DateTypeAdapter())\n                .serializeSpecialFloatingPointValues()\n                .create();\n        return gson.toJson(this);\n    }\n\n    //COMMON SCOPES!\n    public static Calibration last() {\n        Sensor sensor = Sensor.currentSensor();\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .orderBy(\"timestamp desc\")\n                .executeSingle();\n    }\n\n    public static Calibration first() {\n        Sensor sensor = Sensor.currentSensor();\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .orderBy(\"timestamp asc\")\n                .executeSingle();\n    }\n    public static double max_recent() {\n        Sensor sensor = Sensor.currentSensor();\n        Calibration calibration = new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .where(\"timestamp > ?\", (new Date().getTime() - (60000 * 60 * 24 * 4)))\n                .orderBy(\"bg desc\")\n                .executeSingle();\n        if(calibration != null) {\n            return calibration.bg;\n        } else {\n            return 120;\n        }\n    }\n\n    public static double min_recent() {\n        Sensor sensor = Sensor.currentSensor();\n        Calibration calibration = new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .where(\"timestamp > ?\", (new Date().getTime() - (60000 * 60 * 24 * 4)))\n                .orderBy(\"bg asc\")\n                .executeSingle();\n        if(calibration != null) {\n            return calibration.bg;\n        } else {\n            return 100;\n        }\n    }\n\n    public static List<Calibration> latest(int number) {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .orderBy(\"timestamp desc\")\n                .limit(number)\n                .execute();\n    }\n\n    public static List<Calibration> allForSensor() {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .orderBy(\"timestamp desc\")\n                .execute();\n    }\n\n    public static List<Calibration> allForSensorInLastFourDays() {\n        Sensor sensor = Sensor.currentSensor();\n        if (sensor == null) { return null; }\n        return new Select()\n                .from(Calibration.class)\n                .where(\"Sensor = ? \", sensor.getId())\n                .where(\"slope_confidence != 0\")\n                .where(\"sensor_confidence != 0\")\n                .where(\"timestamp > ?\", (new Date().getTime() - (60000 * 60 * 24 * 4)))\n                .orderBy(\"timestamp desc\")\n                .execute();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/CalibrationRequest.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.provider.BaseColumns;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\n\nimport java.util.List;\n\n/**\n * Created by stephenblack on 12/9/14.\n */\n\n@Table(name = \"CalibrationRequest\", id = BaseColumns._ID)\npublic class CalibrationRequest extends Model {\n    private static final int max = 250;\n    private static final int min = 70;\n\n    @Column(name = \"requestIfAbove\")\n    public double requestIfAbove;\n\n   @Column(name = \"requestIfBelow\")\n    public double requestIfBelow;\n\n    public static void createRange(double low, double high) {\n        CalibrationRequest calibrationRequest = new CalibrationRequest();\n        calibrationRequest.requestIfAbove = low;\n        calibrationRequest.requestIfBelow = high;\n        calibrationRequest.save();\n    }\n    public static void createOffset(double center, double distance) {\n        CalibrationRequest calibrationRequest = new CalibrationRequest();\n        calibrationRequest.requestIfAbove = center + distance;\n        calibrationRequest.requestIfBelow = max;\n        calibrationRequest.save();\n\n        calibrationRequest.requestIfAbove = min;\n        calibrationRequest.requestIfBelow = center - distance;\n        calibrationRequest.save();\n    }\n\n    public static void clearAll(){\n        List<CalibrationRequest> calibrationRequests =  new Select()\n                                                            .from(CalibrationRequest.class)\n                                                            .execute();\n        if (calibrationRequests.size() >=1) {\n            for (CalibrationRequest calibrationRequest : calibrationRequests) {\n                calibrationRequest.delete();\n            }\n        }\n    }\n\n    public static boolean shouldRequestCalibration(BgReading bgReading){\n        CalibrationRequest calibrationRequest =  new Select()\n                .from(CalibrationRequest.class)\n                .where(\"requestIfAbove < ?\", bgReading.calculated_value)\n                .where(\"requestIfBelow > ?\", bgReading.calculated_value)\n                .executeSingle();\n        if (calibrationRequest != null && Math.abs(bgReading.calculated_value_slope * 60000) < 1.8) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * Created by stephenblack on 11/6/14.\n */\n\n@Table(name = \"TransmitterData\", id = BaseColumns._ID)\npublic class TransmitterData extends Model {\n    private final static String TAG = BgReading.class.getSimpleName();\n\n    @Column(name = \"timestamp\", index = true)\n    public long timestamp;\n\n    @Column(name = \"raw_data\")\n    public double raw_data;\n//\n//    @Column(name = \"filtered_data\")\n//    public double filtered_data;\n\n    @Column(name = \"sensor_battery_level\")\n    public int sensor_battery_level;\n\n    @Column(name = \"uuid\", index = true)\n    public String uuid;\n\n    public static TransmitterData create(byte[] buffer, int len, Long timestamp) {\n                StringBuilder data_string = new StringBuilder();\n        if (len < 6) { return null; };\n\n        for (int i = 0; i < len; ++i) {\n            data_string.append((char) buffer[i]);\n        }\n        String[] data = data_string.toString().split(\"\\\\s+\");\n\n        randomDelay(100, 2000);\n        TransmitterData lastTransmitterData = TransmitterData.last();\n        if (lastTransmitterData != null && lastTransmitterData.raw_data == Integer.parseInt(data[0]) && Math.abs(lastTransmitterData.timestamp - timestamp) < (10000)) { //Stop allowing duplicate data, its bad!\n            return null;\n        }\n\n        TransmitterData transmitterData = new TransmitterData();\n        if(data.length > 1) {\n            transmitterData.sensor_battery_level = Integer.parseInt(data[1]);\n        }\n        if (Integer.parseInt(data[0]) < 1000) { return null; } // Sometimes the HM10 sends the battery level and readings in separate transmissions, filter out these incomplete packets!\n        transmitterData.raw_data = Integer.parseInt(data[0]);\n        transmitterData.timestamp = timestamp;\n        transmitterData.uuid = UUID.randomUUID().toString();\n\n        transmitterData.save();\n        return transmitterData;\n    }\n\n    public static TransmitterData create(int raw_data ,int sensor_battery_level, long timestamp) {\n        randomDelay(100, 2000);\n        TransmitterData lastTransmitterData = TransmitterData.last();\n        if (lastTransmitterData != null && lastTransmitterData.raw_data == raw_data && Math.abs(lastTransmitterData.timestamp - new Date().getTime()) < (10000)) { //Stop allowing duplicate data, its bad!\n            return null;\n        }\n\n        TransmitterData transmitterData = new TransmitterData();\n        transmitterData.sensor_battery_level = sensor_battery_level;\n        transmitterData.raw_data = raw_data ;\n        transmitterData.timestamp = timestamp;\n        transmitterData.uuid = UUID.randomUUID().toString();\n        transmitterData.save();\n        return transmitterData;\n    }\n\n    public static TransmitterData last() {\n        return new Select()\n                .from(TransmitterData.class)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n    }\n\n    public static void randomDelay(float min, float max){\n        int random = (int)(max * Math.random() + min);\n        try {\n            Log.d(\"Sleeping \", \"for \" + random + \"ms\");\n            Thread.sleep(random);\n        } catch (InterruptedException e) {\n            Log.e(\"Random Delay \", \"INTERUPTED\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/User.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Interfaces.UserInterface;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonObject;\nimport com.google.gson.annotations.Expose;\nimport com.google.gson.internal.bind.DateTypeAdapter;\n\nimport java.util.Date;\n\nimport retrofit.Callback;\nimport retrofit.RestAdapter;\nimport retrofit.RetrofitError;\nimport retrofit.client.Response;\nimport retrofit.converter.GsonConverter;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\n@Table(name = \"User\", id = BaseColumns._ID)\npublic class User extends Model {\n    private static final String baseUrl = \"http://10.0.2.2:3000\";\n\n    public static Gson gson = new GsonBuilder()\n            .excludeFieldsWithoutExposeAnnotation()\n            .registerTypeAdapter(Date.class, new DateTypeAdapter())\n            .create();\n\n    @Expose\n    @Column(name = \"email\")\n    public String email;\n\n    @Expose\n    @Column(name = \"password\")\n    public String password;\n\n    @Expose\n    @Column(name = \"token\")\n    public String token;\n\n    @Expose\n    @Column(name = \"token_expiration\")\n    public double token_expiration;\n\n    @Expose\n    @Column(name = \"uuid\", index = true)\n    public String uuid;\n\n\n    public static User currentUser() {\n        User user = new Select()\n                .from(User.class)\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n        return user;\n    }\n\n    //TODO: Add refresh token attempt instance method!!\n\n    public static void authenticate() {\n        final User user = User.currentUser();\n        userInterface().authenticate(user, new Callback<String>() {\n                    @Override\n                    public void success(String gsonResponse, Response response) {\n                        JsonObject jobj = new Gson().fromJson(gsonResponse, JsonObject.class);\n                        user.token = jobj.get(\"token\").getAsString();\n                        user.token_expiration = jobj.get(\"expiration\").getAsDouble();\n                        user.save();\n                    }\n                    @Override\n                    public void failure(RetrofitError error) {\n                        Response response = error.getResponse();\n                        Log.w(\"REST CALL ERROR:\", \"****************\");\n                        Log.w(\"REST CALL STATUS:\", \"\" + response.getStatus());\n                        Log.w(\"REST CALL REASON:\", response.getReason());\n                    }\n                }\n        );\n    }\n\n    public static UserInterface userInterface() {\n        RestAdapter adapter = adapterBuilder().build();\n        UserInterface userInterface =\n                adapter.create(UserInterface.class);\n        return userInterface();\n    }\n\n    public static RestAdapter.Builder adapterBuilder() {\n        RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();\n        adapterBuilder\n                .setEndpoint(baseUrl)\n                .setConverter(new GsonConverter(gson));\n        return adapterBuilder;\n    }\n\n\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Models/UserNotification.java",
    "content": "package com.eveningoutpost.dexdrip.Models;\n\nimport android.provider.BaseColumns;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\n\nimport java.util.Date;\n\n/**\n * Created by stephenblack on 11/29/14.\n */\n\n@Table(name = \"Notifications\", id = BaseColumns._ID)\npublic class UserNotification extends Model {\n\n    @Column(name = \"timestamp\", index = true)\n    public double timestamp;\n\n    @Column(name = \"message\")\n    public String message;\n\n    @Column(name = \"bg_alert\")\n    public boolean bg_alert;\n\n    @Column(name = \"calibration_alert\")\n    public boolean calibration_alert;\n\n    @Column(name = \"double_calibration_alert\")\n    public boolean double_calibration_alert;\n\n    @Column(name = \"extra_calibration_alert\")\n    public boolean extra_calibration_alert;\n\n    public static UserNotification lastBgAlert() {\n        return new Select()\n                .from(UserNotification.class)\n                .where(\"bg_alert = ?\", true)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n    }\n    public static UserNotification lastCalibrationAlert() {\n        return new Select()\n                .from(UserNotification.class)\n                .where(\"calibration_alert = ?\", true)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n    }\n    public static UserNotification lastDoubleCalibrationAlert() {\n        return new Select()\n                .from(UserNotification.class)\n                .where(\"double_calibration_alert = ?\", true)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n    }\n    public static UserNotification lastExtraCalibrationAlert() {\n        return new Select()\n                .from(UserNotification.class)\n                .where(\"extra_calibration_alert = ?\", true)\n                .orderBy(\"_ID desc\")\n                .executeSingle();\n    }\n\n    public static UserNotification create(String message, String type) {\n        UserNotification userNotification = new UserNotification();\n        userNotification.timestamp = new Date().getTime();\n        userNotification.message = message;\n        if (type == \"bg_alert\") {\n            userNotification.bg_alert = true;\n        } else if (type == \"calibration_alert\") {\n            userNotification.calibration_alert = true;\n        } else if (type == \"double_calibration_alert\") {\n            userNotification.double_calibration_alert = true;\n        } else if (type == \"extra_calibration_alert\") {\n            userNotification.extra_calibration_alert = true;\n        }\n        userNotification.save();\n        return userNotification;\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/NavDrawerBuilder.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.preference.Preference;\nimport android.preference.PreferenceManager;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Tables.BgReadingTable;\nimport com.eveningoutpost.dexdrip.Tables.CalibrationDataTable;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.utils.Preferences;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * Created by stephenblack on 11/5/14.\n */\npublic class NavDrawerBuilder {\n    public final List<Calibration> last_two_calibrations = Calibration.latest(2);\n    public final List<BgReading> last_two_bgReadings = BgReading.latestUnCalculated(2);\n    public final List<BgReading> bGreadings_in_last_30_mins = BgReading.last30Minutes();\n    public final boolean is_active_sensor = Sensor.isActive();\n    public final double time_now = new Date().getTime();\n    public List<Intent> nav_drawer_intents;\n    public List<String> nav_drawer_options;\n    public Context context;\n\n    public NavDrawerBuilder(Context aContext) {\n        context = aContext;\n        this.nav_drawer_intents = nav_drawer_intents();\n        this.nav_drawer_options = nav_drawer_options();\n\n    }\n\n    private final List<String> nav_drawer_options() {\n        List<String> options = new ArrayList<String>();\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        boolean IUnderstand = prefs.getBoolean(\"I_understand\", false);\n        if(IUnderstand == false) {\n            options.add(\"Settings\");\n            return options;\n        }\n\n        options.add(\"xDrip\");\n        if(is_active_sensor) {\n            options.add(\"Calibration Graph\");\n        }\n        options.add(\"BG Data Table\");\n        options.add(\"Calibration Data Table\");\n//        options.add(\"Sensor Data Table\");\n\n        if(is_active_sensor) {\n            if(!CollectionServiceStarter.isBTShare(context)) {\n                if (last_two_bgReadings.size() > 1) {\n                    if (last_two_calibrations.size() > 1) {\n                        if (bGreadings_in_last_30_mins.size() >= 2) {\n                            if (time_now - last_two_calibrations.get(0).timestamp < (1000 * 60 * 60)) { //Put steps in place to discourage over calibration\n                                options.add(\"Override Calibration\");\n                            } else {\n                                options.add(\"Add Calibration\");\n                            }\n                        } else {\n                            options.add(\"Cannot Calibrate right now\");\n                        }\n                        if (last_two_calibrations.get(0).slope >= 1.4 || last_two_calibrations.get(0).slope <= 0.5) {\n                            options.add(\"Add Double Calibration\");\n                        }\n                    } else {\n                        options.add(\"Add Double Calibration\");\n                    }\n                }\n            }\n            options.add(\"Stop Sensor\");\n        } else { options.add(\"Start Sensor\"); }\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            if(CollectionServiceStarter.isBTWixel(context) || CollectionServiceStarter.isBTShare(context)) {\n                options.add(\"Scan for BT\");\n            }\n        }\n        options.add(\"System Status\");\n        options.add(\"Settings\");\n//        options.add(\"Fake Numbers\");\n//        options.add(\"Add Double Calibration\");\n//        options.add(\"Share Test\");\n        return options;\n    }\n\n    private List<Intent> nav_drawer_intents() {\n        List<Intent> options = new ArrayList<Intent>();\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        boolean IUnderstand = prefs.getBoolean(\"I_understand\", false);\n        if(IUnderstand == false) {\n            options.add(new Intent(context, SettingsActivity.class));\n            return options;\n        }\n\n        options.add(new Intent(context, Home.class));\n        if(is_active_sensor) {\n            options.add(new Intent(context, CalibrationGraph.class));\n        }\n        options.add(new Intent(context, BgReadingTable.class));\n        options.add(new Intent(context, CalibrationDataTable.class));\n//        options.add(new Intent(context, SensorDataTable.class));\n\n\n        if(is_active_sensor) {\n            if(!CollectionServiceStarter.isBTShare(context)) {\n                if (last_two_bgReadings.size() > 1) {\n                    if (last_two_calibrations.size() > 1) {\n                        if (bGreadings_in_last_30_mins.size() >= 2) {\n                            if (time_now - last_two_calibrations.get(0).timestamp < (1000 * 60 * 60)) { //Put steps in place to discourage over calibration\n                                options.add(new Intent(context, CalibrationOverride.class));\n                            } else {\n                                options.add(new Intent(context, AddCalibration.class));\n                            }\n                        } else {\n                            options.add(new Intent(context, Home.class));\n                        }\n                        if (last_two_calibrations.get(0).slope >= 1.4 || last_two_calibrations.get(0).slope <= 0.5) {\n                            options.add(new Intent(context, DoubleCalibrationActivity.class));\n                        }\n                    } else {\n                        options.add(new Intent(context, DoubleCalibrationActivity.class));\n                    }\n                }\n            }\n            options.add(new Intent(context, StopSensor.class));\n        } else { options.add(new Intent(context, StartNewSensor.class)); }\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            if(CollectionServiceStarter.isBTWixel(context) || CollectionServiceStarter.isBTShare(context)) {\n                options.add(new Intent(context, BluetoothScan.class));\n            }\n        }\n        options.add(new Intent(context, SystemStatus.class));\n//        options.add(new Intent(context, SettingsActivity.class));\n        options.add(new Intent(context, Preferences.class));\n//        options.add(new Intent(context, FakeNumbers.class));\n//        options.add(new Intent(context, DoubleCalibrationActivity.class));\n//        options.add(new Intent(context, ShareTest.class));\n        return options;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/NavigationDrawerFragment.java",
    "content": "package com.eveningoutpost.dexdrip;\n\n\nimport android.app.ActionBar;\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.support.v4.app.ActionBarDrawerToggle;\nimport android.support.v4.view.GravityCompat;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\nimport java.util.List;\n\npublic class NavigationDrawerFragment extends Fragment {\n    private static final String STATE_SELECTED_POSITION = \"selected_navigation_drawer_position\";\n    private static final String PREF_USER_LEARNED_DRAWER = \"navigation_drawer_learned\";\n    private NavigationDrawerCallbacks mCallbacks;\n    private ActionBarDrawerToggle mDrawerToggle;\n    private DrawerLayout mDrawerLayout;\n    private ListView mDrawerListView;\n    private View mFragmentContainerView;\n    private int mCurrentSelectedPosition = 0;\n    private boolean mFromSavedInstanceState;\n    private boolean mUserLearnedDrawer;\n    private String menu_name;\n    public NavDrawerBuilder navDrawerBuilder;\n    private int menu_position;\n    private List<String> menu_option_list;\n    private List<Intent> intent_list;\n\n    public NavigationDrawerFragment() {\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());\n        sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();\n        mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);\n\n        if (savedInstanceState != null) {\n            mCurrentSelectedPosition = 0;\n            mFromSavedInstanceState = true;\n        }\n    }\n\n    @Override\n    public void onActivityCreated(Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n        setHasOptionsMenu(true);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        mDrawerListView = (ListView) inflater.inflate(\n                R.layout.fragment_navigation_drawer, container, false);\n        mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                selectItem(position);\n            }\n        });\n\n        navDrawerBuilder = new NavDrawerBuilder(getActivity());\n        List<String> menu_option_list = navDrawerBuilder.nav_drawer_options;\n        String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);\n\n        mDrawerListView.setAdapter(new ArrayAdapter<String>(\n                getActionBar().getThemedContext(),\n                android.R.layout.simple_list_item_activated_1,\n                android.R.id.text1,\n                menu_options\n                ));\n        return mDrawerListView;\n    }\n\n    public boolean isDrawerOpen() {\n        return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);\n    }\n\n    public void setUp(int fragmentId, DrawerLayout drawerLayout, String current_activity, Context context) {\n        navDrawerBuilder = new NavDrawerBuilder(context);\n        menu_name = current_activity;\n        menu_option_list = navDrawerBuilder.nav_drawer_options;\n        String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);\n        menu_position = menu_option_list.indexOf(menu_name);\n        intent_list = navDrawerBuilder.nav_drawer_intents;\n\n        mFragmentContainerView = getActivity().findViewById(fragmentId);\n        mDrawerLayout = drawerLayout;\n        mCurrentSelectedPosition = menu_position;\n        mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);\n        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);\n\n        ActionBar actionBar = getActionBar();\n        actionBar.setDisplayHomeAsUpEnabled(true);\n        actionBar.setHomeButtonEnabled(true);\n\n//        mDrawerListView = (ListView) inflater.inflate(\n//                R.layout.fragment_navigation_drawer, container, false);\n//        mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n//            @Override\n//            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n//                selectItem(position);\n//            }\n//        });\n\n//        navDrawerBuilder = new NavDrawerBuilder();\n//        List<String> menu_option_list = navDrawerBuilder.nav_drawer_options();\n//        String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);\n\n        mDrawerListView.setAdapter(new ArrayAdapter<String>(\n                getActionBar().getThemedContext(),\n                android.R.layout.simple_list_item_activated_1,\n                android.R.id.text1,\n                menu_options\n        ));\n\n\n        mDrawerToggle = new ActionBarDrawerToggle(\n                getActivity(),\n                mDrawerLayout,\n                R.drawable.ic_drawer,\n                R.string.navigation_drawer_open,\n                R.string.navigation_drawer_close\n        ) {\n            @Override\n            public void onDrawerClosed(View drawerView) {\n                super.onDrawerClosed(drawerView);\n                if (!isAdded()) {\n                    return;\n                }\n\n                getActivity().invalidateOptionsMenu();\n            }\n\n            @Override\n            public void onDrawerOpened(View drawerView) {\n                super.onDrawerOpened(drawerView);\n                if (!isAdded()) {\n                    return;\n                }\n\n                if (!mUserLearnedDrawer) {\n                    mUserLearnedDrawer = true;\n                    SharedPreferences sp = PreferenceManager\n                            .getDefaultSharedPreferences(getActivity());\n                    sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();\n                }\n\n                getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()\n            }\n        };\n\n        if (!mUserLearnedDrawer && !mFromSavedInstanceState) {\n            mDrawerLayout.openDrawer(mFragmentContainerView);\n        }\n\n        mDrawerLayout.post(new Runnable() {\n            @Override\n            public void run() {\n                mDrawerToggle.syncState();\n            }\n        });\n\n        mDrawerLayout.setDrawerListener(mDrawerToggle);\n    }\n\n    private void selectItem(int position) {\n        mCurrentSelectedPosition = position;\n        if (mDrawerListView != null) {\n            mDrawerListView.setItemChecked(position, true);\n        }\n        if (mDrawerLayout != null) {\n            mDrawerLayout.closeDrawer(mFragmentContainerView);\n        }\n        if (mCallbacks != null) {\n            mCallbacks.onNavigationDrawerItemSelected(position);\n        }\n    }\n\n    @Override\n    public void onAttach(Activity activity) {\n        super.onAttach(activity);\n        try {\n            mCallbacks = (NavigationDrawerCallbacks) activity;\n        } catch (ClassCastException e) {\n            throw new ClassCastException(\"Activity must implement NavigationDrawerCallbacks.\");\n        }\n    }\n\n    @Override\n    public void onDetach() {\n        super.onDetach();\n        mCallbacks = null;\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);\n    }\n\n    @Override\n    public void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        mDrawerToggle.onConfigurationChanged(newConfig);\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        if (mDrawerLayout != null && isDrawerOpen()) {\n            inflater.inflate(R.menu.global, menu);\n            showGlobalContextActionBar();\n        }\n        super.onCreateOptionsMenu(menu, inflater);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (mDrawerToggle.onOptionsItemSelected(item)) {\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void showGlobalContextActionBar() {\n        ActionBar actionBar = getActionBar();\n        actionBar.setDisplayShowTitleEnabled(true);\n        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);\n        actionBar.setTitle(R.string.app_name);\n    }\n\n    private ActionBar getActionBar() {\n        return getActivity().getActionBar();\n    }\n\n    public static interface NavigationDrawerCallbacks {\n        void onNavigationDrawerItemSelected(int position);\n    }\n\n    public void swapContext(int position) {\n        if (position != menu_position) {\n            Intent[] intent_array = intent_list.toArray(new Intent[intent_list.size()]);\n            startActivity(intent_array[position]);\n            if(menu_position != 0) {\n                getActivity().finish();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Sensor.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.UtilityModels.SensorSendQueue;\n\nimport java.util.UUID;\n\n/**\n * Created by stephenblack on 10/29/14.\n */\n\n@Table(name = \"Sensors\", id = BaseColumns._ID)\npublic class Sensor extends Model {\n\n//    @Expose\n    @Column(name = \"started_at\", index = true)\n    public double started_at;\n\n//    @Expose\n    @Column(name = \"stopped_at\")\n    public double stopped_at;\n\n//    @Expose\n    @Column(name = \"latest_battery_level\")\n    public int latest_battery_level;\n\n//    @Expose\n    @Column(name = \"uuid\", index = true)\n    public String uuid;\n\n    public static Sensor create(double started_at) {\n        Sensor sensor = new Sensor();\n        sensor.started_at = started_at;\n        sensor.uuid = UUID.randomUUID().toString();\n        sensor.save();\n        SensorSendQueue.addToQueue(sensor);\n        Log.w(\"SENSOR MODEL:\", sensor.toString());\n        return sensor;\n    }\n\n    public static Sensor currentSensor() {\n        Sensor sensor = new Select()\n                .from(Sensor.class)\n                .where(\"started_at != 0\")\n                .where(\"stopped_at = 0\")\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n        return sensor;\n    }\n\n    public static boolean isActive() {\n        Sensor sensor = new Select()\n                .from(Sensor.class)\n                .where(\"started_at != 0\")\n                .where(\"stopped_at = 0\")\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n        if(sensor == null) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/ComunicationHeader.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\n\nimport java.io.Serializable;\n\nimport com.google.gson.annotations.Expose;\n\n// This is a struct that is supsoed to tell the protocol version and is the first that the client is sending\n// The complete protocol is:\n// \t1) the client connects\n//  2) send this message.\n//  3) the server will send numberOfRecords of type ???? that it has.\npublic class ComunicationHeader  {\n\t/**\n\t *\n\t */\n\n\n\tint version;\n\tint numberOfRecords;\n//\tString message;\n//\tbyte reserved[];\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/DexCollectionService.java",
    "content": "/*\n * Copyright (C) 2013 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 */\npackage com.eveningoutpost.dexdrip.Services;\n\nimport android.annotation.TargetApi;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCallback;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattDescriptor;\nimport android.bluetooth.BluetoothGattService;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.PowerManager;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;\nimport com.eveningoutpost.dexdrip.Models.TransmitterData;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.UUID;\n\n@TargetApi(Build.VERSION_CODES.KITKAT)\npublic class DexCollectionService extends Service {\n    private final static String TAG = DexCollectionService.class.getSimpleName();\n    private String mDeviceName;\n    private String mDeviceAddress;\n    private boolean is_connected = false;\n    SharedPreferences prefs;\n\n    public DexCollectionService dexCollectionService;\n\n    private BluetoothManager mBluetoothManager;\n    private BluetoothAdapter mBluetoothAdapter;\n    private String mBluetoothDeviceAddress;\n    private BluetoothGatt mBluetoothGatt;\n    private ForegroundServiceStarter foregroundServiceStarter;\n    private int mConnectionState = STATE_DISCONNECTED;\n    private BluetoothDevice device;\n\n    private Context mContext = null;\n\n    private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;\n    private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;\n    private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;\n    private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;\n\n    public final static String ACTION_DATA_AVAILABLE = \"com.example.bluetooth.le.ACTION_DATA_AVAILABLE\";\n    public final static UUID xDripDataService = UUID.fromString(HM10Attributes.HM_10_SERVICE);\n    public final static UUID xDripDataCharacteristic = UUID.fromString(HM10Attributes.HM_RX_TX);\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        throw new UnsupportedOperationException(\"Not yet implemented\");\n    }\n\n    @Override\n    public void onCreate() {\n        foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), this);\n        foregroundServiceStarter.start();\n        mContext = getApplicationContext();\n        dexCollectionService = this;\n        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        listenForChangeInSettings();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n        if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {\n            setFailoverTimer();\n        } else {\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n        attemptConnection();\n        return START_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        close();\n        foregroundServiceStarter.stop();\n        setRetryTimer();\n        Log.w(TAG, \"SERVICE STOPPED\");\n    }\n    public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {\n        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {\n            if(key.compareTo(\"run_service_in_foreground\") == 0) {\n                Log.e(\"FOREGROUND\", \"run_service_in_foreground changed!\");\n                if (prefs.getBoolean(\"run_service_in_foreground\", false)) {\n                    foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), dexCollectionService);\n                    foregroundServiceStarter.start();\n                    Log.w(TAG, \"Moving to foreground\");\n                } else {\n                    dexCollectionService.stopForeground(true);\n                    Log.w(TAG, \"Removing from foreground\");\n                }\n            }\n        }\n    };\n\n    public void listenForChangeInSettings() {\n        prefs.registerOnSharedPreferenceChangeListener(prefListener);\n    }\n\n    public void setRetryTimer() {\n        if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {\n            long retry_in = (1000 * 60 * 2);\n            Log.d(TAG, \"Restarting in: \" + (retry_in / (60 * 1000)) + \" minutes\");\n            Calendar calendar = Calendar.getInstance();\n            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);\n            alarm.setExact(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexCollectionService.class), 0));\n        }\n    }\n\n    public void setFailoverTimer() { //Sometimes it gets stuck in limbo on 4.4, this should make it try again\n        if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {\n            long retry_in = (1000 * 60 * 5);\n            Log.d(TAG, \"Fallover Restarting in: \" + (retry_in / (60 * 1000)) + \" minutes\");\n            Calendar calendar = Calendar.getInstance();\n            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);\n            alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexCollectionService.class), 0));\n        } else {\n            stopSelf();\n        }\n    }\n\n\n\n    public void attemptConnection() {\n        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n        if (mBluetoothManager != null) {\n            mBluetoothAdapter = mBluetoothManager.getAdapter();\n            if (mBluetoothAdapter != null) {\n                if (device != null) {\n                    mConnectionState = STATE_DISCONNECTED;\n                    for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {\n                        if (bluetoothDevice.getAddress().compareTo(device.getAddress()) == 0) {\n                            mConnectionState = STATE_CONNECTED;\n                        }\n                    }\n                }\n\n                Log.w(TAG, \"Connection state: \" + mConnectionState);\n                if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {\n                    ActiveBluetoothDevice btDevice = ActiveBluetoothDevice.first();\n                    if (btDevice != null) {\n                        mDeviceName = btDevice.name;\n                        mDeviceAddress = btDevice.address;\n                        if (mBluetoothAdapter.isEnabled() && mBluetoothAdapter.getRemoteDevice(mDeviceAddress) != null) {\n                            connect(mDeviceAddress);\n                            return;\n                        }\n                    }\n                } else if (mConnectionState == STATE_CONNECTED) { //WOOO, we are good to go, nothing to do here!\n                    Log.w(TAG, \"Looks like we are already connected, going to read!\");\n                    return;\n                }\n            }\n        }\n        setRetryTimer();\n    }\n\n    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {\n        @Override\n        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {\n            if (newState == BluetoothProfile.STATE_CONNECTED) {\n                mConnectionState = STATE_CONNECTED;\n                ActiveBluetoothDevice.connected();\n                Log.w(TAG, \"Connected to GATT server.\");\n                mBluetoothGatt.discoverServices();\n            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {\n                mConnectionState = STATE_DISCONNECTED;\n                ActiveBluetoothDevice.disconnected();\n                Log.w(TAG, \"Disconnected from GATT server.\");\n                setRetryTimer();\n            }\n        }\n\n        @Override\n        public void onServicesDiscovered(BluetoothGatt gatt, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                BluetoothGattService gattService = mBluetoothGatt.getService(xDripDataService);\n                if (gattService != null) {\n                    BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(xDripDataCharacteristic);\n                    if (gattCharacteristic != null ) {\n                        final int charaProp = gattCharacteristic.getProperties();\n\n                        if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {\n                            mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);\n                        } else {\n                            Log.e(TAG, \"characteristic \" + gattCharacteristic.getUuid() + \" doesn't have notify properties\");\n                        }\n                    } else {\n                        Log.e(TAG, \"characteristic \" + xDripDataCharacteristic + \" not found\");\n                    }\n                } else {\n                    Log.e(TAG, \"service \" + xDripDataCharacteristic + \" not found\");\n                }\n            }\n        }\n\n        @Override\n        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {\n            final byte[] data = characteristic.getValue();\n            if (data != null && data.length > 0) { setSerialDataToTransmitterRawData(data, data.length); }\n        }\n    };\n\n    public boolean connect(final String address) {\n        Log.w(TAG, \"going to connect to device at address\" + address);\n        if (mBluetoothAdapter == null || address == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized or unspecified address.\");\n            setRetryTimer();\n            return false;\n        }\n        if (mBluetoothGatt != null) {\n            Log.w(TAG, \"BGatt isnt null, Closing.\");\n            mBluetoothGatt.close();\n            mBluetoothGatt = null;\n        }\n        device = mBluetoothAdapter.getRemoteDevice(address);\n        if (device == null) {\n            Log.w(TAG, \"Device not found.  Unable to connect.\");\n            setRetryTimer();\n            return false;\n        }\n        Log.w(TAG, \"Trying to create a new connection.\");\n        mBluetoothGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);\n        mConnectionState = STATE_CONNECTING;\n        return true;\n    }\n\n    public void disconnect() {\n        if ( mBluetoothGatt == null) { return; }\n        mBluetoothGatt.disconnect();\n        Log.d(TAG, \"Gatt Disconnect\");\n    }\n    public void close() {\n        if (mBluetoothGatt == null) {\n            return;\n        }\n        mBluetoothGatt.close();\n        setRetryTimer();\n        mBluetoothGatt = null;\n        mConnectionState = STATE_DISCONNECTED;\n    }\n\n    public void setSerialDataToTransmitterRawData(byte[] buffer, int len) {\n        Log.w(TAG, \"received some data!\");\n        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);\n        PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,\n                \"ReceivedReading\");\n        wakeLock.acquire();\n\n\n        Long timestamp = new Date().getTime();\n        TransmitterData transmitterData = TransmitterData.create(buffer, len, timestamp);\n        if (transmitterData != null) {\n            Sensor sensor = Sensor.currentSensor();\n            if (sensor != null) {\n                sensor.latest_battery_level = transmitterData.sensor_battery_level;\n                sensor.save();\n\n                BgReading.create(transmitterData.raw_data, this, timestamp);\n            } else {\n                Log.w(TAG, \"No Active Sensor, Data only stored in Transmitter Data\");\n            }\n        }\n        wakeLock.release();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/DexShareCollectionService.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\n\nimport android.annotation.TargetApi;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCallback;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattDescriptor;\nimport android.bluetooth.BluetoothGattService;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.DexShareAttributes;\nimport com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;\n\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.logging.Logger;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\n@TargetApi(Build.VERSION_CODES.KITKAT)\npublic class DexShareCollectionService extends Service {\n    private final static String TAG = DexShareCollectionService.class.getSimpleName();\n    private ForegroundServiceStarter foregroundServiceStarter;\n    private String mDeviceAddress;\n    private String mDeviceName;\n    private boolean is_connected = false;\n    private boolean reconnecting = false;\n\n    private BluetoothManager mBluetoothManager;\n    private BluetoothAdapter mBluetoothAdapter;\n    private BluetoothGatt mBluetoothGatt;\n    private String mBluetoothDeviceAddress;\n    private int mConnectionState = STATE_DISCONNECTED;\n    private BluetoothDevice device;\n\n    private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;\n    private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;\n    private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;\n    private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;\n\n    private BluetoothGattService mShareService;\n    private BluetoothGattCharacteristic mAuthenticationCharacteristic;\n    private BluetoothGattCharacteristic mSendDataCharacteristic;\n    private BluetoothGattCharacteristic mReceiveDataCharacteristic;\n    private BluetoothGattCharacteristic mCommandCharacteristic;\n    private BluetoothGattCharacteristic mResponseCharacteristic;\n    private BluetoothGattCharacteristic mHeartBeatCharacteristic;\n\n    //Gatt Tasks\n    public final int GATT_NOTHING = 0;\n    public final int GATT_SETUP = 1;\n    public final int GATT_WRITING_COMMANDS = 2;\n    public final int GATT_READING_RESPONSE = 3;\n    public int successfulWrites;\n\n    //RXJAVA FUN\n    Action1<byte[]> mDataResponseListener;\n    public int currentGattTask;\n    public int step;\n    public List<byte[]> writePackets;\n    public int recordType;\n    SharedPreferences prefs;\n    ReadDataShare readData;\n\n    public boolean state_authSucess = false;\n    public boolean state_authInProgress = false;\n    public boolean state_notifSetupSucess = false;\n\n    public boolean shouldDisconnect = false;\n    public boolean share2 = false;\n    public Service service;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        readData = new ReadDataShare(this);\n        service = this;\n        foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), service);\n        foregroundServiceStarter.start();\n        final IntentFilter bondintent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);\n        registerReceiver(mPairReceiver, bondintent);\n        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        listenForChangeInSettings();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n        if (CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            setFailoverTimer();\n        } else {\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n        if (Sensor.currentSensor() == null) {\n            setRetryTimer();\n            return START_NOT_STICKY;\n        }\n        Log.w(TAG, \"STARTING SERVICE\");\n        attemptConnection();\n        return START_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        close();\n        setRetryTimer();\n        foregroundServiceStarter.stop();\n        unregisterReceiver(mPairReceiver);\n        Log.w(TAG, \"SERVICE STOPPED\");\n    }\n\n    public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {\n        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {\n            if(key.compareTo(\"run_service_in_foreground\") == 0) {\n                Log.e(\"FOREGROUND\", \"run_service_in_foreground changed!\");\n                if (prefs.getBoolean(\"run_service_in_foreground\", false)) {\n                    foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), service);\n                    foregroundServiceStarter.start();\n                    Log.w(TAG, \"Moving to foreground\");\n                } else {\n                    service.stopForeground(true);\n                    Log.w(TAG, \"Removing from foreground\");\n                }\n            }\n        }\n    };\n\n    public void listenForChangeInSettings() {\n        prefs.registerOnSharedPreferenceChangeListener(prefListener);\n    }\n\n    public void setRetryTimer() {\n        if (CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            BgReading bgReading = BgReading.last();\n            long retry_in;\n            if (bgReading != null) {\n                retry_in = Math.min(Math.max((1000 * 30), (1000 * 60 * 5) - (new Date().getTime() - bgReading.timestamp) - (1000 * 15)), (1000 * 60 * 5));\n            } else {\n                retry_in = (1000 * 20);\n            }\n            Log.d(TAG, \"Restarting in: \" + (retry_in / (60 * 1000)) + \" minutes\");\n            Calendar calendar = Calendar.getInstance();\n            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);\n            alarm.setExact(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexShareCollectionService.class), 0));\n        }\n    }\n\n    public void setFailoverTimer() { //Sometimes it gets stuck in limbo on 4.4, this should make it try again\n        if (CollectionServiceStarter.isBTShare(getApplicationContext())) {\n            long retry_in = (1000 * 60 * 5);\n            Log.d(TAG, \"Fallover Restarting in: \" + (retry_in / (60 * 1000)) + \" minutes\");\n            Calendar calendar = Calendar.getInstance();\n            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);\n            alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexShareCollectionService.class), 0));\n        } else {\n            stopSelf();\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        throw new UnsupportedOperationException(\"Not yet implemented\");\n    }\n\n    public void attemptConnection() {\n        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n        if (mBluetoothManager != null) {\n            if (device != null) {\n                mConnectionState = STATE_DISCONNECTED;\n                for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {\n                    if (bluetoothDevice.getAddress().compareTo(device.getAddress()) == 0) {\n                        mConnectionState = STATE_CONNECTED;\n                    }\n                }\n            }\n            Log.w(TAG, \"Connection state: \" + mConnectionState);\n            if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {\n                ActiveBluetoothDevice btDevice = ActiveBluetoothDevice.first();\n                if (btDevice != null) {\n                    mDeviceName = btDevice.name;\n                    mDeviceAddress = btDevice.address;\n                    mBluetoothAdapter = mBluetoothManager.getAdapter();\n                    if (mBluetoothAdapter.isEnabled() && mBluetoothAdapter.getRemoteDevice(mDeviceAddress) != null) {\n                        connect(mDeviceAddress);\n                        return;\n                    } else {\n                        Log.w(TAG, \"Bluetooth is disabled or BT device cant be found\");\n                        setRetryTimer();\n                        return;\n                    }\n                } else {\n                    Log.w(TAG, \"No bluetooth device to try and connect to\");\n                    setRetryTimer();\n                    return;\n                }\n            } else if (mConnectionState == STATE_CONNECTED) {\n                Log.w(TAG, \"Looks like we are already connected, going to read!\");\n                attemptRead();\n                return;\n            } else {\n                setRetryTimer();\n                return;\n            }\n        } else {\n            setRetryTimer();\n            return;\n        }\n    }\n\n    public void attemptRead() {\n        Log.d(TAG, \"Attempting to read data\");\n        final Action1<Long> systemTimeListener = new Action1<Long>() {\n            @Override\n            public void call(Long s) {\n                if (s != null) {\n                    Log.d(TAG, \"Made the full round trip, got \" + s + \" as the system time\");\n                    final long addativeSystemTimeOffset = new Date().getTime() - s;\n\n                    final Action1<Long> dislpayTimeListener = new Action1<Long>() {\n                        @Override\n                        public void call(Long s) {\n                            if (s != null) {\n                                Log.d(TAG, \"Made the full round trip, got \" + s + \" as the display time offset\");\n                                final long addativeDisplayTimeOffset = addativeSystemTimeOffset - (s*1000);\n\n                                Log.d(TAG, \"Making \" + addativeDisplayTimeOffset + \" the the total time offset\");\n\n                                final Action1<EGVRecord[]> evgRecordListener = new Action1<EGVRecord[]>() {\n                                    @Override\n                                    public void call(EGVRecord[] egvRecords) {\n                                        if (egvRecords != null) {\n                                            Log.d(TAG, \"Made the full round trip, got \" + egvRecords.length + \" EVG Records\");\n                                            BgReading.create(egvRecords, addativeSystemTimeOffset, getApplicationContext());\n                                            if (shouldDisconnect) {\n                                                stopSelf();\n                                            } else {\n                                                setRetryTimer();\n                                            }\n                                        }\n                                    }\n                                };\n\n                                final Action1<SensorRecord[]> sensorRecordListener = new Action1<SensorRecord[]>() {\n                                    @Override\n                                    public void call(SensorRecord[] sensorRecords) {\n                                        if (sensorRecords != null) {\n                                            Log.d(TAG, \"Made the full round trip, got \" + sensorRecords.length + \" Sensor Records\");\n                                            BgReading.create(sensorRecords, addativeSystemTimeOffset, getApplicationContext());\n                                            readData.getRecentEGVs(evgRecordListener);\n                                        }\n                                    }\n                                };\n\n                                final Action1<CalRecord[]> calRecordListener = new Action1<CalRecord[]>() {\n                                    @Override\n                                    public void call(CalRecord[] calRecords) {\n                                        if (calRecords != null) {\n                                            Log.d(TAG, \"Made the full round trip, got \" + calRecords.length + \" Cal Records\");\n                                            Calibration.create(calRecords, addativeDisplayTimeOffset, getApplicationContext());\n                                            readData.getRecentSensorRecords(sensorRecordListener);\n                                        }\n                                    }\n                                };\n                                readData.getRecentCalRecords(calRecordListener);\n                            }\n                        }\n                    };\n                    readData.readDisplayTimeOffset(dislpayTimeListener);\n                }\n            }\n        };\n        readData.readSystemTime(systemTimeListener);\n    }\n\n    public boolean connect(final String address) {\n        Log.w(TAG, \"going to connect to device at address\" + address);\n        if (mBluetoothAdapter == null || address == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized or unspecified address.\");\n            setRetryTimer();\n            return false;\n        }\n        if (mBluetoothGatt != null) {\n            Log.w(TAG, \"BGatt isnt null, Closing.\");\n            mBluetoothGatt.close();\n            mBluetoothGatt = null;\n        }\n        for (BluetoothDevice bluetoothDevice : mBluetoothAdapter.getBondedDevices()) {\n            if (bluetoothDevice.getAddress().compareTo(address) == 0) {\n                Log.v(TAG, \"Device found, already bonded, going to connect\");\n               if(mBluetoothAdapter.getRemoteDevice(bluetoothDevice.getAddress()) != null) {\n                   device = bluetoothDevice;\n                   mBluetoothGatt = device.connectGatt(getApplicationContext(), false, mGattCallback);\n                   return true;\n               }\n            }\n        }\n        device = mBluetoothAdapter.getRemoteDevice(address);\n        if (device == null) {\n            Log.w(TAG, \"Device not found.  Unable to connect.\");\n            setRetryTimer();\n            return false;\n        }\n        Log.w(TAG, \"Trying to create a new connection.\");\n        mBluetoothGatt = device.connectGatt(getApplicationContext(), false, mGattCallback);\n        mConnectionState = STATE_CONNECTING;\n        return true;\n    }\n\n    public void authenticateConnection() {\n        Log.w(TAG, \"Trying to auth\");\n        String receiverSn = prefs.getString(\"share_key\", \"SM00000000\").toUpperCase() + \"000000\";\n        if(receiverSn.compareTo(\"SM00000000000000\") == 0) { // They havnt set their serial number, dont bond!\n            setRetryTimer();\n            return;\n        }\n        byte[] bondkey = (receiverSn).getBytes(StandardCharsets.US_ASCII);\n        if (mBluetoothGatt != null) {\n            if (mShareService != null) {\n                if(!share2) {\n                    mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode);\n                } else {\n                    mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode2);\n                }\n                if (mAuthenticationCharacteristic != null) {\n                    Log.v(TAG, \"Auth Characteristic found: \" + mAuthenticationCharacteristic.toString());\n                    if (mAuthenticationCharacteristic.setValue(bondkey)) {\n                        mBluetoothGatt.writeCharacteristic(mAuthenticationCharacteristic);\n                    } else {\n                        setRetryTimer();\n                    }\n                } else {\n                    Log.w(TAG, \"Authentication Characteristic IS NULL\");\n                    setRetryTimer();\n                }\n            } else {\n                Log.w(TAG, \"CRADLE SERVICE IS NULL\");\n            }\n        } else {\n            setRetryTimer();\n        }\n    }\n\n    public void assignCharacteristics() {\n        if(!share2) {\n            Log.d(TAG, \"Setting #1 characteristics\");\n            mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver);\n            mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse);\n            mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command);\n            mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response);\n            mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat);\n        } else {\n            Log.d(TAG, \"Setting #1 characteristics\");\n            mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver2);\n            mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse2);\n            mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command2);\n            mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response2);\n            mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat2);\n        }\n    }\n\n    public void setListeners(int listener_number) {\n        Log.w(TAG, \"Setting Listener: #\" + listener_number);\n        if (listener_number == 1) {\n            step = 2;\n            setCharacteristicIndication(mReceiveDataCharacteristic);\n        } else {\n            step = 3;\n            attemptRead();\n        }\n    }\n\n\n    public void close() {\n        if (mBluetoothGatt == null) {\n            return;\n        }\n        mBluetoothGatt.close();\n        setRetryTimer();\n        mBluetoothGatt = null;\n        mConnectionState = STATE_DISCONNECTED;\n        Log.w(TAG, \"bt Disconnected\");\n    }\n\n    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic) {\n        setCharacteristicNotification(characteristic, true);\n    }\n\n    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {\n        Log.w(TAG, \"Characteristic setting notification\");\n        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);\n        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));\n        Log.w(TAG, \"Descriptor found: \" + descriptor.getUuid());\n        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);\n        mBluetoothGatt.writeDescriptor(descriptor);\n    }\n\n    public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic) {\n        setCharacteristicIndication(characteristic, true);\n    }\n\n    public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) {\n        Log.w(TAG, \"Characteristic setting indication\");\n        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);\n        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));\n        Log.w(TAG, \"Descriptor found: \" + descriptor.getUuid());\n        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);\n        mBluetoothGatt.writeDescriptor(descriptor);\n    }\n\n    public void writeCommand(List<byte[]> packets, int aRecordType, Action1<byte[]> dataResponseListener) {\n        mDataResponseListener = dataResponseListener;\n        successfulWrites = 0;\n        writePackets = packets;\n        recordType = aRecordType;\n        step = 0;\n        currentGattTask = GATT_WRITING_COMMANDS;\n        gattWritingStep();\n    }\n\n    public void clearGattTask() {\n        currentGattTask = GATT_NOTHING;\n        step = 0;\n    }\n\n    private void gattSetupStep() {\n        step = 1;\n        if(share2) { assignCharacteristics(); }\n        setListeners(1);\n    }\n\n    private void gattWritingStep() {\n        Log.d(TAG, \"Writing command to the Gatt, step: \" + step);\n        int index = step;\n        if (index <= (writePackets.size() - 1)) {\n            Log.d(TAG, \"Writing: \" + writePackets.get(index) + \" index: \" + index);\n            if(mSendDataCharacteristic != null && writePackets != null) {\n                mSendDataCharacteristic.setValue(writePackets.get(index));\n                if (mBluetoothGatt.writeCharacteristic(mSendDataCharacteristic)) {\n                    Log.d(TAG, \"Wrote Successfully\");\n                }\n            }\n        } else {\n            Log.d(TAG, \"Done Writing commands\");\n            clearGattTask();\n        }\n    }\n\n    private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {\n        public void onReceive(Context context, Intent intent) {\n            String action = intent.getAction();\n            final BluetoothDevice bondDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);\n\n            if (mBluetoothGatt != null && mBluetoothGatt.getDevice() != null && bondDevice != null) {\n                if (!bondDevice.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) {\n                    Log.d(TAG, \"Bond state wrong device\");\n                    return; // That wasnt a device we care about!!\n                }\n            }\n\n            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {\n                final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);\n                if (state == BluetoothDevice.BOND_BONDED) {\n                    Log.d(TAG, \"CALLBACK RECIEVED Bonded\");\n                    authenticateConnection();\n                } else if (state == BluetoothDevice.BOND_NONE) {\n                    Log.d(TAG, \"CALLBACK RECIEVED: Not Bonded\");\n                } else if (state == BluetoothDevice.BOND_BONDING) {\n                    Log.d(TAG, \"CALLBACK RECIEVED: Trying to bond\");\n                }\n            }\n        }\n    };\n\n    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {\n        @Override\n        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {\n            Log.w(TAG, \"Gatt state change status: \" + status + \" new state: \" + newState);\n            writeStatusConnectionFailures(status);\n            if (status == 133) {\n                Log.e(TAG, \"Got the status 133 bug, GROSS!!\");\n            }\n            if (newState == BluetoothProfile.STATE_CONNECTED) {\n                mBluetoothGatt = gatt;\n                device = mBluetoothGatt.getDevice();\n                mConnectionState = STATE_CONNECTED;\n                ActiveBluetoothDevice.connected();\n                Log.w(TAG, \"Connected to GATT server.\");\n\n                Log.w(TAG, \"discovering services\");\n                currentGattTask = GATT_SETUP;\n                if (!mBluetoothGatt.discoverServices()) {\n                    Log.w(TAG, \"discovering failed\");\n                    if(shouldDisconnect) {\n                        stopSelf();\n                    } else {\n                        setRetryTimer();\n                    }\n                }\n            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {\n                mConnectionState = STATE_DISCONNECTED;\n                ActiveBluetoothDevice.disconnected();\n                if(shouldDisconnect) {\n                    stopSelf();\n                } else {\n                    setRetryTimer();\n                }\n                Log.w(TAG, \"Disconnected from GATT server.\");\n            } else {\n                Log.w(TAG, \"Gatt callback... strange state.\");\n            }\n        }\n\n        @Override\n        public void onServicesDiscovered(BluetoothGatt gatt, int status) {\n            Log.d(TAG, \"services discovered \" + status);\n           if (status == BluetoothGatt.GATT_SUCCESS) {\n               mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService);\n               if(mShareService == null) {\n                   mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService2);\n                   share2 = true;\n               } else {\n                   share2 = false;\n               }\n                assignCharacteristics();\n                authenticateConnection();\n                gattSetupStep();\n            } else {\n                Log.w(TAG, \"No Services Discovered!\");\n            }\n        }\n\n        @Override\n        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                Log.v(TAG, \"Characteristic Read \" + characteristic.getUuid());\n                if(mHeartBeatCharacteristic.getUuid().equals(characteristic.getUuid())) {\n                    Log.v(TAG, \"Characteristic Read \" + characteristic.getUuid() + \" \" + characteristic.getValue());\n                    setCharacteristicNotification(mHeartBeatCharacteristic);\n                }\n                mBluetoothGatt.readCharacteristic(mHeartBeatCharacteristic);\n            } else {\n                Log.e(TAG, \"Characteristic failed to read\");\n            }\n        }\n\n        @Override\n        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {\n            UUID charUuid = characteristic.getUuid();\n            Log.d(TAG, \"Characteristic Update Received: \" + charUuid);\n            if (charUuid.compareTo(mReceiveDataCharacteristic.getUuid()) == 0) {\n                Log.d(TAG, \"mCharReceiveData Update\");\n                byte[] value = characteristic.getValue();\n                if (value != null) {\n                    Observable.just(characteristic.getValue()).subscribe(mDataResponseListener);\n                }\n            }\n        }\n\n        @Override\n        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();\n                Log.d(TAG, \"Characteristic onDescriptorWrite ch \" + characteristic.getUuid());\n                if(mHeartBeatCharacteristic.getUuid().equals(characteristic.getUuid())) {\n                    state_notifSetupSucess = true;\n                    setCharacteristicIndication(mReceiveDataCharacteristic);\n                }\n                if(mReceiveDataCharacteristic.getUuid().equals(characteristic.getUuid())) {\n                    setCharacteristicIndication(mResponseCharacteristic);\n                }\n                if(mResponseCharacteristic.getUuid().equals(characteristic.getUuid())) {\n                    attemptRead();\n                }\n            } else if ((status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) != 0 || (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION) != 0) {\n                if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {\n                    device = gatt.getDevice();\n                    state_authInProgress = true;\n                    bondDevice();\n                } else {\n                    Log.e(TAG, \"The phone is trying to read from paired device without encryption. Android Bug?\");\n                }\n            } else {\n                Log.e(TAG, \"Unknown error writing descriptor\");\n            }\n        }\n\n        @Override\n        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {\n            Log.d(TAG, \"characteristic wrote \" + status);\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                Log.d(TAG, \"Wrote a characteristic successfully \" + characteristic.getUuid());\n                if (mAuthenticationCharacteristic.getUuid().equals(characteristic.getUuid())) {\n                    state_authSucess = true;\n                    mBluetoothGatt.readCharacteristic(mHeartBeatCharacteristic);\n                }\n            } else if ((status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) != 0 || (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION) != 0) {\n                if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {\n                    device = gatt.getDevice();\n                    state_authInProgress = true;\n                    bondDevice();\n                } else {\n                    Log.e(TAG, \"The phone is trying to read from paired device without encryption. Android Bug?\");\n                }\n            } else {\n                Log.e(TAG, \"Unknown error writing Characteristic\");\n            }\n        }\n    };\n\n    public void bondDevice() {\n        final IntentFilter bondintent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);\n        registerReceiver(mPairReceiver, bondintent);\n        if(!share2){ device.setPin(\"000000\".getBytes()); }\n        device.createBond();\n    }\n\n    private void writeStatusConnectionFailures(int status) {\n        if(status != 0) {\n            Log.e(TAG, \"ERRR: GATT_WRITE_NOT_PERMITTED \" + (status & BluetoothGatt.GATT_WRITE_NOT_PERMITTED));\n            Log.e(TAG, \"ERRR: GATT_INSUFFICIENT_AUTHENTICATION \" + (status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION));\n            Log.e(TAG, \"ERRR: GATT_REQUEST_NOT_SUPPORTED \" + (status & BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED));\n            Log.e(TAG, \"ERRR: GATT_INSUFFICIENT_ENCRYPTION \" + (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION));\n            Log.e(TAG, \"ERRR: GATT_INVALID_OFFSET \" + (status & BluetoothGatt.GATT_INVALID_OFFSET));\n            Log.e(TAG, \"ERRR: GATT_FAILURE \" + (status & BluetoothGatt.GATT_FAILURE));\n            Log.e(TAG, \"ERRR: GATT_INVALID_ATTRIBUTE_LENGTH \" + (status & BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH));\n            Log.e(TAG, \"ERRR: GATT_READ_NOT_PERMITTED\" + (status & BluetoothGatt.GATT_READ_NOT_PERMITTED));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/MongoWrapper.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\nimport java.io.IOException;\nimport java.net.UnknownHostException;\n\nimport android.util.Log;\n\nimport com.mongodb.BasicDBObject;\nimport com.mongodb.DB;\nimport com.mongodb.DBCollection;\nimport com.mongodb.DBCursor;\nimport com.mongodb.DBObject;\nimport com.mongodb.MongoClient;\nimport com.mongodb.MongoException;\nimport com.mongodb.MongoClientURI;\n\nimport java.util.Date;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class MongoWrapper {\n\n\tMongoClient mongoClient_;\n\tString dbUriStr_;\n\tString dbName_;\n\tString collection_;\n\tString index_;\n\tString machineName_;\n\tprivate final static String TAG = WixelReader.class.getName();\n\n\tpublic MongoWrapper(String dbUriStr, String collection, String index, String machineName) {\n\t\tdbUriStr_ = dbUriStr;\n\t\t// dbName is the last part of the string starting with /dbname\n\t\tdbName_ = dbUriStr.substring(dbUriStr.lastIndexOf('/') + 1);\n\t\tcollection_ = collection;\n\t\tindex_ = index;\n\t\tmachineName_ = machineName;\n\t}\n\n\t// Unfortunately, this also throws other exceptions that are not documetned...\n    public DBCollection openMongoDb() throws UnknownHostException {\n\n    \tMongoClientURI dbUri = new MongoClientURI(dbUriStr_); //?? thros\n\t    mongoClient_ = new MongoClient(dbUri);\n\n\t    DB db = mongoClient_.getDB( dbName_ );\n\t    DBCollection coll = db.getCollection(collection_);\n\t    coll.createIndex(new BasicDBObject(index_, 1));  // create index on \"i\", ascending\n\n\t    return coll;\n\n    }\n\n     public void closeMongoDb() {\n         if(mongoClient_ != null) {\n    \t \tmongoClient_.close();\n         }\n     }\n\n     public boolean WriteDebugDataToMongo(String message)\n     {\n    \t String complete = machineName_ + \" \" + new Date().toLocaleString() + \" \" + message;\n    \t BasicDBObject doc = new BasicDBObject(\"DebugMessage\", complete);\n    \t return WriteToMongo(doc);\n     }\n\n\n     public boolean WriteToMongo(TransmitterRawData trd)\n     {\n    \t BasicDBObject bdbo = trd.toDbObj(machineName_ + \" \" + new Date(trd.CaptureDateTime).toLocaleString());\n    \t return WriteToMongo(bdbo);\n     }\n\n     public boolean WriteToMongo(BasicDBObject bdbo)\n     {\n     \tDBCollection coll;\n     \ttry {\n     \t\tcoll = openMongoDb();\n         \tcoll.insert(bdbo);\n\n \t\t} catch (UnknownHostException e) {\n \t\t   Log.e(TAG, \"WriteToMongo cought UnknownHostException! \",e);\n \t\t\treturn false;\n \t\t} catch (MongoException e) {\n \t\t   Log.e(TAG, \"WriteToMongo cought MongoException! \", e);\n \t\t\treturn false;\n \t\t} catch (Exception e) {\n \t\t   Log.e(TAG, \"WriteToMongo cought Exception! \", e);\n \t\t\tcloseMongoDb();\n \t\t\treturn false;\n \t\t}\n     \tfinally {\n \t\t\tcloseMongoDb();\n \t\t}\n     \treturn true;\n     }\n\n     // records will be marked by their timestamp\n     public List<TransmitterRawData> ReadFromMongo(int numberOfRecords) {\n    \tSystem.out.println( \"Starting to read from mongodb\");\n\n    \tList<TransmitterRawData> trd_list = new LinkedList<TransmitterRawData>();\n      \tDBCollection coll;\n      \tTransmitterRawData lastTrd = null;\n      \ttry {\n      \t\tcoll = openMongoDb();\n            BasicDBObject query = new BasicDBObject(\"RawValue\", new BasicDBObject(\"$exists\", true));\n            DBCursor cursor = coll.find(query);\n            cursor.sort(new BasicDBObject(\"CaptureDateTime\", -1));\n            try {\n                while(cursor.hasNext() && trd_list.size() < numberOfRecords) {\n                    //System.out.println(cursor.next());\n                    Log.e(TAG, \"Read an object from mongodb\");\n                    TransmitterRawData trd = new TransmitterRawData((BasicDBObject)cursor.next());\n                    // Do our best to fix the relative time...\n                    trd.RelativeTime = new Date().getTime() - trd.CaptureDateTime;\n                    // since we are reading it from the db, it was uploaded...\n                    trd.Uploaded = 1;\n                    if(lastTrd == null) {\n                    \ttrd_list.add(0,trd);\n                    \tlastTrd = trd;\n                    \tSystem.out.println( trd.toTableString());\n                    } else if(!WixelReader.almostEquals(lastTrd, trd)) {\n                    \tlastTrd = trd;\n                    \ttrd_list.add(0,trd);\n                    \tSystem.out.println( trd.toTableString());\n                    }\n\n                }\n             } finally {\n                cursor.close();\n             }\n\n        } catch (UnknownHostException e) {\n            Log.e(TAG, \"ReadFromMongo: cought UnknownHostException! \", e);\n            return null;\n        } catch (MongoException e) {\n            Log.e(TAG, \"ReadFromMongo: cought MongoException! \" , e);\n            return trd_list;\n        } catch (Exception e) {\n  \t\t      Log.e(TAG, \"ReadFromMongo: cought Exception! \" , e);\n  \t\t      closeMongoDb();\n \t\t\treturn null;\n \t\t}finally {\n  \t\t\tcloseMongoDb();\n  \t\t}\n      \treturn trd_list;\n\n     }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/SyncService.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.IBinder;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;\nimport com.eveningoutpost.dexdrip.UtilityModels.CalibrationSendQueue;\nimport com.eveningoutpost.dexdrip.UtilityModels.MongoSendTask;\nimport com.eveningoutpost.dexdrip.UtilityModels.NightscoutUploader;\nimport com.eveningoutpost.dexdrip.UtilityModels.RestCalls;\nimport com.eveningoutpost.dexdrip.UtilityModels.SensorSendQueue;\n\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.List;\n\npublic class SyncService extends Service {\n    int mStartMode;\n    private Context mContext;\n    private Boolean enableRESTUpload;\n    private Boolean enableMongoUpload;\n    private SharedPreferences prefs;\n\n    @Override\n    public void onCreate() {\n        Log.w(\"SYNC SERVICE:\", \"STARTING SERVICE\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        attemptSend();\n        return START_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        setRetryTimer();\n        Log.w(\"SYNC SERVICE\", \"SERVICE STOPPED\");\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        throw new UnsupportedOperationException(\"Not yet implemented\");\n    }\n\n    public void attemptSend() {\n        mContext = getApplicationContext();\n        prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n        enableRESTUpload = prefs.getBoolean(\"cloud_storage_api_enable\", false);\n        enableMongoUpload = prefs.getBoolean(\"cloud_storage_mongodb_enable\", false);\n\n        if (enableRESTUpload || enableMongoUpload) { syncToMogoDb(); }\n\n        if (false) {\n            for (SensorSendQueue job : SensorSendQueue.queue()) {\n                RestCalls.sendSensor(job);\n            }\n            for (CalibrationSendQueue job : CalibrationSendQueue.queue()) {\n                RestCalls.sendCalibration(job);\n            }\n            for (BgSendQueue job : BgSendQueue.queue()) {\n                RestCalls.sendBgReading(job);\n            }\n        }\n        setRetryTimer();\n    }\n\n    public void setRetryTimer() {\n        Calendar calendar = Calendar.getInstance();\n        AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);\n        alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + (1000 * 30 * 5), PendingIntent.getService(this, 0, new Intent(this, SyncService.class), 0));\n    }\n\n    public void syncToMogoDb() {\n        MongoSendTask task = new MongoSendTask(getApplicationContext());\n        task.execute();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/TransmitterRawData.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\nimport java.util.Date;\nimport com.mongodb.BasicDBObject;\n/**\n * Created by John Costik on 6/7/14.\n */\npublic class TransmitterRawData {\n\n\n    private long _id;\n\n    public String Id;\n    public int TransmissionId;\n    public String TransmitterId;\n    public int RawValue;\n    public int FilteredValue;\n    public int BatteryLife;\n    public int ReceivedSignalStrength;\n    public long CaptureDateTime;\n    public int Uploaded;\n    public int UploadAttempts;\n    public int UploaderBatteryLife;\n    // When sending set this value to the relative time...\n    // The time between the capture and now...\n    public long RelativeTime;\n\n    public int getTransmissionId() {\n        return TransmissionId;\n    }\n\n    public void setTransmissionId(int transmissionId) {\n        TransmissionId = transmissionId;\n    }\n\n    public int getUploaded() {\n        return Uploaded;\n    }\n\n    public void setUploaded(int uploaded) {\n        Uploaded = uploaded;\n    }\n\n    public int getUploadAttempts() {\n        return UploadAttempts;\n    }\n\n    public void setUploadAttempts(int uploadAttempts) {\n        UploadAttempts = uploadAttempts;\n    }\n\n    public int getUploaderBatteryLife() {\n        return UploaderBatteryLife;\n    }\n\n    public void setUploaderBatteryLife(int uploaderBatteryLife) {\n        UploaderBatteryLife = uploaderBatteryLife;\n    }\n\n    public int getBatteryLife() {\n        return BatteryLife;\n    }\n\n    public void setBatteryLife(int batteryLife) {\n        BatteryLife = batteryLife;\n    }\n\n    public int getReceivedSignalStrength() {\n        return ReceivedSignalStrength;\n    }\n\n    public void setReceivedSignalStrength(int receivedSignalStrength) {\n        ReceivedSignalStrength = receivedSignalStrength;\n    }\n\n    public String getTransmitterId() {\n        return TransmitterId;\n    }\n\n    public void setTransmitterId(String transmitterId) {\n        TransmitterId = transmitterId;\n    }\n\n    public int getRawValue() {\n        return RawValue;\n    }\n\n    public void setRawValue(int rawValue) {\n        RawValue = rawValue;\n    }\n\n    public int getFilteredValue() {\n        return FilteredValue;\n    }\n\n    public void setFilteredValue(int filteredValue) {\n        FilteredValue = filteredValue;\n    }\n\n    public long getCaptureDateTime() {\n        return CaptureDateTime;\n    }\n\n    public void setCaptureDateTime(long captureDateTime) {\n        CaptureDateTime = captureDateTime;\n    }\n\n    public long get_id() {\n        return _id;\n    }\n\n    public void set_id(long _id) {\n        this._id = _id;\n    }\n\n    private Long getRelativeTime() {\n        return RelativeTime;\n    }\n\n    public TransmitterRawData(){\n\n    }\n/*\n    public TransmitterRawData(String id, String raw, String filter, String battery, String rssi, int uploaderBattery){\n        RawValue = Integer.parseInt(raw);\n        FilteredValue = Integer.parseInt(filter);\n        TransmitterId = id;\n        BatteryLife = Integer.parseInt(battery);\n        ReceivedSignalStrength = Integer.parseInt(rssi);\n        CaptureDateTime = new Date().getTime();\n        UploaderBatteryLife = uploaderBattery;\n\n        Uploaded = 0;\n        UploadAttempts = 1;\n    }\n\n    public TransmitterRawData(byte[] buffer, int len, Context context){\n\n        StringBuilder toParse = new StringBuilder();\n        for (int i = 0; i < len; ++i) {\n            toParse.append((char) buffer[i]);\n        }\n        String[] parsed = toParse.toString().split(\"\\\\s+\");\n\n        RawValue = Integer.parseInt(parsed[1]);\n        FilteredValue = Integer.parseInt(parsed[2]);\n        TransmitterId = parsed[0];\n        BatteryLife = Integer.parseInt(parsed[3]);\n        ReceivedSignalStrength = Integer.parseInt(parsed[4]);\n        TransmissionId = Integer.parseInt(parsed[5]);\n        CaptureDateTime = new Date().getTime();\n\n        Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n        UploaderBatteryLife = i.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n        Uploaded = 0;\n        UploadAttempts = 1;\n    }\n*/\n    public String toTableString()\n    {\n        String displayDt = new Date(getCaptureDateTime()).toLocaleString() + System.getProperty(\"line.separator\");\n        String transmitterId = \"Transmitter Id: \" + getTransmitterId() + System.getProperty(\"line.separator\");\n        String transmissionId = \"Transmission Id: \" + getTransmissionId() + System.getProperty(\"line.separator\");\n        String rawVal = \"Raw Value: \" + getRawValue() + System.getProperty(\"line.separator\");\n        String filterVal = \"Filtered Value: \" + getFilteredValue() + System.getProperty(\"line.separator\");\n        String batteryVal = \"Transmitter Battery: \" + getBatteryLife() + \" \" + System.getProperty(\"line.separator\");\n        String signalVal = \"RSSI: \" + getReceivedSignalStrength() + \" \" + System.getProperty(\"line.separator\");\n        String uploadDeviceBatteryVal = \"Uploader Battery: \" + getUploaderBatteryLife() + \" \" + System.getProperty(\"line.separator\");\n        String uploaded = \"Uploaded: \" + getUploaded() + \" \" + System.getProperty(\"line.separator\");\n        String RelativeTime = \"relateive time (seconds): \" + getRelativeTime() / 1000 + \" \"+ System.getProperty(\"line.separator\");\n\n        return displayDt + transmitterId + transmissionId + rawVal + filterVal + batteryVal + signalVal + uploadDeviceBatteryVal + uploaded + RelativeTime;\n    }\n\n    public BasicDBObject toDbObj(String DebugInfo) {\n    \tBasicDBObject doc = new BasicDBObject(\"TransmissionId\", TransmissionId).\n    \t\t\tappend(\"TransmitterId\", TransmitterId).\n    \t\t\tappend(\"RawValue\", RawValue).\n    \t\t\tappend(\"FilteredValue\", FilteredValue).\n    \t\t\tappend(\"BatteryLife\", BatteryLife).\n    \t\t\tappend(\"ReceivedSignalStrength\", ReceivedSignalStrength).\n    \t\t\tappend(\"CaptureDateTime\", CaptureDateTime).\n    \t\t\tappend(\"UploaderBatteryLife\", UploaderBatteryLife).\n    \t\t\tappend(\"DebugInfo\", DebugInfo);\n    \treturn doc;\n    }\n\n    public TransmitterRawData(BasicDBObject src) {\n    \tTransmissionId = src.getInt(\"TransmissionId\");\n    \tTransmitterId  = src.getString(\"TransmitterId\");\n    \tRawValue       = src.getInt(\"RawValue\");\n    \tFilteredValue  = src.getInt(\"FilteredValue\");\n    \tBatteryLife    = src.getInt(\"BatteryLife\");\n    \tReceivedSignalStrength = src.getInt(\"ReceivedSignalStrength\");\n    \tCaptureDateTime = src.getLong(\"CaptureDateTime\");\n    \tUploaderBatteryLife = src.getInt(\"UploaderBatteryLife\");\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Services/WixelReader.java",
    "content": "package com.eveningoutpost.dexdrip.Services;\n\nimport java.io.IOException;\nimport java.util.Date;\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.TransmitterData;\n\npublic class WixelReader  extends Thread {\n\n    private final static String TAG = WixelReader.class.getName();\n    private static WixelReader singleton;\n\n    public synchronized static WixelReader getInstance(Context ctx) {\n        if(singleton == null) {\n           singleton = new WixelReader(ctx);\n        }\n        return singleton;\n    }\n\n    private final Context mContext;\n\n    private volatile boolean mStop = false;\n    private static boolean sStarted = false;\n\n    public WixelReader(Context ctx) {\n        mContext = ctx.getApplicationContext();\n    }\n\n    public static void sStart(Context ctx) {\n        if(sStarted) {\n            return;\n        }\n        WixelReader theWixelReader =  getInstance(ctx);\n        theWixelReader.start();\n        sStarted = true;\n\n    }\n\n    public static void sStop() {\n        if(!sStarted) {\n            return;\n        }\n        WixelReader theWixelReader =  getInstance(null);\n        theWixelReader.Stop();\n        try {\n            theWixelReader.join();\n        } catch (InterruptedException e) {\n            Log.e(TAG, \"cought InterruptedException, could not wait for the wixel thread to exit\", e);\n        }\n        sStarted = false;\n        // A stopped thread can not start again, so we need to kill it and will start a new one\n        // on demand\n        singleton = null;\n    }\n\n    public static boolean IsConfigured(Context ctx) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);\n        String recieversIpAddresses = prefs.getString(\"wifi_recievers_addresses\", \"\");\n        if(recieversIpAddresses == null || recieversIpAddresses.equals(\"\") ) {\n            return false;\n        }\n        return true;\n    }\n\n    public static boolean almostEquals( TransmitterRawData e1, TransmitterRawData e2)\n    {\n        if (e1 == null || e2==null) {\n            return false;\n        }\n        // relative time is in ms\n        if ((Math.abs(e1.CaptureDateTime - e2.CaptureDateTime) < 120 * 1000 ) &&\n                (e1.TransmissionId == e2.TransmissionId)) {\n            return true;\n        }\n        return false;\n    }\n\n // last in the array, is first in time\n    public static List<TransmitterRawData> Merge2Lists(List<TransmitterRawData> list1 , List<TransmitterRawData> list2)\n    {\n        List<TransmitterRawData> merged = new LinkedList <TransmitterRawData>();\n        while (true) {\n            if(list1.size() == 0 && list2.size() == 0) {\n                break;\n            }\n            if (list1.size() == 0) {\n                merged.addAll(list2);\n                break;\n            }\n            if (list2.size() == 0) {\n                merged.addAll(list1);\n                break;\n            }\n            if (almostEquals(list1.get(0), list2.get(0))) {\n                list2.remove(0);\n                merged.add(list1.remove(0));\n                continue;\n            }\n            if(list1.get(0).RelativeTime > list2.get(0).RelativeTime) {\n                merged.add(list1.remove(0));\n            } else {\n                merged.add(list2.remove(0));\n            }\n\n        }\n        return merged;\n    }\n\n    public static List<TransmitterRawData> MergeLists(List <List<TransmitterRawData>> allTransmitterRawData)\n    {\n        List<TransmitterRawData> MergedList;\n        MergedList = allTransmitterRawData.remove(0);\n        for (List<TransmitterRawData> it : allTransmitterRawData) {\n            MergedList = Merge2Lists(MergedList, it);\n        }\n\n        return MergedList;\n    }\n\n    public static List<TransmitterRawData> ReadHost(String hostAndIp, int numberOfRecords)\n    {\n        int port;\n        System.out.println(\"Reading From \" + hostAndIp);\n        Log.i(TAG,\"Reading From \" + hostAndIp);\n        String []hosts = hostAndIp.split(\":\");\n        if(hosts.length != 2) {\n            System.out.println(\"Invalid hostAndIp \" + hostAndIp);\n            Log.e(TAG, \"Invalid hostAndIp \" + hostAndIp);\n\n            return null;\n        }\n        try {\n            port = Integer.parseInt(hosts[1]);\n        } catch (NumberFormatException nfe) {\n            System.out.println(\"Invalid port \" +hosts[1]);\n            Log.e(TAG, \"Invalid hostAndIp \" + hostAndIp, nfe);\n            return null;\n\n        }\n        if (port < 10 || port > 65536) {\n            System.out.println(\"Invalid port \" +hosts[1]);\n            Log.e(TAG, \"Invalid hostAndIp \" + hostAndIp);\n            return null;\n\n        }\n        System.out.println(\"Reading from \" + hosts[0] + \" \" + port);\n        List<TransmitterRawData> ret;\n        try {\n            ret = Read(hosts[0], port, numberOfRecords);\n        } catch(Exception e) {\n            // We had some error, need to move on...\n            System.out.println(\"read from host failed cought expation\" + hostAndIp);\n            Log.e(TAG, \"read from host failed \" + hostAndIp, e);\n\n            return null;\n\n        }\n        return ret;\n    }\n\n    public static List<TransmitterRawData> ReadFromMongo(String dbury, int numberOfRecords)\n    {\n        Log.i(TAG,\"Reading From \" + dbury);\n    \tList<TransmitterRawData> tmpList;\n    \t// format is dburi/db/collection. We need to find the collection and strip it from the dburi.\n    \tint indexOfSlash = dbury.lastIndexOf('/');\n    \tif(indexOfSlash == -1) {\n    \t\t// We can not find a collection name\n    \t\tLog.e(TAG, \"Error bad dburi. Did not find a collection name starting with / \" + dbury);\n    \t\t// in order for the user to understand that there is a problem, we return null\n    \t\treturn null;\n\n    \t}\n    \tString collection = dbury.substring(indexOfSlash + 1);\n    \tdbury = dbury.substring(0, indexOfSlash);\n\n    \t// Make sure that we have another /, since this is used in the constructor.\n    \tindexOfSlash = dbury.lastIndexOf('/');\n    \tif(indexOfSlash == -1) {\n    \t\t// We can not find a collection name\n    \t\tLog.e(TAG, \"Error bad dburi. Did not find a collection name starting with / \" + dbury);\n    \t\t// in order for the user to understand that there is a problem, we return null\n    \t\treturn null;\n    \t}\n\n    \tMongoWrapper mt = new MongoWrapper(dbury, collection, \"CaptureDateTime\", \"MachineNameNotUsed\");\n    \treturn mt.ReadFromMongo(numberOfRecords);\n    }\n\n    // format of string is ip1:port1,ip2:port2;\n    public static TransmitterRawData[] Read(String hostsNames, int numberOfRecords)\n    {\n        String []hosts = hostsNames.split(\",\");\n        if(hosts.length == 0) {\n            Log.e(TAG, \"Error no hosts were found \" + hostsNames);\n            return null;\n        }\n        List <List<TransmitterRawData>> allTransmitterRawData =  new LinkedList <List<TransmitterRawData>>();\n\n        // go over all hosts and read data from them\n        for(String host : hosts) {\n\n            List<TransmitterRawData> tmpList;\n            if (host.startsWith(\"mongodb://\")) {\n            \ttmpList = ReadFromMongo(host ,numberOfRecords);\n            } else {\n            \ttmpList = ReadHost(host, numberOfRecords);\n            }\n            if(tmpList != null && tmpList.size() > 0) {\n                allTransmitterRawData.add(tmpList);\n            }\n        }\n        // merge the information\n        if (allTransmitterRawData.size() == 0) {\n            System.out.println(\"Could not read anything from \" + hostsNames);\n            Log.e(TAG, \"Could not read anything from \" + hostsNames);\n            return null;\n\n        }\n        List<TransmitterRawData> mergedData= MergeLists(allTransmitterRawData);\n\n        int retSize = Math.min(numberOfRecords, mergedData.size());\n        TransmitterRawData []trd_array = new TransmitterRawData[retSize];\n        mergedData.subList(mergedData.size() - retSize, mergedData.size()).toArray(trd_array);\n\n        System.out.println(\"Final Results========================================================================\");\n        for (int i= 0; i < trd_array.length; i++) {\n //           System.out.println( trd_array[i].toTableString());\n        }\n        return trd_array;\n\n    }\n\n    public static List<TransmitterRawData> Read(String hostName,int port, int numberOfRecords)\n    {\n        List<TransmitterRawData> trd_list = new LinkedList<TransmitterRawData>();\n        try\n        {\n            Log.i(TAG, \"Read called\");\n            Gson gson = new GsonBuilder().create();\n\n            // An example of using gson.\n            ComunicationHeader ch = new ComunicationHeader();\n            ch.version = 1;\n            ch.numberOfRecords = numberOfRecords;\n            String flat = gson.toJson(ch);\n            ComunicationHeader ch2 = gson.fromJson(flat, ComunicationHeader.class);\n            System.out.println(\"Results code\" + flat + ch2.version);\n\n\n            // Real client code\n            Socket MySocket = new Socket(hostName, port);\n\n            System.out.println(\"After the new socket \\n\");\n            MySocket.setSoTimeout(2000);\n\n            System.out.println(\"client connected... \" );\n\n            PrintWriter out = new PrintWriter(MySocket.getOutputStream(), true);\n            BufferedReader in = new BufferedReader(new InputStreamReader(MySocket.getInputStream()));\n\n            out.println(flat);\n\n            while(true) {\n                String data = in.readLine();\n                if(data == null) {\n                    System.out.println(\"recieved null exiting\");\n                    break;\n                }\n                if(data.equals(\"\")) {\n                    System.out.println(\"recieved \\\"\\\" exiting\");\n                    break;\n                }\n\n                //System.out.println( \"data size \" +data.length() + \" data = \"+ data);\n                TransmitterRawData trd = gson.fromJson(data, TransmitterRawData.class);\n                trd.CaptureDateTime = System.currentTimeMillis() - trd.RelativeTime;\n\n                trd_list.add(0,trd);\n                //  System.out.println( trd.toTableString());\n                if(trd_list.size() == numberOfRecords) {\n                \t// We have the data we want, let's get out\n                \tbreak;\n                }\n            }\n\n\n            MySocket.close();\n            return trd_list;\n        }catch(SocketTimeoutException s) {\n            Log.e(TAG, \"Socket timed out! \", s);\n        }\n        catch(IOException e) {\n            Log.e(TAG, \"cought IOException! \", e);\n        }\n        return trd_list;\n    }\n\n\n    public void run()\n    {\n    \tLong LastReportedTime = new Date().getTime();\n    \tTransmitterRawData LastReportedReading = null;\n    \tLog.e(TAG, \"Starting... LastReportedReading \" + LastReportedReading);\n    \ttry {\n\t        while (!mStop && !interrupted()) {\n\t        \t// try to read one object...\n                TransmitterRawData[] LastReadingArr = null;\n                if(WixelReader.IsConfigured(mContext)) {\n                    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n                    String recieversIpAddresses = prefs.getString(\"wifi_recievers_addresses\", \"\");\n\t        \t\tLastReadingArr = Read(recieversIpAddresses ,1);\n                }\n\t        \tif (LastReadingArr != null  && LastReadingArr.length  > 0) {\n\t        \t\t// Last in the array is the most updated reading we have.\n\t        \t\tTransmitterRawData LastReading = LastReadingArr[LastReadingArr.length -1];\n\n\t        \t\t//if (LastReading.CaptureDateTime > LastReportedReading + 5000) {\n\t        \t\t// Make sure we do not report packets from the far future...\n\t        \t\tif ((LastReading.CaptureDateTime > LastReportedTime ) &&\n\t        \t\t        (!almostEquals(LastReading, LastReportedReading)) &&\n\t        \t\t        LastReading.CaptureDateTime < new Date().getTime() + 12000) {\n\t        \t\t\t// We have a real new reading...\n\t        \t\t\tLog.e(TAG, \"calling setSerialDataToTransmitterRawData \" + LastReading.RawValue +\n\t        \t\t\t        \" LastReading.CaptureDateTime \" + LastReading.CaptureDateTime + \" \" + LastReading.TransmissionId);\n\t        \t\t\tsetSerialDataToTransmitterRawData(LastReading.RawValue , LastReading.BatteryLife, LastReading.CaptureDateTime);\n\t        \t\t\tLastReportedReading = LastReading;\n\t        \t\t\tLastReportedTime = LastReading.CaptureDateTime;\n\t        \t\t}\n\t        \t}\n\t        \t// let's sleep (right now for 30 seconds)\n\t        \tThread.sleep(30000);\n\t        }\n    \t} catch (InterruptedException e) {\n    \t    Log.e(TAG, \"cought InterruptedException! \", e);\n            // time to get out...\n        }\n    }\n\n    // this function is only a test function. It is used to set many points fast in order to allow\n    // faster testing without real data.\n    public void runFake()\n    {\n        // let's start by faking numbers....\n        int i = 0;\n        int added = 5;\n        while (!mStop) {\n            try {\n                for (int j = 0 ; j < 3; j++) {\n                    Thread.sleep(1000);\n                    if(mStop ) {\n                    // we were asked to leave, so do it....\n                        return;\n                    }\n                }\n                i+=added;\n                if (i==50) {\n                    added = -5;\n                }\n                if (i==0) {\n                    added = 5;\n                }\n\n                int fakedRaw = 150000 + i * 1000;\n                Log.e(TAG, \"calling setSerialDataToTransmitterRawData \" + fakedRaw);\n                setSerialDataToTransmitterRawData(fakedRaw, 100, new Date().getTime());\n\n               } catch (InterruptedException e) {\n                   // time to get out...\n                   Log.e(TAG, \"cought InterruptedException! \", e);\n                   break;\n               }\n        }\n    }\n\n    public void Stop()\n    {\n        mStop = true;\n        interrupt();\n    }\n    public void setSerialDataToTransmitterRawData(int raw_data ,int sensor_battery_leve, Long CaptureTime) {\n\n        TransmitterData transmitterData = TransmitterData.create(raw_data, sensor_battery_leve, CaptureTime);\n        if (transmitterData != null) {\n            Sensor sensor = Sensor.currentSensor();\n            if (sensor != null) {\n                BgReading bgReading = BgReading.create(transmitterData.raw_data, mContext, CaptureTime);\n                sensor.latest_battery_level = transmitterData.sensor_battery_level;\n                sensor.save();\n            } else {\n                Log.w(TAG, \"No Active Sensor, Data only stored in Transmitter Data\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/SettingsActivity.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.media.Ringtone;\nimport android.media.RingtoneManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.ListPreference;\nimport android.preference.Preference;\nimport android.preference.PreferenceActivity;\nimport android.preference.PreferenceCategory;\nimport android.preference.PreferenceManager;\nimport android.preference.RingtonePreference;\nimport android.text.TextUtils;\n\npublic class SettingsActivity extends PreferenceActivity {\n\n    @Override\n    protected void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n        setupSimplePreferencesScreen();\n    }\n\n    private void setupSimplePreferencesScreen() {\n        addPreferencesFromResource(R.xml.pref_license);\n\n        PreferenceCategory fakeHeader = new PreferenceCategory(this);\n        getPreferenceScreen().addPreference(fakeHeader);\n        addPreferencesFromResource(R.xml.pref_general);\n\n\n        fakeHeader = new PreferenceCategory(this);\n        getPreferenceScreen().addPreference(fakeHeader);\n        addPreferencesFromResource(R.xml.pref_notifications);\n\n        fakeHeader = new PreferenceCategory(this);\n        getPreferenceScreen().addPreference(fakeHeader);\n        addPreferencesFromResource(R.xml.pref_data_source);\n\n        fakeHeader = new PreferenceCategory(this);\n        getPreferenceScreen().addPreference(fakeHeader);\n        addPreferencesFromResource(R.xml.pref_data_sync);\n\n        bindPreferenceSummaryToValue(findPreference(\"dex_collection_method\"));\n        bindPreferenceSummaryToValue(findPreference(\"units\"));\n        bindPreferenceSummaryToValue(findPreference(\"share_key\"));\n    }\n\n    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {\n        @Override\n        public boolean onPreferenceChange(Preference preference, Object value) {\n            String stringValue = value.toString();\n\n            if (preference instanceof ListPreference) {\n                ListPreference listPreference = (ListPreference) preference;\n                int index = listPreference.findIndexOfValue(stringValue);\n                preference.setSummary(\n                                index >= 0\n                                        ? listPreference.getEntries()[index]\n                                        : null);\n\n            } else if (preference instanceof RingtonePreference) {\n                if (TextUtils.isEmpty(stringValue)) {\n                    preference.setSummary(R.string.pref_ringtone_silent);\n                } else {\n                    Ringtone ringtone = RingtoneManager.getRingtone(\n                            preference.getContext(), Uri.parse(stringValue));\n\n                    if (ringtone == null) {\n                        preference.setSummary(null);\n                    } else {\n                        String name = ringtone.getTitle(preference.getContext());\n                        preference.setSummary(name);\n                    }\n                }\n            } else {\n                preference.setSummary(stringValue);\n            }\n            return true;\n        }\n    };\n\n    private static void bindPreferenceSummaryToValue(Preference preference) {\n        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);\n        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,\n                PreferenceManager\n                        .getDefaultSharedPreferences(preference.getContext())\n                        .getString(preference.getKey(), \"\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/DexcomShareInterface.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport java.util.Map;\n\nimport retrofit.Callback;\nimport retrofit.client.Response;\nimport retrofit.http.Body;\nimport retrofit.http.POST;\nimport retrofit.http.QueryMap;\n\n/**\n * Created by stephenblack on 3/16/15.\n */\npublic interface DexcomShareInterface {\n    @POST(\"/Publisher/ReadPublisherLatestGlucoseValues\")\n    ShareGlucose[] getShareBg(@QueryMap Map<String, String> options);\n\n    @POST(\"/General/LoginPublisherAccountByName\")\n    void getSessionId(@Body ShareAuthenticationBody body, Callback<Response> callback);\n    //Since this seems to respond with a string we need a callback that will parse the response body\n    //new String(((TypedByteArray) response.getBody()).getBytes());\n\n    @POST(\"/Publisher/IsRemoteMonitoringSessionActive\")\n    void checkSessionActive(@QueryMap Map<String, String> options, Callback<Response> callback);\n    // needs ?sessionId={YourSessionId}\n    // returns true or false\n\n    @POST(\"/Publisher/PostReceiverEgvRecords\")\n    void uploadBGRecords(@QueryMap Map<String, String> options, @Body ShareUploadPayload payload, Callback<Response> callback);\n    // needs ?sessionId={YourSessionId}\n    // body ShareUploadPayload\n    // status code\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/Egv.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.google.gson.annotations.Expose;\n\n/**\n * Created by stephenblack on 3/19/15.\n */\npublic class Egv {\n    @Expose\n    public int Trend;\n\n    @Expose\n    public int Value;\n\n    @Expose\n    public String ST;\n\n    @Expose\n    public String DT;\n\n\n    public Egv(BgReading bg) {\n        this.Value = (int) bg.calculated_value;\n        this.DT = toDateString(bg.timestamp);\n        this.ST = toDateString(bg.timestamp);\n        this.Trend = slopeOrdinal(bg);\n    }\n\n    public String toDateString(double timestamp) {\n        long shortened = (long) Math.floor((timestamp/1000));\n        return \"/Date(\" + Long.toString(shortened*1000) + \")/\";\n    }\n\n    public int slopeOrdinal(BgReading bg) {\n        double slope_by_minute = bg.calculated_value_slope * 60000;\n        int arrow = 0;\n        if (slope_by_minute <= (-3.5)) {\n            arrow = 7;\n        } else if (slope_by_minute <= (-2)) {\n            arrow = 6;\n        } else if (slope_by_minute <= (-1)) {\n            arrow = 5;\n        } else if (slope_by_minute <= (1)) {\n            arrow = 4;\n        } else if (slope_by_minute <= (2)) {\n            arrow = 3;\n        } else if (slope_by_minute <= (3.5)) {\n            arrow = 2;\n        } else {\n            arrow = 1;\n        }\n        if(bg.hide_slope) {\n            arrow = 9;\n        }\n        return arrow;\n    }\n//    {\n//\n//        \"Trend\":4,\n//            \"ST\":\"\\/Date(1426783106000 - 1426754317000)\\/\",\n//            \"DT\":\"\\/Date(1426754317000)\\/\",\n//            \"Value\":97\n//    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareAuthenticationBody.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport com.google.gson.annotations.Expose;\n\n/**\n * Created by stephenblack on 3/16/15.\n */\npublic class ShareAuthenticationBody {\n    @Expose\n    public String password;\n\n    @Expose\n    public String applicationId;\n\n    @Expose\n    public String accountName;\n\n    public ShareAuthenticationBody(String aPassword, String aAccountName) {\n        this.password = aPassword;\n        this.accountName = aAccountName;\n        this.applicationId = \"d89443d2-327c-4a6f-89e5-496bbb0317db\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareGlucose.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.BatteryManager;\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.google.gson.annotations.Expose;\n\n/**\n * Created by stephenblack on 3/16/15.\n */\n@Table(name = \"ShareGlucose\", id = BaseColumns._ID)\npublic class ShareGlucose extends Model {\n    public Context mContext;\n    @Expose\n    @Column(name = \"DT\")\n    public String DT;\n\n    @Expose\n    @Column(name = \"ST\")\n    public String ST;\n\n    @Expose\n    @Column(name = \"Trend\")\n    public double Trend;\n\n    @Expose\n    @Column(name = \"Value\")\n    public double Value;\n\n    @Expose\n    @Column(name = \"WT\")\n    public String WT;\n\n    public void processShareData(Context context) {\n        Log.d(\"SHARE\", \"Share Data being processed!\"); // TODO maybe set this up??\n//        mContext = context;\n//        Log.d(\"SHARE\", \"Timestamp before parsing: \" + WT);\n//        Log.d(\"SHARE\", \"Timestamp before parsing: \" + WT.replaceAll(\"[^\\\\d.]\", \"\"));\n//\n//        double timestamp = (Double.parseDouble(WT.replaceAll(\"[^\\\\d.]\", \"\")));\n//        Log.d(\"SHARE\", \"Timestamp: \" + timestamp);\n//        if (!Bg.alreadyExists(timestamp)) {\n//            Log.d(\"SHARE\", \"Data looks new!!\");\n//            Bg bg = new Bg();\n//            bg.direction = slopeDirection();\n//            bg.battery = Integer.toString(getBatteryLevel());\n//            bg.bgdelta = calculateDelta(timestamp, Value);\n//            bg.datetime = timestamp;\n//            bg.sgv = Integer.toString((int) Value);\n//            bg.save();\n//            DataCollectionService.newDataArrived(mContext, true);\n//            Log.d(\"SHARE\", \"Share Data Processed Successfully!\");\n//        } else {\n//            Log.d(\"SHARE\", \"A Bg Value similar to this timestamp already exists.\");\n//        }\n    }\n\n    public String slopeDirection() {\n        switch((int) Trend) {\n            case 1:\n                return \"DoubleUp\";\n            case 2:\n                return \"SingleUp\";\n            case 3:\n                return \"FortyFiveUp\";\n            case 4:\n                return \"Flat\";\n            case 5:\n                return \"FortyFiveDown\";\n            case 6:\n                return \"SingleDown\";\n            case 7:\n                return \"DoubleDown\";\n            default:\n                return \"\";\n        }\n    }\n\n\n    public int getBatteryLevel() {\n        Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n        int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n        int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);\n        if(level == -1 || scale == -1) {\n            return 50;\n        }\n        return (int)(((float)level / (float)scale) * 100.0f);\n    }\n\n    public double calculateDelta(double timestamp, double currentValue) {\n//        Bg bg = Bg.mostRecentBefore(timestamp);\n//        if (bg != null && Math.abs(bg.datetime - timestamp) < (60*1000*15)) {\n//            return (bg.sgv_double() - currentValue);\n//        } else {\n            return 0;\n//        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareRest.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.AsyncTask;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.squareup.okhttp.OkHttpClient;\n\nimport java.security.cert.CertificateException;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport retrofit.Callback;\nimport retrofit.RequestInterceptor;\nimport retrofit.RestAdapter;\nimport retrofit.RetrofitError;\nimport retrofit.android.AndroidLog;\nimport retrofit.client.OkClient;\nimport retrofit.client.Response;\nimport retrofit.converter.GsonConverter;\nimport retrofit.mime.TypedByteArray;\n\n/**\n * Created by stephenblack on 12/26/14.\n */\npublic class ShareRest {\n    private Context mContext;\n    private String login;\n    private String password;\n    private SharedPreferences prefs;\n    OkClient client;\n\n    public static Gson gson = new GsonBuilder()\n            .excludeFieldsWithoutExposeAnnotation()\n            .create();\n\n    public ShareRest(Context context) {\n        client = getOkClient();\n        mContext = context;\n        prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        login = prefs.getString(\"dexcom_account_name\", \"\");\n        password = prefs.getString(\"dexcom_account_password\", \"\");\n    }\n\n    public boolean getBgData() {\n        if (prefs.getBoolean(\"share_poll\", false) && login.compareTo(\"\") != 0 && password.compareTo(\"\") != 0) {\n            return loginAndGetData();\n        } else {\n            return false;\n        }\n    }\n    public boolean sendBgData(BgReading bg) {\n        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);\n        String receiverSn = preferences.getString(\"share_key\", \"SM00000000\").toUpperCase();\n        if (prefs.getBoolean(\"share_upload\", false) && login.compareTo(\"\") != 0 && password.compareTo(\"\") != 0 && receiverSn.compareTo(\"SM00000000\") != 0) {\n            return loginAndSendData(bg);\n        } else {\n            return false;\n        }\n    }\n\n    private boolean loginAndGetData() {\n        try {\n            dexcomShareAuthorizeInterface().getSessionId(new ShareAuthenticationBody(password, login), new Callback() {\n                @Override\n                public void success(Object o, Response response) {\n                    Log.d(\"ShareRest\", \"Success!! got a response on auth.\");\n                    String returnedSessionId = new String(((TypedByteArray) response.getBody()).getBytes()).replace(\"\\\"\", \"\");\n\n                    getBgData(returnedSessionId);\n                }\n\n                @Override\n                public void failure(RetrofitError retrofitError) {\n                    Log.e(\"RETROFIT ERROR: \", \"\"+retrofitError.toString());\n                }\n            });\n            return true;\n        } catch (Exception e) {\n                Log.e(\"REST CALL ERROR: \", \"BOOOO\");\n                    return false;\n        }\n    }\n\n    private boolean loginAndSendData(final BgReading bg) {\n        try {\n            dexcomShareAuthorizeInterface().getSessionId(new ShareAuthenticationBody(password, login), new Callback() {\n                @Override\n                public void success(Object o, Response response) {\n                    Log.d(\"ShareRest\", \"Success!! got a response on auth.\");\n                    String returnedSessionId = new String(((TypedByteArray) response.getBody()).getBytes()).replace(\"\\\"\", \"\");\n\n                    sendBgData(returnedSessionId, bg);\n                }\n\n                @Override\n                public void failure(RetrofitError retrofitError) {\n                    Log.e(\"RETROFIT ERROR: \", \"\"+retrofitError.toString());\n                }\n            });\n            return true;\n        } catch (Exception e) {\n            Log.e(\"REST CALL ERROR: \", \"BOOOO\");\n            return false;\n        }\n    }\n\n    private void getBgData(String sessionId) {\n        DataFetcher dataFetcher = new DataFetcher(mContext, sessionId);\n        dataFetcher.execute((Void) null);\n    }\n\n    private void sendBgData(String sessionId, BgReading bg) {\n        DataSender dataSender = new DataSender(mContext, sessionId, bg);\n        dataSender.execute((Void) null);\n    }\n\n    private DexcomShareInterface dexcomShareAuthorizeInterface() {\n        RestAdapter adapter = authoirizeAdapterBuilder().build();\n        DexcomShareInterface dexcomShareInterface =\n                adapter.create(DexcomShareInterface.class);\n        return dexcomShareInterface;\n    }\n\n    private DexcomShareInterface dexcomShareGetBgInterface() {\n        RestAdapter adapter = getBgAdapterBuilder().build();\n        DexcomShareInterface dexcomShareInterface =\n                adapter.create(DexcomShareInterface.class);\n        return dexcomShareInterface;\n    }\n\n    private DexcomShareInterface dexcomShareSendBgInterface() {\n        RestAdapter adapter = authoirizeAdapterBuilder().build();\n        DexcomShareInterface dexcomShareInterface =\n                adapter.create(DexcomShareInterface.class);\n        return dexcomShareInterface;\n    }\n\n    private DexcomShareInterface checkSessionActive() {\n        RestAdapter adapter = getBgAdapterBuilder().build();\n        DexcomShareInterface checkSessionActive =\n                adapter.create(DexcomShareInterface.class);\n        return checkSessionActive;\n    }\n\n    private RestAdapter.Builder authoirizeAdapterBuilder() {\n        RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();\n        adapterBuilder\n                .setClient(client)\n                .setLogLevel(RestAdapter.LogLevel.FULL).setLog(new AndroidLog(\"SHAREREST\"))\n                .setEndpoint(\"https://share1.dexcom.com/ShareWebServices/Services\")\n                .setRequestInterceptor(authorizationRequestInterceptor)\n                .setConverter(new GsonConverter(new GsonBuilder()\n                        .excludeFieldsWithoutExposeAnnotation()\n                        .create()));\n        return adapterBuilder;\n    }\n\n    private RestAdapter.Builder getBgAdapterBuilder() {\n        RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();\n        adapterBuilder\n                .setClient(client)\n                .setLogLevel(RestAdapter.LogLevel.FULL).setLog(new AndroidLog(\"SHAREREST\"))\n                .setEndpoint(\"https://share1.dexcom.com/ShareWebServices/Services\")\n                .setRequestInterceptor(getBgRequestInterceptor)\n                .setConverter(new GsonConverter(new GsonBuilder()\n                        .excludeFieldsWithoutExposeAnnotation()\n                        .create()));\n        return adapterBuilder;\n    }\n\n    RequestInterceptor authorizationRequestInterceptor = new RequestInterceptor() {\n        @Override\n        public void intercept(RequestInterceptor.RequestFacade request) {\n            request.addHeader(\"User-Agent\", \"Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0\");\n            request.addHeader(\"Content-Type\", \"application/json\");\n            request.addHeader(\"Accept\", \"application/json\");\n        }\n    };\n    RequestInterceptor getBgRequestInterceptor = new RequestInterceptor() {\n        @Override\n        public void intercept(RequestInterceptor.RequestFacade request) {\n            request.addHeader(\"User-Agent\", \"Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0\");\n            request.addHeader(\"Content-Type\", \"application/json\");\n            request.addHeader(\"Content-Length\", \"0\");\n            request.addHeader(\"Accept\", \"application/json\");\n        }\n    };\n\n    public OkHttpClient getOkHttpClient() {\n\n        try {\n            final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {\n                @Override\n                public void checkClientTrusted(\n                        java.security.cert.X509Certificate[] chain,\n                        String authType) throws CertificateException {\n                }\n\n                @Override\n                public void checkServerTrusted(\n                        java.security.cert.X509Certificate[] chain,\n                        String authType) throws CertificateException {\n                }\n\n                @Override\n                public java.security.cert.X509Certificate[] getAcceptedIssuers() {\n                    return null;\n                }\n            } };\n\n            final SSLContext sslContext = SSLContext.getInstance(\"SSL\");\n            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());\n            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();\n\n            OkHttpClient okHttpClient = new OkHttpClient();\n            okHttpClient.setSslSocketFactory(sslSocketFactory);\n            okHttpClient.setHostnameVerifier(new HostnameVerifier() {\n\n                @Override\n                public boolean verify(String hostname, SSLSession session) {\n                        return true;\n                }\n            });\n\n            return okHttpClient;\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n    }\n\n    public OkClient getOkClient (){\n        OkHttpClient client1 = getOkHttpClient();\n        OkClient _client = new OkClient(client1);\n        return _client;\n    }\n\n    public Map<String, String> queryParamMap(String sessionId) {\n        Map map = new HashMap<String, String>();\n        map.put(\"sessionID\", sessionId);\n        map.put(\"minutes\", String.valueOf(minutesCount()));\n        map.put(\"maxCount\", String.valueOf(requestCount()));\n        return map;\n\n    }\n\n    public class DataFetcher extends AsyncTask<Void, Void, Boolean> {\n        Context mContext;\n        String mSessionId;\n        DataFetcher(Context context, String sessionId) {\n            mContext = context;\n            mSessionId = sessionId;\n        }\n\n        @Override\n        protected Boolean doInBackground(Void... params) {\n            try {\n                try {\n                    final ShareGlucose[] shareGlucoses = dexcomShareGetBgInterface().getShareBg(queryParamMap(mSessionId));\n                    Log.d(\"REST Success: \", \"YAY!\");\n                    if(shareGlucoses != null && shareGlucoses.length > 0) {\n                        for (ShareGlucose shareGlucose : shareGlucoses) {\n                            shareGlucose.processShareData(mContext);\n                        }\n                    return true;\n                    }\n                    return false;\n                } catch (Exception e) {\n                    Log.d(\"REST CALL ERROR: \", \"BOOOO\");\n                    return false;\n                }\n            }\n            catch (RetrofitError e) { Log.d(\"Retrofit Error: \", \"BOOOO\"); }\n            catch (Exception ex) { Log.d(\"Unrecognized Error: \", \"BOOOO\"); }\n            return false;\n        }\n    }\n\n    public class DataSender extends AsyncTask<Void, Void, Boolean> {\n        Context mContext;\n        String mSessionId;\n        BgReading mBg;\n        DataSender(Context context, String sessionId, BgReading bg) {\n            mContext = context;\n            mSessionId = sessionId;\n            mBg = bg;\n        }\n\n        @Override\n        protected Boolean doInBackground(Void... params) {\n            try {\n                SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);\n                String receiverSn = preferences.getString(\"share_key\", \"SM00000000\").toUpperCase();\n                dexcomShareSendBgInterface().uploadBGRecords(querySessionMap(mSessionId), new ShareUploadPayload(receiverSn, mBg), new Callback() {\n                    @Override\n                    public void success(Object o, Response response) {\n                        Log.d(\"ShareRest\", \"Success!! Uploaded!!\");\n                    }\n\n                    @Override\n                    public void failure(RetrofitError retrofitError) {\n                        Log.e(\"RETROFIT ERROR: \", \"\"+retrofitError.toString());\n                    }\n                });\n            }\n            catch (RetrofitError e) { Log.d(\"Retrofit Error: \", \"BOOOO\"); }\n            catch (Exception ex) { Log.d(\"Unrecognized Error: \", \"BOOOO\"); }\n            return false;\n        }\n    }\n    public int requestCount() {\n        BgReading bg = BgReading.last();\n        if(bg != null) {\n            return 20;\n        } else if (bg.timestamp < new Date().getTime()) {\n            return Math.min((int) Math.ceil(((new Date().getTime() - bg.timestamp) / (5 * 1000 * 60))), 10);\n        } else {\n            return 1;\n        }\n    }\n\n    public int minutesCount() {\n        BgReading bg = BgReading.last();\n        if(bg != null && bg.timestamp < new Date().getTime()) {\n            return Math.min((int) Math.ceil(((new Date().getTime() - bg.timestamp) / (1000 * 60))), 1440);\n        } else {\n            return 1440;\n        }\n    }\n\n    public Map<String, String> querySessionMap(String sessionId) {\n        Map map = new HashMap<String, String>();\n        map.put(\"sessionID\", sessionId);\n        return map;\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareUploadPayload.java",
    "content": "package com.eveningoutpost.dexdrip.ShareModels;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.google.gson.annotations.Expose;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by stephenblack on 3/19/15.\n */\npublic class ShareUploadPayload {\n    @Expose\n    public String SN;\n\n    @Expose\n    public Egv[] Egvs;\n\n    @Expose\n    public long TA = -5;\n\n    public ShareUploadPayload(String sn, BgReading bg) {\n        this.SN = sn;\n        List<Egv> egvList = new ArrayList<Egv>();\n        egvList.add(new Egv(bg));\n        this.Egvs = egvList.toArray(new Egv[egvList.size()]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/ShareTest.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCallback;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattDescriptor;\nimport android.bluetooth.BluetoothGattService;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.PacketBuilder;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadData;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.DexShareAttributes;\nimport com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;\n\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.UUID;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\n\npublic class ShareTest extends Activity {\n    private final static String TAG = ShareTest.class.getSimpleName();\n    Button button;\n    Button closeButton;\n    Button readButton;\n    Button bondButton;\n    TextView details;\n\n    private String mDeviceName;\n    private String mDeviceAddress;\n    private boolean is_connected = false;\n    private boolean reconnecting = false;\n    SharedPreferences prefs;\n\n    private BluetoothManager mBluetoothManager;\n    private BluetoothAdapter mBluetoothAdapter;\n    private String mBluetoothDeviceAddress;\n    private BluetoothGatt mBluetoothGatt;\n    private ForegroundServiceStarter foregroundServiceStarter;\n    private int mConnectionState = STATE_DISCONNECTED;\n    private BluetoothDevice device;\n    int mStartMode;\n    private Context mContext = null;\n\n    private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;\n    private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;\n    private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;\n    private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;\n\n    private BluetoothGattService mShareService;\n    private BluetoothGattCharacteristic mAuthenticationCharacteristic;\n    private BluetoothGattCharacteristic mSendDataCharacteristic;\n    private BluetoothGattCharacteristic mReceiveDataCharacteristic;\n    private BluetoothGattCharacteristic mHeartBeatCharacteristic;\n    private BluetoothGattCharacteristic mCommandCharacteristic;\n    private BluetoothGattCharacteristic mResponseCharacteristic;\n\n    //Gatt Tasks\n    public final int GATT_NOTHING = 0;\n    public final int GATT_SETUP = 1;\n    public final int GATT_WRITING_COMMANDS = 2;\n    public final int GATT_READING_RESPONSE = 3;\n    public int successfulWrites;\n\n    //RXJAVA FUN\n    Action1<byte[]> mDataResponseListener;\n\n    public ReadDataShare mReadDataShare;\n\n    public int currentGattTask;\n    public int step;\n\n    public List<byte[]> writePackets;\n    public int recordType;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_share_test);\n        button = (Button) findViewById(R.id.connect);\n        closeButton = (Button) findViewById(R.id.closeConnect);\n        bondButton = (Button) findViewById(R.id.bond);\n        readButton = (Button) findViewById(R.id.read);\n        details = (TextView) findViewById(R.id.connection_details);\n        addListenerOnButton();\n        addListenerOnCloseButton();\n        IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);\n        registerReceiver(mPairReceiver, intent);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        close();\n        Log.w(TAG, \"CLOSING CONNECTION\");\n    }\n\n    public void addListenerOnButton() {\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                attemptConnection();\n            }\n        });\n        readButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                attemptRead();\n            }\n        });\n        bondButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                bond(mBluetoothGatt);\n            }\n        });\n    }\n\n    public void addListenerOnCloseButton() {\n        closeButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                close();\n                details.setText(\"\");\n            }\n        });\n    }\n\n    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {\n        @Override\n        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {\n            if (newState == BluetoothProfile.STATE_CONNECTED) {\n                mBluetoothGatt = gatt;\n                mConnectionState = STATE_CONNECTED;\n                ActiveBluetoothDevice.connected();\n                Log.w(TAG, \"Connected to GATT server.\");\n                Log.w(TAG, \"Connection state: Bonded - \" + device.getBondState());\n\n                if (device.getBondState() == BluetoothDevice.BOND_BONDED) {\n                    currentGattTask = GATT_SETUP;\n                    mBluetoothGatt.discoverServices();\n\n                } else {\n                    device.setPin(\"000000\".getBytes());\n                    device.createBond();\n                }\n            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {\n                mConnectionState = STATE_DISCONNECTED;\n                ActiveBluetoothDevice.disconnected();\n                Log.w(TAG, \"Disconnected from GATT server.\");\n            }\n        }\n\n        @Override\n        public void onServicesDiscovered(BluetoothGatt gatt, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                Log.w(TAG, \"Services Discovered: \" + status);\n                authenticateConnection(gatt);\n\n            }\n        }\n\n        @Override\n        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                Log.w(TAG, \"Characteristic Read\");\n                byte[] value = characteristic.getValue();\n                if(value != null) {\n                    Log.w(TAG, \"VALUE\" + value);\n                } else {\n                    Log.w(TAG, \"Characteristic was null\");\n                }\n                nextGattStep();\n            } else {\n                Log.w(TAG, \"Characteristic failed to read\");\n            }\n        }\n\n        @Override\n        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {\n            Log.w(TAG, \"Characteristic changed\");\n            UUID charUuid = characteristic.getUuid();\n            Log.w(TAG, \"Characteristic Update Received: \" + charUuid);\n            if(charUuid.compareTo(mResponseCharacteristic.getUuid()) == 0) {\n                Log.w(TAG, \"mResponseCharacteristic Update\");\n            }\n            if(charUuid.compareTo(mCommandCharacteristic.getUuid()) == 0) {\n                Log.w(TAG, \"mCommandCharacteristic Update\");\n            }\n            if(charUuid.compareTo(mHeartBeatCharacteristic.getUuid()) == 0) {\n                Log.w(TAG, \"mHeartBeatCharacteristic Update\");\n            }\n            if(charUuid.compareTo(mReceiveDataCharacteristic.getUuid()) == 0) {\n                Log.w(TAG, \"mReceiveDataCharacteristic Update\");\n                byte[] value = characteristic.getValue();\n                if(value != null) {\n                    Log.w(TAG, \"Characteristic: \" + value);\n                    Log.w(TAG, \"Characteristic: \" + value.toString());\n                    Log.w(TAG, \"Characteristic getstring: \" + characteristic.getStringValue(0));\n                    Log.w(TAG, \"SUBSCRIBED TO RESPONSE LISTENER\");\n                    Observable.just(characteristic.getValue()).subscribe(mDataResponseListener);\n                } else {\n                    Log.w(TAG, \"Characteristic was null\");\n                }\n            }\n            Log.w(TAG, \"NEW VALUE: \" + characteristic.getValue().toString());\n        }\n\n        @Override\n        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {\n            Log.w(TAG, \"Wrote a discriptor, status: \" + status);\n            if(step == 2 && currentGattTask == GATT_SETUP) {\n                setListeners(2);\n            } else if(step == 3) {\n                setListeners(3);\n            } else if(step == 4) {\n                setListeners(4);\n            } else if(step == 5) {\n                Log.w(TAG, \"Done setting Listeners\");\n            }\n        }\n\n        @Override\n        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {\n            Log.w(TAG, \"Wrote a characteristic: \" + status);\n            nextGattStep();\n        }\n    };\n\n    public void attemptConnection() {\n        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n        if (device != null) {\n            details.append(\"\\nConnection state: \" + \" Device is not null\");\n            mConnectionState = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT);\n        }\n\n        Log.w(TAG, \"Connection state: \" + mConnectionState);\n        details.append(\"\\nConnection state: \" + mConnectionState);\n        if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {\n            ActiveBluetoothDevice btDevice = new Select().from(ActiveBluetoothDevice.class)\n                    .orderBy(\"_ID desc\")\n                    .executeSingle();\n            if (btDevice != null) {\n                details.append(\"\\nBT Device: \" + btDevice.name);\n                mDeviceName = btDevice.name;\n                mDeviceAddress = btDevice.address;\n                mBluetoothAdapter = mBluetoothManager.getAdapter();\n                boolean newConnection = true;\n                if(newConnection) {\n                    is_connected = connect(mDeviceAddress);\n                    details.append(\"\\nConnecting...: \");\n                }\n            }\n        }\n    }\n\n    public void attemptRead() {\n        final ReadDataShare readData = new ReadDataShare(this);\n        final Action1<Long> systemTimeListener = new Action1<Long>() {\n            @Override\n            public void call(Long s) {\n\n                Log.d(TAG, \"Made the full round trip, got \" + s + \" as the system time\");\n                Log.d(\"SYSTTIME\", \"Made the full round trip, got \" + s + \" as the system time\");\n                final long addativeSystemTimeOffset = new Date().getTime() - s;\n                Log.d(TAG, \"Made the full round trip, got \" + addativeSystemTimeOffset + \" offset\");\n                Log.d(\"SYSTTIME\", \"Made the full round trip, got \" + addativeSystemTimeOffset + \" offset\");\n\n                final Action1<CalRecord[]> calRecordListener = new Action1<CalRecord[]>() {\n                    @Override\n                    public void call(CalRecord[] calRecords) {\n                        Log.d(TAG, \"Made the full round trip, got \" + calRecords.length + \" Cal Records\");\n                        Calibration.create(calRecords, addativeSystemTimeOffset, getApplicationContext());\n\n                        final Action1<SensorRecord[]> sensorRecordListener = new Action1<SensorRecord[]>() {\n                            @Override\n                            public void call(SensorRecord[] sensorRecords) {\n                                Log.d(TAG, \"Made the full round trip, got \" + sensorRecords.length + \" Sensor Records\");\n                                BgReading.create(sensorRecords, addativeSystemTimeOffset, getApplicationContext());\n\n                                final Action1<EGVRecord[]> evgRecordListener = new Action1<EGVRecord[]>() {\n                                    @Override\n                                    public void call(EGVRecord[] egvRecords) {\n                                        Log.d(TAG, \"Made the full round trip, got \" + egvRecords.length + \" EVG Records\");\n                                        BgReading.create(egvRecords, addativeSystemTimeOffset, getApplicationContext());\n                                    }\n                                };\n                                readData.getRecentEGVs(evgRecordListener);\n                            }\n                        };\n                        readData.getRecentSensorRecords(sensorRecordListener);\n                    }\n                };\n                readData.getRecentCalRecords(calRecordListener);\n            }\n        };\n        readData.readSystemTime(systemTimeListener);\n    }\n\n    public void bond(BluetoothGatt gatt) {\n        reconnecting = true;\n        attemptConnection();\n    }\n\n    public boolean connect(final String address) {\n\n        details.append(\"\\nConnecting to device\");\n        Log.w(TAG, \"CONNECTING TO DEVICE\");\n        if (mBluetoothAdapter == null || address == null) {\n            details.append(\"\\nBT adapter is null\");\n            Log.w(TAG, \"BluetoothAdapter not initialized or unspecified address.\");\n            return false;\n        }\n        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {\n            details.append(\"\\nTrying to use an existing mBluetoothGatt for connection.\");\n            if (mBluetoothGatt.connect()) {\n                mConnectionState = STATE_CONNECTING;\n                return true;\n            } else {\n                return false;\n            }\n        } else {\n            device = mBluetoothAdapter.getRemoteDevice(address);\n            device.setPin(\"000000\".getBytes());\n            if (device == null) {\n                Log.w(TAG, \"Device not found.  Unable to connect.\");\n                details.append(\"\\nDevice not found.  Unable to connect.\");\n                return false;\n            }\n            mBluetoothGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);\n            Log.w(TAG, \"Trying to create a new connection.\");\n            details.append(\"\\nTrying to create a new connection to device\");\n            mConnectionState = STATE_CONNECTING;\n            return true;\n        }\n    }\n\n    public void authenticateConnection(BluetoothGatt bluetoothGatt) {\n        Log.w(TAG, \"Trying to auth\");\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        String receiverSn = prefs.getString(\"share_key\", \"SM00000000\").toUpperCase();\n        if(bluetoothGatt != null) {\n            mBluetoothGatt = bluetoothGatt;\n            mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService);\n            if (mShareService != null) {\n                mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode);\n                if(mAuthenticationCharacteristic != null) {\n                    Log.w(TAG, \"Auth Characteristic found: \" + mAuthenticationCharacteristic.toString());\n                    mAuthenticationCharacteristic.setValue((receiverSn + \"000000\").getBytes(StandardCharsets.US_ASCII));\n                    currentGattTask = GATT_SETUP;\n                    step = 1;\n                    bluetoothGatt.writeCharacteristic(mAuthenticationCharacteristic);\n                } else {\n                    Log.w(TAG, \"Authentication Characteristic IS NULL\");\n                }\n            } else {\n                Log.w(TAG, \"CRADLE SERVICE IS NULL\");\n            }\n        }\n    }\n\n    public void assignCharacteristics() {\n        mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver);\n        mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse);\n        mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat);\n        mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command);\n        mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response);\n    }\n\n    public void setListeners(int listener_number) {\n\n        Log.w(TAG, \"Setting Listener: #\" + listener_number);\n        if(listener_number == 1) {\n            step = 3;\n            setCharacteristicIndication(mReceiveDataCharacteristic);\n        } else if(listener_number == 3) {\n            setCharacteristicIndication(mResponseCharacteristic);\n            step = 5;\n        }\n     }\n\n    public void disconnect() {\n        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized\");\n            return;\n        }\n        mBluetoothGatt.disconnect();\n    }\n\n    public void close() {\n        disconnect();\n        if (mBluetoothGatt == null) {\n            return;\n        }\n        mBluetoothGatt.close();\n        mBluetoothGatt = null;\n        mConnectionState = STATE_DISCONNECTED;\n        Log.w(TAG, \"bt Disconnected\");\n    }\n\n    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {\n        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized\");\n            return;\n        }\n        mBluetoothGatt.readCharacteristic(characteristic);\n    }\n\n    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic){ setCharacteristicNotification(characteristic, true);}\n    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {\n        Log.w(TAG, \"Characteristic setting notification\");\n        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);\n        Log.w(TAG, \"UUID FOUND: \" + characteristic.getUuid());\n        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));\n        Log.w(TAG, \"Descriptor found: \" + descriptor.getUuid());\n        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);\n        mBluetoothGatt.writeDescriptor(descriptor);\n    }\n\n    public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic){ setCharacteristicIndication(characteristic, true);}\n    public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) {\n        Log.w(TAG, \"Characteristic setting notification\");\n        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);\n        Log.w(TAG, \"UUID FOUND: \" + characteristic.getUuid());\n        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));\n        Log.w(TAG, \"Descriptor found: \" + descriptor.getUuid());\n        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);\n        mBluetoothGatt.writeDescriptor(descriptor);\n    }\n\n    private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {\n        public void onReceive(Context context, Intent intent) {\n            String action = intent.getAction();\n\n            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {\n                final int state        = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);\n                final int prevState    = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);\n                if (state == BluetoothDevice.BOND_BONDED) {\n                    Log.d(TAG, \"CALLBACK RECIEVED Bonded\");\n                    currentGattTask = GATT_SETUP;\n                    mBluetoothGatt.discoverServices();\n                } else if (state == BluetoothDevice.BOND_NONE){\n                    Log.d(TAG, \"CALLBACK RECIEVED: Not Bonded\");\n                    Toast.makeText(getApplicationContext(), \"unBonded\", Toast.LENGTH_LONG).show();\n                } else if (state == BluetoothDevice.BOND_BONDING) {\n                    Log.d(TAG, \"CALLBACK RECIEVED: Trying to bond\");\n                    Toast.makeText(getApplicationContext(), \"trying to bond\", Toast.LENGTH_LONG).show();\n                }\n            }\n        }\n    };\n\n    public void writeCommand(List<byte[]> packets, int aRecordType, Action1<byte[]> dataResponseListener) {\n        mDataResponseListener = dataResponseListener;\n        successfulWrites = 0;\n        writePackets = packets;\n        recordType = aRecordType;\n        step = 0;\n        currentGattTask = GATT_WRITING_COMMANDS;\n        gattWritingStep();\n    }\n\n    private void nextGattStep() {\n        Log.d(TAG, \"Next Gatt Step\");\n        step++;\n        switch (currentGattTask) {\n        case GATT_NOTHING:\n            Log.d(TAG, \"Next NOTHING: \" + step);\n            break;\n        case GATT_SETUP:\n            Log.d(TAG, \"Next GATT SETUP: \" + step);\n            gattSetupStep();\n            break;\n        case GATT_WRITING_COMMANDS:\n            Log.d(TAG, \"Next GATT WRITING: \" + step);\n            gattWritingStep();\n            break;\n        }\n    }\n\n    public void clearGattTask() {\n        currentGattTask = GATT_NOTHING;\n        step = 0;\n    }\n\n    private void gattSetupStep() {\n        step = 1;\n        assignCharacteristics();\n        setListeners(1);\n    }\n\n    private void gattWritingStep() {\n        Log.d(TAG, \"Writing command to the Gatt, step: \" + step);\n        int index = step;\n        if (index <= (writePackets.size() - 1)) {\n            Log.d(TAG, \"Writing: \" + writePackets.get(index) + \" index: \" + index);\n            mSendDataCharacteristic.setValue(writePackets.get(index));\n            mBluetoothGatt.writeCharacteristic(mSendDataCharacteristic);\n        } else {\n            clearGattTask();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.DatePicker;\nimport android.widget.TimePicker;\nimport android.widget.Toast;\n\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\nimport java.util.Calendar;\nimport java.util.List;\n\n\npublic class StartNewSensor extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Start Sensor\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    public Button button;\n    public DatePicker dp;\n    public TimePicker tp;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(Sensor.isActive() == false) {\n            setContentView(R.layout.activity_start_new_sensor);\n\n            button = (Button)findViewById(R.id.startNewSensor);\n            dp = (DatePicker)findViewById(R.id.datePicker);\n            tp = (TimePicker)findViewById(R.id.timePicker);\n            addListenerOnButton();\n\n\n        } else {\n            Intent intent = new Intent(this, StopSensor.class);\n            startActivity(intent);\n            finish();\n        }\n    }\n    @Override\n    protected void onResume(){\n        super.onResume();\n        NavigationDrawerFragment mNavigationDrawerFragment;\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        NavDrawerBuilder navDrawerBuilder = new NavDrawerBuilder(getApplicationContext());\n        List<String> menu_option_list = navDrawerBuilder.nav_drawer_options;\n        int menu_position = menu_option_list.indexOf(menu_name);\n\n        if (position != menu_position) {\n            List<Intent> intent_list = navDrawerBuilder.nav_drawer_intents;\n            Intent[] intent_array = intent_list.toArray(new Intent[intent_list.size()]);\n            startActivity(intent_array[position]);\n            finish();\n        }\n\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button)findViewById(R.id.startNewSensor);\n\n        button.setOnClickListener(new View.OnClickListener() {\n          public void onClick(View v) {\n\n              Calendar calendar = Calendar.getInstance();\n              calendar.set(dp.getYear(), dp.getMonth(), dp.getDayOfMonth(),\n              tp.getCurrentHour(), tp.getCurrentMinute(), 0);\n              long startTime = calendar.getTime().getTime();\n\n              Sensor sensor = Sensor.create(startTime);\n              Log.w(\"NEW SENSOR\", \"Sensor started at \" + startTime);\n\n              Toast.makeText(getApplicationContext(), \"NEW SENSOR STARTED\", Toast.LENGTH_LONG).show();\n              Intent intent = new Intent(getApplicationContext(), Home.class);\n              CollectionServiceStarter.newStart(getApplicationContext());\n              startActivity(intent);\n              finish();\n          }\n\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/StopSensor.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.Toast;\n\nimport java.util.Date;\n\n\npublic class StopSensor extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Stop Sensor\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    public Button button;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(Sensor.isActive() == false) {\n            Intent intent = new Intent(this, StartNewSensor.class);\n            startActivity(intent);\n            finish();\n        } else {\n            setContentView(R.layout.activity_stop_sensor);\n            button = (Button)findViewById(R.id.stop_sensor);\n            addListenerOnButton();\n        }\n    }\n    @Override\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    public void addListenerOnButton() {\n\n        button = (Button)findViewById(R.id.stop_sensor);\n\n        button.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                Sensor sensor = Sensor.currentSensor();\n                sensor.stopped_at = new Date().getTime();\n                Log.w(\"NEW SENSOR\", \"Sensor stopped at \" + sensor.stopped_at);\n                sensor.save();\n\n                Toast.makeText(getApplicationContext(), \"Sensor stopped\", Toast.LENGTH_LONG).show();\n                Intent intent = new Intent(getApplicationContext(), Home.class);\n                startActivity(intent);\n                finish();\n            }\n\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/SystemStatus.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.support.v4.widget.DrawerLayout;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.ImageButton;\nimport android.widget.TextView;\n\nimport com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\n\nimport java.lang.reflect.Method;\n\n\npublic class SystemStatus extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"System Status\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n    public TextView collection_method;\n    public TextView current_device;\n    public TextView connection_status;\n    public TextView notes;\n    public Button restart_collection_service;\n    public Button forget_device;\n    public ImageButton refresh;\n    public SharedPreferences prefs;\n    public BluetoothManager mBluetoothManager;\n    public ActiveBluetoothDevice activeBluetoothDevice;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_system_status);\n        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n\n        collection_method = (TextView)findViewById(R.id.collection_method);\n        connection_status = (TextView)findViewById(R.id.connection_status);\n        current_device = (TextView)findViewById(R.id.remembered_device);\n\n        notes = (TextView)findViewById(R.id.other_notes);\n\n        restart_collection_service = (Button)findViewById(R.id.restart_collection_service);\n        forget_device = (Button)findViewById(R.id.forget_device);\n        refresh = (ImageButton)findViewById(R.id.refresh_current_values);\n\n        set_current_values();\n        restartButtonListener();\n        forgetDeviceListener();\n        refreshButtonListener();\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    private void set_current_values() {\n        activeBluetoothDevice = ActiveBluetoothDevice.first();\n        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n        setCollectionMethod();\n        setCurrentDevice();\n        setConnectionStatus();\n        setNotes();\n    }\n\n    public void setCollectionMethod() {\n        collection_method.setText(prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n    }\n\n    public void setCurrentDevice() {\n        if(activeBluetoothDevice != null) {\n            current_device.setText(activeBluetoothDevice.name);\n        } else {\n            current_device.setText(\"None Set\");\n        }\n    }\n\n    public void setConnectionStatus() {\n        boolean connected = false;\n        if (mBluetoothManager != null && activeBluetoothDevice != null) {\n            for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {\n                if (bluetoothDevice.getAddress().compareTo(activeBluetoothDevice.address) == 0) {\n                    connected = true;\n                }\n            }\n        }\n        if(connected) {\n            connection_status.setText(\"Connected\");\n        } else {\n            connection_status.setText(\"Not Connected\");\n        }\n    }\n\n    public void setNotes() {\n        if(mBluetoothManager == null) {\n            notes.append(\"\\n- This device does not seem to support bluetooth\");\n        } else {\n            if(!mBluetoothManager.getAdapter().isEnabled()) {\n                notes.append(\"\\n- Bluetooth seems to be turned off\");\n            } else {\n                if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){\n                    notes.append(\"\\n- The android version of this device is not compatible with Bluetooth Low Energy\");\n                }\n            }\n        }\n    }\n\n    public void restartButtonListener() {\n        restart_collection_service.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                CollectionServiceStarter.restartCollectionService(getApplicationContext());\n                set_current_values();\n            }\n        });\n    }\n\n    public void forgetDeviceListener() {\n        forget_device.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                if(mBluetoothManager != null && ActiveBluetoothDevice.first() != null) {\n                    BluetoothAdapter bluetoothAdapter = mBluetoothManager.getAdapter();\n                    if(bluetoothAdapter != null) {\n                        for( BluetoothDevice bluetoothDevice : bluetoothAdapter.getBondedDevices()) {\n                            if(bluetoothDevice.getAddress().compareTo(ActiveBluetoothDevice.first().address) == 0) {\n                                try {\n                                    Method m = bluetoothDevice.getClass().getMethod(\"removeBond\", (Class[]) null);\n                                    m.invoke(bluetoothDevice, (Object[]) null);\n                                    notes.append(\"\\n- Bluetooth unbonded, if using share tell it to forget your device.\");\n                                    notes.append(\"\\n- Scan for devices again to set connection back up!\");\n                                } catch (Exception e) { Log.e(\"SystemStatus\", e.getMessage()); }\n                            }\n                        }\n\n                        ActiveBluetoothDevice.forget();\n                        bluetoothAdapter.disable();\n                        bluetoothAdapter.enable();\n                        try {\n                            wait(1000);\n                        } catch(Exception e) {\n                            Log.e(\"SystemStatus\", \"Error stalling\");\n                        }\n                    }\n                }\n                CollectionServiceStarter.restartCollectionService(getApplicationContext());\n                set_current_values();\n            }\n        });\n    }\n\n    public void refreshButtonListener() {\n        refresh.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                set_current_values();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Tables/BgReadingTable.java",
    "content": "package com.eveningoutpost.dexdrip.Tables;\n\nimport android.app.ListActivity;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ListAdapter;\nimport android.widget.TextView;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.NavigationDrawerFragment;\nimport com.eveningoutpost.dexdrip.R;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n\npublic class BgReadingTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"BG Data Table\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.raw_data_list);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n\n        getData();\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    private void getData() {\n        final List<BgReading> latest = BgReading.latest(50);\n        ListAdapter adapter = new BgReadingAdapter(this, latest);\n\n        this.setListAdapter(adapter);\n    }\n\n    public static class BgReadingCursorAdapterViewHolder {\n        TextView raw_data_id;\n        TextView raw_data_value;\n        TextView raw_data_slope;\n        TextView raw_data_timestamp;\n\n        public BgReadingCursorAdapterViewHolder(View root) {\n            raw_data_id = (TextView) root.findViewById(R.id.raw_data_id);\n            raw_data_value = (TextView) root.findViewById(R.id.raw_data_value);\n            raw_data_slope = (TextView) root.findViewById(R.id.raw_data_slope);\n            raw_data_timestamp = (TextView) root.findViewById(R.id.raw_data_timestamp);\n        }\n    }\n\n    public static class BgReadingAdapter extends BaseAdapter {\n        private final Context         context;\n        private final List<BgReading> readings;\n\n        public BgReadingAdapter(Context context, List<BgReading> readings) {\n            this.context = context;\n            if(readings == null)\n                readings = new ArrayList<>();\n\n            this.readings = readings;\n        }\n\n        public View newView(Context context, ViewGroup parent) {\n            final View view = LayoutInflater.from(context).inflate(R.layout.raw_data_list_item, parent, false);\n\n            final BgReadingCursorAdapterViewHolder holder = new BgReadingCursorAdapterViewHolder(view);\n            view.setTag(holder);\n\n            return view;\n        }\n\n        public void bindView(View view, Context context, BgReading bgReading) {\n            final BgReadingCursorAdapterViewHolder tag = (BgReadingCursorAdapterViewHolder) view.getTag();\n            tag.raw_data_id.setText(Double.toString(bgReading.calculated_value));\n            tag.raw_data_value.setText(Double.toString(bgReading.age_adjusted_raw_value));\n            tag.raw_data_slope.setText(Double.toString(bgReading.raw_data));\n            tag.raw_data_timestamp.setText(new Date(bgReading.timestamp).toString());\n        }\n\n        @Override\n        public int getCount() {\n            return readings.size();\n        }\n\n        @Override\n        public BgReading getItem(int position) {\n            return readings.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return getItem(position).getId();\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            if (convertView == null)\n                convertView = newView(context, parent);\n\n            bindView(convertView, context, getItem(position));\n            return convertView;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Tables/CalibrationDataTable.java",
    "content": "package com.eveningoutpost.dexdrip.Tables;\n\nimport android.app.ListActivity;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.TextView;\n\nimport com.activeandroid.Cache;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.NavigationDrawerFragment;\nimport com.eveningoutpost.dexdrip.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class CalibrationDataTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Calibration Data Table\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.raw_data_list);\n    }\n\n    @Override\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n        getData();\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    private void getData() {\n        final List<Calibration> latest = Calibration.latest(50);\n\n        CalibrationDataCursorAdapter adapter = new CalibrationDataCursorAdapter(this, latest);\n\n        this.setListAdapter(adapter);\n    }\n\n\n    public static class CalibrationDataCursorAdapterViewHolder {\n        TextView raw_data_id;\n        TextView raw_data_value;\n        TextView raw_data_slope;\n        TextView raw_data_timestamp;\n\n        public CalibrationDataCursorAdapterViewHolder(View root) {\n            raw_data_id = (TextView) root.findViewById(R.id.raw_data_id);\n            raw_data_value = (TextView) root.findViewById(R.id.raw_data_value);\n            raw_data_slope = (TextView) root.findViewById(R.id.raw_data_slope);\n            raw_data_timestamp = (TextView) root.findViewById(R.id.raw_data_timestamp);\n        }\n    }\n\n    public static class CalibrationDataCursorAdapter extends BaseAdapter {\n        private final Context           context;\n        private final List<Calibration> calibrations;\n\n        public CalibrationDataCursorAdapter(Context context, List<Calibration> calibrations) {\n            this.context = context;\n            if(calibrations == null)\n                calibrations = new ArrayList<>();\n\n            this.calibrations = calibrations;\n        }\n\n        public View newView(Context context, ViewGroup parent) {\n            final View view = LayoutInflater.from(context).inflate(R.layout.raw_data_list_item, parent, false);\n\n            final CalibrationDataCursorAdapterViewHolder holder = new CalibrationDataCursorAdapterViewHolder(view);\n            view.setTag(holder);\n\n            return view;\n        }\n\n        public void bindView(View view, Context context, Calibration calibration) {\n            final CalibrationDataCursorAdapterViewHolder tag = (CalibrationDataCursorAdapterViewHolder) view.getTag();\n            tag.raw_data_id.setText(Double.toString(calibration.bg));\n            tag.raw_data_value.setText(Double.toString(calibration.estimate_raw_at_time_of_calibration));\n            tag.raw_data_slope.setText(Double.toString(calibration.slope));\n            tag.raw_data_timestamp.setText(Double.toString(calibration.intercept));\n        }\n\n        @Override\n        public int getCount() {\n            return calibrations.size();\n        }\n\n        @Override\n        public Calibration getItem(int position) {\n            return calibrations.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return getItem(position).getId();\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            if (convertView == null)\n                convertView = newView(context, parent);\n\n            bindView(convertView, context, getItem(position));\n            return convertView;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/Tables/SensorDataTable.java",
    "content": "package com.eveningoutpost.dexdrip.Tables;\n\nimport android.app.ListActivity;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.View;\nimport android.widget.SimpleCursorAdapter;\n\nimport com.activeandroid.Cache;\nimport com.eveningoutpost.dexdrip.NavigationDrawerFragment;\nimport com.eveningoutpost.dexdrip.R;\n\nimport java.util.ArrayList;\n\n\npublic class SensorDataTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {\n    private String menu_name = \"Sensor Data Table\";\n    private NavigationDrawerFragment mNavigationDrawerFragment;\n\n    private ArrayList<String> results = new ArrayList<String>();\n    private View mRootView;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.raw_data_list);\n    }\n\n    @Override\n    protected void onResume(){\n        super.onResume();\n        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);\n        mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);\n        getData();\n    }\n\n    @Override\n    public void onNavigationDrawerItemSelected(int position) {\n        mNavigationDrawerFragment.swapContext(position);\n    }\n\n    private void getData() {\n        Cursor cursor = Cache.openDatabase().rawQuery(\"Select * from Sensors order by _ID desc\", null);\n\n        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,\n                R.layout.raw_data_list_item,\n                cursor,\n                new String[] { \"started_at\", \"latest_battery_level\", \"uuid\", \"uuid\" },\n                new int[] { R.id.raw_data_id, R.id.raw_data_value , R.id.raw_data_slope, R.id.raw_data_timestamp });\n\n        this.setListAdapter(adapter);\n//        ListView listView = (ListView) findViewById(R.id.list);\n//        listView.setAdapter(adapter);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UsbConnectedActivity.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.SyncingService;\n\npublic class UsbConnectedActivity extends Activity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(SyncingService.isG4Connected(getApplicationContext())){\n            Intent checkInIntent = new Intent(getApplicationContext(), CalibrationCheckInActivity.class);\n            startActivity(checkInIntent);\n            finish();\n        } else {\n            //TODO: Put check for usb wixel in here as an elseif\n            Intent homeIntent = new Intent(getApplicationContext(), Home.class);\n            startActivity(homeIntent);\n            finish();\n        }\n        setContentView(R.layout.activity_usb_connected);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.Configuration;\nimport android.graphics.Color;\nimport android.preference.PreferenceManager;\nimport android.text.format.DateFormat;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\n\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\nimport java.util.List;\nimport java.util.TimeZone;\n\nimport lecho.lib.hellocharts.model.Axis;\nimport lecho.lib.hellocharts.model.AxisValue;\nimport lecho.lib.hellocharts.model.Line;\nimport lecho.lib.hellocharts.model.LineChartData;\nimport lecho.lib.hellocharts.model.PointValue;\nimport lecho.lib.hellocharts.model.Viewport;\nimport lecho.lib.hellocharts.util.Utils;\nimport lecho.lib.hellocharts.view.Chart;\n\n/**\n * Created by stephenblack on 11/15/14.\n */\npublic class BgGraphBuilder {\n    public int fuzzer = (1000 * 30 * 5);\n    public double  end_time = (new Date().getTime() + (60000 * 10)) / fuzzer;\n    public double  start_time = end_time - ((60000 * 60 * 24)) / fuzzer;\n    public Context context;\n    public SharedPreferences prefs;\n    public double highMark;\n    public double lowMark;\n    public double defaultMinY;\n    public double defaultMaxY;\n    public boolean doMgdl;\n    final int pointSize;\n    final int axisTextSize;\n    final int previewAxisTextSize;\n    final int hoursPreviewStep;\n\n    private double endHour;\n    private final int numValues =(60/5)*24;\n    private final List<BgReading> bgReadings = BgReading.latestForGraph( numValues, (start_time * fuzzer));\n    private List<PointValue> inRangeValues = new ArrayList<PointValue>();\n    private List<PointValue> highValues = new ArrayList<PointValue>();\n    private List<PointValue> lowValues = new ArrayList<PointValue>();\n    private List<PointValue> rawInterpretedValues = new ArrayList<PointValue>();\n    public Viewport viewport;\n\n\n    public BgGraphBuilder(Context context){\n        this.context = context;\n        this.prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        this.highMark = Double.parseDouble(prefs.getString(\"highValue\", \"170\"));\n        this.lowMark = Double.parseDouble(prefs.getString(\"lowValue\", \"70\"));\n        this.doMgdl = (prefs.getString(\"units\", \"mgdl\").compareTo(\"mgdl\") == 0);\n        defaultMinY = unitized(40);\n        defaultMaxY = unitized(250);\n        pointSize = isXLargeTablet() ? 5 : 3;\n        axisTextSize = isXLargeTablet() ? 20 : Axis.DEFAULT_TEXT_SIZE_SP;\n        previewAxisTextSize = isXLargeTablet() ? 12 : 5;\n        hoursPreviewStep = isXLargeTablet() ? 2 : 1;\n    }\n\n    public LineChartData lineData() {\n        LineChartData lineData = new LineChartData(defaultLines());\n        lineData.setAxisYLeft(yAxis());\n        lineData.setAxisXBottom(xAxis());\n        return lineData;\n    }\n\n    public LineChartData previewLineData() {\n        LineChartData previewLineData = new LineChartData(lineData());\n        previewLineData.setAxisYLeft(yAxis());\n        previewLineData.setAxisXBottom(previewXAxis());\n        previewLineData.getLines().get(4).setPointRadius(2);\n        previewLineData.getLines().get(5).setPointRadius(2);\n        previewLineData.getLines().get(6).setPointRadius(2);\n        return previewLineData;\n    }\n\n    public List<Line> defaultLines() {\n        addBgReadingValues();\n        List<Line> lines = new ArrayList<Line>();\n        lines.add(minShowLine());\n        lines.add(maxShowLine());\n        lines.add(highLine());\n        lines.add(lowLine());\n        lines.add(inRangeValuesLine());\n        lines.add(lowValuesLine());\n        lines.add(highValuesLine());\n        lines.add(rawInterpretedLine());\n        return lines;\n    }\n\n    public Line highValuesLine() {\n        Line highValuesLine = new Line(highValues);\n        highValuesLine.setColor(Utils.COLOR_ORANGE);\n        highValuesLine.setHasLines(false);\n        highValuesLine.setPointRadius(pointSize);\n        highValuesLine.setHasPoints(true);\n        return highValuesLine;\n    }\n\n    public Line lowValuesLine() {\n        Line lowValuesLine = new Line(lowValues);\n        lowValuesLine.setColor(Color.parseColor(\"#C30909\"));\n        lowValuesLine.setHasLines(false);\n        lowValuesLine.setPointRadius(pointSize);\n        lowValuesLine.setHasPoints(true);\n        return lowValuesLine;\n    }\n\n    public Line inRangeValuesLine() {\n        Line inRangeValuesLine = new Line(inRangeValues);\n        inRangeValuesLine.setColor(Utils.COLOR_BLUE);\n        inRangeValuesLine.setHasLines(false);\n        inRangeValuesLine.setPointRadius(pointSize);\n        inRangeValuesLine.setHasPoints(true);\n        return inRangeValuesLine;\n    }\n\n    public Line rawInterpretedLine() {\n        Line line = new Line(rawInterpretedValues);\n        line.setHasLines(false);\n        line.setPointRadius(1);\n        line.setHasPoints(true);\n        return line;\n    }\n\n    private void addBgReadingValues() {\n        for (BgReading bgReading : bgReadings) {\n            if (bgReading.raw_calculated != 0 && prefs.getBoolean(\"interpret_raw\", false)) {\n                rawInterpretedValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.raw_calculated)));\n            } else if (bgReading.calculated_value >= 400) {\n                highValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(400)));\n            } else if (unitized(bgReading.calculated_value) >= highMark) {\n                highValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));\n            } else if (unitized(bgReading.calculated_value) >= lowMark) {\n                inRangeValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));\n            } else if (bgReading.calculated_value >= 40) {\n                lowValues.add(new PointValue((float)(bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));\n            } else if (bgReading.calculated_value > 13) {\n                lowValues.add(new PointValue((float)(bgReading.timestamp/fuzzer), (float) unitized(40)));\n            }\n        }\n    }\n\n    public Line highLine() {\n        List<PointValue> highLineValues = new ArrayList<PointValue>();\n        highLineValues.add(new PointValue((float)start_time, (float)highMark));\n        highLineValues.add(new PointValue((float)end_time, (float)highMark));\n        Line highLine = new Line(highLineValues);\n        highLine.setHasPoints(false);\n        highLine.setStrokeWidth(1);\n        highLine.setColor(Utils.COLOR_ORANGE);\n        return highLine;\n    }\n\n    public Line lowLine() {\n        List<PointValue> lowLineValues = new ArrayList<PointValue>();\n        lowLineValues.add(new PointValue((float)start_time, (float)lowMark));\n        lowLineValues.add(new PointValue((float)end_time, (float)lowMark));\n        Line lowLine = new Line(lowLineValues);\n        lowLine.setHasPoints(false);\n        lowLine.setAreaTransparency(50);\n        lowLine.setColor(Color.parseColor(\"#C30909\"));\n        lowLine.setStrokeWidth(1);\n        lowLine.setFilled(true);\n        return lowLine;\n    }\n\n    public Line maxShowLine() {\n        List<PointValue> maxShowValues = new ArrayList<PointValue>();\n        maxShowValues.add(new PointValue((float)start_time, (float)defaultMaxY));\n        maxShowValues.add(new PointValue((float)end_time, (float)defaultMaxY));\n        Line maxShowLine = new Line(maxShowValues);\n        maxShowLine.setHasLines(false);\n        maxShowLine.setHasPoints(false);\n        return maxShowLine;\n    }\n\n    public Line minShowLine() {\n        List<PointValue> minShowValues = new ArrayList<PointValue>();\n        minShowValues.add(new PointValue((float)start_time, (float)defaultMinY));\n        minShowValues.add(new PointValue((float)end_time, (float)defaultMinY));\n        Line minShowLine = new Line(minShowValues);\n        minShowLine.setHasPoints(false);\n        minShowLine.setHasLines(false);\n        return minShowLine;\n    }\n\n    /////////AXIS RELATED//////////////\n    public Axis yAxis() {\n        Axis yAxis = new Axis();\n        yAxis.setAutoGenerated(false);\n        List<AxisValue> axisValues = new ArrayList<AxisValue>();\n\n        for(int j = 1; j <= 12; j += 1) {\n            if (doMgdl) {\n                axisValues.add(new AxisValue(j * 50));\n            } else {\n                axisValues.add(new AxisValue(j*2));\n            }\n        }\n        yAxis.setValues(axisValues);\n        yAxis.setHasLines(true);\n        yAxis.setMaxLabelChars(5);\n        yAxis.setInside(true);\n        yAxis.setTextSize(axisTextSize);\n        return yAxis;\n    }\n\n    public Axis xAxis() {\n        Axis xAxis = new Axis();\n        xAxis.setAutoGenerated(false);\n        List<AxisValue> xAxisValues = new ArrayList<AxisValue>();\n        GregorianCalendar now = new GregorianCalendar();\n        GregorianCalendar today = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));\n        final java.text.DateFormat timeFormat = hourFormat();\n        timeFormat.setTimeZone(TimeZone.getDefault());\n        double start_hour_block = today.getTime().getTime();\n        double timeNow = new Date().getTime();\n        for(int l=0; l<=24; l++) {\n            if ((start_hour_block + (60000 * 60 * (l))) <  timeNow) {\n                if((start_hour_block + (60000 * 60 * (l + 1))) >=  timeNow) {\n                    endHour = start_hour_block + (60000 * 60 * (l));\n                    l=25;\n                }\n            }\n        }\n        for(int l=0; l<=24; l++) {\n            double timestamp = (endHour - (60000 * 60 * l));\n            xAxisValues.add(new AxisValue((long)(timestamp/fuzzer), (timeFormat.format(timestamp)).toCharArray()));\n        }\n        xAxis.setValues(xAxisValues);\n        xAxis.setHasLines(true);\n        xAxis.setTextSize(axisTextSize);\n        return xAxis;\n    }\n\n    private SimpleDateFormat hourFormat() {\n        return new SimpleDateFormat(DateFormat.is24HourFormat(context) ? \"HH\" : \"h a\");\n    }\n\n    private boolean isXLargeTablet() {\n        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;\n    }\n\n    public Axis previewXAxis(){\n        List<AxisValue> previewXaxisValues = new ArrayList<AxisValue>();\n        final java.text.DateFormat timeFormat = hourFormat();\n        timeFormat.setTimeZone(TimeZone.getDefault());\n        for(int l=0; l<=24; l+=hoursPreviewStep) {\n            double timestamp = (endHour - (60000 * 60 * l));\n            previewXaxisValues.add(new AxisValue((long)(timestamp/fuzzer), (timeFormat.format(timestamp)).toCharArray()));\n        }\n        Axis previewXaxis = new Axis();\n        previewXaxis.setValues(previewXaxisValues);\n        previewXaxis.setHasLines(true);\n        previewXaxis.setTextSize(previewAxisTextSize);\n        return previewXaxis;\n    }\n\n    /////////VIEWPORT RELATED//////////////\n    public Viewport advanceViewport(Chart chart, Chart previewChart) {\n        viewport = new Viewport(previewChart.getMaximumViewport());\n        viewport.inset((float)((86400000 / 2.5)/fuzzer), 0);\n        double distance_to_move = ((new Date().getTime())/fuzzer) - viewport.left - (((viewport.right - viewport.left) /2));\n        viewport.offset((float) distance_to_move, 0);\n        return viewport;\n    }\n\n    public double unitized(double value) {\n        if(doMgdl) {\n            return value;\n        } else {\n            return mmolConvert(value);\n        }\n    }\n\n    public String unitized_string(double value) {\n        DecimalFormat df = new DecimalFormat(\"#\");\n        if (value >= 400) {\n            return \"HIGH\";\n        } else if (value >= 40) {\n            if(doMgdl) {\n                df.setMaximumFractionDigits(0);\n                return df.format(value);\n            } else {\n                df.setMaximumFractionDigits(1);\n                return df.format(mmolConvert(value));\n            }\n        } else if (value > 12) {\n            return \"LOW\";\n        } else {\n            switch((int)value) {\n                case 0:\n                    return \"??0\";\n                case 1:\n                    return \"?SN\";\n                case 2:\n                    return \"??2\";\n                case 3:\n                    return \"?NA\";\n                case 5:\n                    return \"?NC\";\n                case 6:\n                    return \"?CD\";\n                case 9:\n                    return \"?AD\";\n                case 12:\n                    return \"?RF\";\n                default:\n                    return \"???\";\n            }\n        }\n    }\n\n    public String unitizedDeltaString(double value) {\n        DecimalFormat df = new DecimalFormat(\"#\");\n        df.setMaximumFractionDigits(1);\n        String delta_sign = \"\";\n        if (value > 0.1) { delta_sign = \"+\"; }\n        if(doMgdl) {\n            return delta_sign + df.format(unitized(value)) + \" mg/dl\";\n        } else {\n            return delta_sign + df.format(unitized(value)) + \" mmol\";\n        }\n    }\n\n    public double mmolConvert(double mgdl) {\n        return mgdl * Constants.MGDL_TO_MMOLL;\n    }\n\n    public String unit() {\n        if(doMgdl){\n            return \"mg/dl\";\n        } else {\n            return \"mmol\";\n        }\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.os.BatteryManager;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.preference.PreferenceManager;\nimport android.provider.BaseColumns;\nimport android.util.Log;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.ShareModels.ShareRest;\nimport com.eveningoutpost.dexdrip.widgetUpdateService;\n\nimport java.util.List;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\n@Table(name = \"BgSendQueue\", id = BaseColumns._ID)\npublic class BgSendQueue extends Model {\n\n    @Column(name = \"bgReading\", index = true)\n    public BgReading bgReading;\n\n    @Column(name = \"success\", index = true)\n    public boolean success;\n\n    @Column(name = \"mongo_success\", index = true)\n    public boolean mongo_success;\n\n    @Column(name = \"operation_type\")\n    public String operation_type;\n\n    public static BgSendQueue nextBgJob() {\n        return new Select()\n                .from(BgSendQueue.class)\n                .where(\"success = ?\", false)\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n    }\n\n    public static List<BgSendQueue> queue() {\n        return new Select()\n                .from(BgSendQueue.class)\n                .where(\"success = ?\", false)\n                .orderBy(\"_ID asc\")\n                .limit(20)\n                .execute();\n    }\n    public static List<BgSendQueue> mongoQueue() {\n        return new Select()\n                .from(BgSendQueue.class)\n                .where(\"mongo_success = ?\", false)\n                .where(\"operation_type = ?\", \"create\")\n                .orderBy(\"_ID asc\")\n                .limit(30)\n                .execute();\n    }\n\n    public static void addToQueue(BgReading bgReading, String operation_type, Context context) {\n        PowerManager powerManager = (PowerManager) context.getSystemService(context.POWER_SERVICE);\n        PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,\n                \"sendQueue\");\n        wakeLock.acquire();\n\n\n        BgSendQueue bgSendQueue = new BgSendQueue();\n        bgSendQueue.operation_type = operation_type;\n        bgSendQueue.bgReading = bgReading;\n        bgSendQueue.success = false;\n        bgSendQueue.mongo_success = false;\n        bgSendQueue.save();\n        Log.d(\"BGQueue\", \"New value added to queue!\");\n\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n\n        Intent updateIntent = new Intent(Intents.ACTION_NEW_BG_ESTIMATE_NO_DATA);\n        context.sendBroadcast(updateIntent);\n        context.startService(new Intent(context, widgetUpdateService.class));\n\n        if (prefs.getBoolean(\"cloud_storage_mongodb_enable\", false) || prefs.getBoolean(\"cloud_storage_api_enable\", false)) {\n            Log.w(\"SENSOR QUEUE:\", String.valueOf(bgSendQueue.mongo_success));\n            if (operation_type.compareTo(\"create\") == 0) {\n                MongoSendTask task = new MongoSendTask(context, bgSendQueue);\n                task.execute();\n            }\n        }\n\n        if(prefs.getBoolean(\"broadcast_data_through_intents\", false)) {\n            Log.i(\"SENSOR QUEUE:\", \"Broadcast data\");\n            final Bundle bundle = new Bundle();\n            bundle.putDouble(Intents.EXTRA_BG_ESTIMATE, bgReading.calculated_value);\n            bundle.putDouble(Intents.EXTRA_BG_SLOPE, bgReading.calculated_value_slope);\n            if(bgReading.hide_slope) {\n                bundle.putString(Intents.EXTRA_BG_SLOPE_NAME, \"9\");\n            } else {\n                bundle.putString(Intents.EXTRA_BG_SLOPE_NAME, bgReading.slopeName());\n            }\n            bundle.putInt(Intents.EXTRA_SENSOR_BATTERY, getBatteryLevel(context));\n            bundle.putLong(Intents.EXTRA_TIMESTAMP, bgReading.timestamp);\n\n            Intent intent = new Intent(Intents.ACTION_NEW_BG_ESTIMATE);\n            intent.putExtras(bundle);\n            context.sendBroadcast(intent, Intents.RECEIVER_PERMISSION);\n        }\n\n        if(prefs.getBoolean(\"broadcast_to_pebble\", false)) {\n            PebbleSync pebbleSync = new PebbleSync();\n            pebbleSync.sendData(context, bgReading);\n        }\n\n        if(prefs.getBoolean(\"share_upload\", false)) {\n            ShareRest shareRest = new ShareRest(context);\n            Log.w(\"ShareRest\", \"About to call ShareRest!!\");\n            shareRest.sendBgData(bgReading);\n        }\n        wakeLock.release();\n    }\n\n    public void markMongoSuccess() {\n        mongo_success = true;\n        save();\n    }\n\n    public static int getBatteryLevel(Context context) {\n        Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n        int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n        int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);\n        if(level == -1 || scale == -1) {\n            return 50;\n        }\n        return (int)(((float)level / (float)scale) * 100.0f);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CalibrationSendQueue.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.provider.BaseColumns;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\n\nimport java.util.List;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\n@Table(name = \"CalibrationSendQueue\", id = BaseColumns._ID)\npublic class CalibrationSendQueue extends Model {\n\n    @Column(name = \"calibration\", index = true)\n    public Calibration calibration;\n\n    @Column(name = \"success\", index = true)\n    public boolean success;\n\n    @Column(name = \"mongo_success\", index = true)\n    public boolean mongo_success;\n\n    public static CalibrationSendQueue nextCalibrationJob() {\n        CalibrationSendQueue job = new Select()\n                .from(CalibrationSendQueue.class)\n                .where(\"success = ?\", false)\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n        return job;\n    }\n\n    public static List<CalibrationSendQueue> queue() {\n        return new Select()\n                .from(CalibrationSendQueue.class)\n                .where(\"success = ?\", false)\n                .orderBy(\"_ID asc\")\n                .execute();\n    }\n    public static List<CalibrationSendQueue> mongoQueue() {\n        return new Select()\n                .from(CalibrationSendQueue.class)\n                .where(\"mongo_success = ?\", false)\n                .orderBy(\"_ID asc\")\n                .limit(30)\n                .execute();\n    }\n    public static void addToQueue(Calibration calibration, Context context) {\n        CalibrationSendQueue calibrationSendQueue = new CalibrationSendQueue();\n        calibrationSendQueue.calibration = calibration;\n        calibrationSendQueue.success = false;\n        calibrationSendQueue.mongo_success = false;\n        calibrationSendQueue.save();\n\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n\n        if (prefs.getBoolean(\"cloud_storage_mongodb_enable\", false) || prefs.getBoolean(\"cloud_storage_api_enable\", false)) {\n            MongoSendTask task = new MongoSendTask(context, calibrationSendQueue);\n            task.execute();\n        }\n    }\n\n    public void markMongoSuccess() {\n        mongo_success = true;\n        save();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Services.DexCollectionService;\nimport com.eveningoutpost.dexdrip.Services.DexShareCollectionService;\nimport com.eveningoutpost.dexdrip.Services.WixelReader;\n\n/**\n * Created by stephenblack on 12/22/14.\n */\npublic class CollectionServiceStarter {\n    private Context mContext;\n\n    public static boolean isBTWixel(Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String collection_method = prefs.getString(\"dex_collection_method\", \"BluetoothWixel\");\n        if(collection_method.compareTo(\"BluetoothWixel\") == 0) {\n            return true;\n        }\n        return false;\n    }\n    public static boolean isBTShare(Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String collection_method = prefs.getString(\"dex_collection_method\", \"BluetoothWixel\");\n        if(collection_method.compareTo(\"DexcomShare\") == 0) {\n            return true;\n        }\n        return false;\n    }\n    public static boolean isWifiWixel(Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String collection_method = prefs.getString(\"dex_collection_method\", \"BluetoothWixel\");\n        if(collection_method.compareTo(\"WifiWixel\") == 0) {\n            return true;\n        }\n        return false;\n    }\n    public static void newStart(Context context) {\n        CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(context);\n        collectionServiceStarter.start(context);\n    }\n\n    public void start(Context context) {\n        mContext = context;\n\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n        String collection_method = prefs.getString(\"dex_collection_method\", \"BluetoothWixel\");\n\n        if(isBTWixel(context)) {\n            Log.d(\"DexDrip\", \"Starting bt wixel collector\");\n            stopWifWixelThread();\n            stopBtShareService();\n            startBtWixelService();\n        } else if(isWifiWixel(context)){\n            Log.d(\"DexDrip\", \"Starting wifi wixel collector\");\n            stopBtWixelService();\n            stopBtShareService();\n            startWifWixelThread();\n        } else if(isBTShare(context)) {\n            Log.d(\"DexDrip\", \"Starting bt share collector\");\n            stopBtWixelService();\n            stopWifWixelThread();\n            startBtShareService();\n        }\n        Log.d(\"ColServiceStarter\", collection_method);\n    }\n\n    public CollectionServiceStarter(Context context) {\n        mContext = context;\n    }\n\n    public static void restartCollectionService(Context context) {\n        CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(context);\n        collectionServiceStarter.stopBtShareService();\n        collectionServiceStarter.stopBtWixelService();\n        collectionServiceStarter.stopWifWixelThread();\n        collectionServiceStarter.start(context);\n    }\n\n    private void startBtWixelService() {\n        Log.d(\"ColServiceStarter\", \"starting bt wixel service\");\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            mContext.startService(new Intent(mContext, DexCollectionService.class));\n    \t}\n    }\n    private void stopBtWixelService() {\n        Log.d(\"ColServiceStarter\", \"stopping bt wixel service\");\n        mContext.stopService(new Intent(mContext, DexCollectionService.class));\n    }\n    private void startBtShareService() {\n        Log.d(\"ColServiceStarter\", \"starting bt share service\");\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            mContext.startService(new Intent(mContext, DexShareCollectionService.class));\n        }\n    }\n    private void stopBtShareService() {\n        Log.d(\"ColServiceStarter\", \"stopping bt share service\");\n        mContext.stopService(new Intent(mContext, DexShareCollectionService.class));\n    }\n\n    private void startWifWixelThread() {\n        WixelReader.sStart(mContext);\n    }\n\n    private void stopWifWixelThread() {\n        WixelReader.sStop();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Constants.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\n/**\n * Various constants\n */\npublic class Constants {\n    public static final double MMOLL_TO_MGDL = 18.0182;\n    public static final double MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL;\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/DexShareAttributes.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport java.math.BigInteger;\nimport java.util.UUID;\n\n/**\n * Created by stephenblack on 2/4/15.\n */\npublic class DexShareAttributes {\n    //Share Service String\n    public static final UUID CradleService= UUID.fromString(\"F0ABA0B1-EBFA-F96F-28DA-076C35A521DB\");\n\n    //Share Characteristic Strings\n    public static final UUID AuthenticationCode = UUID.fromString(\"F0ABACAC-EBFA-F96F-28DA-076C35A521DB\");\n    public static final UUID ShareMessageReceiver= UUID.fromString(\"F0ABB20A-EBFA-F96F-28DA-076C35A521DB\"); // Max 20 Bytes - Writable\n    public static final UUID ShareMessageResponse= UUID.fromString(\"F0ABB20B-EBFA-F96F-28DA-076C35A521DB\"); // Max 20 Bytes\n    public static final UUID Command= UUID.fromString(\"F0ABB0CC-EBFA-F96F-28DA-076C35A521DB\");\n    public static final UUID Response= UUID.fromString(\"F0ABB0CD-EBFA-F96F-28DA-076C35A521DB\"); // Writable?\n    public static final UUID HeartBeat= UUID.fromString(\"F0AB2B18-EBFA-F96F-28DA-076C35A521DB\");\n\n    //Possible new uuids????  60bfxxxx-60b0-4d4f-0000-000160c48d70\n    public static final UUID CradleService2= UUID.fromString(\"F0ACA0B1-EBFA-F96F-28DA-076C35A521DB\");\n    public static final UUID AuthenticationCode2 = UUID.fromString(\"F0ACACAC-EBFA-F96F-28DA-076C35A521DB\"); // read, write\n    public static final UUID ShareMessageReceiver2= UUID.fromString(\"F0ACB20A-EBFA-F96F-28DA-076C35A521DB\"); // read, write\n    public static final UUID ShareMessageResponse2= UUID.fromString(\"F0ACB20B-EBFA-F96F-28DA-076C35A521DB\"); // indicate, read\n    public static final UUID Command2= UUID.fromString(\"F0ACB0CC-EBFA-F96F-28DA-076C35A521DB\"); // read, write\n    public static final UUID Response2= UUID.fromString(\"F0ACB0CD-EBFA-F96F-28DA-076C35A521DB\"); // indicate, read, write\n    public static final UUID HeartBeat2= UUID.fromString(\"F0AC2B18-EBFA-F96F-28DA-076C35A521DB\"); // notify, read\n\n    //Device Info\n    public static final UUID DeviceService= UUID.fromString(\"00001804-0000-1000-8000-00805f9b34fb\");\n    public static final UUID PowerLevel= UUID.fromString(\"00002a07-0000-1000-8000-00805f9b34fb\");\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ForegroundServiceStarter.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.app.TaskStackBuilder;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Home;\nimport com.eveningoutpost.dexdrip.R;\nimport com.eveningoutpost.dexdrip.Services.DexShareCollectionService;\n\n/**\n * Created by stephenblack on 12/25/14.\n */\npublic class ForegroundServiceStarter {\n    private Service mService;\n    private Context mContext;\n    private boolean run_service_in_foreground = false;\n    private int FOREGROUND_ID = 8811;\n\n    public ForegroundServiceStarter(Context context, Service service) {\n        mContext = context;\n        mService = service;\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n        run_service_in_foreground = prefs.getBoolean(\"run_service_in_foreground\", false);\n    }\n\n    private Notification notification() {\n        Intent intent = new Intent(mContext, Home.class);\n        TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);\n        stackBuilder.addParentStack(Home.class);\n        stackBuilder.addNextIntent(intent);\n        PendingIntent resultPendingIntent =\n                stackBuilder.getPendingIntent(\n                        0,\n                        PendingIntent.FLAG_UPDATE_CURRENT\n                );\n\n        NotificationCompat.Builder b=new NotificationCompat.Builder(mService);\n        b.setOngoing(true);\n        b.setCategory(Notification.CATEGORY_SERVICE);\n        // Hide this notification \"below the fold\" on L+\n        b.setPriority(Notification.PRIORITY_MIN);\n        // Don't show this notification on the lock screen on L+\n        b.setVisibility(Notification.VISIBILITY_SECRET);\n        b.setContentTitle(\"xDrip is Running\")\n                .setContentText(\"xDrip Data collection service is running.\")\n                .setSmallIcon(R.drawable.ic_action_communication_invert_colors_on);\n        b.setContentIntent(resultPendingIntent);\n        return(b.build());\n    }\n\n    public void start() {\n        if (run_service_in_foreground) {\n            Log.e(\"FOREGROUND\", \"should be moving to foreground\");\n            mService.startForeground(FOREGROUND_ID, notification());\n        }\n    }\n\n    public void stop() {\n        if (run_service_in_foreground) {\n            Log.e(\"FOREGROUND\", \"should be moving out of foreground\");\n            mService.stopForeground(true);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/HM10Attributes.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\n/**\n * Created by stephenblack on 10/26/14.\n */\npublic class HM10Attributes {\n    public static String CLIENT_CHARACTERISTIC_CONFIG = \"00002902-0000-1000-8000-00805f9b34fb\";\n    public static String HM_10_SERVICE = \"0000ffe0-0000-1000-8000-00805f9b34fb\";\n    public static String HM_RX_TX = \"0000ffe1-0000-1000-8000-00805f9b34fb\";\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Intents.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\n/**\n * For integration.\n */\npublic interface Intents {\n    String RECEIVER_PERMISSION = \"com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE\";\n\n    String ACTION_NEW_BG_ESTIMATE = \"com.eveningoutpost.dexdrip.BgEstimate\";\n    String EXTRA_BG_ESTIMATE = \"com.eveningoutpost.dexdrip.Extras.BgEstimate\";\n    String EXTRA_BG_SLOPE = \"com.eveningoutpost.dexdrip.Extras.BgSlope\";\n    String EXTRA_BG_SLOPE_NAME = \"com.eveningoutpost.dexdrip.Extras.BgSlopeName\";\n    String EXTRA_SENSOR_BATTERY = \"com.eveningoutpost.dexdrip.Extras.SensorBattery\";\n    String EXTRA_TIMESTAMP = \"com.eveningoutpost.dexdrip.Extras.Time\";\n\n    String ACTION_NEW_BG_ESTIMATE_NO_DATA = \"com.eveningoutpost.dexdrip.BgEstimateNoData\";\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/MongoSendTask.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.os.AsyncTask;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Services.SyncService;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by stephenblack on 12/19/14.\n */\npublic class MongoSendTask extends AsyncTask<String, Void, SyncService> {\n        private Context context;\n        public List<BgSendQueue> bgsQueue = new ArrayList<BgSendQueue>();\n        public List<CalibrationSendQueue> calibrationsQueue = new ArrayList<CalibrationSendQueue>();\n\n        private Exception exception;\n\n        public MongoSendTask(Context pContext, BgSendQueue bgSendQueue) {\n            bgsQueue.add(bgSendQueue);\n            context = pContext;\n        }\n        public MongoSendTask(Context pContext, CalibrationSendQueue calibrationSendQueue) {\n            calibrationsQueue.add(calibrationSendQueue);\n            context = pContext;\n        }\n        public MongoSendTask(Context pContext) {\n            calibrationsQueue = CalibrationSendQueue.mongoQueue();\n            bgsQueue = BgSendQueue.mongoQueue();\n            context = pContext;\n        }\n\n        public SyncService doInBackground(String... urls) {\n            try {\n                List<BgReading> bgReadings = new ArrayList<BgReading>();\n                List<Calibration> calibrations = new ArrayList<Calibration>();\n                for (CalibrationSendQueue job : calibrationsQueue) {\n                    calibrations.add(job.calibration);\n                }\n                for (BgSendQueue job : bgsQueue) {\n                    bgReadings.add(job.bgReading);\n                }\n\n                if(bgReadings.size() + calibrations.size() > 0) {\n                    NightscoutUploader uploader = new NightscoutUploader(context);\n                    boolean uploadStatus = uploader.upload(bgReadings, calibrations, calibrations);\n                    if (uploadStatus) {\n                        for (CalibrationSendQueue calibration : calibrationsQueue) {\n                            calibration.markMongoSuccess();\n                        }\n                        for (BgSendQueue bgReading : bgsQueue) {\n                            bgReading.markMongoSuccess();\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                this.exception = e;\n                return null;\n            }\n            return new SyncService();\n        }\n\n//        protected void onPostExecute(RSSFeed feed) {\n//            // TODO: check this.exception\n//            // TODO: do something with the feed\n//        }\n    }\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/NightscoutUploader.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.os.BatteryManager;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.mongodb.BasicDBObject;\nimport com.mongodb.DB;\nimport com.mongodb.DBCollection;\nimport com.mongodb.MongoClient;\nimport com.mongodb.MongoClientURI;\nimport com.mongodb.WriteConcern;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.ResponseHandler;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.BasicResponseHandler;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.apache.http.message.BasicHeader;\nimport org.apache.http.params.BasicHttpParams;\nimport org.apache.http.params.HttpConnectionParams;\nimport org.apache.http.params.HttpParams;\nimport org.json.JSONObject;\n\nimport java.security.MessageDigest;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * THIS CLASS WAS BUILT BY THE NIGHTSCOUT GROUP FOR THEIR NIGHTSCOUT ANDROID UPLOADER\n * https://github.com/nightscout/android-uploader/\n * I have modified this class to make it fit my needs\n * Modifications include field remappings and lists instead of arrays\n * A DTO would probably be a better future implementation\n * -Stephen Black\n */\npublic class NightscoutUploader {\n        private static final String TAG = NightscoutUploader.class.getSimpleName();\n        private static final int SOCKET_TIMEOUT = 60000;\n        private static final int CONNECTION_TIMEOUT = 30000;\n        private Context mContext;\n        private Boolean enableRESTUpload;\n        private Boolean enableMongoUpload;\n        private SharedPreferences prefs;\n\n        public NightscoutUploader(Context context) {\n            mContext = context;\n            prefs = PreferenceManager.getDefaultSharedPreferences(mContext);\n            enableRESTUpload = prefs.getBoolean(\"cloud_storage_api_enable\", false);\n            enableMongoUpload = prefs.getBoolean(\"cloud_storage_mongodb_enable\", false);\n        }\n\n        public boolean upload(BgReading glucoseDataSet, Calibration meterRecord, Calibration calRecord) {\n            List<BgReading> glucoseDataSets = new ArrayList<BgReading>();\n            glucoseDataSets.add(glucoseDataSet);\n            List<Calibration> meterRecords = new ArrayList<Calibration>();\n            meterRecords.add(meterRecord);\n            List<Calibration> calRecords = new ArrayList<Calibration>();\n            calRecords.add(calRecord);\n            return upload(glucoseDataSets, meterRecords, calRecords);\n        }\n\n        public boolean upload(List<BgReading> glucoseDataSets, List<Calibration> meterRecords, List<Calibration> calRecords) {\n            boolean mongoStatus = false;\n            boolean apiStatus = false;\n\n            if (enableRESTUpload) {\n                long start = System.currentTimeMillis();\n                Log.i(TAG, String.format(\"Starting upload of %s record using a REST API\", glucoseDataSets.size()));\n                apiStatus = doRESTUpload(prefs, glucoseDataSets, meterRecords, calRecords);\n                Log.i(TAG, String.format(\"Finished upload of %s record using a REST API in %s ms\", glucoseDataSets.size(), System.currentTimeMillis() - start));\n            }\n\n            if (enableMongoUpload) {\n                double start = new Date().getTime();\n                mongoStatus = doMongoUpload(prefs, glucoseDataSets, meterRecords, calRecords);\n                Log.i(TAG, String.format(\"Finished upload of %s record using a Mongo in %s ms\", glucoseDataSets.size() + meterRecords.size(), System.currentTimeMillis() - start));\n            }\n\n                return apiStatus || mongoStatus;\n        }\n\n        private boolean doRESTUpload(SharedPreferences prefs, List<BgReading> glucoseDataSets, List<Calibration> meterRecords, List<Calibration> calRecords) {\n            String baseURLSettings = prefs.getString(\"cloud_storage_api_base\", \"\");\n            ArrayList<String> baseURIs = new ArrayList<String>();\n\n            try {\n                for (String baseURLSetting : baseURLSettings.split(\" \")) {\n                    String baseURL = baseURLSetting.trim();\n                    if (baseURL.isEmpty()) continue;\n                    baseURIs.add(baseURL + (baseURL.endsWith(\"/\") ? \"\" : \"/\"));\n                }\n            } catch (Exception e) {\n                Log.e(TAG, \"Unable to process API Base URL\");\n                return false;\n            }\n\n            for (String baseURI : baseURIs) {\n                try {\n                    doRESTUploadTo(baseURI, glucoseDataSets, meterRecords, calRecords);\n                } catch (Exception e) {\n                    Log.e(TAG, \"Unable to do REST API Upload\");\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        private void doRESTUploadTo(String baseURI, List<BgReading> glucoseDataSets, List<Calibration> meterRecords, List<Calibration> calRecords) {\n            try {\n                int apiVersion = 0;\n                if (baseURI.endsWith(\"/v1/\")) apiVersion = 1;\n\n                String baseURL = null;\n                String secret = null;\n                String[] uriParts = baseURI.split(\"@\");\n\n                if (uriParts.length == 1 && apiVersion == 0) {\n                    baseURL = uriParts[0];\n                } else if (uriParts.length == 1 && apiVersion > 0) {\n                    throw new Exception(\"Starting with API v1, a pass phase is required\");\n                } else if (uriParts.length == 2 && apiVersion > 0) {\n                    secret = uriParts[0];\n                    baseURL = uriParts[1];\n                } else {\n                    throw new Exception(\"Unexpected baseURI\");\n                }\n\n                String postURL = baseURL + \"entries\";\n                Log.i(TAG, \"postURL: \" + postURL);\n\n                HttpParams params = new BasicHttpParams();\n                HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);\n                HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);\n\n                DefaultHttpClient httpclient = new DefaultHttpClient(params);\n\n                HttpPost post = new HttpPost(postURL);\n\n                Header apiSecretHeader = null;\n\n                if (apiVersion > 0) {\n                    if (secret == null || secret.isEmpty()) {\n                        throw new Exception(\"Starting with API v1, a pass phase is required\");\n                    } else {\n                        MessageDigest digest = MessageDigest.getInstance(\"SHA-1\");\n                        byte[] bytes = secret.getBytes(\"UTF-8\");\n                        digest.update(bytes, 0, bytes.length);\n                        bytes = digest.digest();\n                        StringBuilder sb = new StringBuilder(bytes.length * 2);\n                        for (byte b: bytes) {\n                            sb.append(String.format(\"%02x\", b & 0xff));\n                        }\n                        String token = sb.toString();\n                        apiSecretHeader = new BasicHeader(\"api-secret\", token);\n                    }\n                }\n\n                if (apiSecretHeader != null) {\n                    post.setHeader(apiSecretHeader);\n                }\n\n                for (BgReading record : glucoseDataSets) {\n                    JSONObject json = new JSONObject();\n\n                    try {\n                        if (apiVersion >= 1)\n                            populateV1APIBGEntry(json, record);\n                        else\n                            populateLegacyAPIEntry(json, record);\n                    } catch (Exception e) {\n                        Log.w(TAG, \"Unable to populate entry\");\n                        continue;\n                    }\n\n                    String jsonString = json.toString();\n\n                    Log.i(TAG, \"SGV JSON: \" + jsonString);\n\n                    try {\n                        StringEntity se = new StringEntity(jsonString);\n                        post.setEntity(se);\n                        post.setHeader(\"Accept\", \"application/json\");\n                        post.setHeader(\"Content-type\", \"application/json\");\n\n                        ResponseHandler responseHandler = new BasicResponseHandler();\n                        httpclient.execute(post, responseHandler);\n                    } catch (Exception e) {\n                        Log.w(TAG, \"Unable to populate entry\");\n                    }\n                }\n\n                if (apiVersion >= 1) {\n                    for (Calibration record : meterRecords) {\n                        JSONObject json = new JSONObject();\n\n                        try {\n                            populateV1APIMeterReadingEntry(json, record);\n                        } catch (Exception e) {\n                            Log.w(TAG, \"Unable to populate entry\");\n                            continue;\n                        }\n\n                        String jsonString = json.toString();\n                        Log.i(TAG, \"MBG JSON: \" + jsonString);\n\n                        try {\n                            StringEntity se = new StringEntity(jsonString);\n                            post.setEntity(se);\n                            post.setHeader(\"Accept\", \"application/json\");\n                            post.setHeader(\"Content-type\", \"application/json\");\n\n                            ResponseHandler responseHandler = new BasicResponseHandler();\n                            httpclient.execute(post, responseHandler);\n                        } catch (Exception e) {\n                            Log.w(TAG, \"Unable to post data\");\n                        }\n                    }\n                }\n\n                if (apiVersion >= 1) {\n                    for (Calibration calRecord : calRecords) {\n\n                        JSONObject json = new JSONObject();\n\n                        try {\n                            populateV1APICalibrationEntry(json, calRecord);\n                        } catch (Exception e) {\n                            Log.w(TAG, \"Unable to populate entry\");\n                            continue;\n                        }\n\n                        String jsonString = json.toString();\n                        Log.i(TAG, \"CAL JSON: \" + jsonString);\n\n                        try {\n                            StringEntity se = new StringEntity(jsonString);\n                            post.setEntity(se);\n                            post.setHeader(\"Accept\", \"application/json\");\n                            post.setHeader(\"Content-type\", \"application/json\");\n\n                            ResponseHandler responseHandler = new BasicResponseHandler();\n                            httpclient.execute(post, responseHandler);\n                        } catch (Exception e) {\n                            Log.w(TAG, \"Unable to post data\");\n                        }\n                    }\n                }\n\n                // TODO: this is a quick port from the original code and needs to be checked before release\n                postDeviceStatus(baseURL, apiSecretHeader, httpclient);\n\n            } catch (Exception e) {\n                Log.w(TAG, \"Unable to post data\");\n            }\n        }\n\n        private void populateV1APIBGEntry(JSONObject json, BgReading record) throws Exception {\n            SimpleDateFormat format = new SimpleDateFormat(\"MM/dd/yyyy HH:mm:ss a\");\n            format.setTimeZone(TimeZone.getDefault());\n            json.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n            json.put(\"date\", record.timestamp);\n            json.put(\"dateString\", format.format(record.timestamp));\n            json.put(\"sgv\", (int)record.calculated_value);\n            json.put(\"direction\", record.slopeName());\n            json.put(\"type\", \"sgv\");\n            json.put(\"filtered\", record.filtered_data * 1000);\n            json.put(\"unfiltered\", record.age_adjusted_raw_value * 1000);\n            json.put(\"rssi\", 100);\n            json.put(\"noise\", Integer.valueOf(record.noiseValue()));\n        }\n\n        private void populateLegacyAPIEntry(JSONObject json, BgReading record) throws Exception {\n            SimpleDateFormat format = new SimpleDateFormat(\"MM/dd/yyyy HH:mm:ss a\");\n            format.setTimeZone(TimeZone.getDefault());\n            json.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n            json.put(\"date\", record.timestamp);\n            json.put(\"dateString\", format.format(record.timestamp));\n            json.put(\"sgv\", (int)record.calculated_value);\n            json.put(\"direction\", record.slopeName());\n        }\n\n        private void populateV1APIMeterReadingEntry(JSONObject json, Calibration record) throws Exception {\n            SimpleDateFormat format = new SimpleDateFormat(\"MM/dd/yyyy HH:mm:ss a\");\n            format.setTimeZone(TimeZone.getDefault());\n            json.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n            json.put(\"type\", \"mbg\");\n            json.put(\"date\", record.timestamp);\n            json.put(\"dateString\", format.format(record.timestamp));\n            json.put(\"mbg\", record.bg);\n        }\n\n        private void populateV1APICalibrationEntry(JSONObject json, Calibration record) throws Exception {\n            SimpleDateFormat format = new SimpleDateFormat(\"MM/dd/yyyy HH:mm:ss a\");\n            format.setTimeZone(TimeZone.getDefault());\n            json.put(\"device\", \"xDrip-\" + prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n            json.put(\"type\", \"cal\");\n            json.put(\"date\", record.timestamp);\n            json.put(\"dateString\", format.format(record.timestamp));\n            if(record.check_in) {\n                json.put(\"slope\", (long) (record.first_slope));\n                json.put(\"intercept\", (long) ((record.first_intercept)));\n                json.put(\"scale\", record.first_scale);\n            } else {\n                json.put(\"slope\", (long) (record.slope * 1000));\n                json.put(\"intercept\", (long) ((record.intercept * -1000) / (record.slope * 1000)));\n                json.put(\"scale\", 1);\n            }\n        }\n\n        // TODO: this is a quick port from original code and needs to be refactored before release\n        private void postDeviceStatus(String baseURL, Header apiSecretHeader, DefaultHttpClient httpclient) throws Exception {\n            String devicestatusURL = baseURL + \"devicestatus\";\n            Log.i(TAG, \"devicestatusURL: \" + devicestatusURL);\n\n            JSONObject json = new JSONObject();\n            json.put(\"uploaderBattery\", getBatteryLevel());\n            String jsonString = json.toString();\n\n            HttpPost post = new HttpPost(devicestatusURL);\n\n            if (apiSecretHeader != null) {\n                post.setHeader(apiSecretHeader);\n            }\n\n            StringEntity se = new StringEntity(jsonString);\n            post.setEntity(se);\n            post.setHeader(\"Accept\", \"application/json\");\n            post.setHeader(\"Content-type\", \"application/json\");\n\n            ResponseHandler responseHandler = new BasicResponseHandler();\n            httpclient.execute(post, responseHandler);\n        }\n\n        private boolean doMongoUpload(SharedPreferences prefs, List<BgReading> glucoseDataSets,\n                                      List<Calibration> meterRecords,  List<Calibration> calRecords) {\n            SimpleDateFormat format = new SimpleDateFormat(\"MM/dd/yyyy HH:mm:ss a\");\n            format.setTimeZone(TimeZone.getDefault());\n\n            String dbURI = prefs.getString(\"cloud_storage_mongodb_uri\", null);\n            String collectionName = prefs.getString(\"cloud_storage_mongodb_collection\", null);\n            String dsCollectionName = prefs.getString(\"cloud_storage_mongodb_device_status_collection\", \"devicestatus\");\n\n            if (dbURI != null && collectionName != null) {\n                try {\n\n                    // connect to db\n                    MongoClientURI uri = new MongoClientURI(dbURI.trim());\n                    MongoClient client = new MongoClient(uri);\n\n                    // get db\n                    DB db = client.getDB(uri.getDatabase());\n\n                    // get collection\n                    DBCollection dexcomData = db.getCollection(collectionName.trim());\n                    Log.i(TAG, \"The number of EGV records being sent to MongoDB is \" + glucoseDataSets.size());\n                    for (BgReading record : glucoseDataSets) {\n                        // make db object\n                        BasicDBObject testData = new BasicDBObject();\n                        testData.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n                        testData.put(\"date\", record.timestamp);\n                        testData.put(\"dateString\", format.format(record.timestamp));\n                        testData.put(\"sgv\", Math.round(record.calculated_value));\n                        testData.put(\"direction\", record.slopeName());\n                        testData.put(\"type\", \"sgv\");\n                        testData.put(\"filtered\", record.filtered_data * 1000);\n                        testData.put(\"unfiltered\", record.age_adjusted_raw_value * 1000 );\n                        testData.put(\"rssi\", 100);\n                        testData.put(\"noise\", Integer.valueOf(record.noiseValue()));\n                        dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);\n                    }\n\n                    Log.i(TAG, \"The number of MBG records being sent to MongoDB is \" + meterRecords.size());\n                    for (Calibration meterRecord : meterRecords) {\n                        // make db object\n                        BasicDBObject testData = new BasicDBObject();\n                        testData.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n                        testData.put(\"type\", \"mbg\");\n                        testData.put(\"date\", meterRecord.timestamp);\n                        testData.put(\"dateString\", format.format(meterRecord.timestamp));\n                        testData.put(\"mbg\", meterRecord.bg);\n                        dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);\n                    }\n\n                    for (Calibration calRecord : calRecords) {\n                        // make db object\n                        BasicDBObject testData = new BasicDBObject();\n                        testData.put(\"device\", \"xDrip-\"+prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n                        testData.put(\"date\", calRecord.timestamp);\n                        testData.put(\"dateString\", format.format(calRecord.timestamp));\n                        if(calRecord.check_in) {\n                            testData.put(\"slope\", (long) (calRecord.first_slope));\n                            testData.put(\"intercept\", (long) ((calRecord.first_intercept)));\n                            testData.put(\"scale\", calRecord.first_scale);\n                        } else {\n                            testData.put(\"slope\", (long) (calRecord.slope * 1000));\n                            testData.put(\"intercept\", (long) ((calRecord.intercept * -1000) / (calRecord.slope * 1000)));\n                            testData.put(\"scale\", 1);\n                        }\n                        testData.put(\"type\", \"cal\");\n                        dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);\n                    }\n\n                    // TODO: quick port from original code, revisit before release\n                    DBCollection dsCollection = db.getCollection(dsCollectionName);\n                    BasicDBObject devicestatus = new BasicDBObject();\n                    devicestatus.put(\"uploaderBattery\", getBatteryLevel());\n                    devicestatus.put(\"created_at\", new Date());\n                    dsCollection.insert(devicestatus, WriteConcern.UNACKNOWLEDGED);\n\n                    client.close();\n\n                    return true;\n\n                } catch (Exception e) {\n                    Log.e(TAG, \"Unable to upload data to mongo\");\n                }\n            }\n            return false;\n        }\n    public int getBatteryLevel() {\n        Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n        int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n        int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);\n        if(level == -1 || scale == -1) {\n            return 50;\n        }\n        return (int)(((float)level / (float)scale) * 100.0f);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Notifications.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.media.AudioAttributes;\nimport android.media.AudioManager;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\nimport android.preference.PreferenceManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.AddCalibration;\nimport com.eveningoutpost.dexdrip.DoubleCalibrationActivity;\nimport com.eveningoutpost.dexdrip.Home;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Models.CalibrationRequest;\nimport com.eveningoutpost.dexdrip.Models.UserNotification;\nimport com.eveningoutpost.dexdrip.R;\nimport com.eveningoutpost.dexdrip.Sensor;\n\nimport java.text.DecimalFormat;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * Created by stephenblack on 11/28/14.\n */\npublic class Notifications {\n    public static final long[] vibratePattern = {0,1000,300,1000,300,1000};\n    public static boolean bg_notifications;\n    public static boolean bg_vibrate;\n    public static boolean bg_lights;\n    public static boolean bg_sound;\n    public static boolean bg_sound_in_silent;\n    public static int bg_snooze;\n    public static String bg_notification_sound;\n\n    public static boolean calibration_notifications;\n    public static boolean calibration_vibrate;\n    public static boolean calibration_lights;\n    public static boolean calibration_sound;\n    public static int calibration_snooze;\n    public static String calibration_notification_sound;\n\n    public static Context mContext;\n    public static int currentVolume;\n    public static AudioManager manager;\n\n    public static final int BgNotificationId = 001;\n    public static final int calibrationNotificationId = 002;\n    public static final int doubleCalibrationNotificationId = 003;\n    public static final int extraCalibrationNotificationId = 004;\n    public static final int exportCompleteNotificationId = 005;\n\n    public static void setNotificationSettings(Context context) {\n        mContext = context;\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        bg_notifications = prefs.getBoolean(\"bg_notifications\", true);\n        bg_vibrate = prefs.getBoolean(\"bg_vibrate\", true);\n        bg_lights = prefs.getBoolean(\"bg_lights\", true);\n        bg_sound = prefs.getBoolean(\"bg_play_sound\", true);\n        bg_snooze = Integer.parseInt(prefs.getString(\"bg_snooze\", \"20\"));\n        bg_notification_sound = prefs.getString(\"bg_notification_sound\", \"content://settings/system/notification_sound\");\n        bg_sound_in_silent = prefs.getBoolean(\"bg_sound_in_silent\", false);\n\n        calibration_notifications = prefs.getBoolean(\"calibration_notifications\", true);\n        calibration_vibrate = prefs.getBoolean(\"calibration_vibrate\", true);\n        calibration_lights = prefs.getBoolean(\"calibration_lights\", true);\n        calibration_sound = prefs.getBoolean(\"calibration_play_sound\", true);\n        calibration_snooze = Integer.parseInt(prefs.getString(\"calibration_snooze\", \"20\"));\n        calibration_notification_sound = prefs.getString(\"calibration_notification_sound\", \"content://settings/system/notification_sound\");\n    }\n\n    public static void notificationSetter(Context context) {\n        setNotificationSettings(context);\n        BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(context);\n        double high = bgGraphBuilder.highMark;\n        double low = bgGraphBuilder.lowMark;\n        Sensor sensor = Sensor.currentSensor();\n\n        List<BgReading> bgReadings = BgReading.latest(3);\n        List<Calibration> calibrations = Calibration.allForSensorInLastFourDays();\n        if(bgReadings.size() < 3) { return; }\n        if(calibrations.size() < 2) { return; }\n        BgReading bgReading = bgReadings.get(0);\n\n        if (bg_notifications && sensor != null) {\n            if (bgGraphBuilder.unitized(bgReading.calculated_value) >= high || bgGraphBuilder.unitized(bgReading.calculated_value) <= low) {\n                if(bgReading.calculated_value > 14) {\n                    if (bgReading.hide_slope) {\n                        bgAlert(bgReading.displayValue(mContext), \"\");\n                    } else {\n                        bgAlert(bgReading.displayValue(mContext), bgReading.slopeArrow());\n                    }\n                }\n            } else {\n                clearBgAlert();\n            }\n        } else {\n            clearAllBgNotifications();\n        }\n\n        if (calibration_notifications) {\n            if (bgReadings.size() >= 3) {\n                if (calibrations.size() == 0 && (new Date().getTime() - bgReadings.get(2).timestamp <= (60000 * 30)) && sensor != null) {\n                    if ((sensor.started_at + (60000 * 60 * 2)) < new Date().getTime()) {\n                        doubleCalibrationRequest();\n                    } else { clearDoubleCalibrationRequest(); }\n                } else { clearDoubleCalibrationRequest(); }\n            } else { clearDoubleCalibrationRequest(); }\n\n            if (CalibrationRequest.shouldRequestCalibration(bgReading) && (new Date().getTime() - bgReadings.get(2).timestamp <= (60000 * 24))) {\n                extraCalibrationRequest();\n            } else { clearExtraCalibrationRequest(); }\n\n            if (calibrations.size() >= 1 && Math.abs((new Date().getTime() - calibrations.get(0).timestamp))/(1000*60*60) > 12) {\n                Log.e(\"NOTIFICATIONS\", \"Calibration difference in hours: \" + ((new Date().getTime() - calibrations.get(0).timestamp))/(1000*60*60));\n\n                calibrationRequest();\n            } else { clearCalibrationRequest(); }\n\n        } else {\n            clearAllCalibrationNotifications();\n        }\n    }\n\n    public static void soundAlert(String soundUri) {\n        manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);\n        int maxVolume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);\n        currentVolume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);\n        manager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);\n        Uri notification = Uri.parse(bg_notification_sound);\n        MediaPlayer player = MediaPlayer.create(mContext, notification);\n\n        player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {\n            @Override\n            public void onCompletion(MediaPlayer mp) {\n                manager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);\n            }\n        });\n        player.start();\n    }\n\n    public static void clearAllBgNotifications() {\n        notificationDismiss(BgNotificationId);\n    }\n    public static void clearAllCalibrationNotifications() {\n        notificationDismiss(calibrationNotificationId);\n        notificationDismiss(extraCalibrationNotificationId);\n        notificationDismiss(doubleCalibrationNotificationId);\n    }\n\n\n    public static void bgNotificationCreate(String title, String content, Intent intent, int notificationId) {\n        NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);\n        if (bg_vibrate) { mBuilder.setVibrate(vibratePattern);}\n        if (bg_lights) { mBuilder.setLights(0xff00ff00, 300, 1000);}\n        if (bg_sound && !bg_sound_in_silent) { mBuilder.setSound(Uri.parse(bg_notification_sound), AudioAttributes.FLAG_AUDIBILITY_ENFORCED);}\n        if (bg_sound && bg_sound_in_silent) { soundAlert(bg_notification_sound);}\n        NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);\n        mNotifyMgr.cancel(notificationId);\n        mNotifyMgr.notify(notificationId, mBuilder.build());\n    }\n\n    public static void calibrationNotificationCreate(String title, String content, Intent intent, int notificationId) {\n        NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);\n        if (calibration_vibrate) { mBuilder.setVibrate(vibratePattern);}\n        if (calibration_lights) { mBuilder.setLights(0xff00ff00, 300, 1000);}\n        if (calibration_sound) { mBuilder.setSound(Uri.parse(calibration_notification_sound), AudioAttributes.FLAG_AUDIBILITY_ENFORCED);}\n        NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);\n        mNotifyMgr.cancel(notificationId);\n        mNotifyMgr.notify(notificationId, mBuilder.build());\n    }\n\n    public static void notificationUpdate(String title, String content, Intent intent, int notificationId) {\n        NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);\n        NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);\n        mNotifyMgr.notify(notificationId, mBuilder.build());\n    }\n\n    public static NotificationCompat.Builder notificationBuilder(String title, String content, Intent intent) {\n        return new NotificationCompat.Builder(mContext)\n                .setSmallIcon(R.drawable.ic_action_communication_invert_colors_on)\n                .setContentTitle(title)\n                .setContentText(content)\n                .setContentIntent(notificationIntent(intent));\n    }\n    public static PendingIntent notificationIntent(Intent intent){\n        return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);\n\n    }\n\n    public static void notificationDismiss(int notificationId) {\n        NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);\n        mNotifyMgr.cancel(notificationId);\n    }\n\n    public static void bgAlert(String value, String slopeArrow) {\n        UserNotification userNotification = UserNotification.lastBgAlert();\n\n        if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * bg_snooze)))) {\n            if (userNotification != null) { userNotification.delete(); }\n            UserNotification newUserNotification = UserNotification.create(value + \" \" + slopeArrow, \"bg_alert\");\n            String title = value + \" \" + slopeArrow;\n            String content = \"BG LEVEL ALERT: \" + value + \" \" + slopeArrow;\n            Intent intent = new Intent(mContext, Home.class);\n            bgNotificationCreate(title, content, intent, BgNotificationId);\n\n        } else if ((userNotification != null) && (userNotification.timestamp >= ((new Date().getTime()) - (60000 * bg_snooze))))  {\n            String title = value + \" \" + slopeArrow;\n            String content = \"BG LEVEL ALERT: \" + value + \" \" + slopeArrow;\n            Intent intent = new Intent(mContext, Home.class);\n            notificationUpdate(title, content, intent, BgNotificationId);\n        }\n    }\n\n    public static void calibrationRequest() {\n        UserNotification userNotification = UserNotification.lastCalibrationAlert();\n        if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {\n            if (userNotification != null) { userNotification.delete(); }\n            UserNotification newUserNotification = UserNotification.create(\"12 hours since last Calibration\", \"calibration_alert\");\n            String title = \"Calibration Needed\";\n            String content = \"12 hours since last calibration\";\n            Intent intent = new Intent(mContext, AddCalibration.class);\n            calibrationNotificationCreate(title, content, intent, calibrationNotificationId);\n        }\n    }\n    public static void doubleCalibrationRequest() {\n        UserNotification userNotification = UserNotification.lastDoubleCalibrationAlert();\n        if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {\n            if (userNotification != null) { userNotification.delete(); }\n            UserNotification newUserNotification = UserNotification.create(\"Double Calibration\", \"double_calibration_alert\");\n            String title = \"Sensor is ready\";\n            String content = \"Sensor is ready, please enter a double calibration\";\n            Intent intent = new Intent(mContext, DoubleCalibrationActivity.class);\n            calibrationNotificationCreate(title, content, intent, calibrationNotificationId);\n        }\n    }\n\n    public static void extraCalibrationRequest() {\n        UserNotification userNotification = UserNotification.lastExtraCalibrationAlert();\n        if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {\n            if (userNotification != null) { userNotification.delete(); }\n            UserNotification newUserNotification = UserNotification.create(\"Extra Calibration Requested\", \"extra_calibration_alert\");\n            String title = \"Calibration Needed\";\n            String content = \"A calibration entered now will GREATLY increase performance\";\n            Intent intent = new Intent(mContext, AddCalibration.class);\n            calibrationNotificationCreate(title, content, intent, extraCalibrationNotificationId);\n        }\n    }\n\n    public static void clearCalibrationRequest() {\n        UserNotification userNotification = UserNotification.lastCalibrationAlert();\n        if (userNotification != null) {\n            userNotification.delete();\n            notificationDismiss(calibrationNotificationId);\n        }\n    }\n\n    public static void clearDoubleCalibrationRequest() {\n        UserNotification userNotification = UserNotification.lastDoubleCalibrationAlert();\n        if (userNotification != null) {\n            userNotification.delete();\n            notificationDismiss(doubleCalibrationNotificationId);\n        }\n    }\n\n    public static void clearExtraCalibrationRequest() {\n        UserNotification userNotification = UserNotification.lastExtraCalibrationAlert();\n        if (userNotification != null) {\n            userNotification.delete();\n            notificationDismiss(extraCalibrationNotificationId);\n        }\n    }\n\n    public static void clearBgAlert() {\n        UserNotification userNotification = UserNotification.lastBgAlert();\n        if (userNotification != null) {\n            userNotification.delete();\n            notificationDismiss(BgNotificationId);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/PebbleSync.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.BatteryManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.getpebble.android.kit.PebbleKit;\nimport com.getpebble.android.kit.util.PebbleDictionary;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * Created by THE NIGHTSCOUT PROJECT CONTRIBUTORS (and adapted to fit the needs of this project)\n */\npublic class PebbleSync {\n    //    CGM_ICON_KEY = 0x0,\t\t// TUPLE_CSTRING, MAX 2 BYTES (10)\n    //    CGM_BG_KEY = 0x1,\t\t// TUPLE_CSTRING, MAX 4 BYTES (253 OR 22.2)\n    //    CGM_TCGM_KEY = 0x2,\t\t// TUPLE_INT, 4 BYTES (CGM TIME)\n    //    CGM_TAPP_KEY = 0x3,\t\t// TUPLE_INT, 4 BYTES (APP / PHONE TIME)\n    //    CGM_DLTA_KEY = 0x4,\t\t// TUPLE_CSTRING, MAX 5 BYTES (BG DELTA, -100 or -10.0)\n    //    CGM_UBAT_KEY = 0x5,\t\t// TUPLE_CSTRING, MAX 3 BYTES (UPLOADER BATTERY, 100)\n    //    CGM_NAME_KEY = 0x6\t\t// TUPLE_CSTRING, MAX 9 BYTES (xDrip)\n    public static final UUID PEBBLEAPP_UUID = UUID.fromString(\"2c3f5ab3-7506-44e7-b8d0-2c63de32e1ec\");\n    public static final int ICON_KEY = 0;\n    public static final int BG_KEY = 1;\n    public static final int RECORD_TIME_KEY = 2;\n    public static final int PHONE_TIME_KEY = 3;\n    public static final int BG_DELTA_KEY = 4;\n    public static final int UPLOADER_BATTERY_KEY = 5;\n    public static final int NAME_KEY = 6;\n\n    private Context mContext;\n    private BgGraphBuilder bgGraphBuilder;\n    private BgReading mBgReading;\n\n    public PebbleDictionary buildDictionary() {\n        PebbleDictionary dictionary = new PebbleDictionary();\n        dictionary.addString(ICON_KEY, slopeOrdinal());\n        dictionary.addString(BG_KEY, bgReading());\n        dictionary.addUint32(RECORD_TIME_KEY, (int) (mBgReading.timestamp / 1000));\n        dictionary.addUint32(PHONE_TIME_KEY, (int) (new Date().getTime() / 1000));\n        dictionary.addString(BG_DELTA_KEY, bgDelta());\n        dictionary.addString(UPLOADER_BATTERY_KEY, phoneBattery());\n        dictionary.addString(NAME_KEY, \"xDrip\");\n        return dictionary;\n    }\n\n    public void sendData(Context context, BgReading bgReading){\n        mContext = context;\n        bgGraphBuilder = new BgGraphBuilder(mContext);\n        mBgReading = BgReading.last();\n        sendDownload(buildDictionary());\n    }\n\n    public String bgReading() {\n        return bgGraphBuilder.unitized_string(mBgReading.calculated_value);\n    }\n\n    public String bgDelta() {\n        String deltaString = bgGraphBuilder.unitized_string((int)(mBgReading.calculated_value_slope * (5 * 60 * 1000)));\n        if(mBgReading.calculated_value_slope > 0.1) {\n            return (\"+\"+deltaString);\n        } else if(mBgReading.calculated_value_slope > -0.1 && mBgReading.calculated_value_slope < 0.1) {\n            return \"0\";\n        } else {\n            return deltaString;\n        }\n    }\n\n    public String phoneBattery() {\n        return String.valueOf(getBatteryLevel());\n    }\n\n    public String bgUnit() {\n        return bgGraphBuilder.unit();\n    }\n\n    public void sendDownload(PebbleDictionary dictionary) {\n        if (PebbleKit.isWatchConnected(mContext)) {\n            if (dictionary != null && mContext != null) {\n                Log.d(\"PEBBLE PUSHER\", \"Sending data to pebble\");\n                PebbleKit.sendDataToPebble(mContext, PEBBLEAPP_UUID, dictionary);\n            }\n        }\n    }\n\n    public int getBatteryLevel() {\n        Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n        int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n        int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);\n        if(level == -1 || scale == -1) {\n            return 50;\n        }\n        return (int)(((float)level / (float)scale) * 100.0f);\n    }\n\n    public String slopeOrdinal(){\n        double slope_by_minute = mBgReading.calculated_value_slope * 60000;\n        String arrow = \"0\";\n        if (slope_by_minute <= (-3.5)) {\n            arrow = \"7\";\n        } else if (slope_by_minute <= (-2)) {\n            arrow = \"6\";\n        } else if (slope_by_minute <= (-1)) {\n            arrow = \"5\";\n        } else if (slope_by_minute <= (1)) {\n            arrow = \"4\";\n        } else if (slope_by_minute <= (2)) {\n            arrow = \"3\";\n        } else if (slope_by_minute <= (3.5)) {\n            arrow = \"2\";\n        } else {\n            arrow = \"1\";\n        }\n        if(mBgReading.hide_slope) {\n            arrow = \"9\";\n        }\n        return arrow;\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/RedBearLabAttributes.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport java.util.UUID;\n\n/**\n * Created by stephenblack on 2/21/15.\n */\npublic class RedBearLabAttributes {\n    public static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString(\"00002902-0000-1000-8000-00805f9b34fb\");\n    public static UUID REDBEARLAB_SERVICE =  UUID.fromString(\"0000ffe0-0000-1000-8000-00805f9b34fb\");\n    public static UUID REDBEARLAB_TX =  UUID.fromString(\"713d0002-503e-4c75-ba94-3148f18d941e\");\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/RestCalls.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.Interfaces.BgReadingInterface;\nimport com.eveningoutpost.dexdrip.Interfaces.CalibrationInterface;\nimport com.eveningoutpost.dexdrip.Interfaces.SensorInterface;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Models.Calibration;\nimport com.eveningoutpost.dexdrip.Sensor;\nimport com.eveningoutpost.dexdrip.Models.User;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.internal.bind.DateTypeAdapter;\n\nimport java.util.Date;\n\nimport retrofit.Callback;\nimport retrofit.RequestInterceptor;\nimport retrofit.RestAdapter;\nimport retrofit.RetrofitError;\nimport retrofit.client.Response;\nimport retrofit.converter.GsonConverter;\n\n/**\n * Created by stephenblack on 11/6/14.\n */\npublic class RestCalls {\n    private static final String baseUrl = \"http://10.0.2.2:3000\";\n\n\n    public static Gson gson = new GsonBuilder()\n            .excludeFieldsWithoutExposeAnnotation()\n            .registerTypeAdapter(Date.class, new DateTypeAdapter())\n            .create();\n\n\n\n    public static void sendBgReading(final BgSendQueue bgSendQueue) {\n        User user = User.currentUser();\n        bgReadingInterface().createReading(user.uuid, bgSendQueue.bgReading, new Callback<Gson>() {\n                    @Override\n                    public void success(Gson gsonResponse, Response response) {\n                        bgSendQueue.success = true;\n                        bgSendQueue.save();\n                        BgReading bgReading = bgSendQueue.bgReading;\n                        bgReading.synced = true;\n                        bgReading.save();\n                    }\n                    @Override\n                    public void failure(RetrofitError error) {\n                        Response response = error.getResponse();\n                        Log.w(\"REST CALL ERROR:\", \"****************\");\n                        Log.w(\"REST CALL STATUS:\", \"\" + response.getStatus());\n                        Log.w(\"REST CALL REASON:\", response.getReason());\n                    }\n                }\n        );\n    }\n\n\n    public static void updateBgReading(final BgSendQueue bgSendQueue) {\n        User user = User.currentUser();\n        bgReadingInterface().updateReading(user.uuid, bgSendQueue.bgReading.uuid, bgSendQueue.bgReading, new Callback<Gson>() {\n                    @Override\n                    public void success(Gson gsonResponse, Response response) {\n                        Log.w(\"REST CALL Update Success!:\", \"****************\");\n                        bgSendQueue.success = true;\n                        bgSendQueue.save();\n                    }\n                    @Override\n                    public void failure(RetrofitError error) {\n                        Response response = error.getResponse();\n                        Log.w(\"REST CALL ERROR:\", \"****************\");\n                        Log.w(\"REST CALL STATUS:\", \"\" + response.getStatus());\n                        Log.w(\"REST CALL REASON:\", response.getReason());\n                    }\n                }\n        );\n    }\n\n\n    public static void sendCalibration(final CalibrationSendQueue calibrationSendQueue) {\n        User user = User.currentUser();\n        calibrationInterface().createCalibration(user.uuid, calibrationSendQueue.calibration, new Callback<Gson>() {\n                    @Override\n                    public void success(Gson gsonResponse, Response response) {\n                        calibrationSendQueue.success = true;\n                        calibrationSendQueue.save();\n                        Calibration calibration = calibrationSendQueue.calibration;\n                        calibration.save();\n                    }\n                    @Override\n                    public void failure(RetrofitError error) {\n                        Response response = error.getResponse();\n                        Log.w(\"REST CALL ERROR:\", \"****************\");\n                        Log.w(\"REST CALL STATUS:\", \"\" + response.getStatus());\n                        Log.w(\"REST CALL REASON:\", response.getReason());\n                    }\n                }\n        );\n    }\n\n\n    public static void sendSensor(final SensorSendQueue sensorSendQueue) {\n        User user = User.currentUser();\n        sensorInterface().createSensor(user.uuid, sensorSendQueue.sensor, new Callback<Gson>() {\n                    @Override\n                    public void success(Gson gsonResponse, Response response) {\n                        sensorSendQueue.success = true;\n                        sensorSendQueue.save();\n                        Sensor sensor = sensorSendQueue.sensor;\n                        sensor.save();\n                    }\n                    @Override\n                    public void failure(RetrofitError error) {\n                        Response response = error.getResponse();\n                        Log.w(\"REST CALL ERROR:\", \"****************\");\n                        Log.w(\"REST CALL STATUS:\", \"\" + response.getStatus());\n                        Log.w(\"REST CALL REASON:\", response.getReason());\n                    }\n                }\n        );\n    }\n\n    public static BgReadingInterface bgReadingInterface() {\n        RestAdapter adapter = adapterBuilder().build();\n            BgReadingInterface bgReadingInterface =\n                adapter.create(BgReadingInterface.class);\n        return bgReadingInterface;\n    }\n\n    public static SensorInterface sensorInterface() {\n\n        RestAdapter adapter = adapterBuilder().build();\n        SensorInterface sensorInterface =\n                adapter.create(SensorInterface.class);\n        return sensorInterface;\n    }\n\n    public static CalibrationInterface calibrationInterface() {\n        RestAdapter adapter = adapterBuilder().build();\n        CalibrationInterface calibrationInterface =\n                adapter.create(CalibrationInterface.class);\n        return calibrationInterface;\n    }\n\n    public static RestAdapter.Builder adapterBuilder() {\n        RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();\n        adapterBuilder\n                .setEndpoint(baseUrl)\n                .setConverter(new GsonConverter(gson))\n                .setRequestInterceptor(requestInterceptor());\n        return adapterBuilder;\n    }\n\n    public static RequestInterceptor requestInterceptor(){\n        RequestInterceptor requestInterceptor = new RequestInterceptor() {\n            User currentUser = User.currentUser();\n            @Override\n            public void intercept(RequestFacade request) {\n                request.addHeader(\"email\", currentUser.email);\n                request.addHeader(\"token\", currentUser.token);\n            }\n        };\n        return requestInterceptor;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/SensorSendQueue.java",
    "content": "package com.eveningoutpost.dexdrip.UtilityModels;\n\nimport android.provider.BaseColumns;\n\nimport com.activeandroid.Model;\nimport com.activeandroid.annotation.Column;\nimport com.activeandroid.annotation.Table;\nimport com.activeandroid.query.Select;\nimport com.eveningoutpost.dexdrip.Sensor;\n\nimport java.util.List;\n\n/**\n * Created by stephenblack on 11/7/14.\n */\n@Table(name = \"SensorSendQueue\", id = BaseColumns._ID)\npublic class SensorSendQueue extends Model {\n\n    @Column(name = \"Sensor\", index = true)\n    public Sensor sensor;\n\n    @Column(name = \"success\", index = true)\n    public boolean success;\n\n\n    public static SensorSendQueue nextSensorJob() {\n        SensorSendQueue job = new Select()\n                .from(SensorSendQueue.class)\n                .where(\"success =\", false)\n                .orderBy(\"_ID desc\")\n                .limit(1)\n                .executeSingle();\n        return job;\n    }\n\n    public static List<SensorSendQueue> queue() {\n        return new Select()\n                .from(SensorSendQueue.class)\n                .where(\"success = ?\", false)\n                .orderBy(\"_ID desc\")\n                .execute();\n    }\n\n    public static void addToQueue(Sensor sensor) {\n        SensorSendQueue sensorSendQueue = new SensorSendQueue();\n        sensorSendQueue.sensor = sensor;\n        sensorSendQueue.success = false;\n        sensorSendQueue.save();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/utils/DatabaseUtil.java",
    "content": "package com.eveningoutpost.dexdrip.utils;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.text.format.DateFormat;\n\nimport com.activeandroid.Configuration;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.nio.channels.FileChannel;\n\nimport static com.eveningoutpost.dexdrip.utils.FileUtils.*;\n\n/**\n * Save the SQL database to file.\n */\npublic class DatabaseUtil {\n\n    public static String saveSql(Context context) {\n        try {\n\n            final String databaseName = new Configuration.Builder(context).create().getDatabaseName();\n\n            final String dir = getExternalDir();\n            makeSureDirectoryExists(dir);\n\n            final StringBuilder sb = new StringBuilder();\n            sb.append(dir);\n            sb.append(\"/export\");\n            sb.append(DateFormat.format(\"yyyyMMdd-kkmmss\", System.currentTimeMillis()));\n            sb.append(\".sqlite\");\n\n            final String filename = sb.toString();\n            final File sd = Environment.getExternalStorageDirectory();\n            if (sd.canWrite()) {\n                final File currentDB = context.getDatabasePath(databaseName);\n                final File backupDB = new File(filename);\n                if (currentDB.exists()) {\n                    final FileInputStream srcStream = new FileInputStream(currentDB);\n                    final FileChannel src = srcStream.getChannel();\n                    final FileOutputStream destStream = new FileOutputStream(backupDB);\n                    final FileChannel dst = destStream.getChannel();\n                    dst.transferFrom(src, 0, src.size());\n                    src.close();\n                    srcStream.close();\n                    dst.close();\n                    destStream.close();\n                }\n            }\n\n            return filename;\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void loadSql(Context context, Uri uri) {\n        try {\n            final String databaseName = new Configuration.Builder(context).create().getDatabaseName();\n\n            final File currentDB = context.getDatabasePath(databaseName);\n            final File replacement = new File(uri.getPath());\n            if (currentDB.canWrite()) {\n                final FileInputStream srcStream = new FileInputStream(replacement);\n                final FileChannel src = srcStream.getChannel();\n                final FileOutputStream destStream = new FileOutputStream(currentDB);\n                final FileChannel dst = destStream.getChannel();\n                dst.transferFrom(src, 0, src.size());\n                src.close();\n                srcStream.close();\n                dst.close();\n                destStream.close();\n            } else {\n                throw new RuntimeException(\"Couldn't write to \" + currentDB);\n            }\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/utils/FileUtils.java",
    "content": "package com.eveningoutpost.dexdrip.utils;\n\nimport android.os.Environment;\n\nimport java.io.File;\n\npublic class FileUtils {\n\n\tpublic static boolean makeSureDirectoryExists( final String dir ) {\n\t\tfinal File file = new File( dir );\n        return file.exists() || file.mkdirs();\n\t}\n\n\tpublic static String getExternalDir() {\n\t\tfinal StringBuilder sb = new StringBuilder();\n\t\tsb.append( Environment.getExternalStorageDirectory().getAbsolutePath() );\n\t\tsb.append( \"/xdrip\" );\n\n\t\tfinal String dir = sb.toString();\n\t\treturn dir;\n\t}\n\n\tpublic static String combine( final String path1, final String path2 ) {\n\t\tfinal File file1 = new File( path1 );\n\t\tfinal File file2 = new File( file1, path2 );\n\t\treturn file2.getPath();\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java",
    "content": "package com.eveningoutpost.dexdrip.utils;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.Configuration;\nimport android.media.Ringtone;\nimport android.media.RingtoneManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.ListPreference;\nimport android.preference.Preference;\nimport android.preference.PreferenceActivity;\nimport android.preference.PreferenceCategory;\nimport android.preference.PreferenceFragment;\nimport android.preference.PreferenceGroup;\nimport android.preference.PreferenceManager;\nimport android.preference.PreferenceScreen;\nimport android.preference.RingtonePreference;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.R;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;\n\nimport java.util.List;\n\n/**\n * A {@link PreferenceActivity} that presents a set of application settings. On\n * handset devices, settings are presented as a single list. On tablets,\n * settings are split by category, with category headers shown to the left of\n * the list of settings.\n * <p/>\n * See <a href=\"http://developer.android.com/design/patterns/settings.html\">\n * Android Design: Settings</a> for design guidelines and the <a\n * href=\"http://developer.android.com/guide/topics/ui/settings.html\">Settings\n * API Guide</a> for more information on developing a Settings UI.\n */\npublic class Preferences extends PreferenceActivity {\n    public  static SharedPreferences prefs;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        getFragmentManager().beginTransaction().replace(android.R.id.content,\n                new AllPrefsFragment()).commit();\n    }\n\n    @Override\n    protected void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n//        addPreferencesFromResource(R.xml.pref_general);\n\n    }\n\n    @Override\n    protected boolean isValidFragment(String fragmentName) {\n        if (AllPrefsFragment.class.getName().equals(fragmentName)){ return true; }\n        return false;\n    }\n\n    @Override\n    public boolean onIsMultiPane() {\n        return isXLargeTablet(this);\n    }\n    private static boolean isXLargeTablet(Context context) {\n        return (context.getResources().getConfiguration().screenLayout\n                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;\n    }\n\n    @Override\n    public void onBuildHeaders(List<Header> target) {\n        loadHeadersFromResource(R.xml.pref_headers, target);\n    }\n\n    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {\n        @Override\n        public boolean onPreferenceChange(Preference preference, Object value) {\n            String stringValue = value.toString();\n            if (preference instanceof ListPreference) {\n                ListPreference listPreference = (ListPreference) preference;\n                int index = listPreference.findIndexOfValue(stringValue);\n                preference.setSummary(\n                        index >= 0\n                                ? listPreference.getEntries()[index]\n                                : null);\n\n            } else if (preference instanceof RingtonePreference) {\n                // For ringtone preferences, look up the correct display value\n                // using RingtoneManager.\n                if (TextUtils.isEmpty(stringValue)) {\n                    // Empty values correspond to 'silent' (no ringtone).\n                    preference.setSummary(R.string.pref_ringtone_silent);\n\n                } else {\n                    Ringtone ringtone = RingtoneManager.getRingtone(\n                            preference.getContext(), Uri.parse(stringValue));\n\n                    if (ringtone == null) {\n                        // Clear the summary if there was a lookup error.\n                        preference.setSummary(null);\n                    } else {\n                        // Set the summary to reflect the new ringtone display\n                        // name.\n                        String name = ringtone.getTitle(preference.getContext());\n                        preference.setSummary(name);\n                    }\n                }\n\n            } else {\n                // For all other preferences, set the summary to the value's\n                // simple string representation.\n                preference.setSummary(stringValue);\n            }\n            return true;\n        }\n    };\n\n    private static void bindPreferenceSummaryToValue(Preference preference) {\n        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);\n        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,\n                PreferenceManager\n                        .getDefaultSharedPreferences(preference.getContext())\n                        .getString(preference.getKey(), \"\"));\n    }\n\n    public static class AllPrefsFragment extends PreferenceFragment {\n        @Override\n        public void onCreate(Bundle savedInstanceState) {\n            super.onCreate(savedInstanceState);\n            addPreferencesFromResource(R.xml.pref_license);\n            addPreferencesFromResource(R.xml.pref_general);\n            bindPreferenceSummaryToValue(findPreference(\"highValue\"));\n            bindPreferenceSummaryToValue(findPreference(\"lowValue\"));\n            bindPreferenceSummaryToValue(findPreference(\"units\"));\n\n            addPreferencesFromResource(R.xml.pref_notifications);\n            bindPreferenceSummaryToValue(findPreference(\"bg_snooze\"));\n\n            addPreferencesFromResource(R.xml.pref_data_source);\n\n\n            addPreferencesFromResource(R.xml.pref_data_sync);\n            bindPreferenceSummaryToValue(findPreference(\"cloud_storage_mongodb_uri\"));\n            bindPreferenceSummaryToValue(findPreference(\"cloud_storage_mongodb_collection\"));\n            bindPreferenceSummaryToValue(findPreference(\"cloud_storage_mongodb_device_status_collection\"));\n            bindPreferenceSummaryToValue(findPreference(\"cloud_storage_api_base\"));\n\n\n            addPreferencesFromResource(R.xml.pref_advanced_settings);\n\n\n            final Preference collectionMethod = findPreference(\"dex_collection_method\");\n            final Preference runInForeground = findPreference(\"run_service_in_foreground\");\n            final Preference wifiRecievers = findPreference(\"wifi_recievers_addresses\");\n            final Preference predictiveBG = findPreference(\"predictive_bg\");\n            final Preference interpretRaw = findPreference(\"interpret_raw\");\n            final Preference shareKey = findPreference(\"share_key\");\n            final PreferenceCategory collectionCategory = (PreferenceCategory) findPreference(\"collection_category\");\n            final PreferenceCategory otherCategory = (PreferenceCategory) findPreference(\"other_category\");\n            final PreferenceScreen calibrationAlertsScreen = (PreferenceScreen) findPreference(\"calibration_alerts_screen\");\n            final PreferenceCategory alertsCategory = (PreferenceCategory) findPreference(\"alerts_category\");\n            prefs =  getPreferenceManager().getDefaultSharedPreferences(getActivity());\n            Log.d(\"PREF\", prefs.getString(\"dex_collection_method\", \"BluetoothWixel\"));\n\n            if(prefs.getString(\"dex_collection_method\", \"BluetoothWixel\").compareTo(\"DexcomShare\") != 0) {\n                collectionCategory.removePreference(shareKey);\n                otherCategory.removePreference(interpretRaw);\n                alertsCategory.addPreference(calibrationAlertsScreen);\n            } else {\n                otherCategory.removePreference(predictiveBG);\n                alertsCategory.removePreference(calibrationAlertsScreen);\n                prefs.edit().putBoolean(\"calibration_notifications\", false).apply();\n            }\n            if(prefs.getString(\"dex_collection_method\", \"BluetoothWixel\").compareTo(\"BluetoothWixel\") != 0 && prefs.getString(\"dex_collection_method\", \"BluetoothWixel\").compareTo(\"DexcomShare\") != 0) {\n                collectionCategory.removePreference(runInForeground);\n            }\n            if(prefs.getString(\"dex_collection_method\", \"BluetoothWixel\").compareTo(\"WifiWixel\") != 0) {\n                collectionCategory.removePreference(wifiRecievers);\n            }\n            bindPreferenceSummaryToValue(collectionMethod);\n            bindPreferenceSummaryToValue(shareKey);\n            bindPreferenceSummaryToValue(wifiRecievers);\n            collectionMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {\n                @Override\n                public boolean onPreferenceChange(Preference preference, Object newValue) {\n                    if(((String) newValue).compareTo(\"DexcomShare\") != 0) { // NOT USING SHARE\n                        collectionCategory.removePreference(shareKey);\n                        otherCategory.removePreference(interpretRaw);\n                        otherCategory.addPreference(predictiveBG);\n                        alertsCategory.addPreference(calibrationAlertsScreen);\n                    } else {\n                        collectionCategory.addPreference(shareKey);\n                        otherCategory.addPreference(interpretRaw);\n                        otherCategory.removePreference(predictiveBG);\n                        alertsCategory.removePreference(calibrationAlertsScreen);\n                        prefs.edit().putBoolean(\"calibration_notifications\", false).apply();\n                    }\n                    if(((String) newValue).compareTo(\"BluetoothWixel\") != 0 && ((String) newValue).compareTo(\"DexcomShare\") != 0) {\n                        collectionCategory.removePreference(runInForeground);\n                    } else {\n                        collectionCategory.addPreference(runInForeground);\n                    }\n                    if(((String) newValue).compareTo(\"WifiWixel\") != 0) {\n                        collectionCategory.removePreference(wifiRecievers);\n                    } else {\n                        collectionCategory.addPreference(wifiRecievers);\n                    }\n                    String stringValue = newValue.toString();\n                    if (preference instanceof ListPreference) {\n                        ListPreference listPreference = (ListPreference) preference;\n                        int index = listPreference.findIndexOfValue(stringValue);\n                        preference.setSummary(\n                                index >= 0\n                                        ? listPreference.getEntries()[index]\n                                        : null);\n\n                    } else if (preference instanceof RingtonePreference) {\n                        if (TextUtils.isEmpty(stringValue)) {\n                            preference.setSummary(R.string.pref_ringtone_silent);\n\n                        } else {\n                            Ringtone ringtone = RingtoneManager.getRingtone(\n                                    preference.getContext(), Uri.parse(stringValue));\n                            if (ringtone == null) {\n                                preference.setSummary(null);\n                            } else {\n                                String name = ringtone.getTitle(preference.getContext());\n                                preference.setSummary(name);\n                            }\n                        }\n                    } else {\n                        preference.setSummary(stringValue);\n                    }\n                    CollectionServiceStarter.restartCollectionService(preference.getContext());\n                    return true;\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/utils/ShareNotification.java",
    "content": "package com.eveningoutpost.dexdrip.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.support.v4.app.NotificationCompat;\n\n/**\n * Helper class to show a share notificaiton.\n */\npublic class ShareNotification {\n\n    public static void viewOrShare(String mime, Uri uri, NotificationCompat.Builder builder, Context context) {\n        final Intent viewFileIntent = new Intent(Intent.ACTION_VIEW);\n        viewFileIntent.setDataAndType(uri, mime);\n\n        ResolveInfo matches = context.getPackageManager().resolveActivity(viewFileIntent, PackageManager.MATCH_DEFAULT_ONLY);\n\n        if (matches != null) {\n            final PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, viewFileIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n            builder.setContentIntent(resultPendingIntent);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                addShare(builder, mime, uri, context);\n            }\n        } else {\n            final Intent shareIntent = new Intent();\n            shareIntent.setAction(Intent.ACTION_SEND);\n            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);\n            shareIntent.setType(mime);\n            final PendingIntent sharePendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n\n            builder.setContentIntent(sharePendingIntent);\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    private static void addShare(NotificationCompat.Builder notification, String mime, Uri uri, Context context) {\n        final Intent shareIntent = new Intent();\n        shareIntent.setAction(Intent.ACTION_SEND);\n        shareIntent.putExtra(Intent.EXTRA_STREAM, uri);\n        shareIntent.setType(mime);\n        final PendingIntent sharePendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n        notification.addAction(android.R.drawable.ic_menu_share, \"Share\", sharePendingIntent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/widgetUpdateService.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.appwidget.AppWidgetManager;\nimport android.bluetooth.BluetoothDevice;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.IBinder;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\n\nimport com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Services.DexShareCollectionService;\nimport com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;\nimport com.eveningoutpost.dexdrip.UtilityModels.Intents;\n\nimport java.util.Calendar;\nimport java.util.Date;\n\npublic class widgetUpdateService extends Service {\n    public String TAG = \"widgetUpdateService\";\n    BroadcastReceiver _broadcastReceiver;\n    public widgetUpdateService() {}\n\n    @Override\n    public IBinder onBind(Intent intent) { throw new UnsupportedOperationException(\"Not yet implemented\"); }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        setFailoverTimer();\n        _broadcastReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context ctx, Intent intent) {\n                if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {\n                    updateCurrentBgInfo();\n                }\n            }\n        };\n        registerReceiver(_broadcastReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        setFailoverTimer();\n        updateCurrentBgInfo();\n        return START_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (_broadcastReceiver != null) {\n            unregisterReceiver(_broadcastReceiver);\n        }\n    }\n\n    public void setFailoverTimer() { //Keep it alive!\n        if(AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), xDripWidget.class)).length > 0) {\n            long retry_in = (1000 * 60 * 5);\n            Log.d(TAG, \"Fallover Restarting in: \" + (retry_in / (60 * 1000)) + \" minutes\");\n            Calendar calendar = Calendar.getInstance();\n            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);\n            alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, widgetUpdateService.class), 0));\n        }\n    }\n\n    public void updateCurrentBgInfo() {\n        Log.d(TAG, \"Sending update flag to widget\");\n        int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), xDripWidget.class));\n        Log.d(TAG, \"Updating \" + ids.length + \" widgets\");\n        Intent intent = new Intent(this,xDripWidget.class);\n        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);\n        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);\n        sendBroadcast(intent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/xDripWidget.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.preference.PreferenceManager;\nimport android.util.Log;\nimport android.widget.RemoteViews;\nimport android.widget.TextView;\n\nimport com.eveningoutpost.dexdrip.Models.BgReading;\nimport com.eveningoutpost.dexdrip.Services.DexCollectionService;\nimport com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;\n\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n\n/**\n * Implementation of App Widget functionality.\n */\npublic class xDripWidget extends AppWidgetProvider {\n    public static RemoteViews views;\n    public static Context mContext;\n    public static String TAG = \"xDripWidget\";\n\n\n    @Override\n    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n        final int N = appWidgetIds.length;\n        for (int i = 0; i < N; i++) {\n            updateAppWidget(context, appWidgetManager, appWidgetIds[i]);\n        }\n    }\n\n\n    @Override\n    public void onEnabled(Context context) {\n        Log.d(TAG, \"Widget enabled\");\n        context.startService(new Intent(context, widgetUpdateService.class));\n    }\n\n    @Override\n    public void onDisabled(Context context) {\n        Log.d(TAG, \"Widget disabled\");\n        // Enter relevant functionality for when the last widget is disabled\n    }\n\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {\n        mContext = context;\n        views = new RemoteViews(context.getPackageName(), R.layout.x_drip_widget);\n        Log.d(TAG, \"Update widget signal received\");\n        displayCurrentInfo();\n        appWidgetManager.updateAppWidget(appWidgetId, views);\n    }\n\n\n    public static void displayCurrentInfo() {\n        BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(mContext);\n        BgReading lastBgreading = BgReading.lastNoSenssor();\n        if (lastBgreading != null) {\n            double estimate = 0;\n            if ((new Date().getTime()) - (60000 * 11) - lastBgreading.timestamp > 0) {\n                estimate = lastBgreading.calculated_value;\n                Log.d(TAG, \"old value, estimate \" + estimate);\n                views.setTextViewText(R.id.widgetBg, bgGraphBuilder.unitized_string(estimate));\n                views.setTextViewText(R.id.widgetArrow, \"--\");\n                views.setInt(R.id.widgetBg, \"setPaintFlags\", Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);\n            } else {\n                estimate = lastBgreading.calculated_value;\n                String stringEstimate = bgGraphBuilder.unitized_string(estimate);\n                String slope_arrow = BgReading.slopeArrow((lastBgreading.calculated_value_slope * 60000));\n                if (lastBgreading.hide_slope) {\n                    slope_arrow = \"--\";\n                }\n                Log.d(TAG, \"newish value, estimate \" + stringEstimate + slope_arrow);\n                views.setTextViewText(R.id.widgetBg, stringEstimate);\n                views.setTextViewText(R.id.widgetArrow, slope_arrow);\n                views.setInt(R.id.widgetBg, \"setPaintFlags\", 0);\n            }\n            List<BgReading> bgReadingList =  BgReading.latest(2);\n            if(bgReadingList != null && bgReadingList.size() == 2) {\n\n                views.setTextViewText(R.id.widgetDelta, bgGraphBuilder.unitizedDeltaString(lastBgreading.calculated_value - bgReadingList.get(1).calculated_value));\n            } else {\n                views.setTextViewText(R.id.widgetDelta, \"--\");\n            }\n            int timeAgo =(int) Math.floor((new Date().getTime() - lastBgreading.timestamp)/(1000*60));\n            if (timeAgo == 1) {\n                views.setTextViewText(R.id.readingAge, timeAgo + \" Minute ago\");\n            } else {\n                views.setTextViewText(R.id.readingAge, timeAgo + \" Minutes ago\");\n            }\n            if (timeAgo > 15) {\n                views.setTextColor(R.id.readingAge, Color.parseColor(\"#FFBB33\"));\n            } else {\n                views.setTextColor(R.id.readingAge, Color.WHITE);\n            }\n\n            if (bgGraphBuilder.unitized(estimate) <= bgGraphBuilder.lowMark) {\n                views.setTextColor(R.id.widgetBg, Color.parseColor(\"#C30909\"));\n                views.setTextColor(R.id.widgetDelta, Color.parseColor(\"#C30909\"));\n                views.setTextColor(R.id.widgetArrow, Color.parseColor(\"#C30909\"));\n            } else if (bgGraphBuilder.unitized(estimate) >= bgGraphBuilder.highMark) {\n                views.setTextColor(R.id.widgetBg, Color.parseColor(\"#FFBB33\"));\n                views.setTextColor(R.id.widgetDelta, Color.parseColor(\"#FFBB33\"));\n                views.setTextColor(R.id.widgetArrow, Color.parseColor(\"#FFBB33\"));\n            } else {\n                views.setTextColor(R.id.widgetBg, Color.WHITE);\n                views.setTextColor(R.id.widgetDelta, Color.WHITE);\n                views.setTextColor(R.id.widgetArrow, Color.WHITE);\n            }\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java",
    "content": "package com.eveningoutpost.dexdrip;\n\nimport android.app.Application;\n\nimport com.crashlytics.android.Crashlytics;\nimport io.fabric.sdk.android.Fabric;\nimport org.acra.ACRA;\nimport org.acra.ReportField;\nimport org.acra.ReportingInteractionMode;\nimport org.acra.annotation.ReportsCrashes;\nimport org.acra.sender.HttpSender;\n\n/**\n * Created by stephenblack on 3/21/15.\n */\n@ReportsCrashes(\n        formUri = \"https://yoursolace.cloudant.com/acra-xdrip/_design/acra-storage/_update/report\",\n        reportType = HttpSender.Type.JSON,\n        httpMethod = HttpSender.Method.POST,\n        formUriBasicAuthLogin = \"nateriverldstiondrephery\",\n        formUriBasicAuthPassword = \"GEK5Nv7NtMkloAkufNvFgast\",\n        formKey = \"\", // This is required for backward compatibility but not used\n        customReportContent = {\n                ReportField.APP_VERSION_CODE,\n                ReportField.APP_VERSION_NAME,\n                ReportField.ANDROID_VERSION,\n                ReportField.PACKAGE_NAME,\n                ReportField.REPORT_ID,\n                ReportField.BUILD,\n                ReportField.STACK_TRACE\n        },\n        mode = ReportingInteractionMode.TOAST,\n        logcatArguments = {\"-t\", \"500\", \"-v\", \"time\"},\n        resToastText = R.string.toast_crash\n)\n\npublic class xdrip extends Application {\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        Fabric.with(this, new Crashlytics());\n        // The following line triggers the initialization of ACRA\n        //ACRA.init(this);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_add_calibration.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.AddCalibration\">\n\n    <EditText\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberDecimal\"\n        android:ems=\"10\"\n        android:id=\"@+id/bg_value\"\n        android:autoText=\"false\"\n        android:text=\"\"\n        android:singleLine=\"true\"\n        android:textAlignment=\"center\"\n        android:textSize=\"24dp\"\n        android:hint=\"Enter BG Value\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"41dp\" />\n\n    <Button\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Done\"\n        android:id=\"@+id/save_calibration_button\"\n        android:layout_below=\"@+id/bg_value\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"53dp\" />\n\n</RelativeLayout>\n<fragment android:id=\"@+id/navigation_drawer\"\nandroid:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\nandroid:layout_gravity=\"start\"\nandroid:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\ntools:layout=\"@layout/fragment_navigation_drawer\" />\n\n    </android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_add_comparison.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.AddCalibration\">\n\n    <EditText\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"number\"\n        android:ems=\"10\"\n        android:id=\"@+id/bg_value\"\n        android:autoText=\"false\"\n        android:text=\"\"\n        android:layout_centerVertical=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:singleLine=\"true\"\n        android:textAlignment=\"center\"\n        android:textSize=\"24dp\"\n        android:hint=\"Enter BG Value\" />\n\n    <Button\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Done\"\n        android:id=\"@+id/save_calibration_button\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"67dp\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:text=\"This does not get used for anything, its just to keep track of differences for algorithem improvement purposes\"\n        android:id=\"@+id/textView2\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_alignParentStart=\"true\" />\n\n</RelativeLayout>\n<fragment android:id=\"@+id/navigation_drawer\"\nandroid:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\nandroid:layout_gravity=\"start\"\nandroid:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\ntools:layout=\"@layout/fragment_navigation_drawer\" />\n\n    </android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_bluetooth_scan.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.BluetoothScan\">\n\n    <ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:id=\"@android:id/list\"\n        >\n    </ListView>\n\n</RelativeLayout>\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_calibration_check_in.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n    <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.CalibrationCheckInActivity\">\n\n        <TextView android:text=\"Plug in your dexcom reciever then hit this button and cross your fingers!\" android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/check_in_text\" />\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Check in Dexcom calibrations\"\n            android:id=\"@+id/check_in_calibrations\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"53dp\" />\n\n    </RelativeLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_calibration_graph.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n\n    <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" android:paddingLeft=\"1dp\"\n        android:paddingRight=\"1dp\"\n        android:paddingTop=\"1dp\"\n        android:paddingBottom=\"1dp\" tools:context=\".CalibrationGraph\">\n\n        <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.com/tools\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:paddingBottom=\"1dp\"\n            android:paddingLeft=\"1dp\"\n            android:paddingRight=\"1dp\"\n            android:paddingTop=\"1dp\"\n            tools:context=\"lecho.lib.hellocharts.samples.PreviewLineChartActivity$PlaceholderFragment\" >\n\n            <RelativeLayout\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"50dp\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceLarge\"\n                    android:id=\"@+id/currentBgValueRealTime\"\n                    android:layout_centerVertical=\"true\"\n                    android:layout_centerHorizontal=\"true\" />\n            </RelativeLayout>\n\n            <lecho.lib.hellocharts.view.LineChartView\n                android:id=\"@+id/chart\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" >\n            </lecho.lib.hellocharts.view.LineChartView>\n\n\n        </LinearLayout>\n    </RelativeLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_calibration_override.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n    <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n        tools:context=\"com.eveningoutpost.dexdrip.CalibrationOverride\">\n\n        <EditText\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"numberDecimal\"\n            android:ems=\"10\"\n            android:id=\"@+id/bg_value\"\n            android:autoText=\"false\"\n            android:text=\"\"\n            android:singleLine=\"true\"\n            android:textAlignment=\"center\"\n            android:textSize=\"24dp\"\n            android:hint=\"Enter BG Value\"\n            android:layout_marginTop=\"51dp\"\n            android:layout_below=\"@+id/textView5\"\n            android:layout_centerHorizontal=\"true\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Done\"\n            android:id=\"@+id/save_calibration_button\"\n            android:layout_centerVertical=\"true\"\n            android:layout_centerHorizontal=\"true\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:text=\"Entering a calibration now will override your previously entered calibration.\"\n            android:id=\"@+id/textView5\"\n            android:textSize=\"20dp\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_alignParentStart=\"true\" />\n\n    </RelativeLayout>\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_double_calibration.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n    <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n        tools:context=\"com.eveningoutpost.dexdrip.DoubleCalibration\"\n        android:id=\"@+id/double_calibration_rel_layout\">\n        <EditText\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"numberDecimal\"\n            android:ems=\"10\"\n            android:id=\"@+id/bg_value_1\"\n            android:autoText=\"false\"\n            android:singleLine=\"true\"\n            android:textAlignment=\"center\"\n            android:textSize=\"24dp\"\n            android:hint=\"Enter First BG Value\"\n            android:layout_below=\"@+id/textView4\"\n            android:layout_alignStart=\"@+id/textView4\"\n            android:layout_marginTop=\"24dp\" />\n        <EditText\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"numberDecimal\"\n            android:ems=\"10\"\n            android:id=\"@+id/bg_value_2\"\n            android:autoText=\"false\"\n            android:singleLine=\"true\"\n            android:textAlignment=\"center\"\n            android:textSize=\"24dp\"\n            android:hint=\"Enter Second BG Value\"\n            android:layout_marginTop=\"26dp\"\n            android:layout_below=\"@+id/bg_value_1\"\n            android:layout_alignStart=\"@+id/bg_value_1\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\"\n            android:text=\"In order to get started, please perform two finger prick tests and enter the values here!\"\n            android:id=\"@+id/textView4\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_alignParentStart=\"true\" />\n\n\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Done\"\n            android:id=\"@+id/save_calibration_button\"\n            android:layout_centerVertical=\"true\"\n            android:layout_centerHorizontal=\"true\" />\n\n    </RelativeLayout>\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_fake_numbers.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.FakeNumbers\">\n\n    <EditText\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"number\"\n        android:ems=\"10\"\n        android:id=\"@+id/bg_value\"\n        android:autoText=\"false\"\n        android:text=\"\"\n        android:singleLine=\"true\"\n        android:textAlignment=\"center\"\n        android:textSize=\"24dp\"\n        android:hint=\"Enter BG Value\"\n        android:layout_above=\"@+id/save_calibration_button\"\n        android:layout_alignParentStart=\"true\" />\n\n    <Button\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Done\"\n        android:id=\"@+id/log\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignEnd=\"@+id/timePicker\" />\n\n    <DatePicker\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/datePicker\"\n        android:calendarViewShown=\"false\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_centerHorizontal=\"true\" />\n\n    <TimePicker\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/timePicker\"\n        android:layout_centerVertical=\"true\"\n        android:layout_alignParentStart=\"true\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_home.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n    <!-- As the main content view, the view below consumes the entire\n         space available using match_parent in both dimensions. -->\n    <FrameLayout android:id=\"@+id/container\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" >\n\n    </FrameLayout>\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\">\n\n            <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:paddingLeft=\"0dp\"\n                android:paddingRight=\"0dp\"\n                android:layout_weight=\"0.80\"\n                android:paddingTop=\"0dp\"\n                android:paddingBottom=\"0dp\" tools:context=\".Home\"\n                android:layout_marginTop=\"0dp\">\n\n                <TextView\n                    android:layout_width=\"900dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                    android:textColor=\"#C30909\"\n                    android:id=\"@+id/notices\"\n                    android:background=\"#07000000\"\n                    android:paddingEnd=\"10dp\"\n                    android:paddingStart=\"10dp\"\n                    android:gravity=\"left|top\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_alignParentTop=\"true\"\n                    android:text=\"Alerts and messages\" />\n\n                <lecho.lib.hellocharts.view.LineChartView\n                    android:id=\"@+id/chart\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_alignParentStart=\"false\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_marginTop=\"55dp\">\n                </lecho.lib.hellocharts.view.LineChartView>\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:background=\"#07000000\"\n                    android:id=\"@+id/currentBgValueRealTime\"\n                    android:gravity=\"right\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:paddingEnd=\"20dp\"\n                    android:textSize=\"50dp\"\n                    android:paddingTop=\"0dp\" />\n            </RelativeLayout>\n\n            <lecho.lib.hellocharts.view.PreviewLineChartView\n                android:id=\"@+id/chart_preview\"\n                android:layout_width=\"wrap_content\"\n                android:layout_weight=\".20\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_alignParentStart=\"true\"\n                android:layout_height=\"0dp\">\n            </lecho.lib.hellocharts.view.PreviewLineChartView>\n\n        </LinearLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_license_agreement.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.LicenseAgreementActivity\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:id=\"@+id/main_v_layout\">\n\n        <TextView\n            android:text=\"End User License Agreement\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"15sp\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:text=\"@string/pref_I_understand_summery\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"10dp\"\n            android:textSize=\"11sp\"\n            android:id=\"@+id/summary\" />\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:gravity=\"center_horizontal\">\n\n            <CheckBox\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/pref_I_understand_title\"\n                android:id=\"@+id/agreeCheckBox\"\n                android:checked=\"false\" />\n\n            <Button\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Save\"\n                android:id=\"@+id/saveButton\"\n                android:layout_marginTop=\"20dp\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_raw_data_table.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:id=\"@android:id/list\"\n    >\n</ListView>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_share_test.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.ShareTest\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:weightSum=\"1\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Connect\"\n            android:id=\"@+id/connect\"\n            android:layout_gravity=\"center_horizontal\" />\n\n        <LinearLayout\n            android:orientation=\"horizontal\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"55dp\"\n            android:gravity=\"center_horizontal\">\n\n            <Button\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Close\"\n                android:id=\"@+id/closeConnect\"\n                android:layout_gravity=\"center_horizontal\" />\n\n            <Button\n                style=\"?android:attr/buttonStyleSmall\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Read\"\n                android:id=\"@+id/read\"\n                android:layout_gravity=\"right\" />\n\n            <Button\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"bond\"\n                android:id=\"@+id/bond\" />\n\n        </LinearLayout>\n\n        <TextView\n            android:layout_width=\"334dp\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/connection_details\"\n            android:layout_weight=\"1.02\"\n            android:nestedScrollingEnabled=\"true\" />\n    </LinearLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_start_new_sensor.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.StartNewSensor\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:gravity=\"center_horizontal\">\n\n        <DatePicker\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"0dp\"\n            android:id=\"@+id/datePicker\"\n            android:datePickerMode=\"spinner\"\n            android:calendarViewShown=\"false\"\n            android:layout_weight=\"0.30\" />\n\n        <TimePicker\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"0dp\"\n            android:id=\"@+id/timePicker\"\n            android:layout_centerVertical=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_alignParentStart=\"true\"\n            android:timePickerMode=\"spinner\"\n            android:layout_weight=\"0.30\"/>\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\"\n            android:text=\"Do not hit start sensor unless the sensor is already embedded and the transmitter is connected. \\nPLEASE SELECT THE TIME AND DATE THE SENSOR WAS ACTUALLY INSERTED! (as close as you can recall!)\"\n            android:id=\"@+id/textView\"\n            android:layout_above=\"@+id/startNewSensor\"\n            android:layout_toStartOf=\"@+id/startNewSensor\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_marginTop=\"10dp\"\n            android:gravity=\"center_horizontal\"\n            android:textSize=\"15sp\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Start Sensor\"\n            android:id=\"@+id/startNewSensor\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"15dp\" />\n    </LinearLayout>\n\n</RelativeLayout>\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_stop_sensor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:weightSum=\"1\"\n    android:id=\"@+id/stop_sensor_container\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:text=\"Stop Sensor\"\n        android:id=\"@+id/textView3\"\n        android:layout_gravity=\"center_horizontal\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:text=\"Only stop your sensor when you actually plan to remove it, otherwise leave it running!\"\n        android:layout_below=\"@+id/textView\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_marginTop=\"40dp\"\n        android:id=\"@+id/stop_sensor_instructions\"\n        android:layout_gravity=\"right\"\n        android:paddingLeft=\"20dp\"\n        android:paddingRight=\"20dp\"\n        android:gravity=\"center_vertical|center_horizontal\" />\n\n    <Button\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"STOP SENSOR\"\n        android:id=\"@+id/stop_sensor\"\n        android:layout_toEndOf=\"@+id/sensor_age_container\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignEnd=\"@+id/textView3\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"30dp\" />\n\n\n</LinearLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/activity_system_status.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.SystemStatus\">\n\n    <!-- As the main content view, the view below consumes the entire\n         space available using match_parent in both dimensions. -->\n    <FrameLayout android:id=\"@+id/container\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" >\n\n    </FrameLayout>\n    <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n        tools:context=\"com.eveningoutpost.dexdrip.SystemStatus\"\n        android:id=\"@+id/status_layout\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_alignParentStart=\"true\">\n\n            <LinearLayout\n                android:orientation=\"horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:id=\"@+id/layout_horiz\"\n                android:paddingTop=\"10dp\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:text=\"Collection Method:   \"\n                    android:id=\"@+id/textView6\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:id=\"@+id/collection_method\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:orientation=\"horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:paddingTop=\"10dp\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:text=\"Remembered Device:   \"\n                    android:id=\"@+id/textView7\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:id=\"@+id/remembered_device\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:orientation=\"horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingTop=\"10dp\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:text=\"Connection Status:   \"\n                    android:id=\"@+id/textView8\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:id=\"@+id/connection_status\" />\n            </LinearLayout>\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceLarge\"\n                android:text=\"Other Notes:\"\n                android:id=\"@+id/textView9\"\n                android:layout_gravity=\"center_horizontal\"\n                android:paddingTop=\"10dp\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:id=\"@+id/other_notes\"\n                android:layout_gravity=\"center_horizontal\" />\n\n            <LinearLayout\n                android:orientation=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:gravity=\"center|bottom\"\n                android:baselineAligned=\"false\"\n                android:paddingTop=\"10dp\">\n\n                <LinearLayout\n                    android:orientation=\"horizontal\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_horizontal|bottom\"\n                    android:gravity=\"center_horizontal|bottom\">\n\n                    <Button\n                        style=\"?android:attr/buttonStyleSmall\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Restart Collector\"\n                        android:id=\"@+id/restart_collection_service\" />\n\n                    <Button\n                        style=\"?android:attr/buttonStyleSmall\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Forget Device\"\n                        android:id=\"@+id/forget_device\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:orientation=\"horizontal\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_horizontal\"\n                    android:layout_gravity=\"center_horizontal\">\n\n                    <ImageButton\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:id=\"@+id/refresh_current_values\"\n                        android:src=\"@android:drawable/stat_notify_sync\" />\n                </LinearLayout>\n            </LinearLayout>\n\n        </LinearLayout>\n    </RelativeLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_usb_connected.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.eveningoutpost.dexdrip.UsbConnectedActivity\">\n\n    <TextView android:text=\"Usb Device was not recognized\" android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_navigation_drawer.xml",
    "content": "<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:choiceMode=\"singleChoice\"\n    android:divider=\"@android:color/transparent\" android:dividerHeight=\"0dp\"\n    android:background=\"#cccc\"\n    tools:context=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\" />\n"
  },
  {
    "path": "app/src/main/res/layout/listitem_device.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:orientation=\"vertical\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:id=\"@+id/device_list_id\">\n    <TextView android:id=\"@+id/device_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"24dp\"/>\n    <TextView android:id=\"@+id/device_address\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"12dp\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/raw_data_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:id=\"@android:id/list\"\n    >\n</ListView>\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/raw_data_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:id=\"@+id/raw_data_list_item\">\n\n    <TextView android:id=\"@+id/raw_data_id\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:textSize=\"24sp\" />\n\n    <TextView android:id=\"@+id/raw_data_value\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:textSize=\"12sp\"/>\n\n    <TextView android:id=\"@+id/raw_data_slope\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:textSize=\"12sp\"/>\n\n    <TextView android:id=\"@+id/raw_data_timestamp\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:textSize=\"12sp\"/>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/x_drip_widget.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"10dp\"\n    android:paddingTop=\"2dp\"\n    android:paddingBottom=\"10dp\"\n    android:paddingRight=\"10dp\"\n    android:background=\"#55212121\">\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <TextView android:id=\"@+id/widgetBg\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"fill_parent\" android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\" android:text=\"---\"\n            android:textColor=\"#ffffff\" android:textSize=\"55sp\"\n            android:layout_marginTop=\"-5dp\"/>\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingLeft=\"5dp\">\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"#ffffff\"\n                android:textSize=\"37sp\"\n                android:text=\"--\"\n                android:id=\"@+id/widgetArrow\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginBottom=\"-5dp\"\n                android:layout_marginTop=\"-2dp\"\n                android:paddingBottom=\"-2dp\" />\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"#ffffff\"\n                android:textSize=\"10sp\"\n                android:text=\"-- mgdl\"\n                android:id=\"@+id/widgetDelta\"\n                android:layout_gravity=\"center_horizontal\"/>\n        </LinearLayout>\n\n    </LinearLayout>\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textColor=\"#ffffff\"\n        android:textSize=\"10sp\"\n        android:text=\"--- minutes ago\"\n        android:id=\"@+id/readingAge\"\n        android:layout_gravity=\"center_horizontal\"/>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout-xlarge/activity_home.xml",
    "content": "<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n    tools:context=\"com.eveningoutpost.dexdrip.Home\">\n\n    <!-- As the main content view, the view below consumes the entire\n         space available using match_parent in both dimensions. -->\n    <FrameLayout android:id=\"@+id/container\" android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" >\n\n    </FrameLayout>\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\">\n\n            <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:paddingLeft=\"0dp\"\n                android:paddingRight=\"0dp\"\n                android:layout_weight=\"0.80\"\n                android:paddingTop=\"0dp\"\n                android:paddingBottom=\"0dp\" tools:context=\".Home\"\n                android:layout_marginTop=\"0dp\">\n\n                <TextView\n                    android:layout_width=\"900dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                    android:textColor=\"#C30909\"\n                    android:id=\"@+id/notices\"\n                    android:background=\"#07000000\"\n                    android:paddingEnd=\"10dp\"\n                    android:paddingStart=\"10dp\"\n                    android:gravity=\"left|top\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_alignParentTop=\"true\"\n                    android:textSize=\"40dp\"\n                    android:text=\"Alerts and messages\" />\n\n                <lecho.lib.hellocharts.view.LineChartView\n                    android:id=\"@+id/chart\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_alignParentStart=\"false\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_marginTop=\"105dp\">\n                </lecho.lib.hellocharts.view.LineChartView>\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:background=\"#07000000\"\n                    android:id=\"@+id/currentBgValueRealTime\"\n                    android:gravity=\"right\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:paddingEnd=\"20dp\"\n                    android:textSize=\"100dp\"\n                    android:paddingTop=\"0dp\" />\n            </RelativeLayout>\n\n            <lecho.lib.hellocharts.view.PreviewLineChartView\n                android:id=\"@+id/chart_preview\"\n                android:layout_width=\"wrap_content\"\n                android:layout_weight=\".20\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_alignParentStart=\"true\"\n                android:layout_height=\"0dp\">\n            </lecho.lib.hellocharts.view.PreviewLineChartView>\n\n        </LinearLayout>\n\n    <fragment android:id=\"@+id/navigation_drawer\"\n        android:layout_width=\"@dimen/navigation_drawer_width\" android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:name=\"com.eveningoutpost.dexdrip.NavigationDrawerFragment\"\n        tools:layout=\"@layout/fragment_navigation_drawer\" />\n\n</android.support.v4.widget.DrawerLayout>\n\n"
  },
  {
    "path": "app/src/main/res/menu/global.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_bluetooth_scan.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2013 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<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:id=\"@+id/menu_refresh\"\n        android:title=\"@string/menu_refresh\"\n        android:checkable=\"false\"\n        android:orderInCategory=\"1\"\n        android:showAsAction=\"ifRoom\"/>\n    <item android:id=\"@+id/menu_scan\"\n        android:title=\"@string/menu_scan\"\n        android:orderInCategory=\"100\"\n        android:showAsAction=\"ifRoom|withText\"/>\n    <item android:id=\"@+id/menu_stop\"\n        android:title=\"@string/menu_stop\"\n        android:orderInCategory=\"101\"\n        android:showAsAction=\"ifRoom|withText\"/>\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:id=\"@+id/action_export_database\"\n        android:title=\"@string/menu_export_database\"\n        android:checkable=\"false\"\n        android:orderInCategory=\"1\"\n        android:showAsAction=\"never\"/>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_share_test.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.eveningoutpost.dexdrip.ShareTest\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" android:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_system_status.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.eveningoutpost.dexdrip.SystemStatus\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" android:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "app/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"DexCollectionMethods\">\n        <item>Bluetooth Wixel</item>\n        <item>Wifi Wixel</item>\n        <item>DexcomShare</item>\n    </string-array>\n\n    <string-array name=\"DexCollectionMethodValues\">\n        <item>BluetoothWixel</item>\n        <item>WifiWixel</item>\n        <item>DexcomShare</item>\n    </string-array>\n\n\n\n\n    <string-array name=\"bgUnitEntries\">\n        <item>mgdl</item>\n        <item>mmol</item>\n    </string-array>\n\n    <string-array name=\"bgUnitValues\">\n        <item>mgdl</item>\n        <item>mmol</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"navigation_drawer_width\">240dp</dimen>\n\n    <!--\nRefer to App Widget Documentation for margin information\nhttp://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout\n    -->\n    <dimen name=\"widget_margin\">8dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"pref_I_understand_title\"> I UNDERSTAND AND AGREE</string>\n    <string name=\"pref_I_understand_summery\">xDrip MUST NOT BE USED TO MAKE MEDICAL DECISIONS. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </string>\n    <string name=\"app_name\">xDrip</string>\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"title_activity_bluetooth_scan\">BluetoothScan</string>\n    <string name=\"connected\">Connected</string>\n    <string name=\"disconnected\">Disconnected</string>\n    <string name=\"menu_scan\">Scan</string>\n    <string name=\"menu_stop\">Stop</string>\n    <string name=\"menu_refresh\">Refresh</string>\n    <string name=\"menu_export_database\">Export database</string>\n    <string name=\"error_bluetooth_not_supported\">Error: Bluetooth not supported by this device</string>\n    <string name=\"unknown_device\">Unrecognized Device</string>\n    <string name=\"connecting_to_device\">Connecting to device</string>\n    <string name=\"title_activity_raw_data_table\">RawDataTable</string>\n    <string name=\"title_activity_calculated_data_table\">CalculatedDataTable</string>\n    <string name=\"title_activity_add_calibration\">AddCalibration</string>\n    <string name=\"title_activity_start_new_sensor\">StartNewSensor</string>\n    <string name=\"title_activity_stop_sensor\">StopSensor</string>\n    <string name=\"title_activity_nav_drawer\">NavDrawer</string>\n    <string name=\"title_section1\">Home</string>\n    <string name=\"title_section2\">Add Calibration</string>\n    <string name=\"title_section3\">Start Sensor</string>\n    <string name=\"title_section4\">Stop Sensor</string>\n    <string name=\"title_section5\">Scan for BT</string>\n    <string name=\"title_section6\">Raw Data Table</string>\n    <string name=\"title_section7\">Calibration Table</string>\n    <string name=\"navigation_drawer_open\">Open navigation drawer</string>\n    <string name=\"navigation_drawer_close\">Close navigation drawer</string>\n    <string name=\"title_activity_license_agreement\">End User License Agreement</string>\n    <string name=\"action_example\">Example action</string>\n    <string name=\"title_activity_calibration_check_in\">CalibrationCheckInActivity</string>\n    <string name=\"title_activity_usb_connected\">UsbConnectedActivity</string>\n\n    <string-array name=\"menu_options\">\n        <item>Dex Drip</item>\n        <item>Enter Calibration</item>\n        <item>Calculated Data Table</item>\n        <item>Raw Data Table</item>\n        <item>Calibration Table</item>\n        <item>Start Sensor</item>\n        <item>Stop Sensor</item>\n        <item>Scan for BT</item>\n    </string-array>\n\n    <string name=\"title_activity_main\">MainActivity</string>\n    <string name=\"title_activity_calibration_data_table\">CalibrationDataTable</string>\n    <string name=\"title_activity_fake_numbers\">FakeNumbers</string>\n    <string name=\"title_activity_double_calibration\">DoubleCalibrationActivity</string>\n    <string name=\"title_activity_calibration_override\">CalibrationOverride</string>\n    <string name=\"title_activity_calibration_graph\">CalibrationGraph</string>\n    <string name=\"pref_header_cloud_storage\">Cloud Storage</string>\n\n    <!-- MongoDB Settings -->\n    <string name=\"pref_title_mongodb\">MongoDB</string>\n    <string name=\"pref_title_mongo_enabled\">Enabled</string>\n    <string name=\"pref_summary_mongodb_enabled\">If you\\'re using MongoLab and Azure this should be enabled</string>\n    <string name=\"pref_title_mongodb_uri\">URI</string>\n    <string name=\"pref_dialog_mongodb_uri\">Enter MongoDB URI\"</string>\n    <string name=\"pref_message_mongodb_uri\">Replace example values in {}\\'s with your correct values</string>\n    <string name=\"pref_default_mongodb_uri\">mongodb://{user}:{password}@{host}.mongolab.com:{11111}/{database}</string>\n    <string name=\"pref_title_mongodb_collection\">Collection name</string>\n    <string name=\"pref_dialog_mongodb_collection\">Enter collection name</string>\n    <string name=\"pref_message_mongodb_collection\">This is the name of the collection where the CGM data will be stored</string>\n    <string name=\"pref_default_mongodb_collection\">entries</string>\n    <string name=\"pref_title_mongodb_device_status_collection\">Device Status collection name</string>\n    <string name=\"pref_dialog_mongodb_device_status_collection\">Enter Device Status collection name\"</string>\n    <string name=\"pref_message_mongodb_device_status_collection\">This is the name of the collection where the battery and other device data will be stored</string>\n    <string name=\"pref_default_mongodb_device_status_collection\">devicestatus</string>\n    <!-- API Settings -->\n    <string name=\"pref_title_api\">API Upload (REST)</string>\n    <string name=\"pref_title_api_enabled\">Enabled</string>\n    <string name=\"pref_summary_api_enabled\">The REST API is an alternative to direct mongodb upload</string>\n    <string name=\"pref_title_api_url\">Base URL</string>\n    <string name=\"pref_dialog_api_url\">Enter Base API URL</string>\n    <string name=\"pref_message_api_url\">This only the base URL, the uploader will automatically append /entries for the POST.  API_SECRET on the server should match yourpassphrase in this setting.</string>\n    <string name=\"pref_default_api_url\">yourpassphrase@https://{YOUR-SITE}.azurewebsites.net/api/v1</string>\n\n    <!-- wifi Settings -->\n    <string name=\"wifi_recievers_dialog_message\">Comma separated list of ip:port (for example 37.142.132.220:50005,37.142.132.220:50010,mongodb://user:pass@ds053958.mongolab.com:53958/db/collection)</string>\n    <string name=\"wifi_recievers_dialog_title\">Enter ip addresses and ports of receivers (including mongodb addresses if needed)</string>\n\n    <!-- broadcast settings -->\n    <string name=\"pref_title_broadcast_enabled\">Broadcast locally</string>\n    <string name=\"pref_summary_broadcast_enabled\">Enable local broadcast of data so other apps (eg. NightWatch) can listen on new values</string>\n    <string name=\"title_activity_share_test\">ShareTest</string>\n    <string name=\"title_activity_system_status\">SystemStatus</string>\n\n    <string name=\"toast_crash\">Something went wrong :( a report has been sent to help fix the issue.</string>\n    <string name=\"appwidget_text\">EXAMPLE</string>\n    <string name=\"add_widget\">Add widget</string>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings_activity_preferences.xml",
    "content": "<resources>\n    <string name=\"title_activity_preferences\">Preferences</string>\n\n    <!-- Strings related to Settings -->\n\n    <!-- Example General settings -->\n    <string name=\"pref_header_general\">General</string>\n\n    <string name=\"pref_title_social_recommendations\">Enable social recommendations</string>\n    <string name=\"pref_description_social_recommendations\">Recommendations for people to contact\n        based on your message history\n    </string>\n\n    <string name=\"pref_title_display_name\">Display name</string>\n    <string name=\"pref_default_display_name\">John Smith</string>\n\n    <string name=\"pref_title_add_friends_to_messages\">Add friends to messages</string>\n    <string-array name=\"pref_example_list_titles\">\n        <item>Always</item>\n        <item>When possible</item>\n        <item>Never</item>\n    </string-array>\n    <string-array name=\"pref_example_list_values\">\n        <item>1</item>\n        <item>0</item>\n        <item>-1</item>\n    </string-array>\n\n    <!-- Example settings for Data & Sync -->\n    <string name=\"pref_header_data_sync\">Data &amp; sync</string>\n\n    <string name=\"pref_title_sync_frequency\">Sync frequency</string>\n    <string-array name=\"pref_sync_frequency_titles\">\n        <item>15 minutes</item>\n        <item>30 minutes</item>\n        <item>1 hour</item>\n        <item>3 hours</item>\n        <item>6 hours</item>\n        <item>Never</item>\n    </string-array>\n    <string-array name=\"pref_sync_frequency_values\">\n        <item>15</item>\n        <item>30</item>\n        <item>60</item>\n        <item>180</item>\n        <item>360</item>\n        <item>-1</item>\n    </string-array>\n\n    <string name=\"pref_title_system_sync_settings\">System sync settings</string>\n\n    <!-- Example settings for Notifications -->\n    <string name=\"pref_header_notifications\">Notifications</string>\n\n    <string name=\"pref_title_new_message_notifications\">New message notifications</string>\n\n    <string name=\"pref_title_ringtone\">Ringtone</string>\n    <string name=\"pref_ringtone_silent\">Silent</string>\n\n    <string name=\"pref_title_vibrate\">Vibrate</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"android:Theme.Holo\">\n\n        <item name=\"android:background\">#212121</item>\n        <item name=\"android:actionBarStyle\">@style/MyActionBar</item>\n    </style>\n\n    <!-- ActionBar styles -->\n    <style name=\"MyActionBar\"\n        parent=\"@android:style/Widget.Holo.ActionBar\">\n        <item name=\"android:background\">#212121</item>\n        <!--<item name=\"android:color\">#616161</item>-->\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v14/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!--\nRefer to App Widget Documentation for margin information\nhttp://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout\n    -->\n    <dimen name=\"widget_margin\">0dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v21/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:ThemeOverlay.Material\">\n        <item name=\"android:background\">#212121</item>\n        <item name=\"android:actionBarStyle\">@style/MyActionBar</item>\n    </style>\n\n    <!-- ActionBar styles -->\n    <style name=\"MyActionBar\"\n        parent=\"@android:style/Widget.Material.ActionBar\">\n        <item name=\"android:background\">#212121</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/device_filter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2011 The Android Open Source Project\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          http://www.apache.org/licenses/LICENSE-2.0\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<resources>\n    <!--WIXEL-->\n    <usb-device class=\"2\" subclass=\"0\" protocol=\"0\" vendor-id=\"8187\" />\n\n    <!--DEXCOM-->\n    <usb-device class=\"2\" subclass=\"0\" protocol=\"0\"  vendor-id=\"8867\" product-id=\"71\" />\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_advanced_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <PreferenceCategory\n        android:key=\"other_category\"\n        android:title=\"Other Settings\">\n        <SwitchPreference\n            android:title=\"@string/pref_title_broadcast_enabled\"\n            android:key=\"broadcast_data_through_intents\"\n            android:summary=\"@string/pref_summary_broadcast_enabled\"\n            android:defaultValue=\"false\" >\n        </SwitchPreference>\n        <!--<SwitchPreference-->\n            <!--android:title=\"Send to Pebble\"-->\n            <!--android:key=\"broadcast_to_pebble\"-->\n            <!--android:summary=\"If you have a pebble watch you can send bg data straight to it\"-->\n            <!--android:defaultValue=\"false\" >-->\n        <!--</SwitchPreference>-->\n        <CheckBoxPreference\n            android:key=\"predictive_bg\"\n            android:title=\"Display Predictive Values\"\n            android:summary=\"Not Recommended. xDrip will attempt to predict readings each minute based on the past few values.\"\n            android:defaultValue=\"false\" />\n        <CheckBoxPreference\n            android:key=\"interpret_raw\"\n            android:title=\"Interpret Raw Values\"\n            android:summary=\"If using Share, DexDrip will show values when they are normally hidden on the receiver.\"\n            android:defaultValue=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_data_source.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <PreferenceCategory\n        android:key=\"collection_category\"\n        android:title=\"Data Source Settings\">\n        <ListPreference\n            android:key=\"dex_collection_method\"\n            android:title=\"Dexcom Data Collection Method\"\n            android:summary=\"How are you going to receive data from your Dexcom?\"\n            android:entries=\"@array/DexCollectionMethods\"\n            android:entryValues=\"@array/DexCollectionMethodValues\"\n            android:defaultValue=\"BluetoothWixel\"/>\n        <EditTextPreference\n            android:title=\"10 Character Dexcom Receiver Serial Number\"\n            android:key=\"share_key\"\n            android:shouldDisableView=\"true\"\n            android:defaultValue=\"SM00000000\"/>\n        <CheckBoxPreference\n            android:key=\"run_service_in_foreground\"\n            android:title=\"Run Collection Service in foreground\"\n            android:summary=\"Running in foreground prevents android from killing the service to free up memory but it creates an annoying notification.\"\n            android:defaultValue=\"false\" />\n        <EditTextPreference\n            android:title=\"List of recievers\"\n            android:key=\"wifi_recievers_addresses\"\n            android:dialogTitle=\"@string/wifi_recievers_dialog_title\"\n            android:dialogMessage=\"@string/wifi_recievers_dialog_message\"\n            android:defaultValue=\"\">\n        </EditTextPreference>\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_data_sync.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to\n         dismiss it. -->\n    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->\n    <PreferenceCategory\n        android:title=\"Data Sync\"\n        android:key=\"dataSync\">\n\n        <PreferenceScreen\n            android:key=\"cloud_storage_mongo\"\n            android:title=\"@string/pref_title_mongodb\"\n            android:summary=\"@string/pref_summary_mongodb_enabled\">\n\n            <SwitchPreference\n                android:key=\"cloud_storage_mongodb_enable\"\n                android:title=\"Enable Nightscout Mongo DB sync\"\n                android:defaultValue=\"false\" />\n            <EditTextPreference\n                android:dependency=\"cloud_storage_mongodb_enable\"\n                android:title=\"Mongo DB Uri\"\n                android:key=\"cloud_storage_mongodb_uri\"\n                android:dialogTitle=\"@string/pref_dialog_mongodb_uri\"\n                android:dialogMessage=\"@string/pref_message_mongodb_uri\"\n                android:defaultValue=\"@string/pref_default_mongodb_uri\">\n            </EditTextPreference>\n            <EditTextPreference\n                android:dependency=\"cloud_storage_mongodb_enable\"\n                android:title=\"@string/pref_title_mongodb_collection\"\n                android:key=\"cloud_storage_mongodb_collection\"\n                android:dialogTitle=\"@string/pref_dialog_mongodb_collection\"\n                android:dialogMessage=\"@string/pref_message_mongodb_collection\"\n                android:defaultValue=\"@string/pref_default_mongodb_collection\">\n            </EditTextPreference>\n            <EditTextPreference\n                android:dependency=\"cloud_storage_mongodb_enable\"\n                android:title=\"@string/pref_title_mongodb_device_status_collection\"\n                android:key=\"cloud_storage_mongodb_device_status_collection\"\n                android:dialogTitle=\"@string/pref_dialog_mongodb_device_status_collection\"\n                android:dialogMessage=\"@string/pref_message_mongodb_device_status_collection\"\n                android:defaultValue=\"@string/pref_default_mongodb_device_status_collection\">\n            </EditTextPreference>\n\n        </PreferenceScreen>\n\n        <PreferenceScreen\n            android:key=\"cloud_storage_api\"\n            android:title=\"@string/pref_title_api\"\n            android:summary=\"@string/pref_summary_api_enabled\">\n\n            <SwitchPreference\n                android:title=\"@string/pref_title_api_enabled\"\n                android:key=\"cloud_storage_api_enable\"\n                android:disableDependentsState=\"false\"\n                android:summary=\"@string/pref_summary_api_enabled\">\n            </SwitchPreference>\n            <EditTextPreference\n                android:dependency=\"cloud_storage_api_enable\"\n                android:title=\"@string/pref_title_api_url\"\n                android:key=\"cloud_storage_api_base\"\n                android:dialogTitle=\"@string/pref_dialog_api_url\"\n                android:dialogMessage=\"@string/pref_message_api_url\"\n                android:defaultValue=\"@string/pref_default_api_url\">\n            </EditTextPreference>\n\n        </PreferenceScreen>\n\n        <!--<CheckBoxPreference-->\n        <!--android:key=\"share_upload\"-->\n        <!--android:title=\"Upload BG values as Dexcom Share\"-->\n        <!--android:summary=\"If you are using Dexcom Share, choose this option.\"-->\n        <!--android:defaultValue=\"false\" />-->\n        <!--<EditTextPreference-->\n        <!--android:dependency=\"share_upload\"-->\n        <!--android:key=\"dexcom_account_name\"-->\n        <!--android:title=\"Dexcom Account Login\"-->\n        <!--android:summary=\"Your login for Dexcoms Website\"-->\n        <!--android:defaultValue=\"\"/>-->\n        <!--<EditTextPreference-->\n        <!--android:dependency=\"share_upload\"-->\n        <!--android:key=\"dexcom_account_password\"-->\n        <!--android:title=\"Dexcom Account Password\"-->\n        <!--android:inputType=\"textPassword\"-->\n        <!--android:summary=\"Your password for Dexcoms Website\"-->\n        <!--android:defaultValue=\"\"/>-->\n\n\n    </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_general.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <PreferenceCategory\n            android:title=\"General Settings\"\n            android:key=\"bgRange\">\n            <ListPreference\n                android:key=\"units\"\n                android:title=\"Bg Units\"\n                android:entries=\"@array/bgUnitEntries\"\n                android:entryValues=\"@array/bgUnitValues\"\n                android:defaultValue=\"mgdl\"/>\n            <EditTextPreference\n                android:key=\"highValue\"\n                android:title=\"High Value\"\n                android:numeric=\"decimal\"\n                android:summary=\"The maximum value you consider to be in range.\"\n                android:defaultValue=\"170\" />\n            <EditTextPreference\n                android:key=\"lowValue\"\n                android:title=\"Low Value\"\n                android:numeric=\"decimal\"\n                android:summary=\"The minimum value you consider to be in range.\"\n                android:defaultValue=\"70\" />\n        </PreferenceCategory>\n    </PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_headers.xml",
    "content": "<preference-headers xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</preference-headers>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_license.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <PreferenceCategory\n        android:title=\"EULA\"\n        android:key=\"title_I_understand\">\n        <Preference android:title=\"End User License Agreement\"\n            android:key=\"I_understand\" >\n            <intent\n                android:action=\"android.intent.action.MAIN\"\n                android:targetPackage=\"com.eveningoutpost.dexdrip\"\n                android:targetClass=\"com.eveningoutpost.dexdrip.LicenseAgreementActivity\"\n                />\n        </Preference>\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/pref_notifications.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <PreferenceCategory\n        android:title=\"Alerts and Notifications\"\n        android:key=\"alerts_category\">\n        <PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:title=\"BG Level Alerts\">\n            <CheckBoxPreference\n                android:key=\"bg_notifications\"\n                android:title=\"BG Alerts\"\n                android:summary=\"Alert when BG readings cross the threshold.\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"bg_notifications\"\n                android:key=\"bg_vibrate\"\n                android:title=\"Vibrate on BG alerts\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"bg_notifications\"\n                android:key=\"bg_lights\"\n                android:title=\"Flash lights on BG alerts\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"bg_notifications\"\n                android:key=\"bg_play_sound\"\n                android:title=\"Play sound on BG alerts\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"bg_play_sound\"\n                android:key=\"bg_sound_in_silent\"\n                android:title=\"Play alert sounds even in silent mode\"\n                android:defaultValue=\"false\" />\n            <RingtonePreference\n                android:dependency=\"bg_play_sound\"\n                android:key=\"bg_notification_sound\"\n                android:title=\"Alert Sound\"\n                android:ringtoneType=\"notification\"\n                android:summary=\"Set sound used for BG Alerts.\"\n                android:defaultValue=\"content://settings/system/notification_sound\" />\n            <EditTextPreference\n                android:dependency=\"bg_notifications\"\n                android:key=\"bg_snooze\"\n                android:title=\"Alert Snooze\"\n                android:numeric=\"integer\"\n                android:summary=\"Minimum number of minutes to pass before raising the same alert.\"\n                android:defaultValue=\"20\" />\n        </PreferenceScreen>\n\n\n        <PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:title=\"Calibration Alerts\"\n            android:key=\"calibration_alerts_screen\">\n            <CheckBoxPreference\n                android:key=\"calibration_notifications\"\n                android:title=\"Calibration Alerts\"\n                android:summary=\"Alert when a calibration is requested\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"calibration_notifications\"\n                android:key=\"calibration_vibrate\"\n                android:title=\"Vibrate on calibration requests\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"calibration_notifications\"\n                android:key=\"calibration_lights\"\n                android:title=\"Flash lights on calibration requests\"\n                android:defaultValue=\"true\" />\n            <CheckBoxPreference\n                android:dependency=\"calibration_notifications\"\n                android:key=\"calibration_play_sound\"\n                android:title=\"Play sound on calibration requests\"\n                android:defaultValue=\"true\" />\n            <RingtonePreference\n                android:dependency=\"calibration_play_sound\"\n                android:key=\"calibration_notification_sound\"\n                android:title=\"Calibration Request Sound\"\n                android:ringtoneType=\"notification\"\n                android:summary=\"Set sound used for calibration requests.\"\n                android:defaultValue=\"content://settings/system/notification_sound\" />\n            <EditTextPreference\n                android:dependency=\"calibration_notifications\"\n                android:key=\"calibration_snooze\"\n                android:title=\"Calibration request Snooze\"\n                android:numeric=\"integer\"\n                android:summary=\"Number of minutes to pass before raising the same calibration request.\"\n                android:defaultValue=\"20\" />\n        </PreferenceScreen>\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/x_drip_widget_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:minWidth=\"110dp\" android:minHeight=\"40dp\" android:updatePeriodMillis=\"600000\"\n    android:previewImage=\"@drawable/example_appwidget_preview\"\n    android:initialLayout=\"@layout/x_drip_widget\" android:resizeMode=\"horizontal|vertical\"\n    android:widgetCategory=\"home_screen|keyguard\"\n    android:initialKeyguardLayout=\"@layout/x_drip_widget\"/>\n"
  },
  {
    "path": "battle_of_the_dexes.md",
    "content": "\nA few weeks ago I started a new sensor and kicked off the BattleOfTheDexes\nI compared my xDrip Alogrithm against the Dexcom 505 Algorithm.\n_(obviously its just one sample so nothing conclusive, but the results are in)_\n\n&nbsp;\n\n\nMETER | Dexcom | xDrip\n-----:|-----:|-----:\n105 | 87 | **100**\n181 | **188** | 169\n166 | 236 | **185**\n75 | 53 | **66**\n103 | 101 | **103**\n118 | 102 | **111**\n120 | 154 | **144**\n151  | 125 | 137\n102 | 95 | **103**\n89 | **90** | 98\n97 | **106** | 111\n\n&nbsp;\n\nOverall MARDs:\n* Dexcom: 15.5%\n* xDrip: **8.7%**\n\n&nbsp;\n\nNote that Dexcoms actual MARD as calculated in studies is 9% I believe so its quite possible I had a bum sensor here. Also note that xDrip got one extra calibration value on the second day (because it asks for one if it thinks things are off at a time when it thinks the calibration will be the most helpful)\n\n&nbsp;\n\nI stopped this first comparison here because once I restart the sensor on my Dexcom, xDrip winds up with a huge advantage as it already knows the slope from the last few days of calibrations wheras dexcom will be starting from scratch. I will do more comparisons each time I change sensors!\n\n&nbsp;\n\nWant to know more about the project? Check it out [HERE](http://stephenblackwasalreadytaken.github.io/xDrip)\n\n&nbsp;\n\nAll of the code is available and open source, if you want help getting it running just ask, Its constantly getting updated so either watch the repo in github or follow me on twitter @StephenIsTaken\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.1.3'\n        apply plugin: 'java'\n        apply plugin: 'maven'\n//        compile 'com.mcxiaoke.volley:library:1.0.+'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Dec 10 18:45:32 EST 2014\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\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\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\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=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@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\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=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "hardware_setup.md",
    "content": "## What you need to get started\nNote, the following describes what I am currently using and recommend, it could definitely change and you can definitely use other components. Just know that this is all that it has been tested with!\n\n* An Android Device\n * Must be running 4.3 to support BLE\n * Also must have BLE support\n* [A Wixel](http://www.pololu.com/product/1337)\n * I recommend the one without headers(linked) if you want to use wires, if you plan to use a breadboard or make a custom PCB feel free to get the one with headers.\n* An HM-10 BLE Module\n * I removed the link as it seems they replaced the HM10 with a cc41, **DO NOT GET A CC41!!!!!** I use the hm10 formerly sold by sunfounder, if you can find one with the pins at the bottom that is the easiest!\n * The HM11 has been confirmed working but soldering it is VERY TOUGH\n* [Battery Power](http://www.adafruit.com/products/258)\n * I use the one linked and have no problem getting through a day, I have not done extensive battery testing at this point\n * *EDIT: that one was lasting over 6 days, which seemed like a waste of space, now I use [this 500mAh](http://www.adafruit.com/products/1578) Which gets me two days no problem!\n* [Battery Charger](http://www.adafruit.com/products/1904)\n * I use this one, its nice and smallish and does the trick.\n * If you find a nicer smaller one PLEASE LET ME KNOW (I wound up breaking the top bit off of this so I could make it fit in a new enclosure)\n* [Wires](http://www.adafruit.com/product/2051)\n * I use these 30AWG silicon wires because they are super small and flexible\n * Larger wires will make it harder to keep things nice and compact, keep with a small guage!\n* Solder and Soldering Iron\n * Or a breadboard if you dont mind the bulk\n * Or a custom made PCB (and one for me too please?)\n * I used a cheap 15w soldering iron in order to solder and remove the pins from the HM10 (you can probably go a bit higher but I wouldnt go crazy)\n * I used a regular not terrifying soldering iron for the rest of it!\n* [Resistors](http://www.radioshack.com)\n * If you wish to measure the Wixel's battery voltage, you'll need to build a voltage divider using two resistors and a piece of wire\n * You'll need a 1/4w 1K Ohm and a 1/4w 2.2K Ohm resistor.  1/8w should work, and be smaller, but it hasn't been tested\n * Optional:  Small heatshrink tubing to protect the resistors (https://www.adafruit.com/product/344)\n\n ## Putting it together!\n ![SETUP](http://i.imgur.com/EIGki5R.png)\n \n ## For the voltage measurement modification\n ###### If you have already built the xDrip and are adding this, follow this first step:\n  * Remove the solder from the VIN and GND pins on the Wixel if possible using a solder sucker or solder wick.  If this is not possible, then you will have to work carefully by keeping the holes heated while inserting the resistors.  Keep in mind, if you do not have a controllable temperature soldering iron, you risk burning the board or the pads and ruining the Wixel.  **I highly recommend getting a solder sucker.**\n  * You will need to grab a new copy of the Wixel code and upload it to your Wixel for this modification to work.  The process is the same as when you first loaded the code onto the Wixel, except you will need to click the \"Erase Flash\" button first.\n\n ###### Building the voltage divider\n * Bend the one end of each resistor at a 90 degree angle as close to the resistor as possible \n ![Imgur](http://i.imgur.com/TXPCYx9.jpg)\n * Using helping hands or tape, face the two resistors towards each other and place them side by side so that the leads are touching at the top\n ![Imgur](http://i.imgur.com/WJNnoBv.jpg)\n * Solder the touching leads, and then solder on the piece of wire\n ![Imgur](http://i.imgur.com/jLdzr6q.jpg)\n ![Imgur](http://i.imgur.com/W3praDM.jpg)\n * Trim the leads of the 90 degree bend so they are flush with the resistors and trim any excess exposed wire from the piece you added to prevent any possible shorts.\n ![Imgur](http://i.imgur.com/IzpXo1L.jpg)\n * Insert the leads of the voltage divider into the VIN hole and GND hole.  The 1K resistor goes into the VIN hole and the 2.2K resistor goes into the GND hole next to it.  Additionally, insert the wires from the LiPo charger into the appropriate VIN and GND holes.\n ![Imgur](http://i.imgur.com/zpLtRoc.jpg)\n * CAREFULLY bend the resistor leads you inserted so the voltage divider is flat against the Wixel\n ![Imgur](http://i.imgur.com/cvRmHaO.jpg)\n * Solder the VIN and GND pads\n ![Imgur](http://i.imgur.com/N9mqE99.jpg)\n * Trim the excess wire from the resistor leads\n ![Imgur](http://i.imgur.com/EFCnUlv.jpg)\n * The back of your Wixel should look like this\n ![Imgur](http://i.imgur.com/eYh9yOR.jpg)\n * If you want to add a piece of heat shrink tubing to protect the resistors (highly recommended!), put it on now.\n ![Imgur](http://i.imgur.com/4vyTY4v.jpg)\n  * Trim the wire you added to the voltage divider so that it is long enough to reach P0_0, and then insert it into the hole and solder it.\n ![Imgur](http://i.imgur.com/4b625P5.jpg)\n ![Imgur](http://i.imgur.com/97ZKzcC.jpg)\n * Trim the excess leads from the soldered pads on the Wixel\n ![Imgur](http://i.imgur.com/fXgbnp5.jpg)\n * CAREFULLY heat the heat shrink tubing with the iron.  Only touch the tubing for a second to get it to slightly heat up and do this in multiple places.  You only want it to shrink enough to not fall off, it does not have to be super tight against the resistors.  **DO NOT USE A LIGHTER!**\n ![Imgur](http://i.imgur.com/KfWcZfd.jpg)\n * Congratulate yourself for building an electronic circuit!\nI also tossed it all into a \"Crush Proof Pill Box\" from CVS (Cost like $2)\n![Imgur](http://i.imgur.com/uB40JUG.jpg)\n![Imgur](http://i.imgur.com/8xIdz5w.jpg)\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  },
  {
    "path": "xDrip-Experimental.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\"xDrip-Experimental\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n        <option name=\"BUILDABLE\" value=\"true\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/classes/main\" />\n    <output-test url=\"file://$MODULE_DIR$/build/classes/test\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/resources\" type=\"java-test-resource\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "xDrip.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/classes/main\" />\n    <output-test url=\"file://$MODULE_DIR$/build/classes/test\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/test/resources\" type=\"java-test-resource\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>\n\n"
  }
]