Skip to content

Commit

Permalink
Merge branch 'tytydraco:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
kairusds authored Nov 5, 2022
2 parents 0726809 + 44b564e commit 8bda609
Show file tree
Hide file tree
Showing 25 changed files with 404 additions and 270 deletions.
2 changes: 0 additions & 2 deletions OWNERS

This file was deleted.

65 changes: 37 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,44 @@
# LADB

A local ADB shell for Android!

# How does it work?
LADB bundles an ADB server within the app libraries. Normally, this server cannot connect to the local device because it requires an active USB connection. However, Android's Wireless ADB Debugging feature allows the server and the client to speak to each other locally.

# Initial Setup:
1. About -> Build Number -> Click 7 times
2. Developer Settings -> Wireless ADB Debugging -> On
3. Developer Settings -> ADB Debugging -> On

# Troubleshooting:
If you encounter "device unauthorized" or "multiple devices connected", try this:
1. Enable Airplane Mode
2. Disconnect any USB devices
3. Kill and restart LADB

Still not working? Try this:
1. Close LADB completely
2. Developer Settings -> Wireless ADB Debugging -> Off
3. Developer Settings -> ADB Debugging -> Off
4. Developer Settings -> Revoke authorizations
5. Reboot
6. Developer Settings -> Wireless ADB Debugging -> On
7. Developer Settings -> ADB Debugging -> On
8. Enable Airplane Mode
9. Open LADB

# Credit
Thanks to Surge1223 for compiling ADB for the ARM/ARM64 architecture.

LADB bundles an ADB server within the app libraries. Normally, this server cannot connect to the local device because it
requires an active USB connection. However, Android's Wireless ADB Debugging feature allows the server and the client to
speak to each other locally.

# Initial Setup

Use split-screen more or a pop-out window with LADB and Settings at the same time. This is because Android will
invalidate the pairing information if the dialog gets dismissed. Add a Wireless Debugging connection, and copy the
pairing code and port into LADB. Keep both windows open until the Settings dialog dismisses itself.

