master bf149df61f03 cached
108 files
255.2 KB
62.8k tokens
318 symbols
1 requests
Download .txt
Showing preview only (286K chars total). Download the full file or copy to clipboard to get everything.
Repository: amitshekhariitbhu/Android-Debug-Database
Branch: master
Commit: bf149df61f03
Files: 108
Total size: 255.2 KB

Directory structure:
gitextract_t_j5_uvg/

├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.gradle
├── debug-db/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── debug/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           └── debug/
│       │   │               ├── DebugDBInitProvider.java
│       │   │               └── sqlite/
│       │   │                   ├── DebugDBFactory.java
│       │   │                   └── DebugSQLiteDB.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── debug/
│                           └── ExampleUnitTest.java
├── debug-db-base/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   ├── app.js
│       │   │   ├── custom.css
│       │   │   ├── dataTables.altEditor.free.js
│       │   │   └── index.html
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           ├── DebugDB.java
│       │   │           ├── model/
│       │   │           │   ├── Response.java
│       │   │           │   ├── RowDataRequest.java
│       │   │           │   ├── TableDataResponse.java
│       │   │           │   └── UpdateRowResponse.java
│       │   │           ├── server/
│       │   │           │   ├── ClientServer.java
│       │   │           │   └── RequestHandler.java
│       │   │           ├── sqlite/
│       │   │           │   ├── DBFactory.java
│       │   │           │   ├── InMemoryDebugSQLiteDB.java
│       │   │           │   └── SQLiteDB.java
│       │   │           └── utils/
│       │   │               ├── Constants.java
│       │   │               ├── ConverterUtils.java
│       │   │               ├── DataType.java
│       │   │               ├── DatabaseFileProvider.java
│       │   │               ├── DatabaseHelper.java
│       │   │               ├── NetworkUtils.java
│       │   │               ├── PrefHelper.java
│       │   │               ├── TableNameParser.java
│       │   │               └── Utils.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── ExampleUnitTest.java
├── debug-db-encrypt/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── debug/
│       │                   └── encrypt/
│       │                       └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           └── debug/
│       │   │               └── encrypt/
│       │   │                   ├── DebugDBEncryptInitProvider.java
│       │   │                   └── sqlite/
│       │   │                       ├── DebugDBEncryptFactory.java
│       │   │                       └── DebugEncryptSQLiteDB.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── debug/
│                           └── encrypt/
│                               └── ExampleUnitTest.java
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── sample-app/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── sample/
│       │               └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── sample/
│       │   │           ├── MainActivity.java
│       │   │           ├── database/
│       │   │           │   ├── CarDBHelper.java
│       │   │           │   ├── ContactDBHelper.java
│       │   │           │   ├── ExtTestDBHelper.java
│       │   │           │   └── room/
│       │   │           │       ├── AppDatabase.java
│       │   │           │       ├── User.java
│       │   │           │       ├── UserDBHelper.java
│       │   │           │       └── UserDao.java
│       │   │           └── utils/
│       │   │               └── Utils.java
│       │   └── res/
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       ├── values/
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── sample/
│                       └── ExampleUnitTest.java
├── sample-app-encrypt/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── sample/
│       │               └── encrypt/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── sample/
│       │   │           └── encrypt/
│       │   │               ├── MainActivity.java
│       │   │               ├── database/
│       │   │               │   ├── CarDBHelper.java
│       │   │               │   ├── ContactDBHelper.java
│       │   │               │   ├── ExtTestDBHelper.java
│       │   │               │   ├── PersonDBHelper.java
│       │   │               │   └── room/
│       │   │               │       ├── AppDatabase.java
│       │   │               │       ├── User.java
│       │   │               │       ├── UserDBHelper.java
│       │   │               │       └── UserDao.java
│       │   │               └── utils/
│       │   │                   └── Utils.java
│       │   └── res/
│       │       ├── drawable/
│       │       │   └── ic_launcher_background.xml
│       │       ├── drawable-v24/
│       │       │   └── ic_launcher_foreground.xml
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       └── values/
│       │           ├── colors.xml
│       │           ├── dimens.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── sample/
│                       └── encrypt/
│                           └── ExampleUnitTest.java
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Android Studio generated folders
captures/
.externalNativeBuild

# IntelliJ project files
*.iml
.idea/

# Misc
.DS_Store


================================================
FILE: CHANGELOG.md
================================================
Change Log
==========

Version 1.0.6 *(2019-03-07)*
----------------------------

* Fix: Fix query error
* Fix: Fix DebugDb class not found error


Version 1.0.5 *(2019-02-18)*
----------------------------

* Reduce size by taking out encrypted database library as a separate module
* New: Add support for database delete
* Changed compile to implementation
* Fix: Minor bug fixes


Version 1.0.4 *(2018-06-23)*
----------------------------

* Fix: Fix issue of Room Database


Version 1.0.3 *(2018-02-12)*
----------------------------

* New: Add support for debugging inMemory Room Database
* Add example for Room Database


Version 1.0.2 *(2018-01-08)*
----------------------------

* New: Add SqlCipher support
* New: List table name in non case sensitive alphabetical order


Version 1.0.1 *(2017-06-23)*
----------------------------

* New: Add insert row feature
* New: Add custom database files support
* New: Add method for checking isServerRunning
* New: Add pragma support
* Fix: Minor bug fixes


Version 1.0.0 *(2017-02-08)*
----------------------------

* New: Add support for editing database directly
* New: Delete rows directly
* New: Delete Shared Pref
* New: Edit shared preferences directly
* New: Add standard code for checking databases files
* New: Complete offline support
* Refactor library code


Version 0.5.0 *(2017-01-21)*
----------------------------

* New: Export DB
* New: Method to get DB version
* Fix: Fix proguard issue and other minor issues


Version 0.4.0 *(2016-11-29)*
----------------------------

* Optimizations
* Fix: Fix few minor bugs


Version 0.3.0 *(2016-11-23)*
----------------------------

* New: Add support for custom port
* Fix: Fix few minor bugs


Version 0.2.0 *(2016-11-17)*
----------------------------

* New: Add method for getting address
* Fix: Fix few minor bugs


Version 0.1.0 *(2016-11-16)*
----------------------------

Initial release.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

1. Fork it!
2. Checkout the development branch: `git checkout development`
3. Create your feature branch: `git checkout -b my-new-feature`
4. Add your changes to the index: `git add .`
5. Commit your changes: `git commit -m 'Add some feature'`
6. Push to the branch: `git push origin my-new-feature`
7. Submit a pull request against the `development` branch


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
<img src=https://raw.githubusercontent.com/amitshekhariitbhu/Android-Debug-Database/master/assets/debug_db_banner.png >

# Android Debug Database

## Android Debug Database is a powerful library for debugging databases and shared preferences in Android applications

### Android Debug Database allows you to view databases and shared preferences directly in your browser in a very simple way

### What can Android Debug Database do?

* See all the databases.
* See all the data in the shared preferences used in your application.
* Run any sql query on the given database to update and delete your data.
* Directly edit the database values.
* Directly edit the shared preferences.
* Directly add a row in the database.
* Directly add a key-value in the shared preferences.
* Delete database rows and shared preferences.
* Search in your data.
* Sort data.
* Download database.
* Debug Room inMemory database.

## About me

