Fix foreground service permissions and UI issues
- Add CHANGE_NETWORK_STATE for SDK 36 FGS connectedDevice type - Add logging to TetherApiService for debugging - Fix status bar clipping with fitsSystemWindows - Wrap preview box in MaterialCard with scrolling - Fix Docker build permissions in justfile
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@ local.properties
|
|||||||
*.aab
|
*.aab
|
||||||
*.jks
|
*.jks
|
||||||
*.keystore
|
*.keystore
|
||||||
|
.gradle-cache/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.content.Intent
|
|||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import dev.itsh.tetherapi.MainActivity
|
import dev.itsh.tetherapi.MainActivity
|
||||||
import dev.itsh.tetherapi.R
|
import dev.itsh.tetherapi.R
|
||||||
@@ -44,10 +45,12 @@ class TetherApiService : Service() {
|
|||||||
|
|
||||||
private fun startServer(port: Int) {
|
private fun startServer(port: Int) {
|
||||||
if (apiServer?.isAlive == true) {
|
if (apiServer?.isAlive == true) {
|
||||||
|
Log.d(TAG, "Server already running")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Log.d(TAG, "Starting server on port $port")
|
||||||
apiServer = ApiServer(this, port).apply {
|
apiServer = ApiServer(this, port).apply {
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
@@ -57,7 +60,9 @@ class TetherApiService : Service() {
|
|||||||
|
|
||||||
isRunning = true
|
isRunning = true
|
||||||
currentPort = port
|
currentPort = port
|
||||||
|
Log.d(TAG, "Server started successfully")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to start server", e)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,6 +131,7 @@ class TetherApiService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val TAG = "TetherApiService"
|
||||||
const val ACTION_START = "dev.itsh.tetherapi.action.START"
|
const val ACTION_START = "dev.itsh.tetherapi.action.START"
|
||||||
const val ACTION_STOP = "dev.itsh.tetherapi.action.STOP"
|
const val ACTION_STOP = "dev.itsh.tetherapi.action.STOP"
|
||||||
const val EXTRA_PORT = "dev.itsh.tetherapi.extra.PORT"
|
const val EXTRA_PORT = "dev.itsh.tetherapi.extra.PORT"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
@@ -152,26 +153,40 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/settingsCard" />
|
app:layout_constraintTop_toBottomOf="@id/settingsCard" />
|
||||||
|
|
||||||
<HorizontalScrollView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/previewTitle">
|
app:layout_constraintTop_toBottomOf="@id/previewTitle">
|
||||||
|
|
||||||
<TextView
|
<ScrollView
|
||||||
android:id="@+id/previewText"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="match_parent">
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#F5F5F5"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="11sp"
|
|
||||||
tools:text='{"connection": {...}}' />
|
|
||||||
|
|
||||||
</HorizontalScrollView>
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/previewText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#F8F9FA"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text='{"connection": {...}}' />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
21
justfile
21
justfile
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Docker image for Android builds
|
# Docker image for Android builds
|
||||||
android_image := "cimg/android:2025.12"
|
android_image := "cimg/android:2025.12"
|
||||||
gradle_cache := "gradle-cache"
|
gradle_cache := env_var_or_default("GRADLE_CACHE", justfile_directory() + "/.gradle-cache")
|
||||||
|
|
||||||
# Default task
|
# Default task
|
||||||
default:
|
default:
|
||||||
@@ -12,38 +12,41 @@ default:
|
|||||||
build:
|
build:
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v {{justfile_directory()}}:/project \
|
-v {{justfile_directory()}}:/project \
|
||||||
-v {{gradle_cache}}:/home/circleci/.gradle \
|
-v {{gradle_cache}}:/gradle-cache \
|
||||||
|
-e GRADLE_USER_HOME=/gradle-cache \
|
||||||
-w /project \
|
-w /project \
|
||||||
{{android_image}} \
|
{{android_image}} \
|
||||||
./gradlew assembleDebug --no-daemon
|
sh -c './gradlew assembleDebug --no-daemon && chown -R $(stat -c %u:%g /project) /project/.gradle /project/.kotlin /project/app/build 2>/dev/null || true'
|
||||||
@echo "APK: app/build/outputs/apk/debug/app-debug.apk"
|
@echo "APK: app/build/outputs/apk/debug/app-debug.apk"
|
||||||
|
|
||||||
# Build release APK (requires keystore and env vars)
|
# Build release APK (requires keystore and env vars)
|
||||||
release:
|
release:
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v {{justfile_directory()}}:/project \
|
-v {{justfile_directory()}}:/project \
|
||||||
-v {{gradle_cache}}:/home/circleci/.gradle \
|
-v {{gradle_cache}}:/gradle-cache \
|
||||||
-w /project \
|
-e GRADLE_USER_HOME=/gradle-cache \
|
||||||
-e KEYSTORE_PASSWORD \
|
-e KEYSTORE_PASSWORD \
|
||||||
-e KEY_ALIAS \
|
-e KEY_ALIAS \
|
||||||
-e KEY_PASSWORD \
|
-e KEY_PASSWORD \
|
||||||
|
-w /project \
|
||||||
{{android_image}} \
|
{{android_image}} \
|
||||||
./gradlew assembleRelease --no-daemon
|
sh -c './gradlew assembleRelease --no-daemon && chown -R $(stat -c %u:%g /project) /project/.gradle /project/.kotlin /project/app/build 2>/dev/null || true'
|
||||||
@echo "APK: app/build/outputs/apk/release/app-release.apk"
|
@echo "APK: app/build/outputs/apk/release/app-release.apk"
|
||||||
|
|
||||||
# Clean build artifacts
|
# Clean build artifacts
|
||||||
clean:
|
clean:
|
||||||
rm -rf app/build build .gradle
|
rm -rf app/build build .gradle .kotlin
|
||||||
@echo "Cleaned"
|
@echo "Cleaned"
|
||||||
|
|
||||||
# Run gradle tasks
|
# Run gradle tasks
|
||||||
gradle *ARGS:
|
gradle *ARGS:
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v {{justfile_directory()}}:/project \
|
-v {{justfile_directory()}}:/project \
|
||||||
-v {{gradle_cache}}:/home/circleci/.gradle \
|
-v {{gradle_cache}}:/gradle-cache \
|
||||||
|
-e GRADLE_USER_HOME=/gradle-cache \
|
||||||
-w /project \
|
-w /project \
|
||||||
{{android_image}} \
|
{{android_image}} \
|
||||||
./gradlew {{ARGS}} --no-daemon
|
sh -c './gradlew {{ARGS}} --no-daemon && chown -R $(stat -c %u:%g /project) /project/.gradle /project/.kotlin /project/app/build 2>/dev/null || true'
|
||||||
|
|
||||||
# Generate icons from SVG
|
# Generate icons from SVG
|
||||||
icons:
|
icons:
|
||||||
|
|||||||
Reference in New Issue
Block a user