Here is a nice tutorial from XDA on how to do it: [link](https://www.xda-developers.com/debloat-your-phone-run-adb-shell-commands-no-root-no-pc/).

Here is a video tutorial: [link](https://www.youtube.com/shorts/v7hT6rMYqh4).

# Issues

LADB is sadly incompatible with Shizuku at the current moment. That means that if you have Shiuzuku installed, LADB will
usually fail to connect properly. You must uninstall it and reboot to use LADB.

# Troubleshooting

Most errors can be fixed by clearing the app data for LADB, removing all Wireless Debugging connections from Settings,
and rebooting.

# License
While this project is GPLv3 licensed, I would like to add an additional parameter: please do not publish unofficial (user) LADB builds to the Google Play Store.

Still confused? Email me at tylernij@gmail.com.
While this project is GPLv3 licensed, I would like to add a parameter: please do not publish unofficial (user) LADB
builds to the Google Play Store.

# Support

Still confused? Email me at tylernij+LADB@gmail.com.

We also have a Telegram server here: https://t.me/ladb_support.

# Privacy Policy

LADB does not send any device data outside of the app. Your data is not collected or processed.
32 changes: 20 additions & 12 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ plugins {
id 'com.google.android.gms.oss-licenses-plugin'
}


android {
compileSdk 31
compileSdk 33

defaultConfig {
applicationId "com.draco.ladb"
minSdk 26
targetSdk 31
versionCode 38
versionName "2.0"
targetSdk 33
versionCode 39
versionName "2.1"

ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
}
}

Expand All @@ -24,6 +25,12 @@ android {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

buildConfigField 'Boolean', 'ANTI_PIRACY', RELEASE_ANTIPIRACY
}

debug {
buildConfigField 'Boolean', 'ANTI_PIRACY', DEBUG_ANTIPIRACY
}
}
compileOptions {
Expand All @@ -43,19 +50,20 @@ android {
buildFeatures {
viewBinding true
}
namespace 'com.draco.ladb'
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.fragment:fragment-ktx:1.5.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
implementation 'androidx.fragment:fragment-ktx:1.5.3'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'

implementation 'com.github.javiersantos:PiracyChecker:1.2.8'

Expand Down
43 changes: 29 additions & 14 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.draco.ladb"
android:installLocation="internalOnly">

<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />

<application
android:banner="@drawable/banner"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LADB"
android:extractNativeLibs="true"
android:banner="@drawable/banner">
<activity android:name=".views.MainActivity"
android:theme="@style/Theme.LADB">
<activity
android:name=".views.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />

<data android:mimeType="text/x-sh" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity android:name=".views.HelpActivity" android:label="@string/more" />
<activity android:name=".views.BookmarksActivity" android:label="@string/bookmarks" />
<activity
android:name=".views.PairActivity"
android:label="@string/pair" />
<activity
android:name=".views.HelpActivity"
android:label="@string/more" />
<activity
android:name=".views.BookmarksActivity"
android:label="@string/bookmarks" />

<service android:name=".services.QSTile"
android:label="@string/app_name"
<service
android:name=".services.QSTile"
android:exported="true"
android:icon="@drawable/ic_baseline_adb_24"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
android:label="@string/app_name"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,11 @@ class HelpPreferenceFragment : PreferenceFragmentCompat() {

override fun onPreferenceTreeClick(preference: Preference): Boolean {
when (preference.key) {
getString(R.string.reset_key) -> {
getString(R.string.unpair_key) -> {
val context = requireContext()
PreferenceManager.getDefaultSharedPreferences(context).edit(commit = true) {
clear()
putBoolean(context.getString(R.string.paired_key), false)
}

context.filesDir.deleteRecursively()
context.cacheDir.deleteRecursively()

restartApp()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import com.draco.ladb.R

class BookmarksRecyclerAdapter(val context: Context): RecyclerView.Adapter<BookmarksRecyclerAdapter.ViewHolder>() {
class BookmarksRecyclerAdapter(context: Context) : RecyclerView.Adapter<BookmarksRecyclerAdapter.ViewHolder>() {
private val list = sortedSetOf<String>()
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)

Expand Down Expand Up @@ -65,7 +65,7 @@ class BookmarksRecyclerAdapter(val context: Context): RecyclerView.Adapter<Bookm
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
updateList(false)
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recycler_item, parent, false)
.inflate(R.layout.recycler_item, parent, false)
return ViewHolder(view)
}

Expand Down
56 changes: 39 additions & 17 deletions app/src/main/java/com/draco/ladb/utils/ADB.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class ADB(private val context: Context) {
const val OUTPUT_BUFFER_DELAY_MS = 100L

@SuppressLint("StaticFieldLeak")
@Volatile private var instance: ADB? = null
@Volatile
private var instance: ADB? = null
fun getInstance(context: Context): ADB = instance ?: synchronized(this) {
instance ?: ADB(context).also { instance = it }
}
Expand Down Expand Up @@ -86,26 +87,44 @@ class ADB(private val context: Context) {

if (autoShell) {
/* Only do wireless debugging steps on compatible versions */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (secureSettingsGranted && !isWirelessDebuggingEnabled()) {
if (secureSettingsGranted) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !isWirelessDebuggingEnabled()) {
debug("Enabling wireless debugging...")
Settings.Global.putInt(
context.contentResolver,
"adb_wifi_enabled",
1
)

Thread.sleep(3_000)
} else if (!isUSBDebuggingEnabled()) {
debug("Enabling USB debugging...")
Settings.Global.putInt(
context.contentResolver,
Settings.Global.ADB_ENABLED,
1
)

Thread.sleep(3_000)
}
}

/* Check again... */
if (!isWirelessDebuggingEnabled()) {
debug("Wireless debugging is not enabled!")
debug("Settings -> Developer options -> Wireless debugging")
debug("Waiting for wireless debugging...")
/* Check again... */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !isWirelessDebuggingEnabled()) {
debug("Wireless debugging is not enabled!")
debug("Settings -> Developer options -> Wireless debugging")
debug("Waiting for wireless debugging...")

while (!isWirelessDebuggingEnabled()) {
Thread.sleep(1_000)
}
while (!isWirelessDebuggingEnabled()) {
Thread.sleep(1_000)
}
} else if (!isUSBDebuggingEnabled()) {
debug("USB debugging is not enabled!")
debug("Settings -> Developer options -> USB debugging")
debug("Waiting for USB debugging...")

while (!isUSBDebuggingEnabled()) {
Thread.sleep(1_000)
}
}

Expand All @@ -116,10 +135,9 @@ class ADB(private val context: Context) {
val waitProcess = adb(false, listOf("wait-for-device")).waitFor(2, TimeUnit.MINUTES)
if (!waitProcess) {
debug("Could not detect any devices")
debug("Make sure pairing info is correct:")
debug("More -> Factory reset")
debug("To try again, restart the server:")
debug("More -> Restart")
debug("Fix 1) Toggle Wi-Fi or reboot")
debug("Fix 2) Re-enter pairing information (More -> Factory Reset)")
debug("To try again, restart the server (More -> Restart)")

tryingToPair = false
return false
Expand Down Expand Up @@ -149,7 +167,8 @@ class ADB(private val context: Context) {
else
sendToShellProcess("echo 'Entered non-adb shell'")

val startupCommand = sharedPrefs.getString(context.getString(R.string.startup_command_key), "echo 'Success! ※\\(^o^)/※'")!!
val startupCommand =
sharedPrefs.getString(context.getString(R.string.startup_command_key), "echo 'Success! ※\\(^o^)/※'")!!
if (startupCommand.isNotEmpty())
sendToShellProcess(startupCommand)

Expand All @@ -162,6 +181,9 @@ class ADB(private val context: Context) {
private fun isWirelessDebuggingEnabled() =
Settings.Global.getInt(context.contentResolver, "adb_wifi_enabled", 0) == 1

private fun isUSBDebuggingEnabled() =
Settings.Global.getInt(context.contentResolver, Settings.Global.ADB_ENABLED, 0) == 1

/**
* Wait restart the shell once it dies
*/
Expand Down Expand Up @@ -193,7 +215,7 @@ class ADB(private val context: Context) {

/* Continue once finished pairing (or 10s elapses) */
pairShell.waitFor(10, TimeUnit.SECONDS)
pairShell.destroyForcibly()
pairShell.destroyForcibly().waitFor()
return pairShell.exitValue() == 0
}

Expand Down
Loading

0 comments on commit 8bda609

Please sign in to comment.