Hi, I am Amit Shekhar, Founder @ [Outcome School](https://outcomeschool.com) • IIT 2010-14 • I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.

### Follow Amit Shekhar

- [X/Twitter](https://twitter.com/amitiitbhu)
- [LinkedIn](https://www.linkedin.com/in/amit-shekhar-iitbhu)
- [GitHub](https://github.com/amitshekhariitbhu)

### Follow Outcome School

- [YouTube](https://youtube.com/@OutcomeSchool)
- [X/Twitter](https://x.com/outcome_school)
- [LinkedIn](https://www.linkedin.com/company/outcomeschool)
- [GitHub](http://github.com/OutcomeSchool)

## I teach at Outcome School

- [AI and Machine Learning](https://outcomeschool.com/program/ai-and-machine-learning)
- [Android](https://outcomeschool.com/program/android)

Join Outcome School and get a high-paying tech job: [Outcome School](https://outcomeschool.com)

## [Outcome School Blog](https://outcomeschool.com/blog) - High-quality content to learn Android concepts.

### All these features work without rooting your device -> No need of rooted device

### Using Android Debug Database Library in your application

Add this in your `settings.gradle`:
```groovy
maven { url 'https://jitpack.io' }
```

If you are using `settings.gradle.kts`, add the following:
```kotlin
maven { setUrl("https://jitpack.io") }
```

Add this in your `build.gradle`
```groovy
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.7'
```

If you are using `build.gradle.kts`, add the following:
```kotlin
debugImplementation("com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.7")
```

Using the Android Debug Database with encrypted database

Add this in your `build.gradle`
```groovy
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db-encrypt:1.0.7'
```

If you are using `build.gradle.kts`, add the following:
```kotlin
debugImplementation("com.github.amitshekhariitbhu.Android-Debug-Database:debug-db-encrypt:1.0.7")
```

And to provide the password for the DB, you should add this in the Gradle:
DB_PASSWORD_{VARIABLE}, if for example, PERSON is the database name: DB_PASSWORD_PERSON
```groovy
debug {
    resValue("string", "DB_PASSWORD_PERSON", "password")
}
```

Use `debugImplementation` so that it will only compile in your debug build and not in your release build.

That’s all, just start the application, you will see in the logcat an entry like follows :

* D/DebugDB: Open http://XXX.XXX.X.XXX:8080 in your browser

* You can also always get the debug address url from your code by calling the method `DebugDB.getAddressLog();`

Now open the provided link in your browser.

Important:

* Your Android phone and laptop should be connected to the same Network (Wifi or LAN).
* If you are using it over usb, run `adb forward tcp:8080 tcp:8080`

Note      : If you want use different port other than 8080.
            In the app build.gradle file under buildTypes do the following change

```groovy
debug {
    resValue("string", "PORT_NUMBER", "8081")
}
```

You will see something like this :

### Seeing values

<img src=https://raw.githubusercontent.com/amitshekhariitbhu/Android-Debug-Database/master/assets/debugdb.png >

### Editing values

<img src=https://raw.githubusercontent.com/amitshekhariitbhu/Android-Debug-Database/master/assets/debugdb_edit.png >

### Working with emulator

* Android Default Emulator: Run the command in the terminal - `adb forward tcp:8080 tcp:8080` and open http://localhost:8080
* Genymotion Emulator: Enable bridge from configure virtual device (option available in genymotion)

### Getting address with toast, in case you missed the address log in logcat

As this library is auto-initialize, if you want to get the address log, add the following method and call (we have to do like this to avoid build error in release build as this library will not be included in the release build) using reflection.

```java
public static void showDebugDBAddressLogToast(Context context) {
    if (BuildConfig.DEBUG) {
       try {
            Class<?> debugDB = Class.forName("com.amitshekhar.DebugDB");
            Method getAddressLog = debugDB.getMethod("getAddressLog");
            Object value = getAddressLog.invoke(null);
            Toast.makeText(context, (String) value, Toast.LENGTH_LONG).show();
       } catch (Exception ignore) {

       }
    }
}
```

### Adding custom database files

As this library is auto-initialize, if you want to debug custom database files, add the following method and call

```java
public static void setCustomDatabaseFiles(Context context) {
    if (BuildConfig.DEBUG) {
        try {
            Class<?> debugDB = Class.forName("com.amitshekhar.DebugDB");
            Class[] argTypes = new Class[]{HashMap.class};
            Method setCustomDatabaseFiles = debugDB.getMethod("setCustomDatabaseFiles", argTypes);
            HashMap<String, Pair<File, String>> customDatabaseFiles = new HashMap<>();
            // set your custom database files
            customDatabaseFiles.put(ExtTestDBHelper.DATABASE_NAME,
                    new Pair<>(new File(context.getFilesDir() + "/" + ExtTestDBHelper.DIR_NAME +
                                                    "/" + ExtTestDBHelper.DATABASE_NAME), ""));
            setCustomDatabaseFiles.invoke(null, customDatabaseFiles);
        } catch (Exception ignore) {

        }
    }
}
```

### Adding InMemory Room databases

As this library is auto-initialize, if you want to debug inMemory Room databases, add the following method and call

```java
public static void setInMemoryRoomDatabases(SupportSQLiteDatabase... database) {
    if (BuildConfig.DEBUG) {
        try {
            Class<?> debugDB = Class.forName("com.amitshekhar.DebugDB");
            Class[] argTypes = new Class[]{HashMap.class};
            HashMap<String, SupportSQLiteDatabase> inMemoryDatabases = new HashMap<>();
            // set your inMemory databases
            inMemoryDatabases.put("InMemoryOne.db", database[0]);
            Method setRoomInMemoryDatabase = debugDB.getMethod("setInMemoryRoomDatabases", argTypes);
            setRoomInMemoryDatabase.invoke(null, inMemoryDatabases);
        } catch (Exception ignore) {

        }
    }
}
```

### Find this project useful ? :heart:

* Support it by clicking the :star: button on the upper right of this page. :v:

### TODO

* Simplify emulator issue [Issue Link](https://github.com/amitshekhariitbhu/Android-Debug-Database/issues/6)
* And of course many more features and bug fixes.

You can connect with me on:

- [Twitter](https://twitter.com/amitiitbhu)
- [LinkedIn](https://www.linkedin.com/in/amit-shekhar-iitbhu)
- [GitHub](https://github.com/amitshekhariitbhu)
- [Facebook](https://www.facebook.com/amit.shekhar.iitbhu)

[**Read all of our blogs here.**](https://outcomeschool.com/blog)

### License

```
   Copyright (C) 2024 Amit Shekhar

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
```

### Contributing to Android Debug Database

All pull requests are welcome, make sure to follow the [contribution guidelines](CONTRIBUTING.md)
when you submit pull request.


================================================
FILE: build.gradle
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id 'com.android.application' version '7.3.0' apply false
    id 'com.android.library' version '7.3.0' apply false
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
ext {
    compileSdk = 33
    targetSdk = 33
    minSdk = 14
}

================================================
FILE: debug-db/.gitignore
================================================
/build


================================================
FILE: debug-db/build.gradle
================================================
apply plugin: 'com.android.library'

android {
    compileSdk rootProject.ext.compileSdk
    defaultConfig {
        minSdk rootProject.ext.minSdk
        targetSdk rootProject.ext.targetSdk
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    api project(':debug-db-base')
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

================================================
FILE: debug-db/gradle.properties
================================================
ARTIFACT_ID=debug-db

================================================
FILE: debug-db/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile


================================================
FILE: debug-db/src/androidTest/java/com/amitshekhar/debug/ExampleInstrumentedTest.java
================================================
package com.amitshekhar.debug;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumented test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.amitshekhar.debug.test", appContext.getPackageName());
    }
}


================================================
FILE: debug-db/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.amitshekhar.debug">

    <application>
        <provider
            android:name=".DebugDBInitProvider"
            android:authorities="${applicationId}.DebugDBInitProvider"
            android:enabled="true"
            android:exported="false" />
    </application>

</manifest>


================================================
FILE: debug-db/src/main/java/com/amitshekhar/debug/DebugDBInitProvider.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.debug;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;

import com.amitshekhar.DebugDB;
import com.amitshekhar.debug.sqlite.DebugDBFactory;

/**
 * Created by amitshekhar on 16/11/16.
 */

public class DebugDBInitProvider extends ContentProvider {


    public DebugDBInitProvider() {
    }

    @Override
    public boolean onCreate() {
        DebugDB.initialize(getContext(), new DebugDBFactory());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public void attachInfo(Context context, ProviderInfo providerInfo) {
        if (providerInfo == null) {
            throw new NullPointerException("DebugDBInitProvider ProviderInfo cannot be null.");
        }
        // So if the authorities equal the library internal ones, the developer forgot to set his applicationId
        if ("com.amitshekhar.debug.DebugDBInitProvider".equals(providerInfo.authority)) {
            throw new IllegalStateException("Incorrect provider authority in manifest. Most likely due to a "
                    + "missing applicationId variable in application\'s build.gradle.");
        }
        super.attachInfo(context, providerInfo);
    }

}


================================================
FILE: debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugDBFactory.java
================================================
package com.amitshekhar.debug.sqlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.amitshekhar.sqlite.DBFactory;
import com.amitshekhar.sqlite.SQLiteDB;

public class DebugDBFactory implements DBFactory {

    @Override
    public SQLiteDB create(Context context, String path, String password) {
        return new DebugSQLiteDB(SQLiteDatabase.openOrCreateDatabase(path, null));
    }

}


================================================
FILE: debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugSQLiteDB.java
================================================
package com.amitshekhar.debug.sqlite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

import com.amitshekhar.sqlite.SQLiteDB;

public class DebugSQLiteDB implements SQLiteDB {

    private final SQLiteDatabase database;

    public DebugSQLiteDB(SQLiteDatabase database) {
        this.database = database;
    }

    @Override
    public int delete(String table, String whereClause, String[] whereArgs) {
        return database.delete(table, whereClause, whereArgs);
    }

    @Override
    public boolean isOpen() {
        return database.isOpen();
    }

    @Override
    public void close() {
        database.close();
    }

    @Override
    public Cursor rawQuery(String sql, String[] selectionArgs) {
        return database.rawQuery(sql, selectionArgs);
    }

    @Override
    public void execSQL(String sql) throws SQLException {
        database.execSQL(sql);
    }

    @Override
    public long insert(String table, String nullColumnHack, ContentValues values) {
        return database.insert(table, nullColumnHack, values);
    }

    @Override
    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
        return database.update(table, values, whereClause, whereArgs);
    }

    @Override
    public int getVersion() {
        return database.getVersion();
    }
}


================================================
FILE: debug-db/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">debug-db</string>
</resources>


================================================
FILE: debug-db/src/test/java/com/amitshekhar/debug/ExampleUnitTest.java
================================================
package com.amitshekhar.debug;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() {
        assertEquals(4, 2 + 2);
    }
}

================================================
FILE: debug-db-base/build.gradle
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

apply plugin: 'com.android.library'

android {
    compileSdk rootProject.ext.compileSdk
    defaultConfig {
        minSdk rootProject.ext.minSdk
        targetSdk rootProject.ext.targetSdk
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        resValue("string", "PORT_NUMBER", "8080")
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation "androidx.room:room-runtime:2.5.0"
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

================================================
FILE: debug-db-base/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
-renamesourcefileattribute SourceFile

-keepparameternames
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,EnclosingMethod

# Preserve all annotations.

-keepattributes *Annotation*

# Preserve all public classes, and their public and protected fields and
# methods.

-keep public class * {
    public protected *;
}

# Preserve all .class method names.

-keepclassmembernames class * {
    java.lang.Class class$(java.lang.String);
    java.lang.Class class$(java.lang.String, boolean);
}

# Preserve all native method names and the names of their classes.

-keepclasseswithmembernames class * {
    native <methods>;
}

# Preserve the special static methods that are required in all enumeration
# classes.

-keepclassmembers class * extends java.lang.Enum {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your library doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Your library may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:

# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface


================================================
FILE: debug-db-base/src/androidTest/java/com/amitshekhar/ExampleInstrumentedTest.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumentation test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() throws Exception {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.amitshekhar.test", appContext.getPackageName());
    }
}


================================================
FILE: debug-db-base/src/main/AndroidManifest.xml
================================================
<!--
  ~ /*
  ~  *    Copyright (C) 2019 Amit Shekhar
  ~  *    Copyright (C) 2011 Android Open Source Project
  ~  *
  ~  *    Licensed under the Apache License, Version 2.0 (the "License");
  ~  *    you may not use this file except in compliance with the License.
  ~  *    You may obtain a copy of the License at
  ~  *
  ~  *        http://www.apache.org/licenses/LICENSE-2.0
  ~  *
  ~  *    Unless required by applicable law or agreed to in writing, software
  ~  *    distributed under the License is distributed on an "AS IS" BASIS,
  ~  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  *    See the License for the specific language governing permissions and
  ~  *    limitations under the License.
  ~  */
  -->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.amitshekhar">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

</manifest>


================================================
FILE: debug-db-base/src/main/assets/app.js
================================================
$( document ).ready(function() {
    getDBList();
    $("#query").keypress(function(e){
        if(e.which == 13) {
            queryFunction();
        }
    });
    //update currently selected database
    $( document ).on( "click", "#db-list .list-group-item", function() {
        $("#db-list .list-group-item").each(function() {
            $(this).removeClass('selected');
        });
        $(this).addClass('selected');
    });

    //update currently table database
    $( document ).on( "click", "#table-list .list-group-item", function() {
        $("#table-list .list-group-item").each(function() {
            $(this).removeClass('selected');
        });
        $(this).addClass('selected');
    });


});

var isDatabaseSelected = true;

function getData(tableName) {

   $.ajax({url: "getAllDataFromTheTable?tableName="+tableName, success: function(result){

           result = JSON.parse(result);
           inflateData(result);

   }});

}

function queryFunction() {

   var query = $('#query').val();

   $.ajax({url: "query?query="+escape(query), success: function(result){

           result = JSON.parse(result);
           inflateData(result);

   }});

}

function downloadDb() {
    if (isDatabaseSelected) {
        $.ajax({url: "downloadDb", success: function(){
             window.location = 'downloadDb';
        }});
    }
}

function deleteDb() {
    if (isDatabaseSelected) {
        $.ajax({url: "deleteDb", success: function(result){
            result = JSON.parse(result);
            if(result.isSuccessful){
               console.log("Database deleted successfully");
               showSuccessInfo("Database Deleted Successfully");
               getDBList();
            } else {
               console.log("Database delete failed");
               showErrorInfo("Database Delete Failed");
            }
        }});
    }
}

function getDBList() {

   $.ajax({url: "getDbList", success: function(result){

           result = JSON.parse(result);
           var dbList = result.rows;
           $('#db-list').empty();
           var isSelectionDone = false;
           for(var count = 0; count < dbList.length; count++){
             var dbName = dbList[count][0];
             var isEncrypted = dbList[count][1];
             var isDownloadable = dbList[count][2];
             var dbAttribute = isEncrypted == "true" ? ' <span class="glyphicon glyphicon-lock" aria-hidden="true" style="color:blue"></span>' : "";
             if(dbName.indexOf("journal") == -1 && dbName.indexOf("-wal") == -1 && dbName.indexOf("-shm") == -1){
                $("#db-list").append("<a href='#' id=" + dbName + " class='list-group-item' onClick='openDatabaseAndGetTableList(\""+ dbName + "\", \""+ isDownloadable + "\");'>" + dbName + dbAttribute + "</a>");
                if(!isSelectionDone){
                    isSelectionDone = true;
                    $('#db-list').find('a').trigger('click');
                }
             }
           }

   }});

}

var lastTableName = getHashValue('table');
function openDatabaseAndGetTableList(db, isDownloadable) {

    if("APP_SHARED_PREFERENCES" == db) {
        $('#run-query').removeClass('active');
        $('#run-query').addClass('disabled');
        $('#selected-db-download').removeClass('active');
        $('#selected-db-delete').removeClass('active');
        $('#selected-db-download').addClass('disabled');
        $('#selected-db-delete').addClass('disabled');
        isDatabaseSelected = false;
        $("#selected-db-info").text("SharedPreferences");
    } else {
        $('#run-query').removeClass('disabled');
        $('#run-query').addClass('active');
        $("#selected-db-info").text("Selected Database : "+db);
        if("true" == isDownloadable) {
            $('#selected-db-download').addClass('active');
            $('#selected-db-delete').addClass('active');
            $('#selected-db-download').removeClass('disabled');
            $('#selected-db-delete').removeClass('disabled');
        } else {
            $('#selected-db-download').removeClass('active');
            $('#selected-db-delete').removeClass('active');
            $('#selected-db-download').addClass('disabled');
            $('#selected-db-delete').addClass('disabled');
        }
        isDatabaseSelected = true;
    }


   $.ajax({url: "getTableList?database="+db, success: function(result){

           result = JSON.parse(result);
           var tableList = result.rows;
           var dbVersion = result.dbVersion;
           if("APP_SHARED_PREFERENCES" != db) {
                $("#selected-db-info").text("Selected Database : "+db +" Version : "+dbVersion);
           }
           $('#table-list').empty()
           for(var count = 0; count < tableList.length; count++){
                var tableName = tableList[count];
				$("#table-list").append("<a href='#table=" + tableName + "' data-db-name='" + db + "' data-table-name='" + tableName
					+ "' class='list-group-item' onClick='getData(\"" + tableName + "\");'>" + tableName + "</a>");
			}

			if (lastTableName !== null) {
				$('a[data-table-name=' + lastTableName + ']').trigger('click');
			}
   }});

}

function inflateData(result){

   if(result.isSuccessful){

      if(!result.isSelectQuery){
         showSuccessInfo("Query Executed Successfully");
         return;
      }

      var columnHeader = result.tableInfos;

      // set function to return cell data for different usages like set, display, filter, search etc..
      for(var i = 0; i < columnHeader.length; i++) {
        columnHeader[i]['targets'] = i;
        columnHeader[i]['data'] = function(row, type, val, meta) {
            var dataType = row[meta.col].dataType;
            if (type == "sort" && dataType == "boolean") {
                return row[meta.col].value ? 1 : 0;
            }
            return row[meta.col].value;
        }
      }
      var columnData = result.rows;
       var tableId = "#db-data";
        if ($.fn.DataTable.isDataTable(tableId) ) {
          $(tableId).DataTable().destroy();
        }

       $("#db-data-div").remove();
       $("#parent-data-div").append('<div id="db-data-div"><table class="display nowrap" cellpadding="0" border="0" cellspacing="0" width="100%" class="table table-striped table-bordered display" id="db-data"></table></div>');

       var availableButtons;
       if (result.isEditable) {
            availableButtons = [
                {
                    text : 'Add',
                    name : 'add' // don not change name
                },
                {
                    extend: 'selected', // Bind to Selected row
                    text: 'Edit',
                    name: 'edit'        // do not change name
                },
                {
                    extend: 'selected',
                    text: 'Delete',
                    name: 'delete'
                }
            ];
       } else {
            availableButtons = [];
       }

       $(tableId).dataTable({
           "data": columnData,
           "columnDefs": columnHeader,
           'bPaginate': true,
           'searching': true,
           'bFilter': true,
           'bInfo': true,
           "bSort" : true,
           "scrollX": true,
           "iDisplayLength": 10,
           "dom": "Bfrtip",
            select: 'single',
            altEditor: true,     // Enable altEditor
            buttons: availableButtons
       })

       //attach row-updated listener
       $(tableId).on('update-row.dt', function (e, updatedRowData, callback) {
            var updatedRowDataArray = JSON.parse(updatedRowData);
            //add value for each column
            var data = columnHeader;
            for(var i = 0; i < data.length; i++) {
                data[i].value = updatedRowDataArray[i].value;
                data[i].dataType = updatedRowDataArray[i].dataType;
            }
            //send update table data request to server
            updateTableData(data, callback);
       });


       //attach delete-updated listener
       $(tableId).on('delete-row.dt', function (e, updatedRowData, callback) {
            var deleteRowDataArray = JSON.parse(updatedRowData);

            console.log(deleteRowDataArray);

            //add value for each column
            var data = columnHeader;
            for(var i = 0; i < data.length; i++) {
                data[i].value = deleteRowDataArray[i].value;
                data[i].dataType = deleteRowDataArray[i].dataType;

            }

            //send delete table data request to server
            deleteTableData(data, callback);
       });



       $(tableId).on('add-row.dt', function (e, updatedRowData, callback) {
                   var deleteRowDataArray = JSON.parse(updatedRowData);

                   console.log(deleteRowDataArray);

                   //add value for each column
                   var data = columnHeader;
                   for(var i = 0; i < data.length; i++) {
                       data[i].value = deleteRowDataArray[i].value;
                       data[i].dataType = deleteRowDataArray[i].dataType;
                   }

                   //send delete table data request to server
                   addTableData(data, callback);
              });

       // hack to fix alignment issue when scrollX is enabled
       $(".dataTables_scrollHeadInner").css({"width":"100%"});
       $(".table ").css({"width":"100%"});
   }else{
      if(!result.isSelectQuery){
         showErrorInfo("Query Execution Failed");
      }else {
         showErrorInfo("Some Error Occurred");
      }
   }

}

//send update database request to server
function updateTableData(updatedData, callback) {
    //get currently selected element
    var selectedTableElement = $("#table-list .list-group-item.selected");

    var filteredUpdatedData = updatedData.map(function(columnData){
        return {
            title: columnData.title,
            isPrimary: columnData.isPrimary,
            value: columnData.value,
            dataType: columnData.dataType
        }
    });
    //build request parameters
    var requestParameters = {};
    requestParameters.dbName = selectedTableElement.attr('data-db-name');
    requestParameters.tableName = selectedTableElement.attr('data-table-name');;
    requestParameters.updatedData = encodeURIComponent(JSON.stringify(filteredUpdatedData));

    //execute request
    $.ajax({
        url: "updateTableData",
        type: 'GET',
        data: requestParameters,
        success: function(response) {
            response = JSON.parse(response);
            if(response.isSuccessful){
               console.log("Data updated successfully");
               callback(true);
               showSuccessInfo("Data Updated Successfully");
            } else {
               console.log("Data updated failed");
               callback(false);
            }
        }
    })
}


function deleteTableData(deleteData, callback) {

    var selectedTableElement = $("#table-list .list-group-item.selected");
        var filteredUpdatedData = deleteData.map(function(columnData){
            return {
                title: columnData.title,
                isPrimary: columnData.isPrimary,
                value: columnData.value,
                dataType: columnData.dataType
            }
        });

        //build request parameters
        var requestParameters = {};
        requestParameters.dbName = selectedTableElement.attr('data-db-name');
        requestParameters.tableName = selectedTableElement.attr('data-table-name');;
        requestParameters.deleteData = encodeURIComponent(JSON.stringify(filteredUpdatedData));

        //execute request
        $.ajax({
            url: "deleteTableData",
            type: 'GET',
            data: requestParameters,
            success: function(response) {
                response = JSON.parse(response);
                if(response.isSuccessful){
                   console.log("Data deleted successfully");
                   callback(true);
                   showSuccessInfo("Data Deleted Successfully");
                } else {
                   console.log("Data delete failed");
                   callback(false);
                }
            }
    })
}

function addTableData(deleteData, callback) {

    var selectedTableElement = $("#table-list .list-group-item.selected");
    var filteredUpdatedData = deleteData.map(function(columnData){
        return {
            title: columnData.title,
            isPrimary: columnData.isPrimary,
            value: columnData.value,
            dataType: columnData.dataType
        }
    });

    console.log(filteredUpdatedData);

    //build request parameters
    var requestParameters = {};
    requestParameters.dbName = selectedTableElement.attr('data-db-name');
    requestParameters.tableName = selectedTableElement.attr('data-table-name');;
    requestParameters.addData = encodeURIComponent(JSON.stringify(filteredUpdatedData));

    console.log(requestParameters);

    //execute request
    $.ajax({
        url: "addTableData",
        type: 'GET',
        data: requestParameters,
        success: function(response) {
            response = JSON.parse(response);
            if(response.isSuccessful){
               console.log("Data Added successfully");
               callback(true);
               getData(requestParameters.tableName);
               showSuccessInfo("Data Added Successfully");
            } else {
               console.log("Data Adding failed");
               callback(false);
            }
        }
    });
}

function showSuccessInfo(message){
    var snackbarId = "snackbar";
    var snackbarElement = $("#"+snackbarId);
    snackbarElement.addClass("show");
    snackbarElement.css({"backgroundColor": "#5cb85c"});
    snackbarElement.html(message)
    setTimeout(function(){
        snackbarElement.removeClass("show");
    }, 3000);
}

function showErrorInfo(message){
    var snackbarId = "snackbar";
    var snackbarElement = $("#"+snackbarId);
    snackbarElement.addClass("show");
    snackbarElement.css({"backgroundColor": "#d9534f"});
    snackbarElement.html(message)
    setTimeout(function(){
        snackbarElement.removeClass("show");
    }, 3000);
}

function getHashValue(key) {
	var matches = location.hash.match(new RegExp(key + '=([^&]*)'));
	return matches ? matches[1] : null;
}


================================================
FILE: debug-db-base/src/main/assets/custom.css
================================================
.padding-fifty {
   padding-top: 50px;
}

.padding-twenty {
    padding-top: 20px;
}

.display-none {
    display: none;
}

.list-group-item {
    word-break: break-all;
}

.list-group-item.selected {
    background: #dff0d8 !important;
    color: #3c763d !important;
    font-weight: bold;
}

#snackbar {
    visibility: hidden;
    min-width: 250px;
    margin-left: -125px;
    background-color: #5cb85c;
    color: #fff;
    text-align: center;
    border-radius: 2px;
    padding: 16px;
    position: fixed;
    z-index: 1;
    left: 50%;
    bottom: 30px;
    font-size: 17px;
}

#snackbar.show {
    visibility: visible;
    -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
    animation: fadein 0.5s, fadeout 0.5s 2.5s;
}

@-webkit-keyframes fadein {
    from {bottom: 0; opacity: 0;}
    to {bottom: 30px; opacity: 1;}
}

@keyframes fadein {
    from {bottom: 0; opacity: 0;}
    to {bottom: 30px; opacity: 1;}
}

@-webkit-keyframes fadeout {
    from {bottom: 30px; opacity: 1;}
    to {bottom: 0; opacity: 0;}
}


================================================
FILE: debug-db-base/src/main/assets/dataTables.altEditor.free.js
================================================
/*! Datatables altEditor 1.0
 */
/**
 * @summary     altEditor
 * @description Lightweight editor for DataTables
 * @version     1.0
 * @file        dataTables.editor.lite.js
 * @author      kingkode (www.kingkode.com)
 * @contact     www.kingkode.com/contact
 * @copyright   Copyright 2016 Kingkode
 *
 * This source file is free software, available under the following license:
 *   MIT license - http://datatables.net/license/mit
 *
 * This source file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
 *
 * For details please refer to: http://www.kingkode.com
 */
(function(factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery', 'datatables.net'], function($) {
            return factory($, window, document);
        });
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = function(root, $) {
            if (!root) {
                root = window;
            }

            if (!$ || !$.fn.dataTable) {
                $ = require('datatables.net')(root, $).$;
            }

            return factory($, root, root.document);
        };
    } else {
        // Browser
        factory(jQuery, window, document);
    }
}(function($, window, document, undefined) {
    'use strict';
    var DataTable = $.fn.dataTable;


    var _instance = 0;

    /**
     * altEditor provides modal editing of records for Datatables
     *
     * @class altEditor
     * @constructor
     * @param {object} oTD DataTables settings object
     * @param {object} oConfig Configuration object for altEditor
     */
    var altEditor = function(dt, opts) {
        if (!DataTable.versionCheck || !DataTable.versionCheck('1.10.8')) {
            throw ("Warning: altEditor requires DataTables 1.10.8 or greater");
        }

        // User and defaults configuration object
        this.c = $.extend(true, {},
            DataTable.defaults.altEditor,
            altEditor.defaults,
            opts
        );

        /**
         * @namespace Settings object which contains customisable information for altEditor instance
         */
        this.s = {
            /** @type {DataTable.Api} DataTables' API instance */
            dt: new DataTable.Api(dt),

            /** @type {String} Unique namespace for events attached to the document */
            namespace: '.altEditor' + (_instance++)
        };


        /**
         * @namespace Common and useful DOM elements for the class instance
         */
        this.dom = {
            /** @type {jQuery} altEditor handle */
            modal: $('<div class="dt-altEditor-handle"/>'),
        };


        /* Constructor logic */
        this._constructor();
    }



    $.extend(altEditor.prototype, {
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Constructor
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

        /**
         * Initialise the RowReorder instance
         *
         * @private
         */
        _constructor: function() {
            // console.log('altEditor Enabled')
            var that = this;
            var dt = this.s.dt;

            this._setup();

            dt.on('destroy.altEditor', function() {
                dt.off('.altEditor');
                $(dt.table().body()).off(that.s.namespace);
                $(document.body).off(that.s.namespace);
            });
        },

        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Private methods
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

        /**
         * Setup dom and bind button actions
         *
         * @private
         */
        _setup: function() {
            // console.log('Setup');

            var that = this;
            var dt = this.s.dt;

            // add modal
            $('body').append('\
            <div class="modal fade" id="altEditor-modal" tabindex="-1" role="dialog">\
              <div class="modal-dialog">\
                <div class="modal-content">\
                  <div class="modal-header">\
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>\
                    <h4 class="modal-title"></h4>\
                  </div>\
                  <div class="modal-body">\
                    <p></p>\
                  </div>\
                  <div class="modal-footer">\
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>\
                    <button type="button" class="btn btn-primary">Save changes</button>\
                  </div>\
                </div>\
              </div>\
            </div>');


            // add Edit Button
            if (this.s.dt.button('edit:name')) {
                this.s.dt.button('edit:name').action(function(e, dt, node, config) {
                    var rows = dt.rows({
                        selected: true
                    }).count();

                    that._openEditModal();
                });

                $(document).on('click', '#editRowBtn', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    that._editRowData();
                });

            }

            // add Delete Button
            if (this.s.dt.button('delete:name')) {
                this.s.dt.button('delete:name').action(function(e, dt, node, config) {
                    var rows = dt.rows({
                        selected: true
                    }).count();

                    that._openDeleteModal();
                });

                $(document).on('click', '#deleteRowBtn', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    that._deleteRow();
                });
            }

            // add Add Button
            if (this.s.dt.button('add:name')) {
                this.s.dt.button('add:name').action(function(e, dt, node, config) {
                    var rows = dt.rows({
                        selected: true
                    }).count();

                    that._openAddModal();
                });

                $(document).on('click', '#addRowBtn', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    that._addRowData();
                });
            }

        },

        /**
         * Emit an event on the DataTable for listeners
         *
         * @param  {string} name Event name
         * @param  {array} args Event arguments
         * @private
         */
        _emitEvent: function(name, args) {
            this.s.dt.iterator('table', function(ctx, i) {
                $(ctx.nTable).triggerHandler(name + '.dt', args);
            });
        },

        /**
         * Open Edit Modal for selected row
         *
         * @private
         */
        _openEditModal: function() {
            var that = this;
            var dt = this.s.dt;

            var columnDefs = [];

            for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
                columnDefs.push({
                    title: dt.context[0].aoColumns[i].sTitle,
                    dataType: dt.context[0].aoColumns[i].dataType,
                    isPrimary: dt.context[0].aoColumns[i].isPrimary,
                })
            }

            var adata = dt.rows({
                selected: true
            });


            var data = "";

            data += "<form class='form-horizontal' name='altEditor-form' role='form'>";

            for (var j in columnDefs) {
                var cellData = adata.data()[0][j];
                var inputSectionHTML = "<div class='form-group'><label for='__INPUT_NAME__' class='col-sm-4 control-label'>__INPUT_NAME__</label>__INPUT_HTML__</div>";

                var inputHTML = "<div class='col-sm-7'><input data-type='__INPUT_DATA_TYPE__' __INPUT_READ_ONLY_ATTRIBUTE__ type='__INPUT_TYPE__'  id='__INPUT_NAME__' name='__INPUT_NAME__' placeholder='__INPUT_NAME__' style='overflow:hidden'  class='form-control' value='__INPUT_VALUE__'></div>";

                var option1Checked = "";
                var option2Checked = "checked";
                if (cellData.dataType == "boolean") {
                    if(JSON.parse(cellData.value)) {
                        option1Checked = "checked";
                        option2Checked = "";
                    }
                    inputHTML = "<div class='col-sm-7'><div class='checkbox'><label><label class='radio-inline'><input data-type='__INPUT_DATA_TYPE__' __OPTION_1_CHECKED__ type='radio' name='__INPUT_NAME__' id='__INPUT_NAME__' value='1'>true</label><label class='radio-inline'><input data-type='__INPUT_DATA_TYPE__' __OPTION_2_CHECKED__ type='radio' name='__INPUT_NAME__' id='__INPUT_NAME__' value='0'>false</label></div></div>"
                }
                //set input type
                var inputType = "text";
                var inputReadOnlyAttribute = "";
                switch (cellData.dataType) {
                    case 'integer':
                        inputType = "number";
                        break;
                    case 'real':
                        inputType = "number";
                        break;
                    case 'boolean':
                        inputType = "checkbox";
                        break;
                    case 'long':
                        inputType = "number";
                        break;
                    case 'float':
                        inputType = "number";
                        break;
                    case 'text':
                        inputType = "text";
                        break;
                    case 'string_set':
                        inputType = "text";
                        break;
                }
                //set input to read-only if it is a primary key
                if (columnDefs[j].isPrimary) {
                    inputReadOnlyAttribute = "readonly"
                }

                //append input html
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_HTML__/g, inputHTML);
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_READ_ONLY_ATTRIBUTE__/g, inputReadOnlyAttribute);
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_TYPE__/g, inputType);
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_DATA_TYPE__/g, cellData.dataType);
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_VALUE__/g, cellData.value);
                inputSectionHTML = inputSectionHTML.replace(/__INPUT_NAME__/g, columnDefs[j].title);
                inputSectionHTML = inputSectionHTML.replace(/__OPTION_1_CHECKED__/g, option1Checked);
                inputSectionHTML = inputSectionHTML.replace(/__OPTION_2_CHECKED__/g, option2Checked);
                data += inputSectionHTML;
            }
            data += "</form>";


            $('#altEditor-modal').on('show.bs.modal', function() {
                $('#altEditor-modal').find('.modal-title').html('Edit Record');
                $('#altEditor-modal').find('.modal-body').html('<pre>' + data + '</pre>');
                $('#altEditor-modal').find('.modal-footer').html("<button type='button' data-content='remove' class='btn btn-default' data-dismiss='modal'>Close</button>\
               <button type='button' data-content='remove' class='btn btn-primary' id='editRowBtn'>Save Changes</button>");
            });

            $('#altEditor-modal').modal('show');
            $('#altEditor-modal input[0]').focus();

        },

        _editRowData: function() {
            var that = this;
            var dt = this.s.dt;

            var data = [];

            $('form[name="altEditor-form"] input').each(function(i) {
                var addToList = true;
                var value = $(this).val();
                if($(this).attr('type') == "radio" && $(this).prop('checked') == false) {
                    addToList = false;
                }
                value = $(this).attr('type') == "radio" ? $(this).val() == "1" : value;
                if (addToList){
                    data.push({
                        "value": value,
                        "dataType": $(this).attr('data-type')
                    });
                }
            });
            var editButtonCurrentText = $("#editRowBtn").text();
            $("#editRowBtn").addClass('disabled');
            $("#editRowBtn").text("Saving..");
            that._emitEvent("update-row", [
                JSON.stringify(data),
                function(isUpdated) {


                    //set error message and other properties based on whether update is successfull or not
                    var alertAdditionClasses = "alert-success";
                    var alertMessage = "This record has been updated";
                    var alertHeading = "Success";
                    if (!isUpdated) {
                        alertAdditionClasses = "alert-danger";
                        alertMessage = "Error occurred while updating this record";
                        alertHeading = "Error";
                    }

                    //create alert element html and append it to modal
                    var messageHTML = '\
                        <div class="alert __ALERT_ADDITION_CLASSES__" role="alert">\
                            <strong>__ALERT_HEADING__!</strong>\
                            __ALERT_MESSAGE__.\
                        </div>\
                    ';
                    messageHTML = messageHTML.replace(/__ALERT_ADDITION_CLASSES__/g, alertAdditionClasses);
                    messageHTML = messageHTML.replace(/__ALERT_HEADING__/g, alertHeading);
                    messageHTML = messageHTML.replace(/__ALERT_MESSAGE__/g, alertMessage);
                    $('#altEditor-modal .modal-body').append(messageHTML);

                    //update datatable, if update is successfull
                    if (isUpdated) {
                        dt.row({
                            selected: true
                        }).data(data);
                        //remove existing alert elements
                        $('#altEditor-modal').modal('hide');
                    }
                    $("#editRowBtn").removeClass('disabled');
                    $("#editRowBtn").text(editButtonCurrentText);
                }
            ]);
        },


        /**
         * Open Delete Modal for selected row
         *
         * @private
         */
        _openDeleteModal: function() {
            var that = this;
            var dt = this.s.dt;

            var columnDefs = [];

            for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
                columnDefs.push({
                    title: dt.context[0].aoColumns[i].sTitle
                })
            }

            var adata = dt.rows({
                selected: true
            });

            var data = "";

            data += "<form name='altEditor-form' role='form'>";
            for (var i in columnDefs) {
                var cellData = adata.data()[0][i];

                var inputType = "text";
                switch (cellData.dataType) {
                    case 'integer':
                        inputType = "number";
                        break;
                    case 'real':
                        inputType = "number";
                        break;
                    case 'boolean':
                        inputType = "checkbox";
                        break;
                    case 'long':
                        inputType = "number";
                        break;
                    case 'float':
                        inputType = "number";
                        break;
                    case 'text':
                        inputType = "text";
                        break;
                    case 'string_set':
                        inputType = "text";
                        break;
                }

                data += "<div class='form-group'><label for='" + columnDefs[i].title + "'>" + columnDefs[i].title + " : </label><input  type='hidden' data-type='" + inputType + "'  id='" + columnDefs[i].title + "' name='" + columnDefs[i].title + "' placeholder='" + columnDefs[i].title + "' style='overflow:hidden'  class='form-control' value='" + cellData.value + "' >" + cellData.value + "</input></div>";
            }
            data += "</form>";

            $('#altEditor-modal').on('show.bs.modal', function() {
                $('#altEditor-modal').find('.modal-title').html('Delete Record');
                $('#altEditor-modal').find('.modal-body').html('<pre>' + data + '</pre>');
                $('#altEditor-modal').find('.modal-footer').html("<button type='button' data-content='remove' class='btn btn-default' data-dismiss='modal'>Close</button>\
               <button type='button' data-content='remove' class='btn btn-danger' id='deleteRowBtn'>Delete</button>");
            });

            $('#altEditor-modal').modal('show');
            $('#altEditor-modal input[0]').focus();

        },

        _deleteRow: function() {
            var that = this;
            var dt = this.s.dt;

            var data = [];

            $('form[name="altEditor-form"] input').each(function(i) {
                var addToList = true;
                var value = $(this).val();
                value = $(this).val();

                console.log("Value : " + value);
                if (addToList){
                    data.push({
                        "value": value,
                        "dataType": $(this).attr('data-type')
                    });
                }
            });

            $('#altEditor-modal .modal-body .alert').remove();

            var message = '<div class="alert alert-success" role="alert">\
           <strong>Success!</strong> This record has been deleted.\
         </div>';

            $('#altEditor-modal .modal-body').append(message);


            that._emitEvent("delete-row", [
                            JSON.stringify(data),
                            function(isDeleted) {
                               if (isDeleted) {
                                    dt.row({
                                        selected: true
                                    }).remove();

                                    dt.draw();
                               }

                                //remove existing alert elements
                                $('#altEditor-modal').modal('hide');
                            }
                        ]);



        },


        /**
         * Open Add Modal for selected row
         *
         * @private
         */
        _openAddModal: function() {
            var that = this;
            var dt = this.s.dt;

            var columnDefs = [];

            for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
                columnDefs.push({
                    title: dt.context[0].aoColumns[i].sTitle,
                    dataType: dt.context[0].aoColumns[i].sType,
                    isPrimary: dt.context[0].aoColumns[i].isPrimary,
                    value : "",
                })
            }


           var data = "";

           data += "<form class='form-horizontal' name='altEditor-form' role='form'>";

           for (var j in columnDefs) {
               var inputSectionHTML = "<div class='form-group'><label for='__INPUT_NAME__' class='col-sm-4 control-label'>__INPUT_NAME__</label>__INPUT_HTML__</div>";

               var inputHTML = "<div class='col-sm-7'><input data-type='__INPUT_DATA_TYPE__' __INPUT_READ_ONLY_ATTRIBUTE__ type='__INPUT_TYPE__'  id='__INPUT_NAME__' name='__INPUT_NAME__' placeholder='__INPUT_NAME__' style='overflow:hidden'  class='form-control' value='__INPUT_VALUE__'></div>";

               var option1Checked = "";
               var option2Checked = "checked";
               if (columnDefs[j].dataType == "boolean") {
                   if(JSON.parse(columnDefs[j].value)) {
                       option1Checked = "checked";
                       option2Checked = "";
                   }
                   inputHTML = "<div class='col-sm-7'><div class='checkbox'><label><label class='radio-inline'><input data-type='__INPUT_DATA_TYPE__' __OPTION_1_CHECKED__ type='radio' name='__INPUT_NAME__' id='__INPUT_NAME__' value='1'>true</label><label class='radio-inline'><input data-type='__INPUT_DATA_TYPE__' __OPTION_2_CHECKED__ type='radio' name='__INPUT_NAME__' id='__INPUT_NAME__' value='0'>false</label></div></div>"
               }
               //set input type
               var inputType = "text";
               var inputReadOnlyAttribute = "";
               switch (columnDefs[j].dataType) {
                   case 'num':
                       inputType = "number";
                       break;
                   case 'string':
                       inputType = "text";
                       break;
               }
               //set input to read-only if it is a primary key
//               if (columnDefs[j].isPrimary) {
//                   inputReadOnlyAttribute = "readonly"
//               }

               //append input html
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_HTML__/g, inputHTML);
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_READ_ONLY_ATTRIBUTE__/g, inputReadOnlyAttribute);
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_TYPE__/g, inputType);
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_DATA_TYPE__/g, columnDefs[j].dataType);
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_VALUE__/g, columnDefs[j].value);
               inputSectionHTML = inputSectionHTML.replace(/__INPUT_NAME__/g, columnDefs[j].title);
               inputSectionHTML = inputSectionHTML.replace(/__OPTION_1_CHECKED__/g, option1Checked);
               inputSectionHTML = inputSectionHTML.replace(/__OPTION_2_CHECKED__/g, option2Checked);
               data += inputSectionHTML;
           }
           data += "</form>";


            $('#altEditor-modal').on('show.bs.modal', function() {
                $('#altEditor-modal').find('.modal-title').html('Add Record');
                $('#altEditor-modal').find('.modal-body').html('<pre>' + data + '</pre>');
                $('#altEditor-modal').find('.modal-footer').html("<button type='button' data-content='remove' class='btn btn-default' data-dismiss='modal'>Close</button>\
               <button type='button' data-content='remove' class='btn btn-primary' id='addRowBtn'>Add Record</button>");
            });

            $('#altEditor-modal').modal('show');
            $('#altEditor-modal input[0]').focus();
        },

        _addRowData: function() {
            console.log('add row')
            var that = this;
            var dt = this.s.dt;

            var data = [];

            $('form[name="altEditor-form"] input').each(function(i) {
                var addToList = true;
                var value = $(this).val();
                if($(this).attr('type') == "radio" && $(this).prop('checked') == false) {
                    addToList = false;
                }
                value = $(this).attr('type') == "radio" ? $(this).val() == "1" : value;
                if (addToList){
                    data.push({
                        "value": value,
                        "dataType": $(this).attr('data-type')
                    });
                }
            });
            var editButtonCurrentText = $("#editRowBtn").text();
            $("#addRowBtn").addClass('disabled');
            $("#addRowBtn").text("Saving..");

            console.log(JSON.stringify(data));

            that._emitEvent("add-row", [
                JSON.stringify(data),
                function(isAdded) {


                    //set error message and other properties based on whether update is successfull or not
                    var alertAdditionClasses = "alert-success";
                    var alertMessage = "This record has been added";
                    var alertHeading = "Success";
                    if (!isAdded) {
                        alertAdditionClasses = "alert-danger";
                        alertMessage = "Error occurred while adding this record";
                        alertHeading = "Error";
                    }

                    //create alert element html and append it to modal
                    var messageHTML = '\
                        <div class="alert __ALERT_ADDITION_CLASSES__" role="alert">\
                            <strong>__ALERT_HEADING__!</strong>\
                            __ALERT_MESSAGE__.\
                        </div>\
                    ';
                    messageHTML = messageHTML.replace(/__ALERT_ADDITION_CLASSES__/g, alertAdditionClasses);
                    messageHTML = messageHTML.replace(/__ALERT_HEADING__/g, alertHeading);
                    messageHTML = messageHTML.replace(/__ALERT_MESSAGE__/g, alertMessage);
                    $('#altEditor-modal .modal-body').append(messageHTML);

                    //update datatable, if update is successfull
                    if (isAdded) {
                        dt.row().data(data);
                        //remove existing alert elements
                        $('#altEditor-modal').modal('hide');
                    }
                    $("#addRowBtn").removeClass('disabled');
                    $("#addRowBtn").text(editButtonCurrentText);
                }
            ]);
        },

        _getExecutionLocationFolder: function() {
            var fileName = "dataTables.altEditor.js";
            var scriptList = $("script[src]");
            var jsFileObject = $.grep(scriptList, function(el) {

                if (el.src.indexOf(fileName) !== -1) {
                    return el;
                }
            });
            var jsFilePath = jsFileObject[0].src;
            var jsFileDirectory = jsFilePath.substring(0, jsFilePath.lastIndexOf("/") + 1);
            return jsFileDirectory;
        }
    });



    /**
     * altEditor version
     *
     * @static
     * @type      String
     */
    altEditor.version = '1.0';


    /**
     * altEditor defaults
     *
     * @namespace
     */
    altEditor.defaults = {
        /** @type {Boolean} Ask user what they want to do, even for a single option */
        alwaysAsk: false,

        /** @type {string|null} What will trigger a focus */
        focus: null, // focus, click, hover

        /** @type {column-selector} Columns to provide auto fill for */
        columns: '', // all

        /** @type {boolean|null} Update the cells after a drag */
        update: null, // false is editor given, true otherwise

        /** @type {DataTable.Editor} Editor instance for automatic submission */
        editor: null
    };


    /**
     * Classes used by altEditor that are configurable
     *
     * @namespace
     */
    altEditor.classes = {
        /** @type {String} Class used by the selection button */
        btn: 'btn'
    };


    // Attach a listener to the document which listens for DataTables initialisation
    // events so we can automatically initialise
    $(document).on('preInit.dt.altEditor', function(e, settings, json) {
        if (e.namespace !== 'dt') {
            return;
        }

        var init = settings.oInit.altEditor;
        var defaults = DataTable.defaults.altEditor;

        if (init || defaults) {
            var opts = $.extend({}, init, defaults);

            if (init !== false) {
                new altEditor(settings, opts);
            }
        }
    });


    // Alias for access
    DataTable.altEditor = altEditor;

    return altEditor;
}));


