Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,24 @@ android {
defaultConfig {
applicationId = "com.sameerasw.airsync"
minSdk = 30
versionCode = 31
versionCode = 32
versionName = "4.0.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
// optimized dev build
// debug {
// isMinifyEnabled = true
// isShrinkResources = true
// isDebuggable = false
//
// proguardFiles(
// getDefaultProguardFile("proguard-android-optimize.txt"),
// "proguard-rules.pro"
// )
// }
// end
// debug {
// isMinifyEnabled = true
// isShrinkResources = true
// isDebuggable = false
// proguardFiles(
// getDefaultProguardFile("proguard-android-optimize.txt"),
// "proguard-rules.pro"
// )
// }
// end

release {
isMinifyEnabled = true
Expand Down
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@
android:name=".presentation.ui.activities.QRScannerActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/Theme.AirSync">
<!-- Allow external apps to launch the scanner -->
<intent-filter>
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/com/sameerasw/airsync/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.widget.ImageView
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
Expand Down Expand Up @@ -173,8 +174,8 @@ class MainActivity : ComponentActivity() {
// Install and configure the splash screen before any UI rendering
val splashScreen = installSplashScreen()

// Make activity draw behind system bars - let the theme handle the colors
androidx.core.view.WindowCompat.setDecorFitsSystemWindows(window, false)
// Enable edge-to-edge for Android 15+ and backward compatibility
enableEdgeToEdge()

super.onCreate(savedInstanceState)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ class BleConnectionManager(private val context: Context) {
}

private fun updateBleState(regularConnectionActive: Boolean, manuallyDisconnected: Boolean) {
if (!isBleEnabled || manuallyDisconnected) {
Log.d(TAG, "BLE disabled or user manually disconnected, stopping/pausing server")
if (!isBleEnabled) {
Log.d(TAG, "BLE disabled in settings, stopping/pausing server")
bleServer?.pauseAdvertising()
return
}
Expand All @@ -67,7 +67,7 @@ class BleConnectionManager(private val context: Context) {
Log.d(TAG, "Regular connection active — pausing BLE advertising")
bleServer?.pauseAdvertising()
} else {
// No regular connection — ensure server is started and advertising.
// No regular connection — ensure server is started and advertising so devices can discover and connect
Log.d(TAG, "No regular connection — resuming BLE advertising")
bleServer?.start()
bleServer?.resumeAdvertising()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,11 @@ class BleGattServer(private val context: Context) {
}
isAuthenticated = false
authenticatedFlag.set(false)
_connectionState.value = BleConnectionState.DISCONNECTED
stopHeartbeat()
_connectionState.value = if (gattServer != null) BleConnectionState.ADVERTISING else BleConnectionState.DISCONNECTED
isAdvertisingPaused = false
if (gattServer != null && isBleSyncEnabled) {
startAdvertising()
}
}
}
27 changes: 22 additions & 5 deletions app/src/main/java/com/sameerasw/airsync/utils/ContactPhotoUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,30 @@ object ContactPhotoUtil {
*/
private fun loadBitmap(context: Context, uri: Uri): Bitmap? {
return try {
context.contentResolver.openInputStream(uri).use { inputStream ->
if (inputStream != null) {
BitmapFactory.decodeStream(inputStream)
} else {
null
val targetSize = 256
val boundsOptions = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
context.contentResolver.openInputStream(uri)?.use { inputStream ->
BitmapFactory.decodeStream(inputStream, null, boundsOptions)
}

var inSampleSize = 1
if (boundsOptions.outHeight > targetSize || boundsOptions.outWidth > targetSize) {
val halfHeight = boundsOptions.outHeight / 2
val halfWidth = boundsOptions.outWidth / 2
while ((halfHeight / inSampleSize) >= targetSize && (halfWidth / inSampleSize) >= targetSize) {
inSampleSize *= 2
}
}

val decodeOptions = BitmapFactory.Options().apply {
this.inSampleSize = inSampleSize
}

context.contentResolver.openInputStream(uri)?.use { inputStream ->
BitmapFactory.decodeStream(inputStream, null, decodeOptions)
}
} catch (e: Exception) {
Log.e(TAG, "Error loading bitmap: ${e.message}")
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,25 @@ object MacDeviceStatusManager {
return try {
if (base64String.isNotEmpty()) {
val decodedBytes = Base64.decode(base64String, Base64.DEFAULT)
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
val boundsOptions = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, boundsOptions)

val targetSize = 512
var inSampleSize = 1
if (boundsOptions.outHeight > targetSize || boundsOptions.outWidth > targetSize) {
val halfHeight = boundsOptions.outHeight / 2
val halfWidth = boundsOptions.outWidth / 2
while ((halfHeight / inSampleSize) >= targetSize && (halfWidth / inSampleSize) >= targetSize) {
inSampleSize *= 2
}
}

val decodeOptions = BitmapFactory.Options().apply {
this.inSampleSize = inSampleSize
}
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, decodeOptions)
} else {
null
}
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/res/values-night/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>

<!-- Edge-to-edge transparency -->
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>

<!-- Dark icons false for dark theme -->
<item name="android:windowLightStatusBar">false</item>
<item name="android:windowLightNavigationBar">false</item>
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>

<!-- Edge-to-edge transparency -->
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>

<!-- Light icons true for light theme (black icons) -->
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
Expand All @@ -30,8 +26,5 @@
<item name="android:windowIsFloating">false</item>

<item name="android:windowAnimationStyle">@android:style/Animation</item>

<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
</resources>