Skip to content

Commit b2f82d7

Browse files
authored
Feat/upgrade target sdk (#479)
- Upgrade targetSDK to 35 - basic edge-to-edge support - Upgrade deps
1 parent ea30758 commit b2f82d7

24 files changed

+223
-48
lines changed

app/build.gradle

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ if (uploadKeyAvailable) {
2727
}
2828

2929
android {
30-
compileSdk 34
30+
compileSdk 36
3131

3232
defaultConfig {
3333
applicationId "org.bspb.smartbirds.pro"
34-
minSdk 21
35-
targetSdk 34
34+
minSdk 23
35+
targetSdk 35
3636
versionCode versionCodeBase
3737
versionName "${versionNameBase}"
3838

@@ -81,7 +81,7 @@ android {
8181

8282
release {
8383
minifyEnabled false
84-
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
84+
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
8585
if (uploadKeyAvailable) {
8686
signingConfig signingConfigs.release
8787
}
@@ -94,7 +94,7 @@ android {
9494
beta {
9595
versionNameSuffix "-BETA"
9696
minifyEnabled false
97-
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
97+
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
9898
if (betaKeyAvailable) {
9999
signingConfig signingConfigs.beta
100100
}
@@ -130,6 +130,7 @@ android {
130130

131131
buildFeatures {
132132
dataBinding = true
133+
buildConfig true
133134
}
134135

135136
testOptions {
@@ -144,69 +145,70 @@ android {
144145
}
145146

146147
dependencies {
147-
def room_version = "2.6.1"
148+
def room_version = "2.8.4"
148149

149150
implementation("androidx.legacy:legacy-support-v4:1.0.0")
150151

151-
implementation('org.jetbrains.kotlin:kotlin-stdlib:2.0.20')
152+
implementation('org.jetbrains.kotlin:kotlin-stdlib:2.3.10')
152153

153154
// KTX extensions
154-
implementation("androidx.core:core-ktx:1.13.1")
155-
implementation("androidx.fragment:fragment-ktx:1.8.2")
155+
implementation("androidx.core:core-ktx:1.17.0")
156+
implementation("androidx.activity:activity-ktx:1.9.3")
157+
implementation("androidx.fragment:fragment-ktx:1.8.9")
156158
implementation("androidx.preference:preference-ktx:1.2.1")
157-
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
158-
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.4")
159+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0")
160+
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.10.0")
159161

160162
implementation fileTree(dir: "libs", include: ["*.jar"])
161-
implementation("com.google.android.gms:play-services-maps:19.0.0")
163+
implementation("com.google.android.gms:play-services-maps:20.0.0")
162164
implementation("com.google.android.gms:play-services-location:21.3.0")
163165

164166
// TODO: migrate to v3.x
165167
implementation("de.greenrobot:eventbus:2.4.1")
166168

167169
// Crashlytics Kit
168-
implementation("com.google.firebase:firebase-crashlytics:19.0.3")
170+
implementation("com.google.firebase:firebase-crashlytics:20.0.4")
169171

170-
implementation("com.google.firebase:firebase-analytics:22.1.0")
172+
implementation("com.google.firebase:firebase-analytics:23.0.0")
171173

172174
// TODO: migrate to https://commons.apache.org/proper/commons-csv/
173175
implementation("com.googlecode.jcsv:jcsv:1.4.0")
174-
implementation('com.google.maps.android:android-maps-utils:3.8.2')
176+
implementation('com.google.maps.android:android-maps-utils:4.0.0')
175177

176178
implementation('org.osmdroid:osmdroid-android:6.1.20')
177179
implementation("com.github.MKergall:osmbonuspack:6.9.0")
178-
implementation("com.google.android.material:material:1.12.0")
180+
implementation("com.google.android.material:material:1.13.0")
179181
implementation("androidx.legacy:legacy-support-v13:1.0.0")
180182

181183
// http://square.github.io/retrofit/
182-
implementation('com.squareup.retrofit2:retrofit:2.11.0')
183-
implementation('com.squareup.retrofit2:converter-gson:2.11.0')
184-
implementation('com.squareup.okhttp3:logging-interceptor:4.12.0')
185-
implementation("com.squareup.okhttp3:okhttp-urlconnection:4.12.0")
184+
implementation('com.squareup.retrofit2:retrofit:3.0.0')
185+
implementation('com.squareup.retrofit2:converter-gson:3.0.0')
186+
implementation('com.squareup.okhttp3:logging-interceptor:5.3.2')
187+
implementation("com.squareup.okhttp3:okhttp-urlconnection:5.3.2")
186188

187-
implementation("androidx.lifecycle:lifecycle-common-java8:2.8.4")
189+
implementation("androidx.lifecycle:lifecycle-common-java8:2.10.0")
188190

189191
// Room
190192
implementation("androidx.room:room-runtime:$room_version")
191193
ksp("androidx.room:room-compiler:$room_version")
192194
implementation("androidx.room:room-ktx:$room_version")
193195

194196
// Coroutines
195-
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1')
197+
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2')
196198

197199
testImplementation("junit:junit:4.13.2")
198200

199201
// Instrumentation testing
200202

201-
androidTestImplementation("androidx.test:runner:1.6.2")
202-
androidTestUtil("androidx.test:orchestrator:1.5.0")
203-
androidTestImplementation("androidx.test:rules:1.6.1")
204-
androidTestImplementation("androidx.test.ext:junit:1.2.1")
203+
androidTestImplementation("androidx.test:runner:1.7.0")
204+
androidTestUtil("androidx.test:orchestrator:1.6.1")
205+
androidTestImplementation("androidx.test:rules:1.7.0")
206+
androidTestImplementation("androidx.test.ext:junit:1.3.0")
205207
// Optional -- UI testing with Espresso
206-
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
207-
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
208+
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
209+
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.7.0")
208210
// mock server for backend
209-
androidTestImplementation('com.squareup.okhttp3:mockwebserver:4.12.0')
211+
androidTestImplementation('com.squareup.okhttp3:mockwebserver:5.3.2')
210212
// Optional -- Hamcrest library
211213
androidTestImplementation("org.hamcrest:hamcrest:3.0")
212214
androidTestImplementation("org.hamcrest:hamcrest-library:3.0")

app/src/main/java/org/bspb/smartbirds/pro/ui/BaseActivity.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
import android.content.ComponentName;
44
import android.content.Context;
55
import android.content.ServiceConnection;
6+
import android.os.Bundle;
67
import android.os.IBinder;
8+
import android.view.View;
79

10+
import androidx.activity.EdgeToEdge;
811
import androidx.appcompat.app.AppCompatActivity;
12+
import androidx.core.view.ViewCompat;
13+
import androidx.core.view.WindowInsetsCompat;
914

1015
import org.bspb.smartbirds.pro.service.DataService;
1116

@@ -29,6 +34,80 @@ public void onServiceDisconnected(ComponentName name) {
2934
}
3035
};
3136

37+
@Override
38+
protected void onCreate(Bundle savedInstanceState) {
39+
super.onCreate(savedInstanceState);
40+
if (shouldEnableEdgeToEdge()) {
41+
EdgeToEdge.enable(
42+
this,
43+
androidx.activity.SystemBarStyle.light(
44+
android.graphics.Color.TRANSPARENT,
45+
android.graphics.Color.TRANSPARENT
46+
)
47+
);
48+
}
49+
}
50+
51+
/**
52+
* Determine if edge-to-edge should be enabled for this activity.
53+
* Override in subclasses to customize behavior.
54+
*
55+
* Note: Edge-to-edge is only enabled on Android 15+ (API 35+) where it's natively
56+
* supported. The backported implementation on older Android versions has compatibility
57+
* issues with Espresso instrumented tests (view visibility calculations fail).
58+
*
59+
* @return true to enable edge-to-edge, false otherwise
60+
*/
61+
protected boolean shouldEnableEdgeToEdge() {
62+
// Only enable on Android 15+ where edge-to-edge is native and Espresso-compatible
63+
// On older versions, the AndroidX backport causes Espresso PerformException
64+
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM;
65+
}
66+
67+
@Override
68+
public void setContentView(int layoutResID) {
69+
super.setContentView(layoutResID);
70+
setupWindowInsets();
71+
}
72+
73+
/**
74+
* Return the resource ID of the container view that should receive window insets.
75+
* Return 0 to disable automatic inset handling (for custom implementations).
76+
*
77+
* @return The resource ID of the container view, or 0 to skip automatic handling
78+
*/
79+
protected abstract int getInsetContainerId();
80+
81+
/**
82+
* Setup window insets for edge-to-edge display.
83+
* Override this method for custom inset handling (e.g., multiple containers).
84+
*/
85+
protected void setupWindowInsets() {
86+
int containerId = getInsetContainerId();
87+
if (containerId == 0) {
88+
return; // Skip automatic handling
89+
}
90+
91+
View container = findViewById(containerId);
92+
if (container != null) {
93+
applyWindowInsets(container);
94+
}
95+
}
96+
97+
/**
98+
* Apply window insets as padding to the given view.
99+
* Override for custom inset application logic (e.g., preserving margins).
100+
*
101+
* @param container The view to apply insets to
102+
*/
103+
protected void applyWindowInsets(View container) {
104+
ViewCompat.setOnApplyWindowInsetsListener(container, (view, windowInsets) -> {
105+
androidx.core.graphics.Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
106+
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
107+
return WindowInsetsCompat.CONSUMED;
108+
});
109+
}
110+
32111
@Override
33112
protected void onStart() {
34113
super.onStart();

app/src/main/java/org/bspb/smartbirds/pro/ui/EditCurrentCommonFormActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ public class EditCurrentCommonFormActivity extends BaseActivity {
2323
CurrentMonitoringCommonFormFragment formFragment;
2424
boolean isFinishing = false;
2525

26+
@Override
27+
protected int getInsetContainerId() {
28+
return R.id.container;
29+
}
30+
2631
public static Intent intent(Context context) {
2732
return intent(context, false);
2833
}

app/src/main/java/org/bspb/smartbirds/pro/ui/EditMonitoringEntryActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public class EditMonitoringEntryActivity extends BaseActivity {
3232

3333
EEventBus eventBus = EEventBus.getInstance();
3434

35+
@Override
36+
protected int getInsetContainerId() {
37+
return R.id.container;
38+
}
39+
3540
public static Intent newIntent(Context context, long entryId, EntryType entryType) {
3641
Intent intent = new Intent(context, EditMonitoringEntryActivity.class);
3742
intent.putExtra(EXTRA_ENTRY_ID, entryId);

app/src/main/java/org/bspb/smartbirds/pro/ui/LoginActivity.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
import android.widget.EditText;
1313
import android.widget.TextView;
1414

15+
import androidx.activity.EdgeToEdge;
16+
import androidx.activity.SystemBarStyle;
1517
import androidx.annotation.Nullable;
1618
import androidx.appcompat.app.AppCompatActivity;
19+
import androidx.core.view.ViewCompat;
20+
import androidx.core.view.WindowInsetsCompat;
1721

1822
import org.bspb.smartbirds.pro.R;
1923
import org.bspb.smartbirds.pro.SmartBirdsApplication;
@@ -50,11 +54,44 @@ public class LoginActivity extends AppCompatActivity {
5054
@Override
5155
protected void onCreate(@Nullable Bundle savedInstanceState) {
5256
super.onCreate(savedInstanceState);
57+
EdgeToEdge.enable(
58+
this,
59+
SystemBarStyle.light(
60+
android.graphics.Color.TRANSPARENT,
61+
android.graphics.Color.TRANSPARENT
62+
)
63+
);
64+
5365
prefs = new UserPrefs(this);
5466
setContentView(R.layout.activity_login);
67+
setupWindowInsets();
5568
initViews();
5669
}
5770

71+
/**
72+
* Setup window insets to handle edge-to-edge display.
73+
* Adds system bar insets to existing padding to prevent content overlap.
74+
*/
75+
private void setupWindowInsets() {
76+
View loginRoot = findViewById(R.id.login_root);
77+
ViewCompat.setOnApplyWindowInsetsListener(loginRoot, (view, windowInsets) -> {
78+
androidx.core.graphics.Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
79+
// Add system bar insets to existing padding
80+
int existingPaddingLeft = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
81+
int existingPaddingTop = getResources().getDimensionPixelSize(R.dimen.activity_vertical_margin);
82+
int existingPaddingRight = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
83+
int existingPaddingBottom = getResources().getDimensionPixelSize(R.dimen.activity_vertical_margin);
84+
85+
view.setPadding(
86+
existingPaddingLeft + insets.left,
87+
existingPaddingTop + insets.top,
88+
existingPaddingRight + insets.right,
89+
existingPaddingBottom + insets.bottom
90+
);
91+
return WindowInsetsCompat.CONSUMED;
92+
});
93+
}
94+
5895
private void initViews() {
5996
mEmailView = findViewById(R.id.email);
6097
mPasswordView = findViewById(R.id.password);
@@ -261,4 +298,3 @@ public void onEventMainThread(LoginResultEvent loginResult) {
261298
}
262299
}
263300
}
264-

app/src/main/java/org/bspb/smartbirds/pro/ui/MainActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ protected void onCreate(Bundle savedInstanceState) {
4545
}
4646
}
4747

48+
@Override
49+
protected int getInsetContainerId() {
50+
return R.id.container;
51+
}
52+
4853
void createFragment() {
4954
if (getSupportFragmentManager().findFragmentById(R.id.container) == null)
5055
getSupportFragmentManager().beginTransaction()

app/src/main/java/org/bspb/smartbirds/pro/ui/MonitoringActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ public static Intent newIntent(Context context) {
9292

9393
private static final int REQUEST_FINISH_MONITORING = 1002;
9494

95+
@Override
96+
protected int getInsetContainerId() {
97+
return R.id.monitoring_root;
98+
}
99+
95100
@NonNull
96101
MapProvider.ProviderType providerType = MapProvider.ProviderType.GOOGLE;
97102
@NonNull

app/src/main/java/org/bspb/smartbirds/pro/ui/MonitoringListActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public class MonitoringListActivity extends BaseActivity implements MonitoringLi
3030

3131
MonitoringListFragment listFragment;
3232

33+
@Override
34+
protected int getInsetContainerId() {
35+
return R.id.monitoring_list_container;
36+
}
37+
3338
@Override
3439
protected void onCreate(Bundle savedInstanceState) {
3540
super.onCreate(savedInstanceState);

app/src/main/java/org/bspb/smartbirds/pro/ui/NewMonitoringEntryActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ public class NewMonitoringEntryActivity extends BaseActivity implements ServiceC
4242

4343
EEventBus eventBus = EEventBus.getInstance();
4444

45+
@Override
46+
protected int getInsetContainerId() {
47+
return R.id.container;
48+
}
49+
4550
public static Intent newIntent(Context context, EntryType entryType) {
4651
return new Intent(context, NewMonitoringEntryActivity.class)
4752
.putExtra(EXTRA_TYPE, entryType);

app/src/main/java/org/bspb/smartbirds/pro/ui/StartMonitoringActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public class StartMonitoringActivity extends BaseActivity {
2424
EEventBus bus = EEventBus.getInstance();
2525
CurrentMonitoringCommonFormFragment formFragment;
2626

27+
@Override
28+
protected int getInsetContainerId() {
29+
return R.id.container;
30+
}
31+
2732
@Override
2833
public void onCreate(Bundle savedInstanceState) {
2934
super.onCreate(savedInstanceState);

0 commit comments

Comments
 (0)