================================================
FILE: debug-db-base/src/main/assets/index.html
================================================
<!DOCTYPE html>
<!--
  ~ /*
  ~  *    Copyright (C) 2019 Amit Shekhar
  ~  *    Copyright (C) 2011 Android Open Source Project
  ~  *
  ~  *    Licensed under the Apache License, Version 2.0 (the "License");
  ~  *    you may not use this file except in compliance with the License.
  ~  *    You may obtain a copy of the License at
  ~  *
  ~  *        http://www.apache.org/licenses/LICENSE-2.0
  ~  *
  ~  *    Unless required by applicable law or agreed to in writing, software
  ~  *    distributed under the License is distributed on an "AS IS" BASIS,
  ~  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  *    See the License for the specific language governing permissions and
  ~  *    limitations under the License.
  ~  */
  -->

<html lang="en">
<head>
    <title>Android Debug Database</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel='shortcut icon' href='favicon.ico' type='image/x-icon'>

    <script src="jquery.min.js"></script>
    <script src="bootstrap.min.js"></script>
    <script src="jquery.dataTables.min.js"></script>
    <script src="dataTables.altEditor.free.js"></script>
    <script src="dataTables.buttons.min.js"></script>
    <script src="dataTables.select.min.js"></script>
    <script src="dataTables.responsive.min.js"></script>

    <link href="bootstrap.min.css" rel="stylesheet">
    <link href="custom.css" rel="stylesheet">
    <link href="jquery.dataTables.min.css" rel="stylesheet">
    <link href="buttons.dataTables.min.css" rel="stylesheet">
    <link href="select.dataTables.min.css" rel="stylesheet">
    <link href="responsive.dataTables.min.css" rel="stylesheet">

</head>
<body>

<!-- Navigation -->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
    <div class="container">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="index.html">Android Debug Database</a>
        </div>
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav navbar-right">
                <li>
                    <a href="https://github.com/amitshekhariitbhu/Android-Debug-Database"
                       target="_blank">GitHub</a>
                </li>
                <li>
                    <a href="https://twitter.com/amitiitbhu"
                       target="_blank">Twitter</a>
                </li>
                <li>
                    <a href="https://outcomeschool.com/blog"
                       target="_blank">Outcome School Blog</a>
                </li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Other Projects<b
                            class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li>
                            <a href="https://github.com/amitshekhariitbhu/Fast-Android-Networking"
                               target="_blank">Fast Android Networking</a>
                        </li>
                        <li>
                            <a href="https://github.com/amitshekhariitbhu/RxJava2-Android-Samples"
                               target="_blank">RxJava2 Android Samples</a>
                        </li>
                        <li>
                            <a href="https://github.com/amitshekhariitbhu/GlideBitmapPool"
                               target="_blank">Glide Bitmap Pool</a>
                        </li>
                        <li>
                            <a href="https://github.com/amitshekhariitbhu/awesome-android-complete-reference"
                               target="_blank">Awesome Android Complete Reference</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
        <!-- /.navbar-collapse -->
    </div>
    <!-- /.container -->
</nav>


<div class="container padding-fifty">

    <div class="row padding-twenty">
        <div class="col-sm-12">
            <div class="form-group">
                <label for="query">Query</label>
                <input class="form-control" id="query">
            </div>
            <button id="selected-db-download" type="button" onclick="downloadDb()"
                    class="btn btn-info">
                Download
            </button>
            <button id="selected-db-delete" type="button" onclick="deleteDb()" class="btn btn-info">
                Delete
            </button>
            <label id="selected-db-info" class="panel-info">Welcome</label>
            <button id="run-query" type="submit" onclick="queryFunction()"
                    class="btn btn-primary pull-right disabled">Run
                Query
            </button>
        </div>
    </div>


    <div class="row padding-twenty">

        <div class="col-sm-2">
            <div class="panel panel-info">
                <div class="panel-heading">Databases</div>
            </div>
            <div id="db-list" class="list-group">
            </div>
        </div>

        <div class="col-sm-2">
            <div class="panel panel-info">
                <div class="panel-heading">Tables</div>
            </div>
            <div id="table-list" class="list-group">
            </div>
        </div>

        <div id="parent-data-div" class="col-sm-8">
            <div class="panel panel-info">
                <div class="panel-heading">Data</div>
            </div>
        </div>
    </div>

    <div id="snackbar">Data Updated Successfully</div>

</div>

<script src="app.js"></script>
</body>
</html>


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/DebugDB.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar;

import android.content.Context;
import android.util.Log;
import android.util.Pair;

import androidx.sqlite.db.SupportSQLiteDatabase;

import com.amitshekhar.server.ClientServer;
import com.amitshekhar.sqlite.DBFactory;
import com.amitshekhar.utils.NetworkUtils;

import java.io.File;
import java.util.HashMap;

/**
 * Created by amitshekhar on 15/11/16.
 */

public class DebugDB {

    private static final String TAG = DebugDB.class.getSimpleName();
    private static final int DEFAULT_PORT = 8080;
    private static ClientServer clientServer;
    private static String addressLog = "not available";

    private DebugDB() {
        // This class in not publicly instantiable
    }

    public static void initialize(Context context, DBFactory dbFactory) {
        int portNumber;

        try {
            portNumber = Integer.valueOf(context.getString(R.string.PORT_NUMBER));
        } catch (NumberFormatException ex) {
            Log.e(TAG, "PORT_NUMBER should be integer", ex);
            portNumber = DEFAULT_PORT;
            Log.i(TAG, "Using Default port : " + DEFAULT_PORT);
        }

        clientServer = new ClientServer(context, portNumber, dbFactory);
        clientServer.start();
        addressLog = NetworkUtils.getAddressLog(context, portNumber);
        Log.d(TAG, addressLog);
    }

    public static String getAddressLog() {
        Log.d(TAG, addressLog);
        return addressLog;
    }

