[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "## 💬 Contributing\n\nIf you consider contributing to this repository, please first discuss the desired changes via issue, email, or any other method\n\n### 🕵️‍ Pull request requirements\n\n1. Implement all functions thoroughly and remove any unused or non-working code\n2. Format all terminal output in a similar way as the existing\n3. Ensure every code change and usage variant is tested\n4. Update the README.md and changelog.txt with details of changes to the commands\n\n### ✏️ Right to make changes\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "### 🐞 Whats wrong\n~Describe requested functionality or existing bug~\n### 🌈 Desired state\n~Describe desired code and functional changes~\n### 📏 Challenges\n~Hint any special or complicated tasks~\n### 📂 Sources\n~Recommend related code samples or documentation~\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## ⚠️ Progress checklist\n- [ ] 🏗 **Features fully completed**\n- [ ] 🔬 **Shellcheck issues resolved**\n- [ ] 🔨 **All changes tested**\n- [ ] 💬 **Terminal output satisfactory**\n- [ ] 👀 **Diff examined thoroughly**\n- [ ] 📝 **API changes included in `README.md`**\n- [ ] 📣 **Major changes listed in `changelog.txt`**\n"
  },
  {
    "path": ".github/workflows/count_lines.yml",
    "content": "name: Count lines\non: [push]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Count lines of text in this repository\n        run: git ls-files *[^.png] | xargs wc -l | grep total | awk '{print $1}' > count.txt\n\n      - uses: pCYSl5EDgo/cat@master\n        id: count\n        with:\n          path: count.txt\n\n      - run: echo $TEXT\n        env:\n          TEXT: ${{ steps.count.outputs.text }}\n"
  },
  {
    "path": ".github/workflows/shellcheck.yml",
    "content": "name: 'Shellcheck'\non: push\njobs:\n  shellcheck:\n    name: Shellcheck\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@master\n    - name: Shellcheck\n      uses: ludeeus/action-shellcheck@master\n      env:\n        SHELLCHECK_OPTS: -e SC1090 -e SC2207 -e SC2001 -e SC1091\n        # SC1090 - non-constant source\n        # SC2207 - no arrays like this ($())\n        # SC2001 - replace sed with ${variable//search/replace}\n        # SC1091 - common_tools was not specified as input (see shellcheck -x)\n"
  },
  {
    "path": ".gitignore",
    "content": "*DS_Store\nios/go-ios\nios/nohup.out\nios/selfidentity.plist\n"
  },
  {
    "path": "LICENCE.md",
    "content": "MIT License\n\nCopyright (c) 2019 IntergalacticPenguin - Adam Svoboda\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![Header](/media/header_v2.png?raw=true)\n<div id='section-id-2'/>\n\n## What is its purpose?\n🛠 **Control Android & iOS devices:** Capture screen, manage apps, simulate input, examine system logs etc.<br>\n\n⚡️ **Speed++** Are you an app developer or a tester? Boost your effectivity, discover new tools!\n\n\n<div id='section-id-8'/>\n\n## All features\n\n📲 **Control Android and iOS devices** or Emulators/Simulators using terminal commands<br>\n\n🛠 **Take screeshots, change device settings**, gather app & device information<br>\n\n⚙️ **Manage mobile applications** - install, restart, wipe data and much more<br>\n\n📋 **Handle multiple devices effortlessly** - select from list or target all connected devices<br>\n\n⏳ **Save your precious time** - stop doing repetitive tasks manually<br>\n\n🔄 **Automatic update** - get new features and fixes ASAP<br>\n\n## Table of contents\n🔩 Maybe you just want to skip to [Installation](#section-id-22)?<br>\n<br>\n<bold>[🤖 Android Commands](#section-id-52)</bold>\n- [Capture screen](#section-id-54)\n\t- [📸 ascreenshot](#section-id-56)\n\t- [🎥 arecord](#section-id-60)\n- [Control device](#section-id-66)\n\t- [✏️ apaste](#section-id-68)\n\t- [🌐 aurl](#section-id-78)\n\t- [🏴 adarkmode](#section-id-82)\n\t- [🔊 atalkback](#section-id-85)\n\t- [📐 abounds](#section-id-88)\n\t- [🚗 aanimationspeed](#section-id-92)\n\t- [🔠 afontscale](#section-id-96)\n\t- [🎹 acontrol](#section-id-100)\n\t- [📷 acamera](#section-id-104)\n\t- [⚡️ awireless](#section-id-107)\n\t- [👋 apowerbutton](#section-id-108)\n- [Manage packages](#section-id-111)\n\t- [🚀 alaunch](#section-id-113)\n\t- [🕵️ aappinfo](#section-id-118)\n\t- [🔪 akill](#section-id-128)\n\t- [🧽 aerase](#section-id-132)\n\t- [🚚 ainstall](#section-id-136)\n\t- [🗑 auninstall](#section-id-140)\n\t- [🔥 awipe](#section-id-146)\n\t- [🐁 apermissionreset](#section-id-149)\n\t- [🛍 agoogleplay](#section-id-153)\n\t- [🏭 abuildproject](#section-id-157)\n- [Manage device](#section-id-161)\n\t- [⚙️ aoptions](#section-id-163)\n\t- [📜 alog](#section-id-176)\n\t- [📋 acheckdevice](#section-id-180)\n\t- [😎 aservices](#section-id-192)\n\t- [♻ areboot](#section-id-196)\n\t- [📱 aemulator](#section-id-199)\n\t- [🐒 atestmonkey](#section-id-215)\n\n\n<strong>[🍎 iOS Commands](#section-id-233)</strong><br>\n- [Capture screen](#section-id-235)\n\t- [📸 iscreenshot](#section-id-237)\n\t- [🎥 irecord](#section-id-241)\n\t- [📹 iquicktime](#section-id-250)\n- [Manage applications](#section-id-255)\n\t- [🚚 iinstall](#section-id-256)\n\t- [🗑 iuninstall](#section-id-260)\n\t- [🚀 ilaunch](#section-id-266)\n\t- [🔪 ikill](#section-id-271)\n- [Manage device](#section-id-276)\n\t- [⚙️ ioptions](#section-id-278)\n\t- [💬 ilang](#section-id-281)\n\t- [📜 ilog](#section-id-285)\n\t- [📋 icheckdevice](#section-id-288)\n\t- [♻ ireboot](#section-id-292)\n\t- [📱 isimulator](#section-id-295)\n\t- [🖥 iconsole](#section-id-309)\n\n💭 Do you want to share [Feedback or Contribute](#section-id-312)?\n\n<div id='section-id-22'/>\n\n# 💻 Installation\n<details>\n\t  <summary>Click here to reveal step by step guide ↓</summary>\n\n_Note: This tool targets macOS for compatibility, but most interactions should work on any Unix system._\n<br>\n1. **Open terminal**\n2. **Clone this repository** `git clone https://github.com/IntergalacticPenguin/mobile-toolkit.git`\n3. **Setup Android tools**\n\t* **[Download](https://developer.android.com/studio/ \"Android Studio\") and install Android Studio** and **Android command line tools** (using Android Studio SDK manager)\n\t* **Edit .zshrc** (or .bash_profile if you have bash shell) `open -e ~/.zshrc`\n\t  * **Insert this line at the end** `PATH=$PATH:/Users/dummyuser/Library/Android/sdk/platform-tools export PATH`\n\t  * **Don't forget to replace \"dummyuser\" with your account username**\n\t  * **Use full path to the \"platform-tools\" directory**\n\t* **[Allow USB debugging](https://developer.android.com/studio/debug/dev-options) on your device, connect it and authorize your computer** (click OK on the device screen)\n4. **Setup iOS tools**\n\t* **Install latest Xcode and iOS command line tools** using [App Store](https://apps.apple.com/cz/app/xcode/id497799835?mt=12)\n\t* **Install [Homebrew](https://brew.sh/ \"Homberew\") package manager**\n\t* **Run Xcode, connect iOS device to USB and authorize your computer** (click \"Trust\" on the device screen)\n\t* **Run any script i.e. `iscreenshot`, installation of all required tools will be initiated automatically** ([jq](https://stedolan.github.io/jq/) and [go-ios](https://github.com/danielpaulus/go-ios \"go-ios\"))\n5. **Add Mobile Toolkit to $PATH**, it is mandatory for iOS scripts and it will let you run scripts in any directory\n\t* **Edit .zshrc** (or .bash_profile if you have bash shell) `open -e ~/.zshrc`\n\t  * **Insert the following lines at the end** <br> `PATH=$PATH:/Users/dummyuser/mobile-toolkit/android` <br>\n\t`PATH=$PATH:/Users/dummyuser/mobile-toolkit/ios`\n\t  * **Don't forget to replace \"dummyuser\" with your account username**\n\t  * **Use full path to the \"mobile-toolkit\" directory** (where you cloned this repository)\n\t  * **Add** `export PATH` **to the end of the file**\n\n</details>\n\n<div id='section-id-52'/>\n\n# 🤖 Android Commands\n\n<div id='section-id-54'/>\n\n## Capture screen\n\n<div id='section-id-56'/>\n\n### 📸 ascreenshot\n* `ascreenshot` Save screenshot to ~/Desktop\n* `ascreenshot -a` Take screenshot on all connected devices\n\n<div id='section-id-60'/>\n\n### 🎥 arecord\n1. `arecord` Record screen\n2. End recording using `ctrl + c`\n3. Save screen video footage to ~/Desktop\n4. Records audio by default on devices running Android 12 and up (when using Scrcpy version 2.0.0 or higher)\n  * `arecord <custom-name>` Specify your own filename by passing it as argument\n  * `arecord -l` Use legacy `-l` option to record using ADB instead of Scrcpy\n\n<div id='section-id-66'/>\n\n## Control device\n\n<div id='section-id-68'/>\n\n### ✏️ apaste\n`apaste \"john.doe@fakemail.com\" password1 \"5005 1002 3332 1112\" \"2/19\" 5004`\n\n* `apaste <text>` Insert text into currently focused field\n* `apaste \"john.doe@fakemail.com\" password1 ` Every additional argument will be inserted into subsequent field\n* `apaste \"This is sample multi-word text.\"` use \"\" to insert multi-word text into one field\n* `apaste -l` Insert \"Lorem Ipsum paragraph\"\n* `apaste -a <input-text>` Insert any text input (options displayed above) on all connected devices\n* `apaste -a -l` Insert \"Lorem Ipsum paragraph\" on all connected devices\n\n<div id='section-id-78'/>\n\n### 🌐 aurl\n* `aurl \"google.com\"` Open link in web browser or corresponding application\n* `aurl -a \"google.com\"` Open link in web browser or corresponding application on all connected devices\n\n<div id='section-id-82'/>\n\n### 🏴 adarkmode\n* `adarkmode` Toggle system dark mode\n\n<div id='section-id-85'/>\n\n### 🔊 atalkback\n* `atalkback` Toggle TalkBack screen reader accessiblity option\n\n<div id='section-id-88'/>\n\n### 📐 abounds\n* `abounds` Toggle UI layout bounds\n* App restart may be necessary on lower APIs\n\n<div id='section-id-92'/>\n\n### 🚗 aanimationspeed\n* `aanimationspeed` set slower animation speed or restore default\n* `aanimationspeed <speed>` set animation speed multiplier\n\n<div id='section-id-96'/>\n\n### 🔠 afontscale\n* `afontscale` set large font scale (1.3x bigger than default) or restore default\n* `afontscale <scale>` set font scale multiplier\n\n<div id='section-id-100'/>\n\n### 🎹 acontrol\n* `acontrol` start [scrcpy](https://github.com/Genymobile/scrcpy \"scrcpy\") session\n* Provides realtime device screen mirroring and keyboard+mouse control\n\n<div id='section-id-104'/>\n\n### 📷 acamera\n* Start the default camera application\n\n<div id='section-id-107'/>\n\n### ⚡️ awireless\n* Enable or disable wireless ADB connection\n* Use ADB and toolkit without having USB cable attached\n\n<div id='section-id-108'/>\n\n### 👋 apowerbutton\n* Lock/Unlock the device (send Power button key event)\n* Useful to unlock the device after the screen is locked automatically\n\n<div id='section-id-111'/>\n\n## Manage packages\n\n<div id='section-id-113'/>\n\n### 🚀 alaunch\n* `alaunch` List third-party apps and choose one to run it\n* `alaunch -s` List all available apps (including os pre-installed) and choose one to run it\n* `alaunch com.dummy.package.name.app` Run app by package name\n\n<div id='section-id-118'/>\n\n### 🕵️ aappinfo\n* `aappinfo` List foreground app information\n\t* Package name\n\t* Version\n\t* Last update\n\t* minSdk and targetSdk\n\t* Permissions\n* (Optional) Open application settings\n* `aappinfo com.dummy.package.name.app` Target specific app by passing package name as argument\n\n<div id='section-id-128'/>\n\n### 🔪 akill\n* `akill` Restart the foreground app\n* `akill com.dummy.package.name.app` Target specific app by passing package name as argument\n\n<div id='section-id-132'/>\n\n### 🧽 aerase\n* `aerase` Delete all local data of the foreground app and restart it\n* `aerase com.dummy.package.name.app` Target specific app by passing package name as argument\n\n<div id='section-id-136'/>\n\n### 🚚 ainstall\n* `ainstall some-app-file.apk` Install and run .apk\n* `ainstall -a some-app-file.apk` Install and run .apk on all connected devices\n\n<div id='section-id-140'/>\n\n### 🗑 auninstall\n* `auninstall` Uninstall third-party app, choose from the list\n* `auninstall com.dummy.package.name.app` pass package name as argument\n* `auninstall -w` Uninstall all-third party packages\n\t* Skips some essential apps, edit IGNORED_PACKAGES in this script to customize the list to your needs\n\n<div id='section-id-146'/>\n\n### 🔥 awipe\n* Wipe internal storage and delete all third-party apps\n\n<div id='section-id-149'/>\n\n### 🐁 apermissionreset\n* Revoke ALL GRANTED runtime permissions for ALL apps\n\t* You'll have to handle permission requests upon opening almost any app\n\n<div id='section-id-153'/>\n\n### 🛍 agoogleplay\n* `agoogleplay \"Dummy App\"` Search for \"Dummy App\" on Google Play\n* `agoogleplay` Search for currently foreground app on Google Play\n\n<div id='section-id-157'/>\n\n### 🏭 abuildproject\n* `abuildproject` Build, install and run Android project located in current directory\n* `abuildproject <relative-path>` Build, install and run Android project located in \\<relative-path>\n\n<div id='section-id-161'/>\n\n## Manage device\n\n<div id='section-id-163'/>\n\n### ⚙️ aoptions\n* `aoptions` Open system settings on a specific activity\n* You can choose from quick presets\n\t* Developer settings\n\t* Locale settings\n\t* Date & time\n\t* Wifi settings\n\t* Storage management\n\t* Power usage\n\t* Root settings activity\n* `aoptions A` Choose from exhaustive list of all available options\n* `aoptions 1,2,3... | dev | locale | date | wifi | storage | power` Use a preset, choose one\n\n<div id='section-id-176'/>\n\n### 📜 alog\n* `alog` Print system log output\n* `alog -f <package-name>` Filter log by package name\n\n<div id='section-id-180'/>\n\n### 📋 acheckdevice\n* Print genereal device information\n* Perform basic safety-checks and toggle \"testing firendly\" settings\n  * 10 minutes screen timeout\n  * Highest brightness\n  * Automatic date\n  * Disabled notification sounds\n  * Internet connectivity and WIFI name\n  * Font scale\n  * enUS locale\n* (Optional) Search for the device on [GSMArena](https://www.gsmarena.com/ \"GSMArena\")\n\n<div id='section-id-192'/>\n\n### 😎 aservices\n* Print running background services\n* Search for more information via Google\n\n<div id='section-id-196'/>\n\n### ♻ areboot\n* Reboot the device\n\n<div id='section-id-199'/>\n\n### 📱 aemulator\n**Required**: Make terminal use Android Studio Java\n  * **Edit .bash_profile** (or .zshrc if you have zsh shell) `open -e ~/.bash_profile` or `open -e ~/.zshrc`\n  * **Add the following line at the end of the file** `export JAVA_HOME='/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home'`\n\n* Android emulator supports all listed scripts by default + extra actions listed below\n* `aemulator <option>` Handle various Android emulator activites\n  * `start` - choose and launch installed emulator\n  * `gprs | edge | 3g` - simulate network latency, choose one\n  * `call <number>` - receive fake call\n  * `sms <number> <text>` - receive fake sms\n  * `gps <lat> <long>` - set manual GPS location\n  * `battery <0-100>` - set battery level\n  * `telnet <command>` - call command via telnet\n\t   * example commands `event | redir | sensor | physics | finger | rotate | fold | unfold...` see [Android emulator documentation](https://developer.android.com/studio/run/emulator-console#console-session) for more information\n\n<div id='section-id-215'/>\n\n### 🐒 atestmonkey\n* `atestmonkey` Default test with random seed and 15000 input events\n* `atestmonkey <event-count>` Test with random seed and custom input event count\n* `atestmonkey <event-count> <seed>` Test with custom seed and custom event count\n* Perform automated stress test using [Application Excersciser Monkey](https://developer.android.com/studio/test/monkey)\n* You can end test prematurely using ctrl^c or `atestmonkeykill` in case something goes wrong\n* App under test needs to be pinned to fullscreen mode to prevent unwanted interactions elsewhere\n* Screen pinning button location is directly tied to OS version and device manufacturer skin.\n\t* It may be tricky to turn on, see examples below:<br><br>\n\t* <details>\n\t\t\t<summary>Google Nexus 5 (Android 6)</summary>\n\t\t\t<br><em>You need to bring the app window to foreground, the button is located in bottom right corner.</em><br><br>\n\t\t\t<img src=\"/media/Pinning_Nexus_v4.png\" width=\"420\"></details>\n\t* <details>\n\t\t\t<summary>Google Pixel 3 (Android 11)</summary>\n\t\t\t<br><em>You need to click on the app icon, the button is located in popup menu.</em><br><br>\n\t\t\t<img src=\"/media/Pinning_Pixel_v2.png\" width=\"420\"></details>\n\n<div id='section-id-233'/>\n\n# 🍎 iOS Commands\n\n<div id='section-id-235'/>\n\n## Capture screen\n\n<div id='section-id-237'/>\n\n### 📸 iscreenshot\n* `iscreenshot` Save screenshot to ~/Desktop\n* `iscreenshot -a` Take screenshot on all connected devices\n\n<div id='section-id-241'/>\n\n### 🎥 irecord\n**Required**: Install [videosnap](https://github.com/matthutchinson/videosnap/releases \"videosnap\") -> download and install `videosnap-0.0.8.pkg`<br>\n**Required**: Install [ffmpeg](https://www.ffmpeg.org/ \"ffmpeg\") `brew install ffmpeg`\n\n1. `irecord` Record screen\n2. End recording using `ctrl + c`\n3. Video footage is saved to ~/Desktop\n4. File is compressed using ffmpeg\n\n<div id='section-id-250'/>\n\n### 📹 iquicktime\n* Run QuickTime and open video source picker (so you can choose a device right away)\n  * You may have to allow security system permission, so the script can access QuickTime application\n* This is a fallback script for `irecord` on M1 macs as it is currently not working\n\n<div id='section-id-255'/>\n\n## Manage applications\n<div id='section-id-256'/>\n\n### 🚚 iinstall\n* `iinstall some-app-file.ipa` Install .ipa (make sure to use properly signed build)\n* `iinstall -a some-app-file.ipa` Install .ipa to all connected devices\n\n<div id='section-id-260'/>\n\n### 🗑 iuninstall\n* `iuninstall` Uninstall third-party app, choose from the list\n* `iuninstall com.dummy.package.name.app` pass bundle name as argument\n* `iuninstall -w` Uninstall all third-party packages\n  * Skips some essential apps, edit IGNORED_PACKAGES in this script to customize the list to your needs\n\n<div id='section-id-266'/>\n\n### 🚀 ilaunch\n* `ilaunch` List third-party apps and choose one to run it\n* `ilaunch -s` List os pre-installed apps and choose one to run it\n* `ilaunch com.dummy.bundle.id.app` Run app by bundle id\n\n<div id='section-id-271'/>\n\n### 🔪 ikill\n* `ikill` List third-party apps and choose one to restart\n* `ikill -s` List os pre-installed apps and choose one to restart\n* `ikill com.dummy.bundle.id.app` Target specific app by passing bundle id as argument\n\n<div id='section-id-276'/>\n\n## Manage device\n\n<div id='section-id-278'/>\n\n### ⚙️ ioptions\n* `ioptions` Open system settings application\n\n<div id='section-id-281'/>\n\n### 💬 ilang\n* `ilang <lang>` Change the device language to different one, according to ISO-639 (i.e. \"cs\")\n* `ilang` Change the device language to different one, choose from a list of all supported\n\n<div id='section-id-285'/>\n\n### 📜 ilog\n* `ilog` Print system log output\n\n<div id='section-id-288'/>\n\n### 📋 icheckdevice\n* Print device information\n* (Optional) Search for the device on [GSMArena](https://www.gsmarena.com/ \"GSMArena\")\n\n<div id='section-id-292'/>\n\n### ♻ ireboot\n* Reboot the device\n\n<div id='section-id-295'/>\n\n### 📱 isimulator\n* Simulator has limited functionality (no camera, biometrics, Appstore...), but **offers some extra options, unavailable on physical iOS devices**\n* `isimulator <option>` Handle various simulator related activites\n  * `start` - choose and launch installed simulator\n  * `screenshot` - save screenshot to ~/Desktop\n  * `record` - save screen recording to ~/Desktop (full resolution and frame rate, without QuickTime hassle)\n  * `paste <text>` - insert text into pasteboard\n  * `import <file>` - import image or video to simulator gallery app\n  * `log` - print simulator log\n  * `url <url>` - open link in web browser or corresponding application\n  * `wipe` - wipe all simulator data\n  * `battery <0-100>` - set battery level displayed in status bar (no functional impact)\n  * `time <hh:mm>` - set time displayed in status bar (no functional impact)\n\n<div id='section-id-309'/>\n\n### 🖥 iconsole\n* `iconsole` Examine iOS or macOS system logs using Console application\n\n<div id='section-id-312'/>\n\n----\n\n<strong>Feedback & Contribution</strong><br>\n\n<sup>⁉️ [Submit an issue](https://github.com/IntergalacticPenguin/mobile-toolkit/issues/new/choose) to report any bugs, request a feature or ask questions.</sup><br>\n<sup>🤝 [Pull requests](https://github.com/IntergalacticPenguin/mobile-toolkit/blob/master/.github/CONTRIBUTING.md \"contribution rules\") are highly **appreciated**, see the [issue board](https://github.com/IntergalacticPenguin/mobile-toolkit/projects/3).</sup><br>\n<sup>💬 Also <strong>visit my [NoMo](https://github.com/IGPenguin/nomo)</strong> project and leave a star.</sup><br>\n<sup>🔗 Find me on [LinkedIn](https://www.linkedin.com/in/intergalacticpenguin/) or [Twitter](https://twitter.com/IGPenguin).</sup><br>\n"
  },
  {
    "path": "android/aanimationspeed",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nset_animation_speed(){\n  adb -s \"$SELECTED_DEVICE\" shell settings put global animator_duration_scale \"$1\"\n  adb -s \"$SELECTED_DEVICE\" shell settings put global transition_animation_scale \"$1\"\n  adb -s \"$SELECTED_DEVICE\" shell settings put global window_animation_scale \"$1\"\n}\n\nrestore_animation_speed(){\n  set_animation_speed 1\n  echo \"🔄 Animation speed restored to default \\\"1\\\"\"\n}\n\nandroid_choose_device\nif [ -n \"$1\" ] 2> /dev/null ;then\n  echo \"🎬 Setting animation speed to \\\"$1\\\" (bigger is slower)...\"\n  set_animation_speed \"$1\"\nelse\n  if [ \"$(adb -s \"$SELECTED_DEVICE\" shell settings get global animator_duration_scale)\" != \"1\" ] || [ \"$(adb -s \"$SELECTED_DEVICE\" shell settings get global transition_animation_scale)\" != \"1\" ] || [ \"$(adb -s \"$SELECTED_DEVICE\" shell settings get global window_animation_scale)\" != \"1\" ] ; then\n    restore_animation_speed\n  else\n    echo \"🎬 Setting animation speed to \\\"5\\\" (bigger is slower)...\"\n    set_animation_speed 5\n  fi\nfi\n"
  },
  {
    "path": "android/aappinfo",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nif [ -n \"$1\" ];\nthen\n    PACKAGE_NAME=$1\n    android_is_package_installed \"$PACKAGE_NAME\"\nelse\n    PACKAGE_NAME=$(android_get_foreground_package)\nfi\n\nVERSION=$(adb -s \"$SELECTED_DEVICE\" shell dumpsys package \"$PACKAGE_NAME\" | grep versionName | sed 's/versionName=//')\nVERSION=$(echo \"$VERSION\" | awk '{print $1}') # Remove ghost whitespaces\nLAST_UPDATE=$(adb -s \"$SELECTED_DEVICE\" shell dumpsys package \"$PACKAGE_NAME\" | grep lastUpdateTime | sed 's/lastUpdateTime=//')\nLAST_UPDATE=$(echo \"$LAST_UPDATE\" | awk '{print $1}') # Remove ghost whitespaces\nSDK=$(adb -s \"$SELECTED_DEVICE\" shell dumpsys package \"$PACKAGE_NAME\" | grep versionCode | grep -o 'minSdk.*')\n\necho \"Package name: $PACKAGE_NAME\"\necho \"Version: $VERSION\"\necho \"Last update: $LAST_UPDATE\"\necho \"SDK: $SDK\"\nadb -s \"$SELECTED_DEVICE\" shell dumpsys package \"$PACKAGE_NAME\" | grep  -v \"):\\\\|perm=\\\\|installPermissionsFixed=true\" | grep -i -e permission\nshould_proceed \"🔨 Do you want to open $PACKAGE_NAME settings?\"\nadb -s \"$SELECTED_DEVICE\" shell am start -a \"android.settings.APPLICATION_DETAILS_SETTINGS\" -d \"package:$PACKAGE_NAME\" &> /dev/null\n"
  },
  {
    "path": "android/abounds",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nredraw_screen(){\n  adb -s \"$1\" shell service check SurfaceFlinger &> /dev/null\n  adb -s \"$1\" shell service call activity 1599295570 &> /dev/null\n}\n\nturn_off_bounds(){\n  echo \"👋 Turning off layout bounds ...\"\n  adb -s \"$1\" shell setprop debug.layout false &> /dev/null\n  redraw_screen \"$1\"\n}\n\nturn_on_bounds(){\n  echo \"📐 Turning on layout bounds...\"\n  adb -s \"$1\" shell setprop debug.layout true &> /dev/null\n  redraw_screen \"$1\"\n}\n\nBOUNDS_STATE=$(adb -s \"$SELECTED_DEVICE\" shell getprop debug.layout | tr -cd '[[:alnum:]]._-')\nif [ -z \"$BOUNDS_STATE\" ] || [ \"$BOUNDS_STATE\" == \"false\" ]; then\n  turn_on_bounds \"$SELECTED_DEVICE\"\nelse\n  turn_off_bounds \"$SELECTED_DEVICE\"\nfi\n"
  },
  {
    "path": "android/abuildproject",
    "content": "#!/bin/bash\n# shellcheck disable=SC2181\n#ignore indirect exit code check at line 54\n\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\ntrap 'cleanup $@' 1 2 3 6 15\n\ncleanup()\n{\n  if [ -n \"$OLD_PWD\" ]; then\n    cd \"$OLD_PWD\" || exit\n  fi\n  rm -f \"$TASK_LIST\"\n  exit\n}\n\nlist_build_variants(){\n  if [ -n \"$1\" ];\n  then\n    OLD_PWD=$PWD\n    cd \"$1\" || exit\n  fi\n\n  if ! [ -f \"gradlew\" ];\n  then\n    echo \"🤷‍ No Android project found in current directory\"\n    exit\n  fi\n\n  TASK_LIST=\"toolkit_task_list.txt\"\n  echo \"⏳ Detecting build variants, this may take a while...\"\n  ./gradlew tasks | grep '^install' > $TASK_LIST\n\n  if [ \"$(nl \"$TASK_LIST\")\" == \"\" ]; then\n    echo \"🤷‍ No Android project build variants available! Aborting...\"\n    exit\n  else\n    echo \"🔨 Available:\"\n    nl $TASK_LIST\n  fi\n}\n\nbuild_project_variant(){\n  read -r -p \"📝 Choose build variant: \" VARIANT_INDEX\n  TASK=$(sed \"$VARIANT_INDEX\"!d $TASK_LIST | awk '{ print $1 }' )\n  if [[ $VARIANT_INDEX == \"\" || $TASK == \"\" ]]; then\n    delete_lastline\n    build_project_variant\n  else\n    echo  \"🚀 Triggering new build...\"\n    ANDROID_SERIAL=$SELECTED_DEVICE ./gradlew \"$TASK\"\n  fi\n  if [ $? == \"0\" ];\n  then\n    VARIANT=${TASK#\"install\"}\n    echo  \"✅ $VARIANT build variant installed successfully\"\n  else\n    echo  \"❌ $VARIANT build variant installation failed\"\n  fi\n}\n\nfind_apk_path(){\n  rm -rf \"./outputs/apk/*\"\n  APK_PATH=$(find . -iname \"*.apk\" | sort | tail -1)\n}\n\nlaunch(){\n  android_detect_package_info \"$1\"\n  echo \"🚀 Launching $APP_NAME...\"\n  adb -s \"$SELECTED_DEVICE\" shell monkey -p \"$PACKAGE_NAME\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n}\n\ncopy_apk_to_desktop(){\n  FILENAME=$(echo \"$PACKAGE_NAME\" | tr . _)\n  FILENAME=\"$FILENAME.apk\"\n  cp \"$APK_PATH\" \"$HOME/Desktop/$FILENAME\"\n  echo \"💾 \\\"$FILENAME\\\" saved to ~/Desktop\"\n}\n\nandroid_choose_device\nlist_build_variants \"$@\"\nbuild_project_variant\nfind_apk_path\nlaunch \"$APK_PATH\"\ncopy_apk_to_desktop\ncleanup\n"
  },
  {
    "path": "android/acamera",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\necho \"📷 Opening camera application...\"\nadb -s \"$SELECTED_DEVICE\" shell am start -a android.media.action.IMAGE_CAPTURE &> /dev/null\n"
  },
  {
    "path": "android/acheckdevice",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nGSM_URL='https://www.gsmarena.com/res.php3?sSearch='\n\necho_info(){\n  MANUFACTURER=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.product.manufacturer | tr -cd '[[:alnum:]]._-')\n  MODEL=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.product.model | tr -cd '[[:alnum:]]._-')\n  VERSION=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.build.version.release | tr -cd '[[:alnum:]]._-')\n  SDK=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.build.version.sdk | tr -cd '[[:alnum:]]._-')\n  INFO=$(printf \"%s %s %s (API %s)\" \"$MANUFACTURER\" \"$MODEL\" \"$VERSION\" \"$SDK\")\n\n  echo \"📱 $INFO\"\n  echo \"  • ID: $SELECTED_DEVICE\"\n  echo \"  • CPU: $(adb -s \"$SELECTED_DEVICE\" shell getprop ro.product.cpu.abi | tr -cd '[[:alnum:]]._-')\"\n  echo \"  • Display density: $(adb -s \"$SELECTED_DEVICE\" shell getprop ro.sf.lcd_density | tr -cd '[[:alnum:]]._-')\"\n}\n\ncheck_screen_timeout(){\n  echo -n \"🕑 Checking screen timeout\"\n  TIMEOUT=$(adb -s \"$SELECTED_DEVICE\" shell settings get system screen_off_timeout)\n  TIMEOUT=${TIMEOUT%$'\\r'} # remove trailing carriage return\n\n  if [ \"$TIMEOUT\" != \"600000\" ]; then\n    yes_or_no \" - 🕤 Timeout is $TIMEOUT miliseconds, set to 10 minutes?\"; if ! [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then return; fi\n    adb -s \"$SELECTED_DEVICE\" shell settings put system screen_off_timeout 600000\n  else\n    echo \" - ✅ 10 minutes\"\n  fi\n}\n\ncheck_screen_brightness(){\n  echo -n \"🔆 Checking screen brightness\"\n  BRIGHTNESS=$(adb -s \"$SELECTED_DEVICE\" shell settings get system screen_brightness)\n  BRIGHTNESS=${BRIGHTNESS%$'\\r'} # remove trailing carriage return\n  if [ \"$BRIGHTNESS\" != \"255\" ]; then\n    yes_or_no \" - 🔥 Brightness is $BRIGHTNESS, set manual max brightness?\"; if ! [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then return; fi\n    adb -s \"$SELECTED_DEVICE\" shell settings put system screen_brightness_mode 0\n    adb -s \"$SELECTED_DEVICE\" shell settings put system screen_brightness 255\n  else\n    echo \" - ✅ MAX\"\n  fi\n}\n\ncheck_notification_volume(){\n  echo -n \"📢 Checking notification volume\"\n  RINGER_MODE=$(adb -s \"$SELECTED_DEVICE\" shell settings get global mode_ringer)\n  RINGER_MODE=${RINGER_MODE%$'\\r'} # remove trailing carriage return\n  if [ \"$RINGER_MODE\" != \"1\" ]; then\n    yes_or_no \" - 🔕 Ringer mode is not 1 (~silent), try to set silent mode?\"; if ! [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then return; fi\n    adb -s \"$SELECTED_DEVICE\" shell input keyevent 164\n  else\n    echo \" - ✅ Muted\"\n  fi\n}\n\ncheck_network_name_contains(){\n  echo -n \"🌐 Checking WIFI network\"\n  NET_STATS=$(adb -s \"$SELECTED_DEVICE\" shell dumpsys netstats | grep -E 'iface=wlan.*networkId' )\n\n  if echo \"$NET_STATS\" | grep -i \"$1\" &> /dev/null; then\n    yes_or_no \" - ❗️ $1 network detected, open wifi settings?\"; if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then adb -s \"$SELECTED_DEVICE\" shell am start -a android.net.wifi.PICK_WIFI_NETWORK &> /dev/null; fi\n  fi\n\n  if ! echo \"$NET_STATS\" | grep -E 'iface=wlan.*networkId' &> /dev/null; then\n    yes_or_no \" - ❌ Disconnected, open wifi settings?\"; if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then adb -s \"$SELECTED_DEVICE\" shell am start -a android.net.wifi.PICK_WIFI_NETWORK &> /dev/null; fi\n  else\n    echo \" - ✅ Connected\"\n  fi\n}\n\ncheck_automatic_date(){\n  echo -n \"📆 Checking date\"\n  AUTO_TIME=$(adb -s \"$SELECTED_DEVICE\" shell settings get global auto_time)\n  AUTO_TIME=${AUTO_TIME%$'\\r'} # remove trailing carriage return\n  if [ \"$AUTO_TIME\" == \"0\" ]; then\n    yes_or_no \" - ❗️ Date is set manually, open date settings?\"\n    if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then\n      adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.DATE_SETTINGS &> /dev/null\n    fi\n  else\n    echo \" - ✅ Automatic\"\n  fi\n}\n\ncheck_locale(){\n  DEFAULT_LOCALE=\"en-US\"\n\n  echo -n \"👄 Checking locale\"\n  CURRENT_LOCALE=$(adb -s \"$SELECTED_DEVICE\" shell getprop persist.sys.locale)\n  CURRENT_LOCALE=${CURRENT_LOCALE%$'\\r'} # remove trailing carriage return\n\n  if [ \"$CURRENT_LOCALE\" != \"$DEFAULT_LOCALE\" ]; then\n    yes_or_no \" - ❗️ Current locale is $CURRENT_LOCALE, open locale settings?\"\n    if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then\n      adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.LOCALE_SETTINGS &> /dev/null\n    fi\n  else\n    echo \" - ✅ $CURRENT_LOCALE\"\n  fi\n}\n\ncheck_font_scale(){\n  DEFAULT_SCALE=\"1.0\"\n\n  echo -n \"🔠 Checking font scale\"\n  SCALE=$(adb -s \"$SELECTED_DEVICE\" shell settings get system font_scale)\n  SCALE=${SCALE%$'\\r'} # remove trailing carriage return\n\n  if [ \"$SCALE\" != \"$DEFAULT_SCALE\" ]; then\n    yes_or_no \" - 🔍 Current scale is $SCALE, change to $DEFAULT_SCALE\"\n    if [ \"$RESPONSE\" == \"y\" ] || [ \"$RESPONSE\" != \"Y\" ]; then\n      adb -s \"$SELECTED_DEVICE\" shell settings put system font_scale \"$DEFAULT_SCALE\"\n    fi\n  else\n    echo \" - ✅ $SCALE\"\n  fi\n}\n\nopen_gsmarena(){\n  should_proceed \"🔍 Search for the device on GSMArena?\"\n  PHONE_URL=$GSM_URL$MODEL\n  open \"$PHONE_URL\"\n}\n\nandroid_choose_device\necho_info\ncheck_screen_timeout\ncheck_screen_brightness\ncheck_notification_volume\ncheck_automatic_date\ncheck_locale\ncheck_network_name_contains edge\ncheck_font_scale\nopen_gsmarena\n\n# More settings available at https://developer.android.com/reference/android/provider/Settings.System.html#SCREEN_OFF_TIMEOUT\n"
  },
  {
    "path": "android/acontrol",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\ncheck_dependency \"scrcpy\"\ncheck_adb_dependency\nandroid_choose_device\nandroid_device_info \"$SELECTED_DEVICE\"\necho \"🔌 Connecting to $MANUFACTURER $MODEL (API $SDK)...\"\nscrcpy -s \"$SELECTED_DEVICE\" &> /dev/null &\n"
  },
  {
    "path": "android/adarkmode",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nturn_off_darkmode(){\n  echo \"⚪️ Turning off dark mode...\"\n  #adb -s \"$SELECTED_DEVICE\" shell settings put secure ui_night_mode 1 &> /dev/null #Not working without a reboot\n  adb -s \"$1\" shell cmd uimode night no &> /dev/null\n}\n\nturn_on_darkmode(){\n  echo \"⚫️ Turning on dark mode...\"\n  #adb -s \"$1\" shell settings put secure ui_night_mode 2 &> /dev/null\n  adb -s \"$1\" shell cmd uimode night yes &> /dev/null\n}\n\nDARKMODE_STATE=$(adb -s \"$SELECTED_DEVICE\" shell cmd uimode night)\n\nif [ \"$DARKMODE_STATE\" != \"Night mode: yes\" ]; then\n  turn_on_darkmode \"$SELECTED_DEVICE\"\nelse\n  turn_off_darkmode \"$SELECTED_DEVICE\"\nfi\n"
  },
  {
    "path": "android/aemulator",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nLOCAL_EMULATOR_LIST=$LOCATION/../data/toolkit_emulator_list.txt\nNET_CHANGED=false\n\ntrap 'ctrlc $@' 1 2 3 6 15\nctrlc(){\n  if $NET_CHANGED ; then\n    disable_network_delay\n  fi\n  exit\n}\n\nhelp(){\n  if [[ $1 != \"\" ]]; then\n    echo \"🤷‍ Unknown option: $1\"\n  else\n    echo \"🤷 Option missing\"\n  fi\n  echo -e \"Use one of the following options:\\\\n  start - choose and launch installed emulator\\\\n  gprs | edge | 3g - set network latency\\\\n  call <number> - receive fake call\\\\n  sms <number> <text> - recieve fake sms\\\\n  gps <lat> <long> - set manual gps location\\\\n  battery <0-100> - set manual battery level\\\\n  telnet <command> - call telnet command (see README.md)\"\n}\n\ncheck_java_dependency(){\n  if ! java -version &> /dev/null; then\n    echo \"❌ Java not available, edit your .bash_profile or .zshrc to use Android Studio version\"\n    echo \"📝 Add the following line: export JAVA_HOME='/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home'\"\n    echo \"🔌 Restart terminal afterwards\"\n    exit 1\n  fi\n}\n\ncheck_running_emulator(){\n  if ! adb devices | grep emulator &> /dev/null; then\n    echo \"❌ No running emulators\"\n    yes_or_no \"❓ Do you want to start one?\"\n    if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]];\n    then\n      launch_emulator\n      android_wait_for_device\n      get_token\n    fi\n    exit\n  fi\n}\n\nget_emulator_list(){\n  echo \"⏳ Getting Android emulator list...\"\n  rm -f \"$LOCAL_EMULATOR_LIST\"\n  \"$ANDROID_HOME\"/cmdline-tools/latest/bin/avdmanager list avd | grep Name | awk '{print $2}' >> \"$LOCAL_EMULATOR_LIST\"\n  if [ \"$(nl \"$LOCAL_EMULATOR_LIST\")\" == \"\" ]; then\n    should_proceed \"🤷‍ No emulators installed, install via Android Studio?\"\n    echo \"⏳ Opening Android Studio...\"\n    open -a /Applications/Android\\ Studio.app\n    exit\n  else\n    echo \"📱 Available:\"\n    nl \"$LOCAL_EMULATOR_LIST\"\n  fi\n}\n\nlaunch_emulator(){\n  get_emulator_list\n\n  if [ -z \"$1\" ]; then\n    read -r -p \"📝 Choose: \" EMULATOR_INDEX\n  else\n    EMULATOR_INDEX=$1\n  fi\n  EMULATOR_NAME=$(sed \"$EMULATOR_INDEX\"!d \"$LOCAL_EMULATOR_LIST\")\n  if [[ $EMULATOR_INDEX == \"\" || $EMULATOR_NAME == \"\" ]]; then\n    delete_lastline\n    launch_emulator\n  else\n    echo  \"🚀 Launching emulator...\"\n    nohup \"$ANDROID_HOME\"/emulator/emulator -avd \"$EMULATOR_NAME\" -no-snapshot &> /dev/null &\n    rm \"$LOCAL_EMULATOR_LIST\"\n  fi\n}\n\nget_token(){\n  check_dependency \"telnet\"\n  [ -f ./emulator_console_auth_token ] || echo \"localhost 5554\" | telnet &> /dev/null\n  TOKEN=$(cat \"$HOME\"/.emulator_console_auth_token)\n}\n\ntelnet_command() {\n  get_token\n  if [ -z \"$1\" ];then\n    read -r -p \"📝 Insert telnet command: \" COMMAND\n  else\n    COMMAND=$1\n  fi\n  { echo \"o localhost 5554\"; sleep 1; echo \"auth $TOKEN\"; sleep 1; echo \"$COMMAND\"; } | telnet &> /dev/null\n}\n\ncall(){\n  if [ -z \"$1\" ];then\n    read -r -p \"📝 Insert caller number: \" NUMBER\n  else\n    NUMBER=$1\n  fi\n  echo \"📞 Making a call...\"\n  telnet_command \"gsm call $NUMBER\"\n  echo \"🔔 Ringing...\"\n}\n\nsend_sms(){\n  if [ -z \"$1\" ];then\n    read -r -p \"📝 Insert sender number: \" NUMBER\n  else\n    NUMBER=$1\n  fi\n\n  if [ -z \"$2\" ];then\n    read -r -p \"📝 Insert text: \" TEXT\n  else\n    TEXT=$2\n  fi\n\n  echo \"📝 Sending fake SMS...\"\n  telnet_command \"sms send $NUMBER $TEXT\"\n  echo \"✅ Done\"\n}\n\nset_gps(){\n  if [ -z \"$1\" ];then\n    read -r -p \"📝 Insert latitude: \" LAT\n  else\n    LAT=$1\n  fi\n\n  if [ -z \"$2\" ];then\n    read -r -p \"📝 Insert longtitude: \" LONG\n  else\n    LONG=$2\n  fi\n\n  echo \"🌎 Setting manual GPS location...\"\n  telnet_command \"geo fix $LONG $LAT\"\n  echo \"✅ Done\"\n}\n\nset_battery_level(){\n  if [ -z \"$1\" ];then\n    read -r -p \"📝 Insert battery level: \" LEVEL\n  else\n    LEVEL=$1\n  fi\n    echo \"🔋 Setting manual battery level...\"\n    { echo \"o localhost 5554\"; sleep 1; echo \"auth $TOKEN\"; sleep 1; echo \"power ac off\"; echo \"power status discharging\"; echo \"power capacity $LEVEL\"; } | telnet &> /dev/null\n    echo \"✅ Done\"\n}\n\nset_network_delay(){\n  DELAY=$1\n  if [[ \"$DELAY\" == \"3g\" ]]; then\n    DELAY=\"umts\"\n  fi\n  NET_CHANGED=true\n  echo \"🌐 Simulating network limit...\"\n  { echo \"o localhost 5554\"; sleep 1; echo \"auth $TOKEN\"; sleep 1; echo \"network delay $DELAY\"; echo \"network speed $DELAY\"; } | telnet &> /dev/null\n  read -r -n 1 -p \"⚡️ Press ENTER to stop...\"\n  disable_network_delay\n  echo \"✅ Done\"\n}\n\ndisable_network_delay(){\n  echo \"🔄 Disabling network limits...\"\n  { echo \"o localhost 5554\"; sleep 1; echo \"auth $TOKEN\"; sleep 1; echo \"network delay none\"; echo \"network speed full\"; } | telnet &> /dev/null\n  NET_CHANGED=false\n}\n\ncheck_for_update\ncheck_java_dependency\n\ncase $1 in\n  'start')\n    launch_emulator \"$2\"\n    ;;\n  'gprs' | 'edge' | '3g')\n    check_running_emulator\n    set_network_delay \"$1\"\n    ;;\n  'call')\n    check_running_emulator\n    call \"$2\"\n    ;;\n  'sms')\n    check_running_emulator\n    send_sms \"$2\" \"$3\"\n    ;;\n  'gps')\n    check_running_emulator\n    set_gps \"$2\" \"$3\"\n    ;;\n  'battery')\n    check_running_emulator\n    set_battery_level \"$2\"\n    ;;\n  'telnet')\n    check_running_emulator\n    telnet_command \"$2\"\n    ;;\n  *)\n    help \"$1\"\n    check_running_emulator\n    ;;\nesac\n"
  },
  {
    "path": "android/aerase",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nif [[ \"$1\" != \"\" ]];\nthen\n    APP=$1\n    android_is_package_installed \"$APP\"\nelse\n    APP=$(android_get_foreground_package)\nfi\n\nshould_proceed \"🧽 Do you really want to erase $APP data?\"\nadb -s \"$SELECTED_DEVICE\" shell pm clear \"$APP\" &> /dev/null\necho \"🚀 Launching...\"\nadb -s \"$SELECTED_DEVICE\" shell monkey -p \"$APP\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n"
  },
  {
    "path": "android/afontscale",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nset_font_scale(){\n  adb -s \"$SELECTED_DEVICE\" shell settings put system font_scale \"$1\"\n}\n\nandroid_choose_device\nif [ -z \"$1\" ] 2> /dev/null\nthen\n  CURRENT_FONT_SIZE=$(adb -s \"$SELECTED_DEVICE\" shell settings get system font_scale)\n  if [ \"$CURRENT_FONT_SIZE\" != \"1.0\" ]; then\n    echo \"🔄 Font scale restored to default \\\"1.0\\\"\"\n    set_font_scale \"1.0\"\n  else\n    echo \"🔍 Setting bigger font scale to \\\"1.3\\\"...\"\n    set_font_scale \"1.3\"\n  fi\nelse\n  echo \"🔍 Setting font scale to \\\"$1\\\"...\"\n  set_font_scale \"$1\"\nfi\n"
  },
  {
    "path": "android/agoogleplay",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nsearch_gp(){\n  APP_NAME=\"$1\"\n  echo \"🛒 Searching for $APP_NAME in Google Play...\"\n  APP_NAME=$(echo \"$APP_NAME\" | sed -e 's/ /\\%20/g')\n  GOOGLE_PLAY_URL=\"http://play.google.com/store/search\\\\?q\\\\=$APP_NAME\\\\&c\\\\=apps\"\n  adb -s \"$SELECTED_DEVICE\" shell am start -a android.intent.action.VIEW -d \"$GOOGLE_PLAY_URL\" &> /dev/null\n}\n\nif [ -z \"$1\" ] ; then\n  search_gp \"$(android_get_foreground_package)\"\n  exit\nelse\n  APP_NAME=\"'$*'\"\n  search_gp \"$APP_NAME\"\nfi\n"
  },
  {
    "path": "android/ainstall",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\ninstall_app(){\n  echo \"⌛️ Installing \\\"$PACKAGE_NAME\\\" to $1...\"\n  TEMPORARY_FILE=\"$TEMPORARY_FILE-$(date +%s)\"\n  adb -s \"$1\" install -t -r \"$2\" &> \"$TEMPORARY_FILE\"\n  if grep -q Failure \"$TEMPORARY_FILE\" ; then\n    echo \"❌ Installation to $1 failed!\"\n    echo \"🤕 Uninstall existing version or troubleshoot the package\"\n    echo \"🔥 Error details: $(grep 'Failure' \"$TEMPORARY_FILE\" | sed 's/^.*: //')\"\n    exit 1\n  fi\n  echo \"🚀 Launching $APP_NAME on $1...\"\n  adb -s \"$1\" shell monkey -p \"$PACKAGE_NAME\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n}\n\ncheck_args_valid(){\n  if [[ \"$1\" != \"-a\" ]]; then\n    FILE=$1\n  else\n    FILE=$2\n  fi\n\n  if [ ! -f \"$PWD/$FILE\" ] && [ ! -f \"$FILE\" ]; then\n      abort \"🤷‍ Installation file not found!\"\n  fi\n\n  if [[ \"$FILE\" != *\".apk\" ]]; then\n      abort \"🤷 Unsupported file!\"\n  fi\n}\n\nrun()\n{\n  if [[ $1 == \"-a\" ]]; then\n    check_for_update\n    android_check_connected\n    android_get_devices_auth_dump\n    android_detect_package_info \"$2\"\n    for line in $(adb devices | grep -v \"List\"  | awk '{print $1}')\n    do\n      DEVICE=$(echo \"$line\" | awk '{print $1}')\n      install_app \"$DEVICE\" \"$2\" &\n    done\n    wait\n  else\n    android_choose_device\n    android_detect_package_info \"$1\"\n    install_app \"$SELECTED_DEVICE\" \"$1\"\n  fi\n}\n\n# \"$@\" - pass all arguments\ncheck_args_valid \"$@\"\nrun \"$@\"\n"
  },
  {
    "path": "android/akill",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nif [[ \"$1\" != \"\" ]];\nthen\n    PACKAGE_NAME=$1\n    android_is_package_installed \"$PACKAGE_NAME\"\nelse\n    PACKAGE_NAME=$(android_get_foreground_package)\nfi\n\necho \"🔪 Package \\\"$PACKAGE_NAME\\\" process killed\"\nadb -s \"$SELECTED_DEVICE\" shell am force-stop \"$PACKAGE_NAME\"\necho \"🚀 Relaunching the app...\"\nadb -s \"$SELECTED_DEVICE\" shell monkey -p \"$PACKAGE_NAME\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n"
  },
  {
    "path": "android/alaunch",
    "content": "#!/bin/bash\nsource \"$(dirname \"$0\")\"/../common_tools\nandroid_choose_device\n\nif [[ \"$1\" == \"-s\" ]]; then\n  PACKAGES=($(adb -s \"$SELECTED_DEVICE\" shell pm list packages -f | sed -e 's/.*=//' | sort))\nelif [[ -n \"$1\" ]]; then\n  PACKAGE=\"$1\"\n  android_is_package_installed \"$PACKAGE\"\nelse\n  PACKAGES=($(adb -s \"$SELECTED_DEVICE\" shell pm list packages -f -3 | sed -e 's/.*=//' | sort))\nfi\n\nif [ -z \"$PACKAGE\" ]; then\n  PACKAGES_LISTED=()\n  for P in \"${PACKAGES[@]}\" #removes trailing \\r\n  do\n    P=${P%$'\\r'}\n    PACKAGES_LISTED+=(\"$P\")\n  done\n\n  if [ ${#PACKAGES_LISTED[@]} -eq 0 ]; then\n      echo \"🤷‍ No third-party apps installed, use \\\"alaunch -s\\\" to list system packages\"\n      exit\n  fi\n\n  echo \"📋 Choose package to launch:\"\n  select OPTION in \"${PACKAGES_LISTED[@]}\"\n  do\n   case $OPTION in\n      *) PACKAGE=$OPTION;break; ;;\n    esac\n  done\nfi\n\necho \"🚀 Launching $PACKAGE...\"\nadb -s \"$SELECTED_DEVICE\" shell monkey -p \"$PACKAGE\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n"
  },
  {
    "path": "android/alog",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nfilter_by_package(){\n  android_is_package_installed \"$1\"\n  echo \"🔍 Filtering by package name: $1\"\n  PID=$(adb -s \"$SELECTED_DEVICE\" shell ps | grep -i \"$1\" | cut -c10-15)\n  adb -s \"$SELECTED_DEVICE\" logcat | grep \"$PID\"\n}\n\nraw_log(){\n  echo \"📜 Device log:\"\n  adb -s \"$SELECTED_DEVICE\" logcat\n}\n\nif [ \"$1\" == \"-f\" ]; then\n  if [ -z \"$2\" ]; then\n    read -r -p \"🔬 Insert package name (Android 7+) or leave empty to proceed: \" PACKAGE\n  else\n    PACKAGE=$2\n  fi\n  filter_by_package \"$PACKAGE\"\nelse\n    raw_log\nfi\n"
  },
  {
    "path": "android/aoptions",
    "content": "#!/bin/bash\nTOOLKIT_LOCATION=$(dirname \"$0\")\nsource \"$TOOLKIT_LOCATION\"/../common_tools\nandroid_choose_device\n\nLOCAL_SETTINGS_LIST_PATH=$TOOLKIT_LOCATION/../data/toolkit_intent_list.txt\n\nimport_intents(){\n  echo \"⏳ Importing settings activity list...\"\n  ANDROID_TOOLS_SETTINGS_INTENT_LIST_PATH=$(find ~/Library/Android/sdk -name 'activity_actions.txt' | sort | tail -1)\n  {\n    grep -i \"android.settings\" \"$ANDROID_TOOLS_SETTINGS_INTENT_LIST_PATH\" # List settings intents\n    grep -i -e \"android.net.wifi.PICK_WIFI_NETWORK\" -e \"android.os.storage.action.MANAGE_STORAGE\" -e \"android.intent.action.MANAGE_PERMISSIONS\" -e \"android.intent.action.SET_WALLPAPER\" -e \"android.intent.action.VIEW_DOWNLOADS\" \"$ANDROID_TOOLS_SETTINGS_INTENT_LIST_PATH\" # List alternate settings intents\n    grep -i \"android.media.action\" \"$ANDROID_TOOLS_SETTINGS_INTENT_LIST_PATH\" # List media intents\n  } >> \"$LOCAL_SETTINGS_LIST_PATH\"\n\n  wc -l \"$LOCAL_SETTINGS_LIST_PATH\" | awk '{print $1}' | grep -q 0 && echo \"❗️ Imported list is empty, reimporting lower sdk variant...\" && rm \"$(find ~/Library/Android/sdk -name 'activity_actions.txt' | sort | tail -1)\" && import_intents && return\n  echo \"✅ Importing from $ANDROID_TOOLS_SETTINGS_INTENT_LIST_PATH completed successfully\"\n}\n\nstart_settings_intent(){\n  SETTINGS_INTENT=$(sed \"$LINE\"!d \"$LOCAL_SETTINGS_LIST_PATH\")\n  echo \"🚀 Starting $SETTINGS_INTENT\"\n  adb -s \"$SELECTED_DEVICE\" shell am start -a \"$SETTINGS_INTENT\" &> /dev/null\n}\n\nsearch_for_intent(){\n  if nl \"$LOCAL_SETTINGS_LIST_PATH\" | grep -i -q \"$1\"; then\n    if [[ $(grep -c -i \"$1\" \"$LOCAL_SETTINGS_LIST_PATH\") -eq 1 ]]; then #If there is only one result\n      LINE=$(nl \"$LOCAL_SETTINGS_LIST_PATH\" | grep -i \"$1\" | awk '{print $1}')\n    else\n      nl \"$LOCAL_SETTINGS_LIST_PATH\" | grep -i \"$1\"\n      read -r -p \"📝 Choose option number: \" LINE\n    fi\n    start_settings_intent\n  else\n    read -r -p \"🤷‍ No \\\"$1\\\" intent found, try again or leave blank: \" KEYWORD\n    search_for_intent \"$KEYWORD\"\n  fi\n}\n\nhandle_preset(){\n  case \"$1\" in\n    \"S\" | \"s\")\n    echo \"🚀 Launching system settings app root activity...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.SETTINGS &> /dev/null\n    ;;\n\n    \"1\" | \"dev\" | \"developer\")\n    echo \"🔨 Opening developer settings...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.APPLICATION_DEVELOPMENT_SETTINGS &> /dev/null\n    ;;\n\n    \"2\" | \"locale\" | \"lang\" | \"language\")\n    echo \"🌍 Opening locale settings...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.LOCALE_SETTINGS &> /dev/null\n    ;;\n\n    \"4\" | \"wifi\" | \"network\")\n    echo \"🌐 Opening WIFI network settings...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.net.wifi.PICK_WIFI_NETWORK &> /dev/null\n    ;;\n\n    \"5\" | \"storage\")\n    echo \"📦 Opening storage management ...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.os.storage.action.MANAGE_STORAGE &> /dev/null\n    ;;\n\n    \"6\" | \"power\")\n    echo \"🔋 Opening power usage statistics...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.intent.action.POWER_USAGE_SUMMARY &> /dev/null\n    ;;\n\n    \"3\" | \"date\" | \"time\" | \"datetime\")\n    echo \"📅 Opening date & time settings...\"\n    adb -s \"$SELECTED_DEVICE\" shell am start -a android.settings.DATE_SETTINGS &> /dev/null\n    ;;\n\n    \"0\" | \"all\" | \"list\" | \"A\" | \"a\")\n    echo \"📜 Available settings activities:\"\n    nl \"$LOCAL_SETTINGS_LIST_PATH\"\n    read -r -p \"📝 Choose option number: \" LINE\n    start_settings_intent\n    ;;\n\n    \"U\" | \"update\" | \"u\")\n    rm \"$LOCAL_SETTINGS_LIST_PATH\"\n    import_intents\n    ;;\n\n    *)\n    search_for_intent \"$1\"\n\n    ;;\n  esac\n}\n\n# Initialize available intent list - inspiration here https://stackoverflow.com/questions/8971160/what-is-the-exhaustive-list-of-all-android-intent-action-actions-available-in\nif [ ! -f \"$LOCAL_SETTINGS_LIST_PATH\" ]; then\n    echo \"✨ Activity list not initialized yet\"\n    import_intents\nfi\n\n# If arugment not passed, show preset chooser\nif [[ \"$1\" == \"\" ]]; then\n  TOOLKIT_INTENT_COUNT=$(wc -l \"$LOCAL_SETTINGS_LIST_PATH\")\n  TOOLKIT_INTENT_COUNT=$(echo \"$TOOLKIT_INTENT_COUNT\" | awk '{print $1}') # Remove ghost whitespaces 🙃\n\n  echo \"📋 Available options:\"\n  tput setaf 3; echo \"A) Show all $TOOLKIT_INTENT_COUNT settings options\"; tput sgr0\n  echo -e \"S) Open system settings application\\\\n1) Developer\\\\n2) Locale\\\\n3) Date & time\\\\n4) Wifi network\\\\n5) Storage management\\\\n6) Power usage\\\\nU) Update settings list from Android sdk\\\\nor\\\\n<text> to search in all settings\"\n  read -r -p \"📝 Enter your selection: \" PRESET\n  handle_preset \"$PRESET\"\n  exit\nelse\n  handle_preset \"$1\"\nfi\n"
  },
  {
    "path": "android/apaste",
    "content": "#!/bin/bash\n# shellcheck disable=SC1001\n#ignore regex - sign occurence\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nLOREM=\"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\nARGUMENT_COUNT=\"$#\"\n\ncheck_text(){\n  if [ -n \"$1\" ]\n  then\n    if ! [[ \"$*\" =~ [^a-zA-Z0-9\\ \\-\\.\\@] ]]; then\n      TEXT=$1\n    else\n      echo \"🤷‍ Only basic alphanumeric characters are supported!\"\n      exit 1\n    fi\n  else\n      echo \"🤷‍ No text to insert!\"\n      exit 1\n  fi\n}\n\nescape_spaces(){\n  ESCAPED_TEXT=$(echo \"$1\" | sed -e 's/ /\\%s/g')\n}\n\nsend_text(){\n  escape_spaces \"$1\"\n  android_get_device_sdk \"$SELECTED_DEVICE\"\n  if (( SDK > 27 )); then\n    # Insert only first character\n    adb -s \"$SELECTED_DEVICE\" shell \"input text '${ESCAPED_TEXT:0:1}'\"\n    # Afterwards the rest - workaround for API 28+ edittext char skip bug\n    adb -s \"$SELECTED_DEVICE\" shell \"input text '${ESCAPED_TEXT:1:${#ESCAPED_TEXT}}'\"\n  else\n    adb -s \"$SELECTED_DEVICE\" shell \"input text '$ESCAPED_TEXT'\"\n  fi\n}\n\nexecute_by_arguments(){\n  echo \"📲 Sending text to $SELECTED_DEVICE...\"\n  # Handle arguments\n  if [ \"$1\" == \"-l\" ];\n  then\n    send_text \"$LOREM\"\n  elif [ \"$ARGUMENT_COUNT\" -gt 1 ];\n  then\n    for ARGUMENT in \"$@\"\n    do\n      send_text \"$ARGUMENT\"\n      sleep 0.5\n      if ! [ \"$ARGUMENT\" = \"${*: -1}\" ]; then #if not last argument, jump to next field\n       adb -s \"$SELECTED_DEVICE\" shell input keyevent 61\n      fi\n    done\n  else\n    send_text \"$TEXT\"\n  fi\n}\n\nexecute_for_all(){\n  check_for_update\n  android_get_devices_auth_dump\n\n  for DEVICE in $(adb devices | grep -v \"List\"  | awk '{print $1}')\n  do\n    (SELECTED_DEVICE=$DEVICE; execute_by_arguments \"$@\") & # Set var and start command in subshell\n  done\n  wait\n}\n\ncheck_text \"$@\"\nif [[ \"$1\" == \"-a\" ]]; then\n  execute_for_all \"${@:2}\" # All arguments starting from 2nd\nelse\n  android_choose_device\n  execute_by_arguments \"$@\"\nfi\n"
  },
  {
    "path": "android/apermissionreset",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\ntput setaf 1\nshould_proceed \"🚫 REVOKE ALL GRANTED PERMISSIONS on $SELECTED_DEVICE?\"\ntput setaf 0\nadb -s \"$SELECTED_DEVICE\" shell pm reset-permissions\n"
  },
  {
    "path": "android/apowerbutton",
    "content": "#!/bin/bash\nsource \"$(dirname \"$0\")\"/../common_tools\nandroid_choose_device\n\n# Reference for key events - https://gist.github.com/arjunv/2bbcca9a1a1c127749f8dcb6d36fb0bc\n\necho \"👋 Sending power button key event...\"\n# Send POWER screen key event (key 26)\nadb -s \"$SELECTED_DEVICE\" shell input keyevent POWER &>/dev/null\n"
  },
  {
    "path": "android/areboot",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nshould_proceed \"🔌 Do you really want to reboot - $SELECTED_DEVICE?\"\necho \"🔄 Rebooting the device...\"\nadb -s \"$SELECTED_DEVICE\" reboot &> /dev/null\n"
  },
  {
    "path": "android/arecord",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\n# Trap signal handling\ntrap 'ctrlc \"$@\"' 1 2 3 6 15\n\nUSE_LEGACY_RECORDING=false\n\ncheck_dependency \"scrcpy\"\n\nctrlc() {\n  adb -s \"$SELECTED_DEVICE\" shell settings put system show_touches 0\n\n  if $RECORDING; then\n    sleep 1\n\n    if $USE_LEGACY_RECORDING; then\n      if [ -z \"$2\" ]; then\n        android_device_info \"$SELECTED_DEVICE\"\n        FILENAME=\"$MANUFACTURER-$MODEL-API$SDK-$(date +%Y-%m-%d-%H-%M-%S)\"\n      else\n        FILENAME=\"$2\"\n      fi\n      echo \"📁 Copying the video from the device...\"\n      adb -s \"$SELECTED_DEVICE\" pull \"$DEVICE_FILE_PATH\"/output.mp4 ~/Desktop/\"$FILENAME\".mp4 &>/dev/null\n      adb -s \"$SELECTED_DEVICE\" shell rm \"$DEVICE_FILE_PATH\"/output.mp4 &>/dev/null\n    else\n      # Do nothing\n      :\n    fi\n\n    echo \"✅ Saved into ~/Desktop/$FILENAME.mp4\"\n\n  fi\n  exit\n}\n\nRECORDING=false\nandroid_choose_device\n\nandroid_get_device_sdk \"$SELECTED_DEVICE\"\nandroid_get_storage_location_per_SDK \"$SDK\"\n\nRECORDING=true\necho \"📹 Recording screen on $SELECTED_DEVICE, stop it using ctrl^c\"\n\nadb -s \"$SELECTED_DEVICE\" shell settings put system show_touches 1\n\n# Parse the flag option\nif [ \"$1\" == \"-l\" ]; then\n  USE_LEGACY_RECORDING=true\nfi\n\nif [ -z \"$2\" ]; then\n  android_device_info \"$SELECTED_DEVICE\"\n  FILENAME=\"$MANUFACTURER-$MODEL-API$SDK-$(date +%Y-%m-%d-%H-%M-%S)\"\nelse\n  FILENAME=\"$2\"\nfi\n\nOUTPUT_PATH=~/Desktop/\"$FILENAME\".mp4\n\n# Perform actions based on flags\nif $USE_LEGACY_RECORDING; then\n  adb -s \"$SELECTED_DEVICE\" shell screenrecord \"$DEVICE_FILE_PATH\"/output.mp4\nelse\n  scrcpy -s \"$SELECTED_DEVICE\" --verbosity=error --no-window --audio-codec=aac --record=file.mp4 --record=\"$OUTPUT_PATH\" &>/dev/null\nfi\n\n# Unset the trap\ntrap - 1 2 3 6 15\n"
  },
  {
    "path": "android/ascreenshot",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nscreenshot(){\n  android_device_info \"$1\"\n  FILENAME=\"$MANUFACTURER-$MODEL-API$SDK-$(date +%Y-%m-%d-%H-%M-%S).png\"\n\n  android_get_storage_location_per_SDK \"$SDK\"\n\n  echo \"📸 Saving screenshot into $FILENAME...\"\n  adb -s \"$1\" shell screencap -p \"$DEVICE_FILE_PATH\"/output.png\n  adb -s \"$1\" pull \"$DEVICE_FILE_PATH\"/output.png ~/Desktop/\"$FILENAME\" &>/dev/null\n  adb -s \"$1\" shell rm \"$DEVICE_FILE_PATH\"/output.png\n}\n\nscreenshot_all(){\n  check_for_update\n  android_get_devices_auth_dump\n  for line in $(adb devices | grep -v \"List\"  | awk '{print $1}')\n  do\n    device=$(echo \"$line\" | awk '{print $1}')\n    screenshot \"$device\" &\n  done\n  wait\n}\n\nif [ \"$1\" == \"-a\" ];\nthen\n  screenshot_all\nelse\n  android_choose_device\n  screenshot \"$SELECTED_DEVICE\"\nfi\n"
  },
  {
    "path": "android/aservices",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nSERVICE_LIST=$LOCATION/../data/toolkit_android_services.txt\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\necho \"🔍 Getting background service list...\"\nadb -s \"$SELECTED_DEVICE\" shell service list | tail -n +2 > \"$SERVICE_LIST\"\ncat \"$SERVICE_LIST\"\n\nSERVICE_COUNT=$(wc -l < \"$SERVICE_LIST\")\nchoose_number \"$SERVICE_COUNT\" \"🔍 Find more about specific service - choose number: \"\nSERVICE_PACKAGE=$(sed \"$CHOICE\"!d \"$SERVICE_LIST\" | cut -d \"[\" -f2 | cut -d \"]\" -f1) #get string in brackets\nQUERY=\"android service '$SERVICE_PACKAGE'\"\necho \"🌐 Performing Google search for: $QUERY\"\nopen https://www.google.com/search?q=\"$QUERY\"\n\n# Potential usage: https://stackoverflow.com/questions/17580199/sending-a-sms-on-android-through-adb/30224091\n# More: https://resources.infosecinstitute.com/android-hacking-security-part-3-exploiting-broadcast-receivers/#gref\n"
  },
  {
    "path": "android/atalkback",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nturn_off_talkback(){\n  echo \"🔇 Turning off TalkBack...\"\n  adb -s \"$1\" shell am force-stop com.google.android.marvin.talkback &> /dev/null\n}\n\nturn_on_talkback(){\n  echo \"🔊 Turning on TalkBack...\"\n  adb -s \"$1\" shell settings put secure enabled_accessibility_services com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService &> /dev/null\n}\n\nTALKBACK_STATE=$(adb -s \"$SELECTED_DEVICE\" shell pidof com.google.android.marvin.talkback)\nif [ -z \"$TALKBACK_STATE\" ] || [ \"$TALKBACK_STATE\" == \"\" ]; then\n  turn_on_talkback \"$SELECTED_DEVICE\"\nelse\n  turn_off_talkback \"$SELECTED_DEVICE\"\nfi\n"
  },
  {
    "path": "android/atestmonkey",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\ntrap 'ctrlc' 1 2 3 6 15\n\nctrlc(){\n  if $RUNNING_TESTS; then\n    MONKEY_TASK_ID=$(adb -s \"$SELECTED_DEVICE\" shell pidof \"com.android.commands.monkey\")\n    adb -s \"$SELECTED_DEVICE\" shell kill \"$MONKEY_TASK_ID\" >/dev/null 2>&1\n    echo \"🔪 Test monkey terminated, the device is safe to use now!\"\n  fi\n\n  unlock_app_fullscreen \"$SELECTED_DEVICE\"\n  exit 2\n}\n\nunlock_app_fullscreen(){\n  adb -s \"$1\" shell am task lock stop >/dev/null 2>&1\n  echo \"🔓 App fullscreen pinning disabled\"\n}\n\nupdate_package_name(){\n  APP_PACKAGE_NAME=\"$(android_get_foreground_package \"$1\")\"\n}\n\ncheck_screen_pinning(){\n  PINNING_ENABLED=$(adb -s \"$1\" shell settings get system lock_to_app_enabled)\n  PINNING_ENABLED=${PINNING_ENABLED%$'\\r'} # remove trailing carriage return\n  if [ \"$PINNING_ENABLED\" != \"1\" ]; then\n    adb -s \"$1\" shell am start -a android.settings.SECURITY_SETTINGS >/dev/null 2>&1\n    read -r -p \"🔑 Enable \\\"Screen pinning\\\" option in security settings, then press enter...\"\n  fi\n}\n\nlock_task_fullscreen(){\n  check_screen_pinning \"$1\"\n  adb -s \"$1\" shell monkey -p \"$APP_PACKAGE_NAME\" -c android.intent.category.LAUNCHER 1 &> /dev/null\n  adb -s \"$1\" shell input keyevent \"KEYCODE_APP_SWITCH\"\n  read -r -p \"📌 Press the \\\"Pin\\\" button in \\\"$APP_PACKAGE_NAME\\\" window, then press enter... \" #TODO add check if already on\n}\n\nrun_test(){\n  SEED=\"$2\"\n  EVENT_COUNT=\"$3\"\n  tput setaf 3 && should_proceed \"🔥 DANGER ZONE ⊗ Send $EVENT_COUNT monkey test events to \\\"$APP_PACKAGE_NAME\\\"? (may take a while)\" && tput sgr0 #set red and white text color\n  echo \"🐒 Running monkey stress test... (press ctrl^c to end now)\"\n  RUNNING_TESTS=true\n  LOG_FILE=~/Desktop/\"monkey-test-log-$SEED-$APP_PACKAGE_NAME-$MANUFACTURER-$MODEL-API$SDK-$(date +%Y-%m-%d-%H-%M-%S).txt\"\n  adb -s \"$1\" shell monkey -p \"$APP_PACKAGE_NAME\" -s \"$SEED\" --pct-appswitch 0 --pct-syskeys 0 --pct-anyevent 0 \"$EVENT_COUNT\" &> \"$LOG_FILE\"\n  unlock_app_fullscreen \"$@\"\n  grep -q \"CRASH\" \"$LOG_FILE\" && tput setaf 1 && echo \"❌ Test failed, see crash log for details, seed: $SEED\" && tput sgr0 && open \"$LOG_FILE\" && exit 1\n  tput setaf 2 && echo \"✅ Test passed, successfully executed $EVENT_COUNT events, seed: $SEED\" && tput sgr0\n}\n\nRUNNING_TESTS=false\nEVENT_COUNT=15000 #Converts to $1 if passed\nSEED=\"$RANDOM\"\n\nandroid_choose_device\nandroid_device_info \"$SELECTED_DEVICE\"\nupdate_package_name \"$SELECTED_DEVICE\"\nlock_task_fullscreen \"$SELECTED_DEVICE\"\n\ncase \"$1\" in #if $1 not number, LOL\n    ''|*[!0-9]*) ;; #nothing left to do\n    *) EVENT_COUNT=\"$1\" ;;\nesac\n\ncase \"$2\" in #if $2 not number, LOL\n    ''|*[!0-9]*) ;; #nothing left to do\n    *) SEED=\"$2\" ;;\nesac\n\nrun_test \"$SELECTED_DEVICE\" \"$SEED\" \"$EVENT_COUNT\"\n"
  },
  {
    "path": "android/atestmonkeykill",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\n\nandroid_choose_device\n\nMONKEY_TASK_ID=$(adb -s \"$SELECTED_DEVICE\" shell pidof \"com.android.commands.monkey\")\n\nif [ -z \"$MONKEY_TASK_ID\"  ]; then\n  echo \"🙈 No test monkey running, device is safe to use\"\n\nelse\n  adb -s \"$SELECTED_DEVICE\" shell kill \"$MONKEY_TASK_ID\" >/dev/null 2>&1\n  echo \"🔪 Test monkey terminated, the device is safe to use now!\"\nfi\n"
  },
  {
    "path": "android/auninstall",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\ninit_uninstalling(){\n  echo \"⏳ Getting third-party package list...\"\n  IGNORED_PACKAGES=( \"com.microsoft.hockeyapp.testerapp\" \"io.crash.air\" \"de.codenauts.hockeyapp\" \"ar.core\" \"com.framerjs.android\" \"com.figma.mirror\" \"com.invisionapp.ifa\" \"com.android.chrome\" \"com.google.ar.core\" \"no.nordicsemi.android.mcp\" \"com.x8bit.bitwarden\" )\n  PACKAGES=($(adb -s \"$SELECTED_DEVICE\" shell pm list packages -f -3 | sed -e 's/.*=//' | sort))\n}\n\nuninstall_all(){\n    for PKG in \"${PACKAGES[@]}\"\n    do\n      PKG=${PKG%$'\\r'} #removes trailing \\r\n      uninstall_package \"$PKG\" &\n    done\n    wait\n}\n\nuninstall_package(){\n  PACKAGE=\"$1\"\n  echo \"${PACKAGES[*]}\" | grep -w \"$PACKAGE\" &> /dev/null || { echo \"🤷‍ Package \\\"$PACKAGE\\\" not installed\"; return 1; }\n  echo \"${IGNORED_PACKAGES[*]}\" | grep -w \"$PACKAGE\" &> /dev/null && { echo \"❌ Package \\\"$PACKAGE\\\" is whitelisted\"; return 1; }\n  echo \"🔥 Uninstalling \\\"$PACKAGE\\\"...\"\n  adb -s \"$SELECTED_DEVICE\" shell pm uninstall \"$PACKAGE\" &> /dev/null\n}\n\nselect_option(){\n    echo \"📋 Choose package number:\"\n    select OPTION in \"${PACKAGES_LISTED[@]}\"\n    do\n     case $OPTION in\n        *) PACKAGE=$OPTION;break; ;;\n      esac\n    done\n    if [[ -z $PACKAGE ]]; then\n      echo \"❌ Invalid option picked, retry\"\n      select_option\n    fi\n}\n\nfilter_packages(){\n    PACKAGES_LISTED=()\n    for PKG in \"${PACKAGES[@]}\" #removes trailing \\r\n    do\n      PKG=${PKG%$'\\r'}\n      echo \"${IGNORED_PACKAGES[@]}\" | grep -w \"$PKG\" &> /dev/null && { echo \"⏩ Skipped \\\"$PKG\\\"\"; continue; }\n      PACKAGES_LISTED+=(\"$PKG\")\n    done\n\n    if [ ${#PACKAGES_LISTED[@]} -eq 0 ]; then\n        echo \"🤷‍ Nothing to uninstall\"\n        exit\n    fi\n}\n\nhandle_arguments(){\n  if [[ -z \"$2\" ]]; then\n    android_choose_device\n  else\n    SELECTED_DEVICE=$2\n  fi\n\n  init_uninstalling\n\n  if [ -z \"$1\" ]; then\n    filter_packages\n    select_option\n    uninstall_package \"$PACKAGE\"\n  elif [[  \"$1\" == \"-w\" ]]; then\n    if [[ -z \"$2\" ]]; then\n      tput setaf 1\n      should_proceed \"💣 Delete all third-party apps on $SELECTED_DEVICE_MODEL - $SELECTED_DEVICE?\"\n      tput sgr0\n    fi\n    uninstall_all\n  elif [[ -n \"$1\" ]]; then\n    uninstall_package \"$1\"\n  fi\n}\n\nhandle_arguments \"$@\"\necho \"✅ Done\"\n"
  },
  {
    "path": "android/aurl",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nopen_url(){\n  check_url \"$2\"\n  echo \"🌎 Opening url on $1...\"\n  adb -s \"$1\" shell am start -a android.intent.action.VIEW -d \"$URL\" &> /dev/null\n}\n\ncheck_args_valid(){\n  if [[ \"$1\" != \"-a\" ]]; then\n    URL=$1\n  else\n    URL=$2\n  fi\n}\n\nrun()\n{\n  if [[ $1 == \"-a\" ]]; then\n    check_for_update\n    android_check_connected\n    android_get_devices_auth_dump\n    for line in $(adb devices | grep -v \"List\"  | awk '{print $1}')\n    do\n      DEVICE=$(echo \"$line\" | awk '{print $1}')\n      open_url \"$DEVICE\" \"$URL\" &\n    done\n    wait\n  else\n    android_choose_device\n    open_url \"$SELECTED_DEVICE\" \"$URL\"\n  fi\n}\n\ncheck_args_valid \"$@\"\nrun \"$@\"\n"
  },
  {
    "path": "android/awipe",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nandroid_choose_device\n\nprompt(){\n  tput setaf 1\n  yes_or_no \"💣 Wipe all data on $SELECTED_DEVICE_MODEL - $SELECTED_DEVICE?\"\n  tput sgr0\n  if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then\n    wipe_apps\n    wipe_data\n  fi\n}\n\nwipe_data(){\n  android_device_info \"$SELECTED_DEVICE\"\n  android_get_storage_location_per_SDK \"$SDK\"\n\n  echo \"🔥 Deleting everything in mnt/sdcard...\"\n  adb -s \"$SELECTED_DEVICE\" shell rm -rf \"$DEVICE_FILE_PATH/*\" &>/dev/null\n}\n\nwipe_apps(){\n  echo \"🔥 Deleting all third-party apps...\"\n  \"$LOCATION\"/auninstall \"-w\" \"$SELECTED_DEVICE\"\n}\n\nprompt\necho \"✅ Done\"\n"
  },
  {
    "path": "android/awireless",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nget_device_ip(){\n  android_choose_device\n  DEVICE_IP=$(adb -s \"$SELECTED_DEVICE\" shell ip route | awk '{print $9}')\n  DEVICE_IP=$(echo \"$DEVICE_IP\" | cut -d' ' -f1)\n}\n\nsetup_network_connection(){\n  echo \"🌎 Setting up wireless connection...\"\n  adb -s \"$SELECTED_DEVICE\" tcpip 5555 &> /dev/null\n  echo \"🌎 Getting device IP...\"\n  delete_lastline\n  echo \"🌎 Device IP: $DEVICE_IP\"\n  echo \"⏳ Connecting via local network...\"\n  STATUS=$(adb connect \"$DEVICE_IP:5555\")\n\n  echo \"$STATUS\" | grep \"refused\" && echo \"❌ Connection refused - already connected?\" && return\n  echo \"✅ Connected successfully, you can unplug the USB cable\"\n}\n\nsetup_usb_connection(){\n  echo \"🔌 Disabling wireless connection...\"\n  adb disconnect \"$DEVICE_IP:5555\" &> /dev/null\n  adb usb &> /dev/null\n}\n\nget_device_ip\n\nif [[ \"$SELECTED_DEVICE\" == \"emulator\"* ]]; then\n  echo \"🤷‍ Emulator is wireless by default...\"\n  exit 1\nfi\n\nif [ \"$SELECTED_DEVICE\" == \"$DEVICE_IP:5555\" ]; then\n  setup_usb_connection\nelse\n  setup_network_connection\nfi\n"
  },
  {
    "path": "changelog.txt",
    "content": "  🎉 This is a new (experimental) version 1.4.1!\n\n    📹 arecord was fixed to work with latest scrcpy version\n    If you are experiencing issues, try running \"brew upgrade scrcpy\"\n\n    📷 iscreenshot was fixed to work with iOS 17 or newer\n    This change is still experimental - please, report back any issues\n\n    👋 apowerbutton was added based on a pull request by luispinho\n    Thanks for your contribution, mate!\n\n    ⭐️ Special thanks to Lenka and František for proposing compatibility fixes\n    https://github.com/vrbajiva\n    https://github.com/franceskoooo\n\n    💌 Rate Mobile Toolkit and provide optional feedback using this link\n    https://forms.gle/nfBHeMSjxEQMs1kv5\n"
  },
  {
    "path": "common_tools",
    "content": "#!/bin/bash\n# shellcheck disable=SC2034\n\n##############################################################################\n### VARs\n\nSCRIPT_LOCATION=$(dirname \"$0\")\nLAST_CHECK_DATE_FILE=\"$SCRIPT_LOCATION/../data/toolkit_last_check_date.txt\"\nTEMPORARY_FILE=\"/private/tmp/mobile-toolkit-cache\"\n\nREGEX_NUMBER='^[0-9]+$'\n\n##############################################################################\n### Android\n\nandroid_check_connected(){\n  android_get_devices\n  #No device connected\n  if [ ${#DEVICES[@]} -eq 0 ]\n  then\n    echo \"❌ No Android devices detected\"\n    exit 1\n  fi\n}\n\nandroid_wait_for_device(){\n  echo \"⏳ Waiting for Android device...\"\n  adb wait-for-any-device\n  android_get_devices\n}\n\nandroid_get_devices_auth_dump(){\n  DEVICES_DUMP=\"$SCRIPT_LOCATION/../data/toolkit_adb_devices_dump.txt\"\n  rm -f $DEVICES_DUMP\n  adb devices | grep -v \"List\" >> $DEVICES_DUMP\n  if cat \"$DEVICES_DUMP\" | grep -q unauthorized ; then\n    read -r -p $'🚨 Unauthorized Android device detected!\\n🔌 Reconnect it, allow USB debugging and press ENTER...'\n    android_get_devices_auth_dump\n  fi\n  if cat \"$DEVICES_DUMP\" | grep -q offline ; then\n    read -r -p $'🚨 Offline Android device detected!\\n🔌 Wait until the startup is complete, then press ENTER...'\n    android_get_devices_auth_dump\n  fi\n}\n\nandroid_get_devices(){\n  #Populate array with device ids\n  DEVICES=()\n  android_get_devices_auth_dump\n  for LINE in $(cat $DEVICES_DUMP | awk '{print $1}')\n  do\n    DEVICE=$(echo \"$LINE\" | awk '{print $1}')\n    DEVICES+=(\"$DEVICE\")\n  done\n}\n\nandroid_get_device_sdk(){\n  SDK=$(adb -s \"$1\" shell getprop ro.build.version.sdk | tr -cd '[[:alnum:]]._-')\n}\n\nandroid_device_info(){\n  MANUFACTURER=$(adb -s \"$1\" shell getprop ro.product.manufacturer | tr -cd '[[:alnum:]]._-')\n  MODEL=$(adb -s \"$1\" shell getprop ro.product.model | tr -cd '[[:alnum:]]._-')\n  VERSION=$(adb -s \"$1\" shell getprop ro.build.version.release | tr -cd '[[:alnum:]]._-')\n  SDK=$(adb -s \"$1\" shell getprop ro.build.version.sdk | tr -cd '[[:alnum:]]._-')\n  INFO=$(printf \"%s) %s %s %s (API %s) - %s\" \"$NUMBER\" \"$MANUFACTURER\" \"$MODEL\" \"$VERSION\" \"$SDK\" \"$1\")\n}\n\nandroid_choose_device() {\n  check_for_update\n  check_adb_dependency\n  android_check_connected\n\n  #Gather device info and choose device\n  if [ ${#DEVICES[@]} -gt 1 ]\n  then\n    NUMBER=1\n    echo \"📱 Available devices:\"\n    for ID in \"${DEVICES[@]}\"\n    do\n      android_device_info \"$ID\"\n      echo \"$INFO\"\n      ((NUMBER++))\n    done\n\n    read -r -p \"📝 Select a device: \" CHOICE\n    while :;\n    do\n    if [[ ! $CHOICE =~ $REGEX_NUMBER ]] || [ \"$CHOICE\" -le \"0\" -o \"$CHOICE\" -gt \"${#DEVICES[@]}\" ]; then\n      echo -en \"\\033[1A\\033[2K\" #deletes last echoed line in terminal\n      read -r -p \"🤷 Invalid input, try again: \" CHOICE\n    else\n      break\n    fi\n    done\n    SELECTED_DEVICE=${DEVICES[(($CHOICE-1))]}\nelse\n  SELECTED_DEVICE=\"${DEVICES[0]}\"\nfi\n\nSELECTED_DEVICE_MODEL=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.product.model | tr -cd '[[:alnum:]]._-')\nSELECTED_DEVICE_SDK=$(adb -s \"$SELECTED_DEVICE\" shell getprop ro.build.version.sdk | tr -cd '[[:alnum:]]._-')\n}\n\nandroid_device_unlocked(){\n  echo \"📱 Checking screen status...\"\n  adb -s \"$1\" shell dumpsys power | grep \"mWakefulness=\" | grep \"Awake\" &> /dev/null\n  return $?\n}\n\nandroid_get_foreground_package(){\n  android_get_device_sdk \"$SELECTED_DEVICE\"\n  if (( \"$SDK\" < 21 )); then\n    android_get_foreground_package_sdk_low\n  elif (( \"$SDK\" < 30 )); then\n    android_get_foreground_package_sdk_21_plus\n  elif (( \"$SDK\" < 31 )); then\n    android_get_foreground_package_sdk_30_plus\n  else\n    android_get_foreground_package_sdk_31_plus\n  fi\n}\n\nandroid_get_foreground_package_sdk_31_plus(){\n  adb -s \"$SELECTED_DEVICE\" shell dumpsys activity recents | grep 'Recent #0' | cut -d= -f3 | cut -d ':' -f2 | cut -d ' ' -f1\n}\n\nandroid_get_foreground_package_sdk_30_plus(){\n  adb -s \"$SELECTED_DEVICE\" shell dumpsys activity recents | grep 'Recent #0' | cut -d= -f6 |  cut -d ':' -f2 | cut -d ' ' -f1\n}\n\nandroid_get_foreground_package_sdk_21_plus(){\n  adb -s \"$SELECTED_DEVICE\" shell dumpsys activity recents | grep 'Recent #0' | cut -d= -f2 | sed 's| .*||' | cut -d '/' -f1\n}\n\nandroid_get_foreground_package_sdk_low(){\n  adb -s \"$SELECTED_DEVICE\" shell dumpsys window windows | grep mCurrentFocus | cut -d'/' -f1 | rev | cut -d' ' -f1 | rev\n}\n\nandroid_get_storage_location_per_SDK(){\n  if (( \"$1\" < 30 )); then\n    DEVICE_FILE_PATH=\"/mnt/sdcard\"\n  else\n    DEVICE_FILE_PATH=\"/storage/self/primary\"\n  fi\n}\n\nandroid_is_package_installed() {\n  adb -s \"$SELECTED_DEVICE\" shell pm list packages -f | sed -e 's/.*=//' | grep -w \"$1\" &> /dev/null\n  EXIT_CODE=$?\n  if [ $EXIT_CODE -ne 0 ]; then\n    echo \"🤷‍ Package \\\"$1\\\" is not installed\"\n    exit 1\n  fi\n}\n\nandroid_detect_package_info(){\n  echo \"🔍 Detecting package name...\"\n  AAPPT_PATH=$(find ~/Library/Android/sdk -name 'aapt' | sort | tail -1)\n  PACKAGE_INFO=$($AAPPT_PATH dump badging \"$1\" > $TEMPORARY_FILE)\n  PACKAGE_NAME=$(cat $TEMPORARY_FILE | grep package:\\ name);\n  PACKAGE_NAME=$(echo \"$PACKAGE_NAME\" | sed 's/^[^'\\'']*'\\''//');\n  PACKAGE_NAME=$(echo \"$PACKAGE_NAME\" | sed 's/'\\''.*//');\n  APP_NAME=$(cat $TEMPORARY_FILE  | grep application-label:)\n  APP_NAME=${APP_NAME#\"application-label:\"}\n}\n\nandroid_unlock_device(){\n  # arg1 = DEVICE_ID\n  # arg2 = MAX_RETRIES\n  MAX_RETRIES=\"$2\"\n  UNLOCK_RETRIES=1\nuntil android_device_unlocked \"$1\";\ndo\n    if [ \"$UNLOCK_RETRIES\" -le \"$MAX_RETRIES\" ]; then\n      echo \"🔆 Screen on attempt $UNLOCK_RETRIES...\"\n      ((UNLOCK_RETRIES++));\n      adb -s \"$1\" shell input keyevent KEYCODE_POWER\n      adb -s \"$1\" shell input keyevent 82\n      sleep 1;\n   else\n      read -r -p \"❌ Screen-wake failed, press ANY KEY after manual unlock...\"\n      break\n   fi\n done\n\n delete_lastline\n echo \"📱 Screen unlocked...\"\n}\n\n##############################################################################\n### iOS\n\ncheck_go_ios_version(){\n  if ! [ -x \"$(command -v \"go-ios\")\" ]; then\n    install_go_ios\n  else\n    #Here it complains about the missing agent/tunnel\n    GO_IOS_VERSION=$(go-ios --version)\n    #echo \"Version of go-ios is: $GO_IOS_VERSION\"\n  fi\n}\n\ninstall_go_ios(){\n  echo \"⏳ Installing https://github.com/danielpaulus/go-ios...\"\n  check_dependency \"go\"\n  CURRENT_DIR=\"$PWD\"\n  TOOLKIT_IOS_LOCATION=$(dirname \"$0\")\n  git clone \"https://github.com/danielpaulus/go-ios.git\" \"$TOOLKIT_IOS_LOCATION/go-ios\" &> /dev/null\n  cd \"$TOOLKIT_IOS_LOCATION/go-ios\"\n\n  go build .\n  chmod +x \"go-ios\"\n  mv \"go-ios\" \"go-ios-temp\"\n  mv \"go-ios-temp\" ..\n  cd ..\n  rm -rf \"$TOOLKIT_IOS_LOCATION/go-ios\"\n  mv \"go-ios-temp\" \"go-ios\"\n\n  cd \"$CURRENT_DIR\"\n}\n\nprompt_xcode_launch(){\n  echo \"❌ Developer image is not mounted and/or device screen is locked\"\n  should_proceed \"❓ Do you want to open Xcode to fix it? (make sure you have the latest version)\"\n  open -a Xcode\n  echo \"⏳ Waiting for Xcode to launch...\"\n  while true ; do\n    sleep 2\n    if [[ $(ps aux | grep -v grep | grep -c Xcode) -ne 0 ]]; then\n      break\n    fi\n  done\n  sleep 4\n  osascript -e 'quit app \"Xcode\"'\n}\n\nios_get_devices(){\n  check_go_ios_version\n  check_dependency \"jq\"\n\n  if [[ $(ps S | grep -c \"go-ios tunnel\") -ne 2 ]]; then\n    echo \"♻️ Launching go-ios tunnel for maximum iOS compatibility (17+)\"\n    nohup go-ios tunnel start --userspace --nojson >/dev/null 2>&1 &\n    GO_IOS_TUNNEL_PID=$!\n    #TODO save tunnel port and use it to avoid delays when trying various ports\n    disown $GO_IOS_TUNNEL_PID\n    sleep 1\n  fi\n\n  IOS_USB_DEVICES=( $(go-ios list --nojson | sort -u) )\n}\n\nios_pair_device(){\n  go-ios pair --udid=\"$1\" --nojson &> /dev/null\n  EXIT_CODE=$?\n  if [ $EXIT_CODE -ne 0 ]; then\n    read -p \"❌ Device is not paired - reconnect it, unlock screen, tap \\\"Trust\\\" and press ENTER...\"\n    ios_pair_device \"$1\"\n  fi\n}\n\nios_check_pairing(){\n  go-ios info --udid=\"$1\" &> \"$TEMPORARY_FILE\"\n  if cat \"$TEMPORARY_FILE\" | grep -q 'UntrustedHostBUID' ; then\n    read -r -p \"❌ Device is not paired - reconnect it, unlock screen, tap \\\"Trust\\\" and press ENTER...\"\n    ios_pair_device \"$1\"\n  fi\n  if cat \"$TEMPORARY_FILE\" | grep -q 'could not retrieve PairRecord' ; then\n    read -r -p \"❌ Device is not paired - reconnect it, unlock screen, tap \\\"Trust\\\" and press ENTER...\"\n    ios_pair_device \"$1\"\n  fi\n}\n\nios_check_developer_image(){\n  IS_MOUNTED=$((go-ios image list --udid=\"$1\" --nojson) 2>&1)\n  if [[ $IS_MOUNTED == *\"none\"* ]]; then\n    prompt_xcode_launch\n    ios_check_developer_image \"$1\"\n  fi\n}\n\nios_check_developer_image_and_pairing(){\n  ios_check_pairing \"$1\"\n  ios_check_developer_image \"$1\"\n}\n\nios_device_info(){\n  ios_check_developer_image_and_pairing \"$1\"\n  MANUFACTURER=\"Apple\"\n  go-ios info --udid=\"$1\" > \"$TEMPORARY_FILE\"\n  MODEL=$(ios_translate_name \"$(cat \"$TEMPORARY_FILE\" | jq -r '.HardwareModel')\")\n  VERSION=$(cat \"$TEMPORARY_FILE\" | jq -r '.ProductVersion')\n  INFO=$(printf \"%s) %s %s %s - %s\" \"$NUMBER\" \"$MANUFACTURER\" \"$MODEL\" \"$VERSION\" \"$ID\")\n}\n\nios_choose_device(){\n  check_for_update\n  ios_get_devices\n\n  if [ ${#IOS_USB_DEVICES[@]} -eq 0 ] #No device connected\n  then\n     echo \"❌ No iOS devices detected\"\n     exit 1\n  fi\n\n  if [ ${#IOS_USB_DEVICES[@]} -gt 1 ]\n  then\n     NUMBER=1\n     echo \"📱 Available devices:\"\n     for ID in \"${IOS_USB_DEVICES[@]}\"\n      do\n        ios_device_info \"$ID\"\n        echo \"$INFO\"\n        ((NUMBER++))\n      done\n\n      read -r -p \"📝 Select a device: \" CHOICE\n      while :;\n      do\n      if [[ ! $CHOICE =~ $REGEX_NUMBER ]] || [ \"$CHOICE\" -le \"0\" -o \"$CHOICE\" -gt \"${#IOS_USB_DEVICES[@]}\" ]; then\n        echo -en \"\\033[1A\\033[2K\" #deletes last echoed line in terminal\n        read -r -p \"🤷 Invalid input, try again: \" CHOICE\n      else\n        break\n      fi\n      done\n      SELECTED_DEVICE=${IOS_USB_DEVICES[(($CHOICE-1))]}\n  else\n     SELECTED_DEVICE=\"${IOS_USB_DEVICES[0]}\"\n  fi\n}\n\nios_get_installed_package_list(){\n  echo \"⏳ Getting third-party package list...\"\n  INSTALLED_PACKAGES=($(go-ios apps --udid=\"$1\" | jq -r '.[] | .CFBundleIdentifier'))\n}\n\nios_get_all_package_list(){\n  echo \"⏳ Getting all package list...\"\n  INSTALLED_PACKAGES=($(go-ios apps --udid=\"$1\" | jq -r '.[] | .CFBundleIdentifier'))\n  SYSTEM_PACKAGES=($(go-ios apps --udid=\"$1\" --system | jq -r '.[] | .CFBundleIdentifier'))\n  ALL_PACKAGES=(\"${INSTALLED_PACKAGES[@]}\" \"${SYSTEM_PACKAGES[@]}\")\n}\n\nios_is_package_installed(){\n  ios_get_all_package_list \"$SELECTED_DEVICE\"\n  echo \"${ALL_PACKAGES[*]}\" | grep -w \"$1\" &> /dev/null\n  EXIT_CODE=$?\n  if [ $EXIT_CODE -ne 0 ]; then\n    echo \"🤷‍ Package \\\"$1\\\" is not installed\"\n    exit 1\n  fi\n}\n\nios_translate_name(){\n  # Translations here https://www.theiphonewiki.com/wiki/Models\n  NAME=$1\n  case $NAME in\n    \"Purple\"*|\"purple\"*)\n      NAME=\"iPhone\"\n      ;;\n    \"M68\"*)\n      NAME=\"iPhone\"\n      ;;\n    \"N90\"*|\"N92\"*)\n      NAME=\"iPhone4\"\n      ;;\n    \"N94\"*)\n      NAME=\"iPhone4S\"\n      ;;\n    \"N88\"*)\n      NAME=\"iPhone3GS\"\n      ;;\n    \"N82\"*)\n      NAME=\"iPhone3G\"\n      ;;\n    \"N71\"*)\n      NAME=\"iPhone6S\"\n      ;;\n    \"N66\"*)\n      NAME=\"iPhone6SPlus\"\n      ;;\n    \"N61\"*)\n      NAME=\"iPhone6\"\n      ;;\n    \"N56\"*)\n      NAME=\"iPhone6Plus\"\n      ;;\n    \"N51\"*|\"N53\"*)\n      NAME=\"iPhone5S\"\n      ;;\n    \"N48\"*)\n      NAME=\"iPhone5C\"\n      ;;\n    \"N41\"*|\"N42\"*)\n      NAME=\"iPhone5\"\n      ;;\n    \"D10\"*)\n      NAME=\"iPhone7\"\n      ;;\n    \"D11\"*)\n      NAME=\"iPhone7Plus\"\n      ;;\n    \"D20\"*)\n      NAME=\"iPhone8\"\n      ;;\n    \"D21\"*)\n      NAME=\"iPhone8Plus\"\n      ;;\n    \"D22\"*|\"Ferrari\"*|\"ferrari\"*)\n      NAME=\"iPhoneX\"\n      ;;\n    \"D32\"*)\n      NAME=\"iPhoneXS\"\n      ;;\n    \"D33\"*)\n      NAME=\"iPhoneXSMax\"\n      ;;\n    \"N104\"*)\n      NAME=\"iPhone11\"\n      ;;\n    \"D421\"*)\n      NAME=\"iPhone11Pro\"\n      ;;\n    \"D431\"*)\n      NAME=\"iPhone11ProMax\"\n      ;;\n    \"D52\"*)\n      NAME=\"iPhone12Mini\"\n      ;;\n    \"D53g\"*)\n      NAME=\"iPhone12\"\n      ;;\n    \"D53p\"*)\n      NAME=\"iPhone12Pro\"\n      ;;\n    \"D54\"*)\n      NAME=\"iPhone12ProMax\"\n      ;;\n    \"N84\"*)\n      NAME=\"iPhoneXR\"\n      ;;\n    \"N69\"*)\n      NAME=\"iPhoneSEgen1\"\n      ;;\n    \"D79\"*)\n      NAME=\"iPhoneSEgen2\"\n      ;;\n    \"D17\"*)\n      NAME=\"iPhone13\"\n      ;;\n    \"D16\"*)\n      NAME=\"iPhone13Mini\"\n      ;;\n    \"D63\"*)\n      NAME=\"iPhone13Pro\"\n      ;;\n    \"D64\"*)\n      NAME=\"iPhone13ProMax\"\n      ;;\n    \"J1\"*)\n      NAME=\"iPad3gen\"\n      ;;\n    \"J2\"*)\n      NAME=\"iPad3gen\"\n      ;;\n    \"J72\"*)\n      NAME=\"iPadAir\"\n      ;;\n    \"J82\"*)\n      NAME=\"iPadAir2\"\n      ;;\n    \"J217\"*|\"J218\"*)\n      NAME=\"iPadAir3gen\"\n      ;;\n    \"J307\"*|\"J308\"*)\n      NAME=\"iPadAir4gen\"\n      ;;\n    \"J85\"*)\n      NAME=\"iPadMiniRetina\"\n      ;;\n    \"J96\"*)\n      NAME=\"iPadMini4\"\n      ;;\n    \"J210\"*|\"J211\"*)\n      NAME=\"iPadMini5gen\"\n      ;;\n    \"J310\"*|\"J311\"*)\n      NAME=\"iPadMini6gen\"\n      ;;\n    \"J98\"*|\"J99\"*|\"J31\"*|\"J127\"*|\"J128\"*|\"J318\"*|\"J317\"*|\"J207\"*|\"J208\"*)\n      NAME=\"iPadPro\"\n      ;;\n    \"J120\"*|\"J121\"*|\"J417\"*|\"J418\"*)\n      NAME=\"iPadPro2gen\"\n      ;;\n    \"J320\"*|\"J321\"*|\"J517\"*|\"J518\"*)\n      NAME=\"iPadPro3gen\"\n      ;;\n    \"J420\"*|\"J421\"*)\n      NAME=\"iPadPro4gen\"\n      ;;\n    \"J522\"*|\"J523\"*)\n      NAME=\"iPadPro5gen\"\n      ;;\n    \"K48\"*)\n      NAME=\"iPad\"\n      ;;\n    \"K93\"*|\"K94\"*|\"K95\"*)\n      NAME=\"iPad2\"\n      ;;\n    \"P101\"*|\"P103\"*)\n      NAME=\"iPad4gen\"\n      ;;\n    \"P105\"*|\"P107\"*)\n      NAME=\"iPadMini\"\n      ;;\n    \"J71s\"*|\"J71t\"*|\"J72s\"*|\"J72t\"*)\n      NAME=\"iPad5gen\"\n      ;;\n    \"J71b\"*|\"J72b\"*)\n      NAME=\"iPad6gen\"\n      ;;\n    \"J171AP\"*|\"J172AP\"*)\n      NAME=\"iPad7gen\"\n      ;;\n    \"J171aAP\"*|\"J172aAP\"*)\n      NAME=\"iPad8gen\"\n      ;;\n    \"J181\"*|\"J182\"*)\n      NAME=\"iPad9gen\"\n      ;;\n  esac\n  echo $NAME\n}\n\n##############################################################################\n### Commons\n\ncheck_adb_dependency(){\n  if ! [ -x \"$(command -v \"adb\")\" ]; then\n    echo \"🤷‍ Android Debug Bridge required!\"\n    should_proceed \"🔄 Install via homebrew? (this may take a while)\"\n    brew install --cask \"android-platform-tools\"\n  fi\n}\n\ncheck_dependency(){\n  if ! [ -x \"$(command -v \"$1\")\" ]; then\n    echo \"💥 \\\"$1\\\" command required!\"\n    should_proceed \"🛒 Install via homebrew? (this may take a while)\"\n    brew install \"$1\"\n  fi\n}\n\ncheck_for_update(){\n  TODAY=$(date +%Y-%m-%d)\n  if [ -f \"$LAST_CHECK_DATE_FILE\" ]; then\n    LAST_CHECK_DATE=$(cat \"$LAST_CHECK_DATE_FILE\")\n  else\n    echo \"$TODAY\" > \"$LAST_CHECK_DATE_FILE\"\n  fi\n\n  CURRENT_DIR=\"$PWD\"\n  cd \"$SCRIPT_LOCATION/..\" || exit\n  CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)\n\n  if [[ \"$CURRENT_BRANCH\" == \"master\" && \"$LAST_CHECK_DATE\" != \"$TODAY\" ]]; then\n    echo \"🔄 Checking for Mobile Toolkit update...\"\n    echo \"$TODAY\" > \"$LAST_CHECK_DATE_FILE\"\n\n    git fetch origin &> /dev/null\n    git status -uno | grep \"up to date\" &> /dev/null\n    if [ $? -ne 0 ]; then\n      yes_or_no \"🆕 Update available, download now?\";\n      if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]]; then\n\techo \"⏬ Updating...\"\n\tgit pull &> /dev/null\n\techo \"✨ New features:\"\n\tcat \"$SCRIPT_LOCATION\"/../changelog.txt\n\techo\n\techo \"✅ Update complete\"\n  exit 0\n      fi\n    fi\n  fi\n\n  cd \"$CURRENT_DIR\" || exit\n}\n\ndelete_lastline(){\n  echo -en \"\\033[1A\\033[2K\"\n}\n\nyes_or_no(){\n  read -r -n 1 -p \"$1 [y/n] \" RESPONSE\n  case \"$RESPONSE\" in\n      [yY])\n          ;;\n      [nN])\n          ;;\n      *)\n        echo\n        echo \"🤷‍ Invalid option\"\n        yes_or_no \"$1\"\n        ;;\n  esac\n  echo\n}\n\nshould_proceed(){\n  read -r -n 1 -p \"$1 [y/n] \" RESPONSE\n  case \"$RESPONSE\" in\n    [yY])\n      ;;\n    *)\n      exit\n      ;;\n  esac\n  echo\n}\n\nchoose_number(){\n  MAX=$1\n  if [ -n \"$2\" ]; then\n    read -r -p \"$2\" CHOICE\n  else\n    read -r -p \"📝 Choose number: \" CHOICE\n  fi\n  while :;\n  do\n    if [[ -z $CHOICE  || $CHOICE -le 0 || $CHOICE -gt $MAX ]]; then\n      delete_lastline\n      read -r -p \"🤷‍ Invalid choice, try again: \" CHOICE\n    else\n      ((++CHOICE))\n      break\n    fi\n  done\n}\n\ncheck_url(){\n  URL=$1\n\n  if [[ $URL == \"\" ]]; then\n    read -r -p \"📝 Insert web url: \" URL\n    check_url \"$URL\"\n  else\n    case $1 in\n      'http://'*)\n        ;;\n      'https://'*)\n        ;;\n      *'://'*)\n        ;;\n      *)\n        URL='http://'$URL\n        ;;\n    esac\n  fi\n}\n\nabort(){\n  echo \"$1\"\n  exit 1\n}\n"
  },
  {
    "path": "data/.gitignore",
    "content": "toolkit*"
  },
  {
    "path": "ios/icheckdevice",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\nios_device_info \"$SELECTED_DEVICE\"\n\nGSM_URL='https://www.gsmarena.com/res.php3?sSearch='\n\nMANUFACTURER=Apple\nINFO=$(printf \"%s %s - iOS %s\" \"$MANUFACTURER\" \"$MODEL\" \"$VERSION\")\n\nPHONE_URL=$GSM_URL$MODEL\n\necho \"📱 $INFO - ID: $SELECTED_DEVICE\"\n\nshould_proceed \"🌐 Search for the device on GSMArena?\"\nopen \"$PHONE_URL\"\n"
  },
  {
    "path": "ios/iconsole",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\necho \"📋 Opening Console app...\"\nopen -a Console\n"
  },
  {
    "path": "ios/iinstall",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\ninstall_app(){\n  echo \"⌛️ Installing \\\"$2\\\" to $1...\"\n  TEMPORARY_FILE=\"$TEMPORARY_FILE-$(date +%s)\"\n  go-ios install --udid=\"$1\" --path=\"$PWD/$2\" &> \"$TEMPORARY_FILE\"\n  if grep -q 'err' \"$TEMPORARY_FILE\" ; then\n    echo \"❌ Installation to $1 failed!\"\n    echo \"🤕 Uninstall existing version or troubleshoot the package\"\n    echo \"🔥 Error details: $(grep 'err' \"$TEMPORARY_FILE\" | jq -r '.err')\"\n    exit 1\n  fi\n  echo \"✅ Successfully installed to $1\"\n  run_app \"$1\" \"$PWD/$2\"\n}\n\nrun_app(){\n  echo \"🚀 Launching \\\"$BUNDLE_ID\\\" on $1...\"\n  TEMPORARY_FILE=\"$TEMPORARY_FILE-$(date +%s)\"\n  go-ios launch \"$BUNDLE_ID\" --udid=\"$1\" &> \"$TEMPORARY_FILE\"\n  if grep -q 'err' \"$TEMPORARY_FILE\" ; then\n    echo \"❌ App launch failed!\"\n    echo \"🤕 Check if developer certificate is trusted in Settings\"\n    echo \"🔥 Error details: $(grep 'error' \"$TEMPORARY_FILE\" | jq -r '.error')\"\n    exit 1\n  fi\n}\n\ncheck_args_valid(){\n  if [[ \"$1\" != \"-a\" ]]; then\n    FILE=$1\n  else\n    FILE=$2\n  fi\n\n  if [ ! -f \"$PWD/$FILE\" ] && [ ! -f \"$FILE\" ]; then\n      abort \"🤷 Installation file not found!\"\n  fi\n\n  if [[ \"$FILE\" != *\".ipa\" ]]; then\n      abort \"🤷 Unsupported file!\"\n  fi\n}\n\nget_bundle_id(){\n  echo \"🔍 Detecting bundle ID...\"\n  unzip \"$1\" &> /dev/null\n  APP_FILENAME=$(ls \"$PWD\"/Payload)\n  BUNDLE_ID=$(grep \"$PWD/Payload/$APP_FILENAME/embedded.mobileprovision\" -a -e \"[.]com[.]\" | sed 's/.[^.]*\\.//' | sed 's/\\<.*$//')\n  if [[ \"$BUNDLE_ID\" == \"\" ]]; then # Fallback for bundle identifiers containing \"app\" instead of \"com\"\n    BUNDLE_ID=$(grep \"$PWD/Payload/$APP_FILENAME/embedded.mobileprovision\" -a -e \"[.]app[.]\" | sed 's/.[^.]*\\.//' | sed 's/\\<.*$//')\n  fi\n  BUNDLE_ID=$(echo \"$BUNDLE_ID\" | head -n 1)\n  rm -rf \"$PWD/Payload\"\n}\n\nrun(){\n  if [[ $1 == \"-a\" ]]; then\n    check_for_update\n    ios_get_devices\n    get_bundle_id \"$2\"\n    for ID in \"${IOS_USB_DEVICES[@]}\"\n     do\n      install_app \"$ID\" \"$2\" &\n    done\n    wait\n  else\n    ios_choose_device\n    get_bundle_id \"$1\"\n    install_app \"$SELECTED_DEVICE\" \"$1\"\n  fi\n}\n\ncheck_args_valid \"$@\"\nrun \"$@\"\n"
  },
  {
    "path": "ios/ikill",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\n\nif [[ \"$1\" == \"-s\" ]]; then\n  PACKAGES=($(go-ios apps --udid=\"$SELECTED_DEVICE\" --system | jq -r '.[] | .CFBundleIdentifier'))\nelif [[ -n \"$1\" ]]; then\n  PACKAGE=\"$1\"\n  ios_is_package_installed \"$PACKAGE\"\nelse\n  PACKAGES=($(go-ios apps --udid=\"$SELECTED_DEVICE\" | jq -r '.[] | .CFBundleIdentifier'))\nfi\n\nif [ -z \"$PACKAGE\" ]; then\n  PACKAGES_LISTED=()\n  for P in \"${PACKAGES[@]}\" #removes trailing \\r\n  do\n    P=${P%$'\\r'}\n    PACKAGES_LISTED+=(\"$P\")\n  done\n\n  if [ ${#PACKAGES_LISTED[@]} -eq 0 ]; then\n      echo \"🤷‍ No third-party apps installed, use \\\"alaunch -s\\\" to list system packages\"\n      exit 1\n  fi\n\n  echo \"📋 Choose application to kill:\"\n  select OPTION in \"${PACKAGES_LISTED[@]}\"\n  do\n   case $OPTION in\n      *) PACKAGE=$OPTION;break; ;;\n    esac\n  done\nfi\n\necho \"🔪 Killing $PACKAGE...\"\ngo-ios kill \"$PACKAGE\" --udid=\"$SELECTED_DEVICE\" &> /dev/null\necho \"🚀 Relaunching the app...\"\ngo-ios launch \"$PACKAGE\" &> /dev/null\n"
  },
  {
    "path": "ios/ilang",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\nLANGUAGES=( \"en\" \"cs\" \"sk\" \"ar\" \"ca\" \"hr\" \"da\" \"nl\" \"en-GB\" \"fi\" \"fr\" \"de\" \"el\" \"he\" \"hi\" \"hu\" \"id\" \"it\" \"ja\" \"ko\" \"ms\" \"nb\" \"pl\" \"pt\" \"pt-BR\" \"ro\" \"ru\" \"es\" \"sv\" \"th\" \"tr\" \"uk\" \"vi\")\n\nif [ -n \"$1\" ]; then\n  LANG=\"$1\"\nelse\n  echo \"📋 Choose desired language:\"\n  select OPTION in \"${LANGUAGES[@]}\"\n  do\n   case $OPTION in\n      *) LANG=$OPTION;break; ;;\n    esac\n  done\nfi\n\necho \"💬 Setting language to \\\"$LANG\\\" (it might take a while)...\"\ngo-ios lang --udid=\"$SELECTED_DEVICE\" --setlang=\"$LANG\" &> /dev/null\n\nEXIT_CODE=$?\nif [ $EXIT_CODE -ne 0 ]; then\n  echo \"🤷‍ Supplied language \\\"$1\\\" is not supported\"\n  exit 1\nfi\n"
  },
  {
    "path": "ios/ilaunch",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\n\nif [[ \"$1\" == \"-s\" ]]; then\n  PACKAGES=($(go-ios apps --udid=\"$SELECTED_DEVICE\" --system | jq -r '.[] | .CFBundleIdentifier'))\nelif [[ -n \"$1\" ]]; then\n  PACKAGE=\"$1\"\n  ios_is_package_installed \"$PACKAGE\"\nelse\n  PACKAGES=($(go-ios apps --udid=\"$SELECTED_DEVICE\" | jq -r '.[] | .CFBundleIdentifier'))\nfi\n\nif [ -z \"$PACKAGE\" ]; then\n  PACKAGES_LISTED=()\n  for P in \"${PACKAGES[@]}\" #removes trailing \\r\n  do\n    P=${P%$'\\r'}\n    PACKAGES_LISTED+=(\"$P\")\n  done\n\n  if [ ${#PACKAGES_LISTED[@]} -eq 0 ]; then\n      echo \"🤷‍ No third-party apps installed, use \\\"alaunch -s\\\" to list system packages\"\n      exit 1\n  fi\n\n  echo \"📋 Choose application to launch:\"\n  select OPTION in \"${PACKAGES_LISTED[@]}\"\n  do\n   case $OPTION in\n      *) PACKAGE=$OPTION;break; ;;\n    esac\n  done\nfi\n\necho \"🚀 Launching \\\"$PACKAGE\\\"...\"\ngo-ios launch \"$PACKAGE\" --udid=\"$SELECTED_DEVICE\" &> /dev/null\n"
  },
  {
    "path": "ios/ilog",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nios_choose_device\necho \"📜 Device log:\"\ngo-ios syslog --udid=\"$SELECTED_DEVICE\" --nojson\n"
  },
  {
    "path": "ios/ioptions",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\n\necho \"🔨 Launching system settings...\"\ngo-ios launch \"com.apple.Preferences\" --udid=\"$SELECTED_DEVICE\" &> /dev/null\n"
  },
  {
    "path": "ios/iquicktime",
    "content": "#!/bin/bash\necho \"📹 Opening QuickTime...\"\n\nosascript <<EOD\ntell application \"QuickTime Player\"\n\tactivate\n\tset newMovieRecording to new movie recording\nend tell\ntell application \"System Events\" to tell process \"QuickTime Player\"\n\tclick button 2 of window 1\nend tell\nreturn\nEOD\n"
  },
  {
    "path": "ios/ireboot",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nios_choose_device\n\nshould_proceed \"🔌 Do you really want to reboot $SELECTED_DEVICE?\"\necho \"🔄 Restarting the device...\"\ngo-ios reboot --udid=\"$SELECTED_DEVICE\" &> /dev/null\n"
  },
  {
    "path": "ios/irecord",
    "content": "#!/bin/bash\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\ntrap 'ctrlc $@' 1 2 3 6 15\n\nRECORDING=false\ncd ~/Desktop || exit\n\nctrlc(){\n  osascript -e 'quit app \"QuickTime Player\"'\n  if $RECORDING ; then\n    compress_video \"$FILENAME\"\n    echo \"✅ Saved into ~/Desktop/$FILENAME\"\n  fi\n  exit\n}\n\ncheck_videosnap_dependency(){ #TODO refactor when videosnap available via Homberew\n  if ! [ -x \"$(command -v \"videosnap\")\" ]; then\n    echo \"💥 \\\"videosnap\\\" command required!\"\n    should_proceed \"🛒 Install via GitHub? (download and install \\\"videosnap-0.0.7.pkg\\\")\"\n    open \"https://github.com/matthutchinson/videosnap/releases/download/v0.0.7/videosnap-0.0.7.pkg\"\n    exit 1\n  fi\n}\n\nstart_quicktime(){\n\techo \"🎬 Initializing QuickTime (webcam LED might turn on)...\"\n\tosascript <<EOD\n\ttell application \"QuickTime Player\"\n\t\tset newMovieRecording to new movie recording\n\t\tset miniaturized of window 1 to true\n\tend tell\nEOD\n}\n\npick_recording_device(){\n  ios_choose_device\n  ios_device_info \"$SELECTED_DEVICE\"\n  DEVICE_NAME=$(go-ios devicename --udid=\"$SELECTED_DEVICE\" --nojson)\n  FILENAME=\"$MANUFACTURER-$MODEL-iOS$VERSION-$(date +%Y-%m-%d-%H-%M-%S).mp4\"\n}\n\nstart_recording(){\n  RECORDING=true\n  echo \"📹 Recording screen on $SELECTED_DEVICE ($DEVICE_NAME), stop it using ctrl^c\"\n  videosnap -p High -d \"$DEVICE_NAME\" \"$FILENAME\" &> /dev/null\n}\n\ncompress_video(){\n  if test -f \"$1\" ; then\n    echo \"📦 Compressing video...\"\n    ffmpeg -i \"$1\" \"LQ-$1\" -hide_banner -loglevel error #ultra basic ffmpeg compression\n    rm \"$1\" && mv \"LQ-$1\" \"$1\"\n  else\n    echo \"❌ Video not captured possibly due to short recording time...\"\n    osascript -e 'quit app \"QuickTime Player\"'\n    exit 1\n  fi\n}\n\nif uname -m | grep -q arm64 ; then\n  echo \"🤕 This script is currently not working on M1 based macs\"\n  echo \"🔗 See https://github.com/matthutchinson/videosnap/issues/24\"\n  echo \"🩹 You can use \\\"iquicktime\\\" temporarily instead\"\n  exit 1\nfi\n\ncheck_videosnap_dependency\ncheck_dependency \"ffmpeg\"\n\nstart_quicktime\npick_recording_device\nstart_recording\n"
  },
  {
    "path": "ios/iscreenshot",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\n\nscreenshot(){\n  ios_device_info \"$1\"\n  FILENAME=\"$MANUFACTURER-$MODEL-iOS$VERSION-$(date +%Y-%m-%d-%H-%M-%S).png\"\n  echo \"📸 Saving screenshot into $FILENAME...\"\n  go-ios screenshot --udid=\"$1\" --output=\"$HOME/Desktop/$FILENAME\" &> /dev/null\n  EXIT_CODE=$?\n  if [ $EXIT_CODE -ne 0 ]; then\n    echo \"🤷 Screenshot failed, error code: $EXIT_CODE\"\n  fi\n}\n\nscreenshot_all(){\n  check_for_update\n  ios_get_devices\n  for ID in \"${IOS_USB_DEVICES[@]}\"\n   do\n    screenshot \"$ID\" &\n  done\n  wait\n}\n\nif [ \"$1\" == \"-a\" ];\nthen\n  screenshot_all\nelse\n  ios_choose_device\n  screenshot \"$SELECTED_DEVICE\"\nfi\n"
  },
  {
    "path": "ios/isimulator",
    "content": "#!/bin/bash\n# shellcheck disable=SC1007\n# ignore irrelevant warning \"remove space after =\"\n\nTOOLKIT_LOCATION=$(dirname \"$0\")\nsource \"$TOOLKIT_LOCATION\"/../common_tools\n\nLOCAL_SIMULATOR_LIST=$TOOLKIT_LOCATION/../data/toolkit_simulator_list.txt\n\nhelp(){\n  if [[ $1 != \"\" ]]; then\n    echo \"🤷‍ Unknown option: $1\"\n  else\n    echo \"🤷 Argument missing\"\n  fi\n  echo -e \"Use one of the following options:\\\\n  start - choose and launch installed simulator\\\\n  screenshot <filename> - save screenshot to Desktop\\\\n  record <filename> - save screen recording to Desktop\\\\n  paste <text> - insert text into pasteboard\\\\n  url <url> - open link in web browser\\\\n  logs - print simulator logs\\\\n  battery <0-100> - set battery level\\\\n  time <hh:mm> - set time\\\\n  import <file> - import photo or video into gallery\\\\n  wipe - wipe all simulator data\"\n}\n\nimport_simulator_list(){\n  xcrun simctl list -v devices | grep -i booted | sed 's/ (Booted) //g' > \"$LOCAL_SIMULATOR_LIST\"\n  RUNNING_SIMULATOR_COUNT=$(wc -l < \"$LOCAL_SIMULATOR_LIST\")\n}\n\nchoose_simulator(){\n  read -r -p \"📝 Choose: \" SIMULATOR_INDEX\n  SIMULATOR_ID=$(sed \"$SIMULATOR_INDEX\"!d \"$LOCAL_SIMULATOR_LIST\")\n  if [[ $SIMULATOR_INDEX == \"\" || $SIMULATOR_ID != *\"(\"* ]]; then\n    delete_lastline\n    choose_simulator\n  fi\n  SIMULATOR_ID=$(echo \"$SIMULATOR_ID\" | sed 's/.*(\\(.*\\))/\\1/')\n}\n\nchoose_running_simulator(){\n  import_simulator_list\n\n  if [[ $RUNNING_SIMULATOR_COUNT -le 0 ]]; then\n    echo \"❌ No running simulators\"\n    yes_or_no \"❓ Do you want to start one?\"\n    if [[ \"$RESPONSE\" == \"y\" ||  \"$RESPONSE\" == \"Y\" ]];\n    then\n      start_simulator\n    fi\n    exit\n  elif [[ $RUNNING_SIMULATOR_COUNT -eq 1 ]]; then\n    SIMULATOR_ID=$(sed 1!d \"$LOCAL_SIMULATOR_LIST\" | sed 's/.*(\\(.*\\))/\\1/')\n    return\n  fi\n\n  echo \"📱 Available simulators:\"\n  nl \"$LOCAL_SIMULATOR_LIST\"\n  choose_simulator\n}\n\nstart_simulator(){\n  echo \"⏳ Getting iOS simulator list...\"\n  rm -f \"$LOCAL_SIMULATOR_LIST\"\n  xcrun simctl list | grep -i \"shutdown\\\\|booted\\\\|-- iOS\\\\|-- tvOS\\\\|-- watchOS\" | grep -v \"unavailable\\\\|Watch:\\\\|Phone:\" | sed 's/ (Shutdown) //g' | sed 's/ (Booted) //g' >> \"$LOCAL_SIMULATOR_LIST\"\n\n  echo \"📱 Available:\"\n  nl \"$LOCAL_SIMULATOR_LIST\"\n  choose_simulator\n  echo  \"🚀 Launching simulator...\"\n  xcrun simctl boot \"$SIMULATOR_ID\"\n  open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/\n  rm \"$LOCAL_SIMULATOR_LIST\"\n}\n\nopen_url(){\n  check_url \"$1\"\n  echo \"🌎 Opening link in a web browser...\"\n  xcrun simctl openurl \"$SIMULATOR_ID\" \"$URL\" &> /dev/null\n}\n\nlaunch_app(){\n  if [[ $1 == \"\" || $1 != \"com.\"*\".\"* ]]; then\n    read -r -p \"📝 Enter bundle id: \" BUNDLE_ID\n    launch_app \"$BUNDLE_ID\"\n  else\n    echo \"🚀 Launching the app...\"\n    xcrun simctl launch \"$SIMULATOR_ID\" \"$1\"\n  fi\n}\n\ninsert_clipboard(){\n  if [[ $1 == \"\" ]]; then\n    read -r -p \"📝 Enter pasteboard text: \" TEXT\n    insert_clipboard \"$TEXT\"\n  else\n    echo \"📥 Inserting text into clipboard...\"\n    echo \"$1\" | xcrun simctl pbcopy \"$SIMULATOR_ID\" &> /dev/null\n  fi\n}\n\nwipe_contents(){\n  should_proceed \"💣 Wipe all simulator data?\"\n  echo \"🚫 Shutting down the device...\"\n  xcrun simctl shutdown \"$SIMULATOR_ID\"\n  echo \"🔥 Wiping data...\"\n  xcrun simctl erase \"$SIMULATOR_ID\"\n  echo \"🚀 Booting...\"\n  xcrun simctl boot \"$SIMULATOR_ID\"\n}\n\nrecord_screen(){\n  echo \"📹 Recording screen on $SIMULATOR_ID, stop it with ctrl^c\"\n  if [ -z \"$1\" ] ; then\n    FILENAME=\"Simulator-$(date +%Y-%m-%d-%H-%M-%S).mp4\"\n  else\n    FILENAME=\"$1.mp4\"\n  fi\n  if ! xcrun simctl io \"$SIMULATOR_ID\" recordVideo \"$HOME/DESKTOP/$FILENAME\"; then\n    echo \"❌ Recording failed!\"\n  else\n    echo \"✅ Video saved to ~/Desktop/$FILENAME\"\n  fi\n}\n\ntake_screenshot(){\n  echo \"📸 Taking screenshot on $SIMULATOR_ID\"\n  if [ -z \"$1\" ] ; then\n    FILENAME=\"Simulator-$(date +%Y-%m-%d-%H-%M-%S).png\"\n  else\n    FILENAME=$1\n  fi\n  xcrun simctl io \"$SIMULATOR_ID\" screenshot \"$HOME/Desktop/$FILENAME\" &> /dev/null\n  echo \"✅ Screenshot saved to ~/Desktop/$FILENAME\"\n}\n\nimport_file(){\n  if [ -z \"$1\" ] ; then\n    echo \"🤷‍ No file for import, use - isimulator import <file>\"\n    exit\n  fi\n  echo \"⏬ Importing file to $SIMULATOR_ID...\"\n  xcrun simctl addmedia \"$SIMULATOR_ID\" \"$PWD/$1\"\n  echo \"✅ File imported successfully\"\n}\n\nprint_logs(){\n  echo \"📜 Simulator logs:\"\n  xcrun simctl spawn \"$SIMULATOR_ID\" log stream --level=debug\n}\n\ncheck_xcode_version(){\n  if [ \"$(FirefoxmdlsVersion= mdls -name kMDItemVersion /Applications/Xcode.app | tr -d \".\" | grep -oE '[0-9]+')\" -lt 110 ]; then\n    should_proceed \"🔄 Xcode 11 or later is required, open App Store?\"\n    open -a \"App Store\"\n    exit 1\n  fi\n}\n\nset_battery_level(){\n  check_xcode_version\n  if [[ -z \"$1\" ]]; then\n    read -r -p \"📝 Enter battery level: \" LEVEL\n    set_battery_level \"$LEVEL\"\n  else\n    echo \"🔋 Setting battery level to: $1\"\n    xcrun simctl status_bar \"$SIMULATOR_ID\" override --batteryLevel \"$1\" # --batteryState charged\n  fi\n}\n\nset_time(){\n  check_xcode_version\n  if [[ -z \"$1\" ]]; then\n    read -r -p \"📝 Enter battery level: \" TIME\n    set_time \"$TIME\"\n  else\n    xcrun simctl status_bar \"$SIMULATOR_ID\" override --time \"$1\"\n  fi\n}\n\ncheck_for_update\n\ncase $1 in\n  'start')\n    import_simulator_list\n    start_simulator \"$2\"\n    ;;\n  'screenshot')\n    choose_running_simulator\n    take_screenshot \"$2\"\n    ;;\n  'record')\n    choose_running_simulator\n    record_screen \"$2\"\n    ;;\n  'import')\n    choose_running_simulator\n    import_file \"$2\"\n    ;;\n  'url')\n    choose_running_simulator\n    open_url \"$2\"\n    ;;\n  'battery')\n    choose_running_simulator\n    set_battery_level \"$2\"\n    ;;\n  'time')\n    choose_running_simulator\n    set_time \"$2\"\n    ;;\n  'launch')\n    choose_running_simulator\n    launch_app \"$2\"\n    ;;\n  'paste')\n    choose_running_simulator\n    insert_clipboard \"$2\"\n    ;;\n  'logs'|'log')\n    choose_running_simulator\n    print_logs \"$2\"\n    ;;\n  'wipe')\n    choose_running_simulator\n    wipe_contents\n    ;;\n   *)\n    help \"$1\"\n    choose_running_simulator\n    ;;\nesac\n"
  },
  {
    "path": "ios/iuninstall",
    "content": "#!/bin/bash\ntrap \"kill 0\" SIGINT # Kill all spawned subprocesses on ctrl^c\nLOCATION=$(dirname \"$0\")\nsource \"$LOCATION\"/../common_tools\nIGNORED_PACKAGES=( \"com.apple.TestFlight\" \"motif.FramerPreview\" \"com.figma.FigmaMirror\" \"com.invisionapp.InVisionApp-iOS\" \"com.8bit.bitwarden\" )\nios_choose_device\n\n\nselect_option(){\n  echo \"📋 Choose package number:\"\n  select OPTION in \"${INSTALLED_PACKAGES[@]}\"\n  do\n   case $OPTION in\n      *) PACKAGE=$OPTION;break; ;;\n    esac\n  done\n  if [[ -z $PACKAGE ]]; then\n    echo \"❌ Invalid option picked, retry\"\n    select_option\n  fi\n}\n\nuninstall_package(){\n  PACKAGE=\"$1\"\n  echo \"${INSTALLED_PACKAGES[*]}\" | grep -w \"$PACKAGE\" &> /dev/null || { echo \"🤷‍ Package \\\"$PACKAGE\\\" not installed\"; return 1; }\n  echo \"${IGNORED_PACKAGES[*]}\" | grep -w \"$PACKAGE\" &> /dev/null && { echo \"❌ Package \\\"$PACKAGE\\\" is whitelisted\"; return 1; }\n\n  echo \"🔥 Uninstalling \\\"$PACKAGE\\\"...\"\n  go-ios uninstall --udid=\"$SELECTED_DEVICE\" \"$PACKAGE\" &> /dev/null\n  return 0\n}\n\nuninstall_all(){\n  tput setaf 1\n  should_proceed \"💣 Delete all third-party apps on $SELECTED_DEVICE?\"\n  tput sgr0\n  for PKG in \"${INSTALLED_PACKAGES[@]}\"\n  do\n    uninstall_package \"$PKG\" &\n  done\n  wait\n}\n\nhandle_arguments(){\n  if [[  \"$1\" == \"-w\" ]]; then\n    uninstall_all\n  elif [[ -n \"$1\" ]]; then\n    uninstall_package \"$1\"\n  fi\n\n  if [ -z \"$1\" ]; then\n    if [ ${#INSTALLED_PACKAGES[@]} -eq 0 ]; then\n        echo \"🤷‍ Nothing to uninstall\"\n        exit\n    fi\n    select_option\n    uninstall_package \"$PACKAGE\"\n  fi\n}\n\n\nios_get_installed_package_list \"$SELECTED_DEVICE\"\nhandle_arguments \"$@\"\necho \"✅ Done\"\n"
  }
]