    public static void shutDown() {
        if (clientServer != null) {
            clientServer.stop();
            clientServer = null;
        }
    }

    public static void setCustomDatabaseFiles(HashMap<String, Pair<File, String>> customDatabaseFiles) {
        if (clientServer != null) {
            clientServer.setCustomDatabaseFiles(customDatabaseFiles);
        }
    }

    public static void setInMemoryRoomDatabases(HashMap<String, SupportSQLiteDatabase> databases) {
        if (clientServer != null) {
            clientServer.setInMemoryRoomDatabases(databases);
        }
    }

    public static boolean isServerRunning() {
        return clientServer != null && clientServer.isRunning();
    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/model/Response.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by amitshekhar on 15/11/16.
 */

public class Response {

    public List<Object> rows = new ArrayList<>();
    public List<String> columns = new ArrayList<>();
    public boolean isSuccessful;
    public String error;
    public int dbVersion;

    public Response() {

    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/model/RowDataRequest.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.model;

/**
 * Created by amitshekhar on 04/02/17.
 */

public class RowDataRequest {

    public String title;
    public boolean isPrimary;
    public String dataType;
    public String value;

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/model/TableDataResponse.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.model;

import java.util.List;

/**
 * Created by amitshekhar on 04/02/17.
 */

public class TableDataResponse {

    public List<TableInfo> tableInfos;
    public boolean isSuccessful;
    public List<Object> rows;
    public String errorMessage;
    public boolean isEditable;
    public boolean isSelectQuery;

    public static class TableInfo {
        public String title;
        public boolean isPrimary;
    }

    public static class ColumnData {
        public String dataType;
        public Object value;
    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/model/UpdateRowResponse.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.model;

/**
 * Created by amitshekhar on 04/02/17.
 */

public class UpdateRowResponse {

    public boolean isSuccessful;

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/server/ClientServer.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.server;

/**
 * Created by amitshekhar on 15/11/16.
 */

import android.content.Context;
import android.util.Log;
import android.util.Pair;

import androidx.sqlite.db.SupportSQLiteDatabase;

import com.amitshekhar.sqlite.DBFactory;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;

public class ClientServer implements Runnable {

    private static final String TAG = "ClientServer";

    private final int mPort;
    private final RequestHandler mRequestHandler;
    private boolean mIsRunning;
    private ServerSocket mServerSocket;

    public ClientServer(Context context, int port, DBFactory dbFactory) {
        mRequestHandler = new RequestHandler(context, dbFactory);
        mPort = port;
    }

    public void start() {
        mIsRunning = true;
        new Thread(this).start();
    }

    public void stop() {
        try {
            mIsRunning = false;
            if (null != mServerSocket) {
                mServerSocket.close();
                mServerSocket = null;
            }
        } catch (Exception e) {
            Log.e(TAG, "Error closing the server socket.", e);
        }
    }

    @Override
    public void run() {
        try {
            mServerSocket = new ServerSocket(mPort);
            while (mIsRunning) {
                Socket socket = mServerSocket.accept();
                mRequestHandler.handle(socket);
                socket.close();
            }
        } catch (SocketException e) {
            // The server was stopped; ignore.
        } catch (IOException e) {
            Log.e(TAG, "Web server error.", e);
        } catch (Exception ignore) {
            Log.e(TAG, "Exception.", ignore);
        }
    }

    public void setCustomDatabaseFiles(HashMap<String, Pair<File, String>> customDatabaseFiles) {
        mRequestHandler.setCustomDatabaseFiles(customDatabaseFiles);
    }

    public void setInMemoryRoomDatabases(HashMap<String, SupportSQLiteDatabase> databases) {
        mRequestHandler.setInMemoryRoomDatabases(databases);
    }

    public boolean isRunning() {
        return mIsRunning;
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/server/RequestHandler.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.server;

import android.content.Context;
import android.content.res.AssetManager;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Pair;

import androidx.sqlite.db.SupportSQLiteDatabase;

import com.amitshekhar.model.Response;
import com.amitshekhar.model.RowDataRequest;
import com.amitshekhar.model.TableDataResponse;
import com.amitshekhar.model.UpdateRowResponse;
import com.amitshekhar.sqlite.DBFactory;
import com.amitshekhar.sqlite.InMemoryDebugSQLiteDB;
import com.amitshekhar.sqlite.SQLiteDB;
import com.amitshekhar.utils.Constants;
import com.amitshekhar.utils.DatabaseFileProvider;
import com.amitshekhar.utils.DatabaseHelper;
import com.amitshekhar.utils.PrefHelper;
import com.amitshekhar.utils.Utils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class RequestHandler {

    private final Context mContext;
    private final Gson mGson;
    private final AssetManager mAssets;
    private final DBFactory mDbFactory;
    private boolean isDbOpened;
    private SQLiteDB sqLiteDB;
    private HashMap<String, Pair<File, String>> mDatabaseFiles;
    private HashMap<String, Pair<File, String>> mCustomDatabaseFiles;
    private String mSelectedDatabase = null;
    private HashMap<String, SupportSQLiteDatabase> mRoomInMemoryDatabases = new HashMap<>();

    public RequestHandler(Context context, DBFactory dbFactory) {
        mContext = context;
        mAssets = context.getResources().getAssets();
        mGson = new GsonBuilder().serializeNulls().create();
        mDbFactory = dbFactory;
    }

    public void handle(Socket socket) throws IOException {
        BufferedReader reader = null;
        PrintStream output = null;
        try {
            String route = null;

            // Read HTTP headers and parse out the route.
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line;
            while (!TextUtils.isEmpty(line = reader.readLine())) {
                if (line.startsWith("GET /")) {
                    int start = line.indexOf('/') + 1;
                    int end = line.indexOf(' ', start);
                    route = line.substring(start, end);
                    break;
                }
            }

            // Output stream that we send the response to
            output = new PrintStream(socket.getOutputStream());

            if (route == null || route.isEmpty()) {
                route = "index.html";
            }

            byte[] bytes;

            if (route.startsWith("getDbList")) {
                final String response = getDBListResponse();
                bytes = response.getBytes();
            } else if (route.startsWith("getAllDataFromTheTable")) {
                final String response = getAllDataFromTheTableResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("getTableList")) {
                final String response = getTableListResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("addTableData")) {
                final String response = addTableDataAndGetResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("updateTableData")) {
                final String response = updateTableDataAndGetResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("deleteTableData")) {
                final String response = deleteTableDataAndGetResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("query")) {
                final String response = executeQueryAndGetResponse(route);
                bytes = response.getBytes();
            } else if (route.startsWith("deleteDb")) {
                final String response = deleteSelectedDatabaseAndGetResponse();
                bytes = response.getBytes();
            } else if (route.startsWith("downloadDb")) {
                bytes = Utils.getDatabase(mSelectedDatabase, mDatabaseFiles);
            } else {
                bytes = Utils.loadContent(route, mAssets);
            }

            if (null == bytes) {
                writeServerError(output);
                return;
            }

            // Send out the content.
            output.println("HTTP/1.0 200 OK");
            output.println("Content-Type: " + Utils.detectMimeType(route));

            if (route.startsWith("downloadDb")) {
                output.println("Content-Disposition: attachment; filename=" + mSelectedDatabase);
            } else {
                output.println("Content-Length: " + bytes.length);
            }
            output.println();
            output.write(bytes);
            output.flush();
        } finally {
            try {
                if (null != output) {
                    output.close();
                }
                if (null != reader) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setCustomDatabaseFiles(HashMap<String, Pair<File, String>> customDatabaseFiles) {
        mCustomDatabaseFiles = customDatabaseFiles;
    }

    public void setInMemoryRoomDatabases(HashMap<String, SupportSQLiteDatabase> databases) {
        mRoomInMemoryDatabases = databases;
    }

    private void writeServerError(PrintStream output) {
        output.println("HTTP/1.0 500 Internal Server Error");
        output.flush();
    }

    private void openDatabase(String database) {
        closeDatabase();
        if (mRoomInMemoryDatabases.containsKey(database)) {
            sqLiteDB = new InMemoryDebugSQLiteDB(mRoomInMemoryDatabases.get(database));
        } else {
            File databaseFile = mDatabaseFiles.get(database).first;
            String password = mDatabaseFiles.get(database).second;
            sqLiteDB = mDbFactory.create(mContext, databaseFile.getAbsolutePath(), password);
        }
        isDbOpened = true;
    }

    private void closeDatabase() {
        if (sqLiteDB != null && sqLiteDB.isOpen()) {
            sqLiteDB.close();
        }
        sqLiteDB = null;
        isDbOpened = false;
    }

    private String getDBListResponse() {
        mDatabaseFiles = DatabaseFileProvider.getDatabaseFiles(mContext);
        if (mCustomDatabaseFiles != null) {
            mDatabaseFiles.putAll(mCustomDatabaseFiles);
        }
        Response response = new Response();
        if (mDatabaseFiles != null) {
            for (HashMap.Entry<String, Pair<File, String>> entry : mDatabaseFiles.entrySet()) {
                String[] dbEntry = {entry.getKey(), !entry.getValue().second.equals("") ? "true" : "false", "true"};
                response.rows.add(dbEntry);
            }
        }
        if (mRoomInMemoryDatabases != null) {
            for (HashMap.Entry<String, SupportSQLiteDatabase> entry : mRoomInMemoryDatabases.entrySet()) {
                String[] dbEntry = {entry.getKey(), "false", "false"};
                response.rows.add(dbEntry);
            }
        }
        response.rows.add(new String[]{Constants.APP_SHARED_PREFERENCES, "false", "false"});
        response.isSuccessful = true;
        return mGson.toJson(response);
    }

    private String getAllDataFromTheTableResponse(String route) {

        String tableName = null;

        if (route.contains("?tableName=")) {
            tableName = route.substring(route.indexOf("=") + 1, route.length());
        }

        TableDataResponse response;

        if (isDbOpened) {
            String sql = "SELECT * FROM " + tableName;
            response = DatabaseHelper.getTableData(sqLiteDB, sql, tableName);
        } else {
            response = PrefHelper.getAllPrefData(mContext, tableName);
        }

        return mGson.toJson(response);

    }

    private String executeQueryAndGetResponse(String route) {
        String query = null;
        String data = null;
        String first;
        try {
            if (route.contains("?query=")) {
                query = route.substring(route.indexOf("=") + 1, route.length());
            }
            try {
                query = URLDecoder.decode(query, "UTF-8");
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (query != null) {
                String[] statements = query.split(";");

                for (int i = 0; i < statements.length; i++) {

                    String aQuery = statements[i].trim();
                    first = aQuery.split(" ")[0].toLowerCase();
                    if (first.equals("select") || first.equals("pragma")) {
                        TableDataResponse response = DatabaseHelper.getTableData(sqLiteDB, aQuery, null);
                        data = mGson.toJson(response);
                        if (!response.isSuccessful) {
                            break;
                        }
                    } else {
                        TableDataResponse response = DatabaseHelper.exec(sqLiteDB, aQuery);
                        data = mGson.toJson(response);
                        if (!response.isSuccessful) {
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (data == null) {
            Response response = new Response();
            response.isSuccessful = false;
            data = mGson.toJson(response);
        }

        return data;
    }

    private String getTableListResponse(String route) {
        String database = null;
        if (route.contains("?database=")) {
            database = route.substring(route.indexOf("=") + 1, route.length());
        }

        Response response;

        if (Constants.APP_SHARED_PREFERENCES.equals(database)) {
            response = PrefHelper.getAllPrefTableName(mContext);
            closeDatabase();
            mSelectedDatabase = Constants.APP_SHARED_PREFERENCES;
        } else {
            openDatabase(database);
            response = DatabaseHelper.getAllTableName(sqLiteDB);
            mSelectedDatabase = database;
        }
        return mGson.toJson(response);
    }


    private String addTableDataAndGetResponse(String route) {
        UpdateRowResponse response;
        try {
            Uri uri = Uri.parse(URLDecoder.decode(route, "UTF-8"));
            String tableName = uri.getQueryParameter("tableName");
            String updatedData = uri.getQueryParameter("addData");
            List<RowDataRequest> rowDataRequests = mGson.fromJson(updatedData, new TypeToken<List<RowDataRequest>>() {
            }.getType());
            if (Constants.APP_SHARED_PREFERENCES.equals(mSelectedDatabase)) {
                response = PrefHelper.addOrUpdateRow(mContext, tableName, rowDataRequests);
            } else {
                response = DatabaseHelper.addRow(sqLiteDB, tableName, rowDataRequests);
            }
            return mGson.toJson(response);
        } catch (Exception e) {
            e.printStackTrace();
            response = new UpdateRowResponse();
            response.isSuccessful = false;
            return mGson.toJson(response);
        }
    }

    private String updateTableDataAndGetResponse(String route) {
        UpdateRowResponse response;
        try {
            Uri uri = Uri.parse(URLDecoder.decode(route, "UTF-8"));
            String tableName = uri.getQueryParameter("tableName");
            String updatedData = uri.getQueryParameter("updatedData");
            List<RowDataRequest> rowDataRequests = mGson.fromJson(updatedData, new TypeToken<List<RowDataRequest>>() {
            }.getType());
            if (Constants.APP_SHARED_PREFERENCES.equals(mSelectedDatabase)) {
                response = PrefHelper.addOrUpdateRow(mContext, tableName, rowDataRequests);
            } else {
                response = DatabaseHelper.updateRow(sqLiteDB, tableName, rowDataRequests);
            }
            return mGson.toJson(response);
        } catch (Exception e) {
            e.printStackTrace();
            response = new UpdateRowResponse();
            response.isSuccessful = false;
            return mGson.toJson(response);
        }
    }


    private String deleteTableDataAndGetResponse(String route) {
        UpdateRowResponse response;
        try {
            Uri uri = Uri.parse(URLDecoder.decode(route, "UTF-8"));
            String tableName = uri.getQueryParameter("tableName");
            String updatedData = uri.getQueryParameter("deleteData");
            List<RowDataRequest> rowDataRequests = mGson.fromJson(updatedData, new TypeToken<List<RowDataRequest>>() {
            }.getType());
            if (Constants.APP_SHARED_PREFERENCES.equals(mSelectedDatabase)) {
                response = PrefHelper.deleteRow(mContext, tableName, rowDataRequests);
            } else {
                response = DatabaseHelper.deleteRow(sqLiteDB, tableName, rowDataRequests);
            }
            return mGson.toJson(response);
        } catch (Exception e) {
            e.printStackTrace();
            response = new UpdateRowResponse();
            response.isSuccessful = false;
            return mGson.toJson(response);
        }
    }

    private String deleteSelectedDatabaseAndGetResponse() {
        UpdateRowResponse response = new UpdateRowResponse();

        if (mSelectedDatabase == null || !mDatabaseFiles.containsKey(mSelectedDatabase)) {
            response.isSuccessful = false;
            return mGson.toJson(response);
        }

        try {
            closeDatabase();

            File dbFile = mDatabaseFiles.get(mSelectedDatabase).first;
            response.isSuccessful = dbFile.delete();

            if (response.isSuccessful) {
                mDatabaseFiles.remove(mSelectedDatabase);
                mCustomDatabaseFiles.remove(mSelectedDatabase);
            }

            return mGson.toJson(response);
        } catch (Exception e) {
            e.printStackTrace();
            response.isSuccessful = false;
            return mGson.toJson(response);
        }
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/DBFactory.java
================================================
package com.amitshekhar.sqlite;

import android.content.Context;

public interface DBFactory {

    SQLiteDB create(Context context, String path, String password);

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/InMemoryDebugSQLiteDB.java
================================================
package com.amitshekhar.sqlite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;

import androidx.sqlite.db.SupportSQLiteDatabase;

/**
 * Created by anandgaurav on 12/02/18.
 */

public class InMemoryDebugSQLiteDB implements SQLiteDB {

    private final SupportSQLiteDatabase database;

    public InMemoryDebugSQLiteDB(SupportSQLiteDatabase database) {
        this.database = database;
    }

    @Override
    public int delete(String table, String whereClause, String[] whereArgs) {
        return database.delete(table, whereClause, whereArgs);
    }

    @Override
    public boolean isOpen() {
        return database.isOpen();
    }

    @Override
    public void close() {
        // no ops
    }

    @Override
    public Cursor rawQuery(String sql, String[] selectionArgs) {
        return database.query(sql, selectionArgs);
    }

    @Override
    public void execSQL(String sql) throws SQLException {
        database.execSQL(sql);
    }

    @Override
    public long insert(String table, String nullColumnHack, ContentValues values) {
        return database.insert(table, 0, values);
    }

    @Override
    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
        return database.update(table, 0, values, whereClause, whereArgs);
    }

    @Override
    public int getVersion() {
        return database.getVersion();
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/SQLiteDB.java
================================================
package com.amitshekhar.sqlite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;


/**
 * Created by anandgaurav on 12/02/18.
 */

public interface SQLiteDB {

    int delete(String table, String whereClause, String[] whereArgs);

    boolean isOpen();

    void close();

    Cursor rawQuery(String sql, String[] selectionArgs);

    void execSQL(String sql) throws SQLException;

    long insert(String table, String nullColumnHack, ContentValues values);

    int update(String table, ContentValues values, String whereClause, String[] whereArgs);

    int getVersion();

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/Constants.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

/**
 * Created by amitshekhar on 16/11/16.
 */

public final class Constants {

    private Constants() {
        // This class in not publicly instantiable
    }

    public static final String APP_SHARED_PREFERENCES = "APP_SHARED_PREFERENCES";
    public static final String PK = "pk";
    public static final String NAME = "name";
    public static final String NULL = "null";

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/ConverterUtils.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import java.io.UnsupportedEncodingException;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class ConverterUtils {

    private static final int MAX_BLOB_LENGTH = 512;

    private static final String UNKNOWN_BLOB_LABEL = "{blob}";

    private ConverterUtils() {
        // This class in not publicly instantiable
    }

    public static String blobToString(byte[] blob) {
        if (blob.length <= MAX_BLOB_LENGTH) {
            if (fastIsAscii(blob)) {
                try {
                    return new String(blob, "US-ASCII");
                } catch (UnsupportedEncodingException ignored) {

                }
            }
        }
        return UNKNOWN_BLOB_LABEL;
    }

    public static boolean fastIsAscii(byte[] blob) {
        for (byte b : blob) {
            if ((b & ~0x7f) != 0) {
                return false;
            }
        }
        return true;
    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DataType.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

/**
 * Created by amitshekhar on 04/02/17.
 */

public class DataType {

    private DataType() {
        // This class in not publicly instantiable
    }

    public static final String BOOLEAN = "boolean";
    public static final String INTEGER = "integer";
    public static final String REAL = "real";
    public static final String TEXT = "text";
    public static final String LONG = "long";
    public static final String FLOAT = "float";
    public static final String STRING_SET = "string_set";

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseFileProvider.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import android.content.Context;
import android.util.Pair;

import java.io.File;
import java.text.MessageFormat;
import java.util.HashMap;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class DatabaseFileProvider {

    private final static String DB_PASSWORD_RESOURCE = "DB_PASSWORD_{0}";

    private DatabaseFileProvider() {
        // This class in not publicly instantiable
    }

    public static HashMap<String, Pair<File, String>> getDatabaseFiles(Context context) {
        HashMap<String, Pair<File, String>> databaseFiles = new HashMap<>();
        try {
            for (String databaseName : context.databaseList()) {
                String password = getDbPasswordFromStringResources(context, databaseName);
                databaseFiles.put(databaseName, new Pair<>(context.getDatabasePath(databaseName), password));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return databaseFiles;
    }

    private static String getDbPasswordFromStringResources(Context context, String name) {
        String nameWithoutExt = name;
        if (nameWithoutExt.endsWith(".db")) {
            nameWithoutExt = nameWithoutExt.substring(0, nameWithoutExt.lastIndexOf('.'));
        }
        String resourceName = MessageFormat.format(DB_PASSWORD_RESOURCE, nameWithoutExt.toUpperCase());
        String password = "";

        int resourceId = context.getResources().getIdentifier(resourceName, "string", context.getPackageName());

        if (resourceId != 0) {
            password = context.getString(resourceId);
        }

        return password;
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseHelper.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import android.content.ContentValues;
import android.database.Cursor;
import android.text.TextUtils;

import com.amitshekhar.model.Response;
import com.amitshekhar.model.RowDataRequest;
import com.amitshekhar.model.TableDataResponse;
import com.amitshekhar.model.UpdateRowResponse;
import com.amitshekhar.sqlite.SQLiteDB;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class DatabaseHelper {

    private DatabaseHelper() {
        // This class in not publicly instantiable
    }

    public static Response getAllTableName(SQLiteDB database) {
        Response response = new Response();
        Cursor c = database.rawQuery("SELECT name FROM sqlite_master WHERE type='table' OR type='view' ORDER BY name COLLATE NOCASE", null);
        if (c.moveToFirst()) {
            while (!c.isAfterLast()) {
                response.rows.add(c.getString(0));
                c.moveToNext();
            }
        }
        c.close();
        response.isSuccessful = true;
        try {
            response.dbVersion = database.getVersion();
        } catch (Exception ignore) {

        }
        return response;
    }

    public static TableDataResponse getTableData(SQLiteDB db, String selectQuery, String tableName) {

        TableDataResponse tableData = new TableDataResponse();
        tableData.isSelectQuery = true;
        if (tableName == null) {
            tableName = getTableName(selectQuery);
        }

        final String quotedTableName = getQuotedTableName(tableName);

        if (tableName != null) {
            final String pragmaQuery = "PRAGMA table_info(" + quotedTableName + ")";
            tableData.tableInfos = getTableInfo(db, pragmaQuery);
        }
        Cursor cursor = null;
        boolean isView = false;
        try {
            cursor = db.rawQuery("SELECT type FROM sqlite_master WHERE name=?",
                    new String[]{quotedTableName});
            if (cursor.moveToFirst()) {
                isView = "view".equalsIgnoreCase(cursor.getString(0));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        tableData.isEditable = tableName != null && tableData.tableInfos != null && !isView;


        if (!TextUtils.isEmpty(tableName)) {
            selectQuery = selectQuery.replace(tableName, quotedTableName);
        }

        try {
            cursor = db.rawQuery(selectQuery, null);
        } catch (Exception e) {
            e.printStackTrace();
            tableData.isSuccessful = false;
            tableData.errorMessage = e.getMessage();
            return tableData;
        }

        if (cursor != null) {
            cursor.moveToFirst();

            // setting tableInfo when tableName is not known and making
            // it non-editable also by making isPrimary true for all
            if (tableData.tableInfos == null) {
                tableData.tableInfos = new ArrayList<>();
                for (int i = 0; i < cursor.getColumnCount(); i++) {
                    TableDataResponse.TableInfo tableInfo = new TableDataResponse.TableInfo();
                    tableInfo.title = cursor.getColumnName(i);
                    tableInfo.isPrimary = true;
                    tableData.tableInfos.add(tableInfo);
                }
            }

            tableData.isSuccessful = true;
            tableData.rows = new ArrayList<>();

            String[] columnNames = cursor.getColumnNames();

            List<TableDataResponse.TableInfo> tableInfoListModified = new ArrayList<>();

            for (String columnName : columnNames) {
                for (TableDataResponse.TableInfo tableInfo : tableData.tableInfos) {
                    if (columnName.equals(tableInfo.title)) {
                        tableInfoListModified.add(tableInfo);
                        break;
                    }
                }
            }

            if (tableData.tableInfos.size() != tableInfoListModified.size()) {
                tableData.tableInfos = tableInfoListModified;
                tableData.isEditable = false;
            }

            if (cursor.getCount() > 0) {

                do {
                    List<TableDataResponse.ColumnData> row = new ArrayList<>();
                    for (int i = 0; i < cursor.getColumnCount(); i++) {
                        TableDataResponse.ColumnData columnData = new TableDataResponse.ColumnData();
                        switch (cursor.getType(i)) {
                            case Cursor.FIELD_TYPE_BLOB:
                                columnData.dataType = DataType.TEXT;
                                columnData.value = ConverterUtils.blobToString(cursor.getBlob(i));
                                break;
                            case Cursor.FIELD_TYPE_FLOAT:
                                columnData.dataType = DataType.REAL;
                                columnData.value = cursor.getDouble(i);
                                break;
                            case Cursor.FIELD_TYPE_INTEGER:
                                columnData.dataType = DataType.INTEGER;
                                columnData.value = cursor.getLong(i);
                                break;
                            case Cursor.FIELD_TYPE_STRING:
                                columnData.dataType = DataType.TEXT;
                                columnData.value = cursor.getString(i);
                                break;
                            default:
                                columnData.dataType = DataType.TEXT;
                                columnData.value = cursor.getString(i);
                        }
                        row.add(columnData);
                    }
                    tableData.rows.add(row);

                } while (cursor.moveToNext());
            }
            cursor.close();
            return tableData;
        } else {
            tableData.isSuccessful = false;
            tableData.errorMessage = "Cursor is null";
            return tableData;
        }

    }


    private static String getQuotedTableName(String tableName) {
        return String.format("[%s]", tableName);
    }

    private static List<TableDataResponse.TableInfo> getTableInfo(SQLiteDB db, String pragmaQuery) {

        Cursor cursor;
        try {
            cursor = db.rawQuery(pragmaQuery, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        if (cursor != null) {

            List<TableDataResponse.TableInfo> tableInfoList = new ArrayList<>();

            cursor.moveToFirst();

            if (cursor.getCount() > 0) {
                do {
                    TableDataResponse.TableInfo tableInfo = new TableDataResponse.TableInfo();

                    for (int i = 0; i < cursor.getColumnCount(); i++) {

                        final String columnName = cursor.getColumnName(i);

                        switch (columnName) {
                            case Constants.PK:
                                tableInfo.isPrimary = cursor.getInt(i) == 1;
                                break;
                            case Constants.NAME:
                                tableInfo.title = cursor.getString(i);
                                break;
                            default:
                        }

                    }
                    tableInfoList.add(tableInfo);

                } while (cursor.moveToNext());
            }
            cursor.close();
            return tableInfoList;
        }
        return null;
    }


    public static UpdateRowResponse addRow(SQLiteDB db, String tableName,
                                           List<RowDataRequest> rowDataRequests) {
        UpdateRowResponse updateRowResponse = new UpdateRowResponse();

        if (rowDataRequests == null || tableName == null) {
            updateRowResponse.isSuccessful = false;
            return updateRowResponse;
        }

        tableName = getQuotedTableName(tableName);

        ContentValues contentValues = new ContentValues();

        for (RowDataRequest rowDataRequest : rowDataRequests) {
            if (Constants.NULL.equals(rowDataRequest.value)) {
                rowDataRequest.value = null;
            }

            switch (rowDataRequest.dataType) {
                case DataType.INTEGER:
                    contentValues.put(rowDataRequest.title, Long.valueOf(rowDataRequest.value));
                    break;
                case DataType.REAL:
                    contentValues.put(rowDataRequest.title, Double.valueOf(rowDataRequest.value));
                    break;
                case DataType.TEXT:
                    contentValues.put(rowDataRequest.title, rowDataRequest.value);
                    break;
                default:
                    contentValues.put(rowDataRequest.title, rowDataRequest.value);
                    break;
            }
        }

        long result = db.insert(tableName, null, contentValues);
        updateRowResponse.isSuccessful = result > 0;

        return updateRowResponse;

    }


    public static UpdateRowResponse updateRow(SQLiteDB db, String tableName, List<RowDataRequest> rowDataRequests) {

        UpdateRowResponse updateRowResponse = new UpdateRowResponse();

        if (rowDataRequests == null || tableName == null) {
            updateRowResponse.isSuccessful = false;
            return updateRowResponse;
        }

        tableName = getQuotedTableName(tableName);

        ContentValues contentValues = new ContentValues();

        String whereClause = null;
        List<String> whereArgsList = new ArrayList<>();

        for (RowDataRequest rowDataRequest : rowDataRequests) {
            if (Constants.NULL.equals(rowDataRequest.value)) {
                rowDataRequest.value = null;
            }
            if (rowDataRequest.isPrimary) {
                if (whereClause == null) {
                    whereClause = rowDataRequest.title + "=? ";
                } else {
                    whereClause = whereClause + "and " + rowDataRequest.title + "=? ";
                }
                whereArgsList.add(rowDataRequest.value);
            } else {
                switch (rowDataRequest.dataType) {
                    case DataType.INTEGER:
                        contentValues.put(rowDataRequest.title, Long.valueOf(rowDataRequest.value));
                        break;
                    case DataType.REAL:
                        contentValues.put(rowDataRequest.title, Double.valueOf(rowDataRequest.value));
                        break;
                    case DataType.TEXT:
                        contentValues.put(rowDataRequest.title, rowDataRequest.value);
                        break;
                    default:
                }
            }
        }

        String[] whereArgs = new String[whereArgsList.size()];

        for (int i = 0; i < whereArgsList.size(); i++) {
            whereArgs[i] = whereArgsList.get(i);
        }

        db.update(tableName, contentValues, whereClause, whereArgs);
        updateRowResponse.isSuccessful = true;
        return updateRowResponse;
    }


    public static UpdateRowResponse deleteRow(SQLiteDB db, String tableName,
                                              List<RowDataRequest> rowDataRequests) {

        UpdateRowResponse updateRowResponse = new UpdateRowResponse();

        if (rowDataRequests == null || tableName == null) {
            updateRowResponse.isSuccessful = false;
            return updateRowResponse;
        }

        tableName = getQuotedTableName(tableName);


        String whereClause = null;
        List<String> whereArgsList = new ArrayList<>();

        for (RowDataRequest rowDataRequest : rowDataRequests) {
            if (Constants.NULL.equals(rowDataRequest.value)) {
                rowDataRequest.value = null;
            }
            if (rowDataRequest.isPrimary) {
                if (whereClause == null) {
                    whereClause = rowDataRequest.title + "=? ";
                } else {
                    whereClause = whereClause + "and " + rowDataRequest.title + "=? ";
                }
                whereArgsList.add(rowDataRequest.value);
            }
        }

        if (whereArgsList.size() == 0) {
            updateRowResponse.isSuccessful = true;
            return updateRowResponse;
        }

        String[] whereArgs = new String[whereArgsList.size()];

        for (int i = 0; i < whereArgsList.size(); i++) {
            whereArgs[i] = whereArgsList.get(i);
        }

        db.delete(tableName, whereClause, whereArgs);
        updateRowResponse.isSuccessful = true;
        return updateRowResponse;
    }


    public static TableDataResponse exec(SQLiteDB database, String sql) {
        TableDataResponse tableDataResponse = new TableDataResponse();
        tableDataResponse.isSelectQuery = false;
        try {

            String tableName = getTableName(sql);

            if (!TextUtils.isEmpty(tableName)) {
                String quotedTableName = getQuotedTableName(tableName);
                sql = sql.replace(tableName, quotedTableName);
            }

            database.execSQL(sql);
        } catch (Exception e) {
            e.printStackTrace();
            tableDataResponse.isSuccessful = false;
            tableDataResponse.errorMessage = e.getMessage();
            return tableDataResponse;
        }
        tableDataResponse.isSuccessful = true;
        return tableDataResponse;
    }

    private static String getTableName(String selectQuery) {
        // TODO: Handle JOIN Query
        TableNameParser tableNameParser = new TableNameParser(selectQuery);
        HashSet<String> tableNames = (HashSet<String>) tableNameParser.tables();

        for (String tableName : tableNames) {
            if (!TextUtils.isEmpty(tableName)) {
                return tableName;
            }
        }

        return null;
    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/NetworkUtils.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.wifi.WifiManager;

/**
 * Created by amitshekhar on 15/11/16.
 */

public final class NetworkUtils {

    private NetworkUtils() {
        // This class in not publicly instantiable
    }

    public static String getAddressLog(Context context, int port) {
        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
        @SuppressLint("DefaultLocale")
        final String formattedIpAddress = String.format("%d.%d.%d.%d",
                (ipAddress & 0xff),
                (ipAddress >> 8 & 0xff),
                (ipAddress >> 16 & 0xff),
                (ipAddress >> 24 & 0xff));
        return "Open http://" + formattedIpAddress + ":" + port + " in your browser";
    }

}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/PrefHelper.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import android.content.Context;
import android.content.SharedPreferences;

import com.amitshekhar.model.Response;
import com.amitshekhar.model.RowDataRequest;
import com.amitshekhar.model.TableDataResponse;
import com.amitshekhar.model.UpdateRowResponse;

import org.json.JSONArray;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class PrefHelper {

    private static final String PREFS_SUFFIX = ".xml";

    private PrefHelper() {
        // This class in not publicly instantiable
    }

    public static List<String> getSharedPreferenceTags(Context context) {

        ArrayList<String> tags = new ArrayList<>();

        String rootPath = context.getApplicationInfo().dataDir + "/shared_prefs";
        File root = new File(rootPath);
        if (root.exists()) {
            for (File file : root.listFiles()) {
                String fileName = file.getName();
                if (fileName.endsWith(PREFS_SUFFIX)) {
                    tags.add(fileName.substring(0, fileName.length() - PREFS_SUFFIX.length()));
                }
            }
        }

        Collections.sort(tags);

        return tags;
    }

    public static Response getAllPrefTableName(Context context) {

        Response response = new Response();

        List<String> prefTags = getSharedPreferenceTags(context);

        for (String tag : prefTags) {
            response.rows.add(tag);
        }

        response.isSuccessful = true;

        return response;
    }

    public static TableDataResponse getAllPrefData(Context context, String tag) {

        TableDataResponse response = new TableDataResponse();
        response.isEditable = true;
        response.isSuccessful = true;
        response.isSelectQuery = true;

        TableDataResponse.TableInfo keyInfo = new TableDataResponse.TableInfo();
        keyInfo.isPrimary = true;
        keyInfo.title = "Key";

        TableDataResponse.TableInfo valueInfo = new TableDataResponse.TableInfo();
        valueInfo.isPrimary = false;
        valueInfo.title = "Value";

        response.tableInfos = new ArrayList<>();
        response.tableInfos.add(keyInfo);
        response.tableInfos.add(valueInfo);

        response.rows = new ArrayList<>();

        SharedPreferences preferences = context.getSharedPreferences(tag, Context.MODE_PRIVATE);
        Map<String, ?> allEntries = preferences.getAll();
        for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
            List<TableDataResponse.ColumnData> row = new ArrayList<>();
            TableDataResponse.ColumnData keyColumnData = new TableDataResponse.ColumnData();
            keyColumnData.dataType = DataType.TEXT;
            keyColumnData.value = entry.getKey();

            row.add(keyColumnData);

            TableDataResponse.ColumnData valueColumnData = new TableDataResponse.ColumnData();
            valueColumnData.value = entry.getValue().toString();
            if (entry.getValue() != null) {
                if (entry.getValue() instanceof String) {
                    valueColumnData.dataType = DataType.TEXT;
                } else if (entry.getValue() instanceof Integer) {
                    valueColumnData.dataType = DataType.INTEGER;
                } else if (entry.getValue() instanceof Long) {
                    valueColumnData.dataType = DataType.LONG;
                } else if (entry.getValue() instanceof Float) {
                    valueColumnData.dataType = DataType.FLOAT;
                } else if (entry.getValue() instanceof Boolean) {
                    valueColumnData.dataType = DataType.BOOLEAN;
                } else if (entry.getValue() instanceof Set) {
                    valueColumnData.dataType = DataType.STRING_SET;
                }
            } else {
                valueColumnData.dataType = DataType.TEXT;
            }
            row.add(valueColumnData);
            response.rows.add(row);
        }

        return response;

    }

    public static UpdateRowResponse addOrUpdateRow(Context context, String tableName,
                                                   List<RowDataRequest> rowDataRequests) {
        UpdateRowResponse updateRowResponse = new UpdateRowResponse();

        if (tableName == null) {
            return updateRowResponse;
        }

        RowDataRequest rowDataKey = rowDataRequests.get(0);
        RowDataRequest rowDataValue = rowDataRequests.get(1);

        String key = rowDataKey.value;
        String value = rowDataValue.value;
        String dataType = rowDataValue.dataType;

        if (Constants.NULL.equals(value)) {
            value = null;
        }

        SharedPreferences preferences = context.getSharedPreferences(tableName, Context.MODE_PRIVATE);

        try {
            switch (dataType) {
                case DataType.TEXT:
                    preferences.edit().putString(key, value).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                case DataType.INTEGER:
                    preferences.edit().putInt(key, Integer.valueOf(value)).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                case DataType.LONG:
                    preferences.edit().putLong(key, Long.valueOf(value)).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                case DataType.FLOAT:
                    preferences.edit().putFloat(key, Float.valueOf(value)).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                case DataType.BOOLEAN:
                    preferences.edit().putBoolean(key, Boolean.valueOf(value)).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                case DataType.STRING_SET:
                    JSONArray jsonArray = new JSONArray(value);
                    Set<String> stringSet = new HashSet<>();
                    for (int i = 0; i < jsonArray.length(); i++) {
                        stringSet.add(jsonArray.getString(i));
                    }
                    preferences.edit().putStringSet(key, stringSet).apply();
                    updateRowResponse.isSuccessful = true;
                    break;
                default:
                    preferences.edit().putString(key, value).apply();
                    updateRowResponse.isSuccessful = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return updateRowResponse;
    }


    public static UpdateRowResponse deleteRow(Context context, String tableName,
                                              List<RowDataRequest> rowDataRequests) {
        UpdateRowResponse updateRowResponse = new UpdateRowResponse();

        if (tableName == null) {
            return updateRowResponse;
        }

        RowDataRequest rowDataKey = rowDataRequests.get(0);

        String key = rowDataKey.value;


        SharedPreferences preferences = context.getSharedPreferences(tableName, Context.MODE_PRIVATE);

        try {
            preferences.edit()
                    .remove(key).apply();
            updateRowResponse.isSuccessful = true;
        } catch (Exception ex) {
            updateRowResponse.isSuccessful = false;
        }

        return updateRowResponse;
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/TableNameParser.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */
package com.amitshekhar.utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Ultra light, Ultra fast parser to extract table name out SQLs, supports oracle dialect SQLs as well.
 *
 * @author Nadeem Mohammad
 *         <p>
 *         Ref : https://github.com/mnadeem/sql-table-name-parser
 */
public final class TableNameParser {

    private static final int NO_INDEX = -1;
    private static final String SPACE = " ";
    private static final String REGEX_SPACE = "\\s+";

    private static final String TOKEN_ORACLE_HINT_START = "/*+";
    private static final String TOKEN_ORACLE_HINT_END = "*/";
    private static final String TOKEN_SINGLE_LINE_COMMENT = "--";
    private static final String TOKEN_SEMI_COLON = ";";
    private static final String TOKEN_PARAN_START = "(";
    private static final String TOKEN_COMMA = ",";
    private static final String TOKEN_SET = "set";
    private static final String TOKEN_OF = "of";
    private static final String TOKEN_DUAL = "dual";
    private static final String TOKEN_DELETE = "delete";
    private static final String TOKEN_CREATE = "create";
    private static final String TOKEN_INDEX = "index";
    private static final String TOKEN_ASTERICK = "*";
    private static final String KEYWORD_JOIN = "join";
    private static final String KEYWORD_INTO = "into";
    private static final String KEYWORD_TABLE = "table";
    private static final String KEYWORD_FROM = "from";
    private static final String KEYWORD_USING = "using";
    private static final String KEYWORD_UPDATE = "update";
    private static final List<String> concerned = Arrays.asList(KEYWORD_TABLE, KEYWORD_INTO, KEYWORD_JOIN, KEYWORD_USING, KEYWORD_UPDATE);
    private static final List<String> ignored = Arrays.asList(TOKEN_PARAN_START, TOKEN_SET, TOKEN_OF, TOKEN_DUAL);
    private static String TOKEN_NEWLINE = "\\r\\n|\\r|\\n|\\n\\r";
    private Map<String, String> tables = new HashMap<String, String>();

    /**
     * Extracts table names out of SQL
     *
     * @param sql
     */
    public TableNameParser(final String sql) {
        String nocomments = removeComments(sql);
        String normalized = normalized(nocomments);
        String cleansed = clean(normalized);
        String[] tokens = cleansed.split(REGEX_SPACE);
        int index = 0;

        String firstToken = tokens[index];
        if (isOracleSpecialDelete(firstToken, tokens, index)) {
            handleSpecialOracleSpecialDelete(firstToken, tokens, index);
        } else if (isCreateIndex(firstToken, tokens, index)) {
            handleCreateIndex(firstToken, tokens, index);
        } else {
            while (moreTokens(tokens, index)) {
                String currentToken = tokens[index++];

                if (isFromToken(currentToken)) {
                    processFromToken(tokens, index);
                } else if (shouldProcess(currentToken)) {
                    String nextToken = tokens[index++];
                    considerInclusion(nextToken);

                    if (moreTokens(tokens, index)) {
                        nextToken = tokens[index++];
                    }
                }
            }
        }
    }

    private String removeComments(final String sql) {
        StringBuilder sb = new StringBuilder(sql);
        int nextCommentPosition = sb.indexOf(TOKEN_SINGLE_LINE_COMMENT);
        while (nextCommentPosition > -1) {
            int end = indexOfRegex(TOKEN_NEWLINE, sb.substring(nextCommentPosition));
            if (end == -1) {
                return sb.substring(0, nextCommentPosition);
            } else {
                sb.replace(nextCommentPosition, end + nextCommentPosition, "");
            }
            nextCommentPosition = sb.indexOf(TOKEN_SINGLE_LINE_COMMENT);
        }
        return sb.toString();
    }

    private int indexOfRegex(String regex, String string) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(string);
        return matcher.find() ? matcher.start() : -1;
    }

    private String normalized(final String sql) {
        String normalized = sql.trim().replaceAll(TOKEN_NEWLINE, SPACE).replaceAll(TOKEN_COMMA, " , ")
                .replaceAll("\\(", " ( ").replaceAll("\\)", " ) ");
        if (normalized.endsWith(TOKEN_SEMI_COLON)) {
            normalized = normalized.substring(0, normalized.length() - 1);
        }
        return normalized;
    }

    private String clean(final String normalized) {
        int start = normalized.indexOf(TOKEN_ORACLE_HINT_START);
        int end = NO_INDEX;
        if (start != NO_INDEX) {
            end = normalized.indexOf(TOKEN_ORACLE_HINT_END);
            if (end != NO_INDEX) {
                String firstHalf = normalized.substring(0, start);
                String secondHalf = normalized.substring(end + 2, normalized.length());
                return firstHalf.trim() + SPACE + secondHalf.trim();
            }
        }
        return normalized;
    }

    private boolean isOracleSpecialDelete(final String currentToken, final String[] tokens, int index) {
        index++;// Point to next token
        if (TOKEN_DELETE.equals(currentToken)) {
            if (moreTokens(tokens, index)) {
                String nextToken = tokens[index++];
                if (!KEYWORD_FROM.equals(nextToken) && !TOKEN_ASTERICK.equals(nextToken)) {
                    return true;
                }
            }
        }
        return false;
    }

    private void handleSpecialOracleSpecialDelete(final String currentToken, final String[] tokens, int index) {
        String tableName = tokens[index + 1];
        considerInclusion(tableName);
    }

    private boolean isCreateIndex(String currentToken, String[] tokens, int index) {
        index++; // Point to next token
        if (TOKEN_CREATE.equals(currentToken.toLowerCase()) && hasIthToken(tokens, index, 3)) {
            String nextToken = tokens[index++];
            if (TOKEN_INDEX.equals(nextToken.toLowerCase())) {
                return true;
            }

        }
        return false;
    }

    private void handleCreateIndex(String currentToken, String[] tokens, int index) {
        String tableName = tokens[index + 4];
        considerInclusion(tableName);
    }

    private boolean hasIthToken(String[] tokens, int currentIndex, int tokenNumber) {
        if (moreTokens(tokens, currentIndex) && tokens.length > currentIndex + tokenNumber) {
            return true;
        }
        return false;
    }

    private boolean shouldProcess(final String currentToken) {
        return concerned.contains(currentToken.toLowerCase());
    }

    private boolean isFromToken(final String currentToken) {
        return KEYWORD_FROM.equals(currentToken.toLowerCase());
    }

    private void processFromToken(final String[] tokens, int index) {
        String currentToken = tokens[index++];
        considerInclusion(currentToken);

        String nextToken = null;
        if (moreTokens(tokens, index)) {
            nextToken = tokens[index++];
        }

        if (shouldProcessMultipleTables(nextToken)) {
            processNonAliasedMultiTables(tokens, index, nextToken);
        } else {
            processAliasedMultiTables(tokens, index, currentToken);
        }
    }

    private void processNonAliasedMultiTables(final String[] tokens, int index, String nextToken) {
        while (nextToken.equals(TOKEN_COMMA)) {
            String currentToken = tokens[index++];
            considerInclusion(currentToken);
            if (moreTokens(tokens, index)) {
                nextToken = tokens[index++];
            } else {
                break;
            }
        }
    }

    private void processAliasedMultiTables(final String[] tokens, int index, String currentToken) {
        String nextNextToken = null;
        if (moreTokens(tokens, index)) {
            nextNextToken = tokens[index++];
        }

        if (shouldProcessMultipleTables(nextNextToken)) {
            while (moreTokens(tokens, index) && nextNextToken.equals(TOKEN_COMMA)) {
                if (moreTokens(tokens, index)) {
                    currentToken = tokens[index++];
                }
                if (moreTokens(tokens, index)) {
                    index++;
                }
                if (moreTokens(tokens, index)) {
                    nextNextToken = tokens[index++];
                }
                considerInclusion(currentToken);
            }
        }
    }

    private boolean shouldProcessMultipleTables(final String nextToken) {
        return nextToken != null && nextToken.equals(TOKEN_COMMA);
    }

    private boolean moreTokens(final String[] tokens, int index) {
        return index < tokens.length;
    }

    private void considerInclusion(final String token) {
        if (!ignored.contains(token.toLowerCase()) && !this.tables.containsKey(token.toLowerCase())) {
            this.tables.put(token.toLowerCase(), token);
        }
    }

    /**
     * @return table names extracted out of sql
     */
    public Collection<String> tables() {
        return new HashSet<String>(this.tables.values());
    }
}


================================================
FILE: debug-db-base/src/main/java/com/amitshekhar/utils/Utils.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar.utils;

import android.content.res.AssetManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

/**
 * Created by amitshekhar on 06/02/17.
 */

public class Utils {

    private static final String TAG = "Utils";

    private Utils() {
        // This class in not publicly instantiable
    }

    public static String detectMimeType(String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            return null;
        } else if (fileName.endsWith(".html")) {
            return "text/html";
        } else if (fileName.endsWith(".js")) {
            return "application/javascript";
        } else if (fileName.endsWith(".css")) {
            return "text/css";
        } else {
            return "application/octet-stream";
        }
    }

    public static byte[] loadContent(String fileName, AssetManager assetManager) throws IOException {
        InputStream input = null;
        try {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            input = assetManager.open(fileName);
            byte[] buffer = new byte[1024];
            int size;
            while (-1 != (size = input.read(buffer))) {
                output.write(buffer, 0, size);
            }
            output.flush();
            return output.toByteArray();
        } catch (FileNotFoundException e) {
            return null;
        } finally {
            try {
                if (null != input) {
                    input.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static byte[] getDatabase(String selectedDatabase, HashMap<String, Pair<File, String>> databaseFiles) {
        if (TextUtils.isEmpty(selectedDatabase) || !databaseFiles.containsKey(selectedDatabase)) {
            return null;
        }

        byte[] byteArray = new byte[0];
        try {
            File file = databaseFiles.get(selectedDatabase).first;

            byteArray = null;
            try {
                InputStream inputStream = new FileInputStream(file);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] b = new byte[(int) file.length()];
                int bytesRead;

                while ((bytesRead = inputStream.read(b)) != -1) {
                    bos.write(b, 0, bytesRead);
                }

                byteArray = bos.toByteArray();
            } catch (IOException e) {
                Log.e(TAG, "getDatabase: ", e);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return byteArray;
    }

}


================================================
FILE: debug-db-base/src/main/res/values/strings.xml
================================================
<!--
  ~ /*
  ~  *    Copyright (C) 2019 Amit Shekhar
  ~  *    Copyright (C) 2011 Android Open Source Project
  ~  *
  ~  *    Licensed under the Apache License, Version 2.0 (the "License");
  ~  *    you may not use this file except in compliance with the License.
  ~  *    You may obtain a copy of the License at
  ~  *
  ~  *        http://www.apache.org/licenses/LICENSE-2.0
  ~  *
  ~  *    Unless required by applicable law or agreed to in writing, software
  ~  *    distributed under the License is distributed on an "AS IS" BASIS,
  ~  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  *    See the License for the specific language governing permissions and
  ~  *    limitations under the License.
  ~  */
  -->

<resources>
    <string name="app_name">Debug-DB</string>
</resources>


================================================
FILE: debug-db-base/src/test/java/com/amitshekhar/ExampleUnitTest.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.amitshekhar;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, 2 + 2);
    }
}


================================================
FILE: debug-db-encrypt/.gitignore
================================================
/build


================================================
FILE: debug-db-encrypt/build.gradle
================================================
apply plugin: 'com.android.library'

android {
    compileSdk rootProject.ext.compileSdk
    defaultConfig {
        minSdk rootProject.ext.minSdk
        targetSdk rootProject.ext.targetSdk
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    api project(':debug-db-base')
    implementation 'net.zetetic:android-database-sqlcipher:3.5.9'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

================================================
FILE: debug-db-encrypt/gradle.properties
================================================
ARTIFACT_ID=debug-db-enncrypt

================================================
FILE: debug-db-encrypt/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile


================================================
FILE: debug-db-encrypt/src/androidTest/java/com/amitshekhar/debug/encrypt/ExampleInstrumentedTest.java
================================================
package com.amitshekhar.debug.encrypt;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumented test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.amitshekhar.debug.encrypt.test", appContext.getPackageName());
    }
}


================================================
FILE: debug-db-encrypt/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.amitshekhar.debug.encrypt">

    <application>
        <provider
            android:name=".DebugDBEncryptInitProvider"
            android:authorities="${applicationId}.DebugDBEncryptInitProvider"
            android:enabled="true"
            android:exported="false" />
    </application>

</manifest>


================================================
FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/DebugDBEncryptInitProvider.java
================================================
package com.amitshekhar.debug.encrypt;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;

import com.amitshekhar.DebugDB;
import com.amitshekhar.debug.encrypt.sqlite.DebugDBEncryptFactory;

public class DebugDBEncryptInitProvider extends ContentProvider {


    public DebugDBEncryptInitProvider() {
    }

    @Override
    public boolean onCreate() {
        DebugDB.initialize(getContext(), new DebugDBEncryptFactory());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public void attachInfo(Context context, ProviderInfo providerInfo) {
        if (providerInfo == null) {
            throw new NullPointerException("DebugDBEncryptInitProvider ProviderInfo cannot be null.");
        }
        // So if the authorities equal the library internal ones, the developer forgot to set his applicationId
        if ("com.amitshekhar.debug.encrypt.DebugDBEncryptInitProvider".equals(providerInfo.authority)) {
            throw new IllegalStateException("Incorrect provider authority in manifest. Most likely due to a "
                    + "missing applicationId variable in application\'s build.gradle.");
        }
        super.attachInfo(context, providerInfo);
    }

}


================================================
FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugDBEncryptFactory.java
================================================
package com.amitshekhar.debug.encrypt.sqlite;

import android.content.Context;

import com.amitshekhar.sqlite.DBFactory;
import com.amitshekhar.sqlite.SQLiteDB;

import net.sqlcipher.database.SQLiteDatabase;

public class DebugDBEncryptFactory implements DBFactory {

    @Override
    public SQLiteDB create(Context context, String path, String password) {
        SQLiteDatabase.loadLibs(context);
        return new DebugEncryptSQLiteDB(SQLiteDatabase.openOrCreateDatabase(path, password, null));
    }

}


================================================
FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugEncryptSQLiteDB.java
================================================
package com.amitshekhar.debug.encrypt.sqlite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;

import com.amitshekhar.sqlite.SQLiteDB;

import net.sqlcipher.database.SQLiteDatabase;

/**
 * Created by anandgaurav on 12/02/18.
 */

public class DebugEncryptSQLiteDB implements SQLiteDB {

    private final SQLiteDatabase database;

    public DebugEncryptSQLiteDB(SQLiteDatabase database) {
        this.database = database;
    }

    @Override
    public int delete(String table, String whereClause, String[] whereArgs) {
        return database.delete(table, whereClause, whereArgs);
    }

    @Override
    public boolean isOpen() {
        return database.isOpen();
    }

    @Override
    public void close() {
        database.close();
    }

    @Override
    public Cursor rawQuery(String sql, String[] selectionArgs) {
        return database.rawQuery(sql, selectionArgs);
    }

    @Override
    public void execSQL(String sql) throws SQLException {
        database.execSQL(sql);
    }

    @Override
    public long insert(String table, String nullColumnHack, ContentValues values) {
        return database.insert(table, nullColumnHack, values);
    }

    @Override
    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
        return database.update(table, values, whereClause, whereArgs);
    }

    @Override
    public int getVersion() {
        return database.getVersion();
    }
}


================================================
FILE: debug-db-encrypt/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">debug-db-encrypt</string>
</resources>


================================================
FILE: debug-db-encrypt/src/test/java/com/amitshekhar/debug/encrypt/ExampleUnitTest.java
================================================
package com.amitshekhar.debug.encrypt;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() {
        assertEquals(4, 2 + 2);
    }
}

================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Thu Apr 07 10:15:47 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME


================================================
FILE: gradle.properties
================================================
#
# /*
#  *    Copyright (C) 2019 Amit Shekhar
#  *    Copyright (C) 2011 Android Open Source Project
#  *
#  *    Licensed under the Apache License, Version 2.0 (the "License");
#  *    you may not use this file except in compliance with the License.
#  *    You may obtain a copy of the License at
#  *
#  *        http://www.apache.org/licenses/LICENSE-2.0
#  *
#  *    Unless required by applicable law or agreed to in writing, software
#  *    distributed under the License is distributed on an "AS IS" BASIS,
#  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  *    See the License for the specific language governing permissions and
#  *    limitations under the License.
#  */
#

# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true
signing.keyId=xxxxxx
signing.password=xxxxxx
signing.secretKeyRingFile=xxxxxx.gpg

================================================
FILE: gradlew
================================================
#!/usr/bin/env sh

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
    echo "$*"
}

die () {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Escape application args
save () {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
  cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: sample-app/build.gradle
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

apply plugin: 'com.android.application'

android {
    compileSdk rootProject.ext.compileSdk
    defaultConfig {
        minSdk rootProject.ext.minSdk
        applicationId "com.sample"
        targetSdk rootProject.ext.targetSdk
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        debug {
            resValue("string", "PORT_NUMBER", "8080")
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    debugImplementation project(':debug-db')
    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation "androidx.room:room-runtime:2.5.0"
    annotationProcessor "androidx.room:room-compiler:2.5.0"
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}


================================================
FILE: sample-app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile


================================================
FILE: sample-app/src/androidTest/java/com/sample/ExampleInstrumentedTest.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.sample;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumentation test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() throws Exception {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.sample", appContext.getPackageName());
    }
}


================================================
FILE: sample-app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?><!--
  ~ /*
  ~  *    Copyright (C) 2019 Amit Shekhar
  ~  *    Copyright (C) 2011 Android Open Source Project
  ~  *
  ~  *    Licensed under the Apache License, Version 2.0 (the "License");
  ~  *    you may not use this file except in compliance with the License.
  ~  *    You may obtain a copy of the License at
  ~  *
  ~  *        http://www.apache.org/licenses/LICENSE-2.0
  ~  *
  ~  *    Unless required by applicable law or agreed to in writing, software
  ~  *    distributed under the License is distributed on an "AS IS" BASIS,
  ~  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  *    See the License for the specific language governing permissions and
  ~  *    limitations under the License.
  ~  */
  -->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>


================================================
FILE: sample-app/src/main/java/com/sample/MainActivity.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *        http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.sample;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

import com.sample.database.CarDBHelper;
import com.sample.database.ContactDBHelper;
import com.sample.database.ExtTestDBHelper;
import com.sample.database.room.User;
import com.sample.database.room.UserDBHelper;
import com.sample.utils.Utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MainActivity extends AppCompatActivity {

    @SuppressLint("CommitPrefEdits")
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Set<String> stringSet = new HashSet<>();
        stringSet.add("SetOne");
        stringSet.add("SetTwo");
        stringSet.add("SetThree");

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        SharedPreferences prefsOne = getSharedPreferences("countPrefOne", Context.MODE_PRIVATE);
        SharedPreferences prefsTwo = getSharedPreferences("countPrefTwo", Context.MODE_PRIVATE);

        sharedPreferences.edit().putString("testOne", "one").commit();
        sharedPreferences.edit().putInt("testTwo", 2).commit();
        sharedPreferences.edit().putLong("testThree", 100000L).commit();
        sharedPreferences.edit().putFloat("testFour", 3.01F).commit();
        sharedPreferences.edit().putBoolean("testFive", true).commit();
        sharedPreferences.edit().putStringSet("testSix", stringSet).commit();

        prefsOne.edit().putString("testOneNew", "one").commit();

        prefsTwo.edit().putString("testTwoNew", "two").commit();

        ContactDBHelper contactDBHelper = new ContactDBHelper(getApplicationContext());
        if (contactDBHelper.count() == 0) {
            for (int i = 0; i < 100; i++) {
                String name = "name_" + i;
                String phone = "phone_" + i;
                String email = "email_" + i;
                String street = "street_" + i;
                String place = "place_" + i;
                contactDBHelper.insertContact(name, phone, email, street, place);
            }
        }

        CarDBHelper carDBHelper = new CarDBHelper(getApplicationContext());
        if (carDBHelper.count() == 0) {
            for (int i = 0; i < 50; i++) {
                String name = "name_" + i;
                String color = "RED";
                float mileage = i + 10.45f;
                carDBHelper.insertCar(name, color, mileage);
            }
        }

        ExtTestDBHelper extTestDBHelper = new ExtTestDBHelper(getApplicationContext());
        if (extTestDBHelper.count() == 0) {
            for (int i = 0; i < 20; i++) {
                String value = "value_" + i;
                extTestDBHelper.insertTest(value);
            }
        }

        // Room database
        UserDBHelper userDBHelper = new UserDBHelper(getApplicationContext());
        if (userDBHelper.count() == 0) {
            List<User> userList = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
                User user = new User();
                user.id = (long) (i + 1);
                user.name = "user_" + i;
                userList.add(user);
            }
            userDBHelper.insertUser(userList);
        }

        // Room inMemory database
        if (userDBHelper.countInMemory() == 0) {
            List<User> userList = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
                User user = new User();
                user.id = (long) (i + 1);
                user.name = "in_memory_user_" + i;
                userList.add(user);
            }
            userDBHelper.insertUserInMemory(userList);
        }

        Utils.setCustomDatabaseFiles(getApplicationContext());
        Utils.setInMemoryRoomDatabases(userDBHelper.getInMemoryDatabase());
    }

    public void showDebugDbAddress(View view) {
        Utils.showDebugDBAddressLogToast(getApplicationContext());
    }
}


================================================
FILE: sample-app/src/main/java/com/sample/database/CarDBHelper.java
================================================
/*
 *
 *  *    Copyright (C) 2019 Amit Shekhar
 *  *    Copyright (C) 2011 Android Open Source Project
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a co
Download .txt
gitextract_t_j5_uvg/

├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.gradle
├── debug-db/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── debug/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           └── debug/
│       │   │               ├── DebugDBInitProvider.java
│       │   │               └── sqlite/
│       │   │                   ├── DebugDBFactory.java
│       │   │                   └── DebugSQLiteDB.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── debug/
│                           └── ExampleUnitTest.java
├── debug-db-base/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   ├── app.js
│       │   │   ├── custom.css
│       │   │   ├── dataTables.altEditor.free.js
│       │   │   └── index.html
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           ├── DebugDB.java
│       │   │           ├── model/
│       │   │           │   ├── Response.java
│       │   │           │   ├── RowDataRequest.java
│       │   │           │   ├── TableDataResponse.java
│       │   │           │   └── UpdateRowResponse.java
│       │   │           ├── server/
│       │   │           │   ├── ClientServer.java
│       │   │           │   └── RequestHandler.java
│       │   │           ├── sqlite/
│       │   │           │   ├── DBFactory.java
│       │   │           │   ├── InMemoryDebugSQLiteDB.java
│       │   │           │   └── SQLiteDB.java
│       │   │           └── utils/
│       │   │               ├── Constants.java
│       │   │               ├── ConverterUtils.java
│       │   │               ├── DataType.java
│       │   │               ├── DatabaseFileProvider.java
│       │   │               ├── DatabaseHelper.java
│       │   │               ├── NetworkUtils.java
│       │   │               ├── PrefHelper.java
│       │   │               ├── TableNameParser.java
│       │   │               └── Utils.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── ExampleUnitTest.java
├── debug-db-encrypt/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── amitshekhar/
│       │               └── debug/
│       │                   └── encrypt/
│       │                       └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── amitshekhar/
│       │   │           └── debug/
│       │   │               └── encrypt/
│       │   │                   ├── DebugDBEncryptInitProvider.java
│       │   │                   └── sqlite/
│       │   │                       ├── DebugDBEncryptFactory.java
│       │   │                       └── DebugEncryptSQLiteDB.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── amitshekhar/
│                       └── debug/
│                           └── encrypt/
│                               └── ExampleUnitTest.java
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── sample-app/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── sample/
│       │               └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── sample/
│       │   │           ├── MainActivity.java
│       │   │           ├── database/
│       │   │           │   ├── CarDBHelper.java
│       │   │           │   ├── ContactDBHelper.java
│       │   │           │   ├── ExtTestDBHelper.java
│       │   │           │   └── room/
│       │   │           │       ├── AppDatabase.java
│       │   │           │       ├── User.java
│       │   │           │       ├── UserDBHelper.java
│       │   │           │       └── UserDao.java
│       │   │           └── utils/
│       │   │               └── Utils.java
│       │   └── res/
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       ├── values/
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── sample/
│                       └── ExampleUnitTest.java
├── sample-app-encrypt/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── sample/
│       │               └── encrypt/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── sample/
│       │   │           └── encrypt/
│       │   │               ├── MainActivity.java
│       │   │               ├── database/
│       │   │               │   ├── CarDBHelper.java
│       │   │               │   ├── ContactDBHelper.java
│       │   │               │   ├── ExtTestDBHelper.java
│       │   │               │   ├── PersonDBHelper.java
│       │   │               │   └── room/
│       │   │               │       ├── AppDatabase.java
│       │   │               │       ├── User.java
│       │   │               │       ├── UserDBHelper.java
│       │   │               │       └── UserDao.java
│       │   │               └── utils/
│       │   │                   └── Utils.java
│       │   └── res/
│       │       ├── drawable/
│       │       │   └── ic_launcher_background.xml
│       │       ├── drawable-v24/
│       │       │   └── ic_launcher_foreground.xml
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       └── values/
│       │           ├── colors.xml
│       │           ├── dimens.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── sample/
│                       └── encrypt/
│                           └── ExampleUnitTest.java
└── settings.gradle
Download .txt
SYMBOL INDEX (318 symbols across 55 files)

FILE: debug-db-base/src/androidTest/java/com/amitshekhar/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 36) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 38) | @Test

FILE: debug-db-base/src/main/assets/app.js
  function getData (line 29) | function getData(tableName) {
  function queryFunction (line 40) | function queryFunction() {
  function downloadDb (line 53) | function downloadDb() {
  function deleteDb (line 61) | function deleteDb() {
  function getDBList (line 77) | function getDBList() {
  function openDatabaseAndGetTableList (line 104) | function openDatabaseAndGetTableList(db, isDownloadable) {
  function inflateData (line 156) | function inflateData(result){
  function updateTableData (line 289) | function updateTableData(updatedData, callback) {
  function deleteTableData (line 327) | function deleteTableData(deleteData, callback) {
  function addTableData (line 364) | function addTableData(deleteData, callback) {
  function showSuccessInfo (line 406) | function showSuccessInfo(message){
  function showErrorInfo (line 417) | function showErrorInfo(message){
  function getHashValue (line 428) | function getHashValue(key) {

FILE: debug-db-base/src/main/java/com/amitshekhar/DebugDB.java
  class DebugDB (line 39) | public class DebugDB {
    method DebugDB (line 46) | private DebugDB() {
    method initialize (line 50) | public static void initialize(Context context, DBFactory dbFactory) {
    method getAddressLog (line 67) | public static String getAddressLog() {
    method shutDown (line 72) | public static void shutDown() {
    method setCustomDatabaseFiles (line 79) | public static void setCustomDatabaseFiles(HashMap<String, Pair<File, S...
    method setInMemoryRoomDatabases (line 85) | public static void setInMemoryRoomDatabases(HashMap<String, SupportSQL...
    method isServerRunning (line 91) | public static boolean isServerRunning() {

FILE: debug-db-base/src/main/java/com/amitshekhar/model/Response.java
  class Response (line 29) | public class Response {
    method Response (line 37) | public Response() {

FILE: debug-db-base/src/main/java/com/amitshekhar/model/RowDataRequest.java
  class RowDataRequest (line 26) | public class RowDataRequest {

FILE: debug-db-base/src/main/java/com/amitshekhar/model/TableDataResponse.java
  class TableDataResponse (line 28) | public class TableDataResponse {
    class TableInfo (line 37) | public static class TableInfo {
    class ColumnData (line 42) | public static class ColumnData {

FILE: debug-db-base/src/main/java/com/amitshekhar/model/UpdateRowResponse.java
  class UpdateRowResponse (line 26) | public class UpdateRowResponse {

FILE: debug-db-base/src/main/java/com/amitshekhar/server/ClientServer.java
  class ClientServer (line 41) | public class ClientServer implements Runnable {
    method ClientServer (line 50) | public ClientServer(Context context, int port, DBFactory dbFactory) {
    method start (line 55) | public void start() {
    method stop (line 60) | public void stop() {
    method run (line 72) | @Override
    method setCustomDatabaseFiles (line 90) | public void setCustomDatabaseFiles(HashMap<String, Pair<File, String>>...
    method setInMemoryRoomDatabases (line 94) | public void setInMemoryRoomDatabases(HashMap<String, SupportSQLiteData...
    method isRunning (line 98) | public boolean isRunning() {

FILE: debug-db-base/src/main/java/com/amitshekhar/server/RequestHandler.java
  class RequestHandler (line 60) | public class RequestHandler {
    method RequestHandler (line 73) | public RequestHandler(Context context, DBFactory dbFactory) {
    method handle (line 80) | public void handle(Socket socket) throws IOException {
    method setCustomDatabaseFiles (line 168) | public void setCustomDatabaseFiles(HashMap<String, Pair<File, String>>...
    method setInMemoryRoomDatabases (line 172) | public void setInMemoryRoomDatabases(HashMap<String, SupportSQLiteData...
    method writeServerError (line 176) | private void writeServerError(PrintStream output) {
    method openDatabase (line 181) | private void openDatabase(String database) {
    method closeDatabase (line 193) | private void closeDatabase() {
    method getDBListResponse (line 201) | private String getDBListResponse() {
    method getAllDataFromTheTableResponse (line 224) | private String getAllDataFromTheTableResponse(String route) {
    method executeQueryAndGetResponse (line 245) | private String executeQueryAndGetResponse(String route) {
    method getTableListResponse (line 294) | private String getTableListResponse(String route) {
    method addTableDataAndGetResponse (line 315) | private String addTableDataAndGetResponse(String route) {
    method updateTableDataAndGetResponse (line 337) | private String updateTableDataAndGetResponse(String route) {
    method deleteTableDataAndGetResponse (line 360) | private String deleteTableDataAndGetResponse(String route) {
    method deleteSelectedDatabaseAndGetResponse (line 382) | private String deleteSelectedDatabaseAndGetResponse() {

FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/DBFactory.java
  type DBFactory (line 5) | public interface DBFactory {
    method create (line 7) | SQLiteDB create(Context context, String path, String password);

FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/InMemoryDebugSQLiteDB.java
  class InMemoryDebugSQLiteDB (line 13) | public class InMemoryDebugSQLiteDB implements SQLiteDB {
    method InMemoryDebugSQLiteDB (line 17) | public InMemoryDebugSQLiteDB(SupportSQLiteDatabase database) {
    method delete (line 21) | @Override
    method isOpen (line 26) | @Override
    method close (line 31) | @Override
    method rawQuery (line 36) | @Override
    method execSQL (line 41) | @Override
    method insert (line 46) | @Override
    method update (line 51) | @Override
    method getVersion (line 56) | @Override

FILE: debug-db-base/src/main/java/com/amitshekhar/sqlite/SQLiteDB.java
  type SQLiteDB (line 12) | public interface SQLiteDB {
    method delete (line 14) | int delete(String table, String whereClause, String[] whereArgs);
    method isOpen (line 16) | boolean isOpen();
    method close (line 18) | void close();
    method rawQuery (line 20) | Cursor rawQuery(String sql, String[] selectionArgs);
    method execSQL (line 22) | void execSQL(String sql) throws SQLException;
    method insert (line 24) | long insert(String table, String nullColumnHack, ContentValues values);
    method update (line 26) | int update(String table, ContentValues values, String whereClause, Str...
    method getVersion (line 28) | int getVersion();

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/Constants.java
  class Constants (line 26) | public final class Constants {
    method Constants (line 28) | private Constants() {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/ConverterUtils.java
  class ConverterUtils (line 28) | public class ConverterUtils {
    method ConverterUtils (line 34) | private ConverterUtils() {
    method blobToString (line 38) | public static String blobToString(byte[] blob) {
    method fastIsAscii (line 51) | public static boolean fastIsAscii(byte[] blob) {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DataType.java
  class DataType (line 26) | public class DataType {
    method DataType (line 28) | private DataType() {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseFileProvider.java
  class DatabaseFileProvider (line 33) | public class DatabaseFileProvider {
    method DatabaseFileProvider (line 37) | private DatabaseFileProvider() {
    method getDatabaseFiles (line 41) | public static HashMap<String, Pair<File, String>> getDatabaseFiles(Con...
    method getDbPasswordFromStringResources (line 54) | private static String getDbPasswordFromStringResources(Context context...

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseHelper.java
  class DatabaseHelper (line 40) | public class DatabaseHelper {
    method DatabaseHelper (line 42) | private DatabaseHelper() {
    method getAllTableName (line 46) | public static Response getAllTableName(SQLiteDB database) {
    method getTableData (line 65) | public static TableDataResponse getTableData(SQLiteDB db, String selec...
    method getQuotedTableName (line 190) | private static String getQuotedTableName(String tableName) {
    method getTableInfo (line 194) | private static List<TableDataResponse.TableInfo> getTableInfo(SQLiteDB...
    method addRow (line 240) | public static UpdateRowResponse addRow(SQLiteDB db, String tableName,
    method updateRow (line 282) | public static UpdateRowResponse updateRow(SQLiteDB db, String tableNam...
    method deleteRow (line 337) | public static UpdateRowResponse deleteRow(SQLiteDB db, String tableName,
    method exec (line 384) | public static TableDataResponse exec(SQLiteDB database, String sql) {
    method getTableName (line 407) | private static String getTableName(String selectQuery) {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/NetworkUtils.java
  class NetworkUtils (line 30) | public final class NetworkUtils {
    method NetworkUtils (line 32) | private NetworkUtils() {
    method getAddressLog (line 36) | public static String getAddressLog(Context context, int port) {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/PrefHelper.java
  class PrefHelper (line 44) | public class PrefHelper {
    method PrefHelper (line 48) | private PrefHelper() {
    method getSharedPreferenceTags (line 52) | public static List<String> getSharedPreferenceTags(Context context) {
    method getAllPrefTableName (line 72) | public static Response getAllPrefTableName(Context context) {
    method getAllPrefData (line 87) | public static TableDataResponse getAllPrefData(Context context, String...
    method addOrUpdateRow (line 145) | public static UpdateRowResponse addOrUpdateRow(Context context, String...
    method deleteRow (line 209) | public static UpdateRowResponse deleteRow(Context context, String tabl...

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/TableNameParser.java
  class TableNameParser (line 37) | public final class TableNameParser {
    method TableNameParser (line 72) | public TableNameParser(final String sql) {
    method removeComments (line 102) | private String removeComments(final String sql) {
    method indexOfRegex (line 117) | private int indexOfRegex(String regex, String string) {
    method normalized (line 123) | private String normalized(final String sql) {
    method clean (line 132) | private String clean(final String normalized) {
    method isOracleSpecialDelete (line 146) | private boolean isOracleSpecialDelete(final String currentToken, final...
    method handleSpecialOracleSpecialDelete (line 159) | private void handleSpecialOracleSpecialDelete(final String currentToke...
    method isCreateIndex (line 164) | private boolean isCreateIndex(String currentToken, String[] tokens, in...
    method handleCreateIndex (line 176) | private void handleCreateIndex(String currentToken, String[] tokens, i...
    method hasIthToken (line 181) | private boolean hasIthToken(String[] tokens, int currentIndex, int tok...
    method shouldProcess (line 188) | private boolean shouldProcess(final String currentToken) {
    method isFromToken (line 192) | private boolean isFromToken(final String currentToken) {
    method processFromToken (line 196) | private void processFromToken(final String[] tokens, int index) {
    method processNonAliasedMultiTables (line 212) | private void processNonAliasedMultiTables(final String[] tokens, int i...
    method processAliasedMultiTables (line 224) | private void processAliasedMultiTables(final String[] tokens, int inde...
    method shouldProcessMultipleTables (line 246) | private boolean shouldProcessMultipleTables(final String nextToken) {
    method moreTokens (line 250) | private boolean moreTokens(final String[] tokens, int index) {
    method considerInclusion (line 254) | private void considerInclusion(final String token) {
    method tables (line 263) | public Collection<String> tables() {

FILE: debug-db-base/src/main/java/com/amitshekhar/utils/Utils.java
  class Utils (line 39) | public class Utils {
    method Utils (line 43) | private Utils() {
    method detectMimeType (line 47) | public static String detectMimeType(String fileName) {
    method loadContent (line 61) | public static byte[] loadContent(String fileName, AssetManager assetMa...
    method getDatabase (line 86) | public static byte[] getDatabase(String selectedDatabase, HashMap<Stri...

FILE: debug-db-base/src/test/java/com/amitshekhar/ExampleUnitTest.java
  class ExampleUnitTest (line 31) | public class ExampleUnitTest {
    method addition_isCorrect (line 32) | @Test

FILE: debug-db-encrypt/src/androidTest/java/com/amitshekhar/debug/encrypt/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/DebugDBEncryptInitProvider.java
  class DebugDBEncryptInitProvider (line 13) | public class DebugDBEncryptInitProvider extends ContentProvider {
    method DebugDBEncryptInitProvider (line 16) | public DebugDBEncryptInitProvider() {
    method onCreate (line 19) | @Override
    method query (line 25) | @Override
    method getType (line 30) | @Override
    method insert (line 35) | @Override
    method delete (line 40) | @Override
    method update (line 45) | @Override
    method attachInfo (line 50) | @Override

FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugDBEncryptFactory.java
  class DebugDBEncryptFactory (line 10) | public class DebugDBEncryptFactory implements DBFactory {
    method create (line 12) | @Override

FILE: debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugEncryptSQLiteDB.java
  class DebugEncryptSQLiteDB (line 15) | public class DebugEncryptSQLiteDB implements SQLiteDB {
    method DebugEncryptSQLiteDB (line 19) | public DebugEncryptSQLiteDB(SQLiteDatabase database) {
    method delete (line 23) | @Override
    method isOpen (line 28) | @Override
    method close (line 33) | @Override
    method rawQuery (line 38) | @Override
    method execSQL (line 43) | @Override
    method insert (line 48) | @Override
    method update (line 53) | @Override
    method getVersion (line 58) | @Override

FILE: debug-db-encrypt/src/test/java/com/amitshekhar/debug/encrypt/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: debug-db/src/androidTest/java/com/amitshekhar/debug/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: debug-db/src/main/java/com/amitshekhar/debug/DebugDBInitProvider.java
  class DebugDBInitProvider (line 36) | public class DebugDBInitProvider extends ContentProvider {
    method DebugDBInitProvider (line 39) | public DebugDBInitProvider() {
    method onCreate (line 42) | @Override
    method query (line 48) | @Override
    method getType (line 53) | @Override
    method insert (line 58) | @Override
    method delete (line 63) | @Override
    method update (line 68) | @Override
    method attachInfo (line 73) | @Override

FILE: debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugDBFactory.java
  class DebugDBFactory (line 9) | public class DebugDBFactory implements DBFactory {
    method create (line 11) | @Override

FILE: debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugSQLiteDB.java
  class DebugSQLiteDB (line 10) | public class DebugSQLiteDB implements SQLiteDB {
    method DebugSQLiteDB (line 14) | public DebugSQLiteDB(SQLiteDatabase database) {
    method delete (line 18) | @Override
    method isOpen (line 23) | @Override
    method close (line 28) | @Override
    method rawQuery (line 33) | @Override
    method execSQL (line 38) | @Override
    method insert (line 43) | @Override
    method update (line 48) | @Override
    method getVersion (line 53) | @Override

FILE: debug-db/src/test/java/com/amitshekhar/debug/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: sample-app-encrypt/src/androidTest/java/com/sample/encrypt/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/MainActivity.java
  class MainActivity (line 44) | public class MainActivity extends AppCompatActivity {
    method onCreate (line 46) | @SuppressLint("CommitPrefEdits")
    method showDebugDbAddress (line 145) | public void showDebugDbAddress(View view) {

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/CarDBHelper.java
  class CarDBHelper (line 35) | public class CarDBHelper extends SQLiteOpenHelper {
    method CarDBHelper (line 44) | public CarDBHelper(Context context) {
    method onCreate (line 48) | @Override
    method onUpgrade (line 63) | @Override
    method insertCar (line 70) | public boolean insertCar(String name, String color, float mileage) {
    method getData (line 80) | public Cursor getData(int id) {
    method numberOfRows (line 86) | public int numberOfRows() {
    method updateCar (line 92) | public boolean updateCar(Integer id, String name, String color, float ...
    method deleteCar (line 102) | public Integer deleteCar(Integer id) {
    method getAllCars (line 109) | public ArrayList<String> getAllCars() {
    method count (line 124) | public int count() {

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/ContactDBHelper.java
  class ContactDBHelper (line 35) | public class ContactDBHelper extends SQLiteOpenHelper {
    method ContactDBHelper (line 47) | public ContactDBHelper(Context context) {
    method onCreate (line 51) | @Override
    method onUpgrade (line 60) | @Override
    method insertContact (line 67) | public boolean insertContact(String name, String phone, String email, ...
    method getData (line 80) | public Cursor getData(int id) {
    method numberOfRows (line 86) | public int numberOfRows() {
    method updateContact (line 92) | public boolean updateContact(Integer id, String name, String phone, St...
    method deleteContact (line 104) | public Integer deleteContact(Integer id) {
    method getAllCotacts (line 111) | public ArrayList<String> getAllCotacts() {
    method count (line 126) | public int count() {

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/ExtTestDBHelper.java
  class ExtTestDBHelper (line 14) | public class ExtTestDBHelper extends SQLiteOpenHelper {
    method ExtTestDBHelper (line 23) | public ExtTestDBHelper(Context context) {
    method onCreate (line 27) | @Override
    method onUpgrade (line 41) | @Override
    method insertTest (line 48) | public boolean insertTest(String value) {
    method count (line 57) | public int count() {
    class CustomDatabasePathContext (line 68) | private static class CustomDatabasePathContext extends ContextWrapper {
      method CustomDatabasePathContext (line 70) | public CustomDatabasePathContext(Context base) {
      method getDatabasePath (line 74) | @Override
      method openOrCreateDatabase (line 82) | @Override
      method openOrCreateDatabase (line 87) | @Override

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/PersonDBHelper.java
  class PersonDBHelper (line 32) | public class PersonDBHelper extends SQLiteOpenHelper {
    method PersonDBHelper (line 42) | public PersonDBHelper(Context context) {
    method onCreate (line 48) | @Override
    method onUpgrade (line 56) | @Override
    method insertPerson (line 62) | public boolean insertPerson(String firstName, String lastName, String ...
    method getData (line 73) | public Cursor getData(int id) {
    method numberOfRows (line 79) | public int numberOfRows() {
    method updatePerson (line 85) | public boolean updatePerson(Integer id, String firstName, String lastN...
    method deletePerson (line 96) | public Integer deletePerson(Integer id) {
    method getAllPerson (line 103) | public ArrayList<String> getAllPerson() {
    method count (line 121) | public int count() {

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/AppDatabase.java
  class AppDatabase (line 10) | @Database(entities = {User.class}, version = 1, exportSchema = false)
    method userDao (line 13) | public abstract UserDao userDao();

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/User.java
  class User (line 9) | @Entity(tableName = "users")

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/UserDBHelper.java
  class UserDBHelper (line 14) | public class UserDBHelper {
    method UserDBHelper (line 19) | public UserDBHelper(Context context) {
    method insertUser (line 28) | public void insertUser(List<User> userList) {
    method insertUserInMemory (line 32) | public void insertUserInMemory(List<User> userList) {
    method count (line 36) | public int count() {
    method countInMemory (line 40) | public int countInMemory() {
    method getInMemoryDatabase (line 44) | public SupportSQLiteDatabase getInMemoryDatabase() {

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/UserDao.java
  type UserDao (line 16) | @Dao
    method loadAll (line 19) | @Query("SELECT * FROM users")
    method loadAllByIds (line 22) | @Query("SELECT * FROM users WHERE id IN (:userIds)")
    method insert (line 25) | @Insert(onConflict = OnConflictStrategy.REPLACE)
    method insertAll (line 28) | @Insert(onConflict = OnConflictStrategy.REPLACE)
    method delete (line 31) | @Delete

FILE: sample-app-encrypt/src/main/java/com/sample/encrypt/utils/Utils.java
  class Utils (line 39) | public class Utils {
    method Utils (line 41) | private Utils() {
    method showDebugDBAddressLogToast (line 45) | public static void showDebugDBAddressLogToast(Context context) {
    method setCustomDatabaseFiles (line 58) | public static void setCustomDatabaseFiles(Context context) {
    method setInMemoryRoomDatabases (line 76) | public static void setInMemoryRoomDatabases(SupportSQLiteDatabase... d...

FILE: sample-app-encrypt/src/test/java/com/sample/encrypt/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: sample-app/src/androidTest/java/com/sample/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 36) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 38) | @Test

FILE: sample-app/src/main/java/com/sample/MainActivity.java
  class MainActivity (line 43) | public class MainActivity extends AppCompatActivity {
    method onCreate (line 45) | @SuppressLint("CommitPrefEdits")
    method showDebugDbAddress (line 133) | public void showDebugDbAddress(View view) {

FILE: sample-app/src/main/java/com/sample/database/CarDBHelper.java
  class CarDBHelper (line 35) | public class CarDBHelper extends SQLiteOpenHelper {
    method CarDBHelper (line 44) | public CarDBHelper(Context context) {
    method onCreate (line 48) | @Override
    method onUpgrade (line 63) | @Override
    method insertCar (line 70) | public boolean insertCar(String name, String color, float mileage) {
    method getData (line 80) | public Cursor getData(int id) {
    method numberOfRows (line 86) | public int numberOfRows() {
    method updateCar (line 92) | public boolean updateCar(Integer id, String name, String color, float ...
    method deleteCar (line 102) | public Integer deleteCar(Integer id) {
    method getAllCars (line 109) | public ArrayList<String> getAllCars() {
    method count (line 124) | public int count() {

FILE: sample-app/src/main/java/com/sample/database/ContactDBHelper.java
  class ContactDBHelper (line 35) | public class ContactDBHelper extends SQLiteOpenHelper {
    method ContactDBHelper (line 47) | public ContactDBHelper(Context context) {
    method onCreate (line 51) | @Override
    method onUpgrade (line 60) | @Override
    method insertContact (line 67) | public boolean insertContact(String name, String phone, String email, ...
    method getData (line 80) | public Cursor getData(int id) {
    method numberOfRows (line 86) | public int numberOfRows() {
    method updateContact (line 92) | public boolean updateContact(Integer id, String name, String phone, St...
    method deleteContact (line 104) | public Integer deleteContact(Integer id) {
    method getAllCotacts (line 111) | public ArrayList<String> getAllCotacts() {
    method count (line 126) | public int count() {

FILE: sample-app/src/main/java/com/sample/database/ExtTestDBHelper.java
  class ExtTestDBHelper (line 14) | public class ExtTestDBHelper extends SQLiteOpenHelper {
    method ExtTestDBHelper (line 23) | public ExtTestDBHelper(Context context) {
    method onCreate (line 27) | @Override
    method onUpgrade (line 41) | @Override
    method insertTest (line 48) | public boolean insertTest(String value) {
    method count (line 57) | public int count() {
    class CustomDatabasePathContext (line 68) | private static class CustomDatabasePathContext extends ContextWrapper {
      method CustomDatabasePathContext (line 70) | public CustomDatabasePathContext(Context base) {
      method getDatabasePath (line 74) | @Override
      method openOrCreateDatabase (line 82) | @Override
      method openOrCreateDatabase (line 87) | @Override

FILE: sample-app/src/main/java/com/sample/database/room/AppDatabase.java
  class AppDatabase (line 10) | @Database(entities = {User.class}, version = 1, exportSchema = false)
    method userDao (line 13) | public abstract UserDao userDao();

FILE: sample-app/src/main/java/com/sample/database/room/User.java
  class User (line 10) | @Entity(tableName = "users")

FILE: sample-app/src/main/java/com/sample/database/room/UserDBHelper.java
  class UserDBHelper (line 14) | public class UserDBHelper {
    method UserDBHelper (line 19) | public UserDBHelper(Context context) {
    method insertUser (line 28) | public void insertUser(List<User> userList) {
    method insertUserInMemory (line 32) | public void insertUserInMemory(List<User> userList) {
    method count (line 36) | public int count() {
    method countInMemory (line 40) | public int countInMemory() {
    method getInMemoryDatabase (line 44) | public SupportSQLiteDatabase getInMemoryDatabase() {

FILE: sample-app/src/main/java/com/sample/database/room/UserDao.java
  type UserDao (line 16) | @Dao
    method loadAll (line 19) | @Query("SELECT * FROM users")
    method loadAllByIds (line 22) | @Query("SELECT * FROM users WHERE id IN (:userIds)")
    method insert (line 25) | @Insert(onConflict = OnConflictStrategy.REPLACE)
    method insertAll (line 28) | @Insert(onConflict = OnConflictStrategy.REPLACE)
    method delete (line 31) | @Delete

FILE: sample-app/src/main/java/com/sample/utils/Utils.java
  class Utils (line 39) | public class Utils {
    method Utils (line 41) | private Utils() {
    method showDebugDBAddressLogToast (line 45) | public static void showDebugDBAddressLogToast(Context context) {
    method setCustomDatabaseFiles (line 58) | public static void setCustomDatabaseFiles(Context context) {
    method setInMemoryRoomDatabases (line 76) | public static void setInMemoryRoomDatabases(SupportSQLiteDatabase... d...

FILE: sample-app/src/test/java/com/sample/ExampleUnitTest.java
  class ExampleUnitTest (line 31) | public class ExampleUnitTest {
    method addition_isCorrect (line 32) | @Test
Condensed preview — 108 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (281K chars).
[
  {
    "path": ".gitignore",
    "chars": 216,
    "preview": "# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Android Studio generated "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 1908,
    "preview": "Change Log\n==========\n\nVersion 1.0.6 *(2019-03-07)*\n----------------------------\n\n* Fix: Fix query error\n* Fix: Fix Debu"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 374,
    "preview": "# Contributing\n\n1. Fork it!\n2. Checkout the development branch: `git checkout development`\n3. Create your feature branch"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 8749,
    "preview": "<img src=https://raw.githubusercontent.com/amitshekhariitbhu/Android-Debug-Database/master/assets/debug_db_banner.png >\n"
  },
  {
    "path": "build.gradle",
    "chars": 1086,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "debug-db/build.gradle",
    "chars": 739,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdk rootProject.ext.compileSdk\n    defaultConfig {\n        min"
  },
  {
    "path": "debug-db/gradle.properties",
    "chars": 20,
    "preview": "ARTIFACT_ID=debug-db"
  },
  {
    "path": "debug-db/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "debug-db/src/androidTest/java/com/amitshekhar/debug/ExampleInstrumentedTest.java",
    "chars": 731,
    "preview": "package com.amitshekhar.debug;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimp"
  },
  {
    "path": "debug-db/src/main/AndroidManifest.xml",
    "chars": 369,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.amitshekhar.debug\">\n\n    <applicat"
  },
  {
    "path": "debug-db/src/main/java/com/amitshekhar/debug/DebugDBInitProvider.java",
    "chars": 2627,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugDBFactory.java",
    "chars": 435,
    "preview": "package com.amitshekhar.debug.sqlite;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\n\ni"
  },
  {
    "path": "debug-db/src/main/java/com/amitshekhar/debug/sqlite/DebugSQLiteDB.java",
    "chars": 1443,
    "preview": "package com.amitshekhar.debug.sqlite;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport andr"
  },
  {
    "path": "debug-db/src/main/res/values/strings.xml",
    "chars": 71,
    "preview": "<resources>\n    <string name=\"app_name\">debug-db</string>\n</resources>\n"
  },
  {
    "path": "debug-db/src/test/java/com/amitshekhar/debug/ExampleUnitTest.java",
    "chars": 382,
    "preview": "package com.amitshekhar.debug;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit tes"
  },
  {
    "path": "debug-db-base/build.gradle",
    "chars": 1585,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/proguard-rules.pro",
    "chars": 2520,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "debug-db-base/src/androidTest/java/com/amitshekhar/ExampleInstrumentedTest.java",
    "chars": 1471,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/AndroidManifest.xml",
    "chars": 1016,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "debug-db-base/src/main/assets/app.js",
    "chars": 14388,
    "preview": "$( document ).ready(function() {\n    getDBList();\n    $(\"#query\").keypress(function(e){\n        if(e.which == 13) {\n    "
  },
  {
    "path": "debug-db-base/src/main/assets/custom.css",
    "chars": 1025,
    "preview": ".padding-fifty {\n   padding-top: 50px;\n}\n\n.padding-twenty {\n    padding-top: 20px;\n}\n\n.display-none {\n    display: none;"
  },
  {
    "path": "debug-db-base/src/main/assets/dataTables.altEditor.free.js",
    "chars": 28138,
    "preview": "/*! Datatables altEditor 1.0\n */\n/**\n * @summary     altEditor\n * @description Lightweight editor for DataTables\n * @ver"
  },
  {
    "path": "debug-db-base/src/main/assets/index.html",
    "chars": 6178,
    "preview": "<!DOCTYPE html>\n<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source P"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/DebugDB.java",
    "chars": 2900,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/model/Response.java",
    "chars": 1111,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/model/RowDataRequest.java",
    "chars": 954,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/model/TableDataResponse.java",
    "chars": 1283,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/model/UpdateRowResponse.java",
    "chars": 882,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/server/ClientServer.java",
    "chars": 2944,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/server/RequestHandler.java",
    "chars": 15309,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/sqlite/DBFactory.java",
    "chars": 167,
    "preview": "package com.amitshekhar.sqlite;\n\nimport android.content.Context;\n\npublic interface DBFactory {\n\n    SQLiteDB create(Cont"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/sqlite/InMemoryDebugSQLiteDB.java",
    "chars": 1456,
    "preview": "package com.amitshekhar.sqlite;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.da"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/sqlite/SQLiteDB.java",
    "chars": 637,
    "preview": "package com.amitshekhar.sqlite;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.da"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/Constants.java",
    "chars": 1147,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/ConverterUtils.java",
    "chars": 1663,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/DataType.java",
    "chars": 1271,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseFileProvider.java",
    "chars": 2385,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/DatabaseHelper.java",
    "chars": 14893,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/NetworkUtils.java",
    "chars": 1647,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/PrefHelper.java",
    "chars": 8284,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/TableNameParser.java",
    "chars": 10036,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/java/com/amitshekhar/utils/Utils.java",
    "chars": 3625,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-base/src/main/res/values/strings.xml",
    "chars": 830,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "debug-db-base/src/test/java/com/amitshekhar/ExampleUnitTest.java",
    "chars": 1126,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "debug-db-encrypt/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "debug-db-encrypt/build.gradle",
    "chars": 805,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdk rootProject.ext.compileSdk\n    defaultConfig {\n        min"
  },
  {
    "path": "debug-db-encrypt/gradle.properties",
    "chars": 29,
    "preview": "ARTIFACT_ID=debug-db-enncrypt"
  },
  {
    "path": "debug-db-encrypt/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "debug-db-encrypt/src/androidTest/java/com/amitshekhar/debug/encrypt/ExampleInstrumentedTest.java",
    "chars": 747,
    "preview": "package com.amitshekhar.debug.encrypt;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegis"
  },
  {
    "path": "debug-db-encrypt/src/main/AndroidManifest.xml",
    "chars": 391,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.amitshekhar.debug.encrypt\">\n\n    <"
  },
  {
    "path": "debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/DebugDBEncryptInitProvider.java",
    "chars": 1913,
    "preview": "package com.amitshekhar.debug.encrypt;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nim"
  },
  {
    "path": "debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugDBEncryptFactory.java",
    "chars": 509,
    "preview": "package com.amitshekhar.debug.encrypt.sqlite;\n\nimport android.content.Context;\n\nimport com.amitshekhar.sqlite.DBFactory;"
  },
  {
    "path": "debug-db-encrypt/src/main/java/com/amitshekhar/debug/encrypt/sqlite/DebugEncryptSQLiteDB.java",
    "chars": 1513,
    "preview": "package com.amitshekhar.debug.encrypt.sqlite;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimp"
  },
  {
    "path": "debug-db-encrypt/src/main/res/values/strings.xml",
    "chars": 79,
    "preview": "<resources>\n    <string name=\"app_name\">debug-db-encrypt</string>\n</resources>\n"
  },
  {
    "path": "debug-db-encrypt/src/test/java/com/amitshekhar/debug/encrypt/ExampleUnitTest.java",
    "chars": 390,
    "preview": "package com.amitshekhar.debug.encrypt;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local "
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Thu Apr 07 10:15:47 CST 2022\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributio"
  },
  {
    "path": "gradle.properties",
    "chars": 1584,
    "preview": "#\n# /*\n#  *    Copyright (C) 2019 Amit Shekhar\n#  *    Copyright (C) 2011 Android Open Source Project\n#  *\n#  *    Licen"
  },
  {
    "path": "gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "gradlew.bat",
    "chars": 2260,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "sample-app/build.gradle",
    "chars": 1763,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "sample-app/src/androidTest/java/com/sample/ExampleInstrumentedTest.java",
    "chars": 1456,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/src/main/AndroidManifest.xml",
    "chars": 1596,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011"
  },
  {
    "path": "sample-app/src/main/java/com/sample/MainActivity.java",
    "chars": 4987,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/CarDBHelper.java",
    "chars": 4530,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/ContactDBHelper.java",
    "chars": 4978,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/ExtTestDBHelper.java",
    "chars": 3316,
    "preview": "package com.sample.database;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.conte"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/room/AppDatabase.java",
    "chars": 320,
    "preview": "package com.sample.database.room;\n\n\nimport androidx.room.Database;\nimport androidx.room.RoomDatabase;\n\n/**\n * Created by"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/room/User.java",
    "chars": 260,
    "preview": "package com.sample.database.room;\n\n\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\n\n/**\n * Created by ana"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/room/UserDBHelper.java",
    "chars": 1257,
    "preview": "package com.sample.database.room;\n\nimport android.content.Context;\n\nimport androidx.room.Room;\nimport androidx.sqlite.db"
  },
  {
    "path": "sample-app/src/main/java/com/sample/database/room/UserDao.java",
    "chars": 683,
    "preview": "package com.sample.database.room;\n\n\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room.Insert;\n"
  },
  {
    "path": "sample-app/src/main/java/com/sample/utils/Utils.java",
    "chars": 3325,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app/src/main/res/layout/activity_main.xml",
    "chars": 1628,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011"
  },
  {
    "path": "sample-app/src/main/res/values/colors.xml",
    "chars": 967,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 201"
  },
  {
    "path": "sample-app/src/main/res/values/dimens.xml",
    "chars": 970,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "sample-app/src/main/res/values/strings.xml",
    "chars": 916,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "sample-app/src/main/res/values/styles.xml",
    "chars": 1142,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "sample-app/src/main/res/values-w820dp/dimens.xml",
    "chars": 1117,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "sample-app/src/test/java/com/sample/ExampleUnitTest.java",
    "chars": 1121,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "sample-app-encrypt/build.gradle",
    "chars": 1181,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdk rootProject.ext.compileSdk\n    defaultConfig {\n       "
  },
  {
    "path": "sample-app-encrypt/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "sample-app-encrypt/src/androidTest/java/com/sample/encrypt/ExampleInstrumentedTest.java",
    "chars": 720,
    "preview": "package com.sample.encrypt;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport"
  },
  {
    "path": "sample-app-encrypt/src/main/AndroidManifest.xml",
    "chars": 760,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/MainActivity.java",
    "chars": 5661,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/CarDBHelper.java",
    "chars": 4538,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/ContactDBHelper.java",
    "chars": 4986,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/ExtTestDBHelper.java",
    "chars": 3324,
    "preview": "package com.sample.encrypt.database;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport andro"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/PersonDBHelper.java",
    "chars": 4808,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/AppDatabase.java",
    "chars": 328,
    "preview": "package com.sample.encrypt.database.room;\n\n\nimport androidx.room.Database;\nimport androidx.room.RoomDatabase;\n\n/**\n * Cr"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/User.java",
    "chars": 267,
    "preview": "package com.sample.encrypt.database.room;\n\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\n\n/**\n * Created"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/UserDBHelper.java",
    "chars": 1265,
    "preview": "package com.sample.encrypt.database.room;\n\nimport android.content.Context;\n\nimport androidx.room.Room;\nimport androidx.s"
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/database/room/UserDao.java",
    "chars": 691,
    "preview": "package com.sample.encrypt.database.room;\n\n\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room."
  },
  {
    "path": "sample-app-encrypt/src/main/java/com/sample/encrypt/utils/Utils.java",
    "chars": 3349,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  },
  {
    "path": "sample-app-encrypt/src/main/res/drawable/ic_launcher_background.xml",
    "chars": 5606,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "sample-app-encrypt/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "chars": 1880,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    "
  },
  {
    "path": "sample-app-encrypt/src/main/res/layout/activity_main.xml",
    "chars": 1636,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011"
  },
  {
    "path": "sample-app-encrypt/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "sample-app-encrypt/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "sample-app-encrypt/src/main/res/values/colors.xml",
    "chars": 208,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"color"
  },
  {
    "path": "sample-app-encrypt/src/main/res/values/dimens.xml",
    "chars": 970,
    "preview": "<!--\n  ~ /*\n  ~  *    Copyright (C) 2019 Amit Shekhar\n  ~  *    Copyright (C) 2011 Android Open Source Project\n  ~  *\n  "
  },
  {
    "path": "sample-app-encrypt/src/main/res/values/strings.xml",
    "chars": 153,
    "preview": "<resources>\n    <string name=\"app_name\">Sample App Encrypt</string>\n    <string name=\"show_debug_db_address\">Show Debug "
  },
  {
    "path": "sample-app-encrypt/src/main/res/values/styles.xml",
    "chars": 383,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "sample-app-encrypt/src/test/java/com/sample/encrypt/ExampleUnitTest.java",
    "chars": 379,
    "preview": "package com.sample.encrypt;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, "
  },
  {
    "path": "settings.gradle",
    "chars": 1179,
    "preview": "/*\n *\n *  *    Copyright (C) 2019 Amit Shekhar\n *  *    Copyright (C) 2011 Android Open Source Project\n *  *\n *  *    Li"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the amitshekhariitbhu/Android-Debug-Database GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 108 files (255.2 KB), approximately 62.8k tokens, and a symbol index with 318 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!