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
60 changes: 31 additions & 29 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ if (uploadKeyAvailable) {
}

android {
compileSdk 34
compileSdk 36

defaultConfig {
applicationId "org.bspb.smartbirds.pro"
minSdk 21
targetSdk 34
minSdk 23
targetSdk 35
versionCode versionCodeBase
versionName "${versionNameBase}"

Expand Down Expand Up @@ -81,7 +81,7 @@ android {

release {
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
if (uploadKeyAvailable) {
signingConfig signingConfigs.release
}
Expand All @@ -94,7 +94,7 @@ android {
beta {
versionNameSuffix "-BETA"
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
if (betaKeyAvailable) {
signingConfig signingConfigs.beta
}
Expand Down Expand Up @@ -130,6 +130,7 @@ android {

buildFeatures {
dataBinding = true
buildConfig true
}

testOptions {
Expand All @@ -144,69 +145,70 @@ android {
}

dependencies {
def room_version = "2.6.1"
def room_version = "2.8.4"

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

implementation('org.jetbrains.kotlin:kotlin-stdlib:2.0.20')
implementation('org.jetbrains.kotlin:kotlin-stdlib:2.3.10')

// KTX extensions
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.fragment:fragment-ktx:1.8.2")
implementation("androidx.core:core-ktx:1.17.0")
implementation("androidx.activity:activity-ktx:1.9.3")
implementation("androidx.fragment:fragment-ktx:1.8.9")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.4")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.10.0")

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

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

// Crashlytics Kit
implementation("com.google.firebase:firebase-crashlytics:19.0.3")
implementation("com.google.firebase:firebase-crashlytics:20.0.4")

implementation("com.google.firebase:firebase-analytics:22.1.0")
implementation("com.google.firebase:firebase-analytics:23.0.0")

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

implementation('org.osmdroid:osmdroid-android:6.1.20')
implementation("com.github.MKergall:osmbonuspack:6.9.0")
implementation("com.google.android.material:material:1.12.0")
implementation("com.google.android.material:material:1.13.0")
implementation("androidx.legacy:legacy-support-v13:1.0.0")

// http://square.github.io/retrofit/
implementation('com.squareup.retrofit2:retrofit:2.11.0')
implementation('com.squareup.retrofit2:converter-gson:2.11.0')
implementation('com.squareup.okhttp3:logging-interceptor:4.12.0')
implementation("com.squareup.okhttp3:okhttp-urlconnection:4.12.0")
implementation('com.squareup.retrofit2:retrofit:3.0.0')
implementation('com.squareup.retrofit2:converter-gson:3.0.0')
implementation('com.squareup.okhttp3:logging-interceptor:5.3.2')
implementation("com.squareup.okhttp3:okhttp-urlconnection:5.3.2")

implementation("androidx.lifecycle:lifecycle-common-java8:2.8.4")
implementation("androidx.lifecycle:lifecycle-common-java8:2.10.0")

// Room
implementation("androidx.room:room-runtime:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")

// Coroutines
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1')
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2')

testImplementation("junit:junit:4.13.2")

// Instrumentation testing

androidTestImplementation("androidx.test:runner:1.6.2")
androidTestUtil("androidx.test:orchestrator:1.5.0")
androidTestImplementation("androidx.test:rules:1.6.1")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test:runner:1.7.0")
androidTestUtil("androidx.test:orchestrator:1.6.1")
androidTestImplementation("androidx.test:rules:1.7.0")
androidTestImplementation("androidx.test.ext:junit:1.3.0")
// Optional -- UI testing with Espresso
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.7.0")
// mock server for backend
androidTestImplementation('com.squareup.okhttp3:mockwebserver:4.12.0')
androidTestImplementation('com.squareup.okhttp3:mockwebserver:5.3.2')
// Optional -- Hamcrest library
androidTestImplementation("org.hamcrest:hamcrest:3.0")
androidTestImplementation("org.hamcrest:hamcrest-library:3.0")
Expand Down
79 changes: 79 additions & 0 deletions app/src/main/java/org/bspb/smartbirds/pro/ui/BaseActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

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

Expand All @@ -29,6 +34,80 @@ public void onServiceDisconnected(ComponentName name) {
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (shouldEnableEdgeToEdge()) {
EdgeToEdge.enable(
this,
androidx.activity.SystemBarStyle.light(
android.graphics.Color.TRANSPARENT,
android.graphics.Color.TRANSPARENT
)
);
}
}

/**
* Determine if edge-to-edge should be enabled for this activity.
* Override in subclasses to customize behavior.
*
* Note: Edge-to-edge is only enabled on Android 15+ (API 35+) where it's natively
* supported. The backported implementation on older Android versions has compatibility
* issues with Espresso instrumented tests (view visibility calculations fail).
*
* @return true to enable edge-to-edge, false otherwise
*/
protected boolean shouldEnableEdgeToEdge() {
// Only enable on Android 15+ where edge-to-edge is native and Espresso-compatible
// On older versions, the AndroidX backport causes Espresso PerformException
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM;
}

@Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
setupWindowInsets();
}

/**
* Return the resource ID of the container view that should receive window insets.
* Return 0 to disable automatic inset handling (for custom implementations).
*
* @return The resource ID of the container view, or 0 to skip automatic handling
*/
protected abstract int getInsetContainerId();

/**
* Setup window insets for edge-to-edge display.
* Override this method for custom inset handling (e.g., multiple containers).
*/
protected void setupWindowInsets() {
int containerId = getInsetContainerId();
if (containerId == 0) {
return; // Skip automatic handling
}

View container = findViewById(containerId);
if (container != null) {
applyWindowInsets(container);
}
}

/**
* Apply window insets as padding to the given view.
* Override for custom inset application logic (e.g., preserving margins).
*
* @param container The view to apply insets to
*/
protected void applyWindowInsets(View container) {
ViewCompat.setOnApplyWindowInsetsListener(container, (view, windowInsets) -> {
androidx.core.graphics.Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
return WindowInsetsCompat.CONSUMED;
});
}

@Override
protected void onStart() {
super.onStart();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class EditCurrentCommonFormActivity extends BaseActivity {
CurrentMonitoringCommonFormFragment formFragment;
boolean isFinishing = false;

@Override
protected int getInsetContainerId() {
return R.id.container;
}

public static Intent intent(Context context) {
return intent(context, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class EditMonitoringEntryActivity extends BaseActivity {

EEventBus eventBus = EEventBus.getInstance();

@Override
protected int getInsetContainerId() {
return R.id.container;
}

public static Intent newIntent(Context context, long entryId, EntryType entryType) {
Intent intent = new Intent(context, EditMonitoringEntryActivity.class);
intent.putExtra(EXTRA_ENTRY_ID, entryId);
Expand Down
38 changes: 37 additions & 1 deletion app/src/main/java/org/bspb/smartbirds/pro/ui/LoginActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
import android.widget.EditText;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.activity.SystemBarStyle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import org.bspb.smartbirds.pro.R;
import org.bspb.smartbirds.pro.SmartBirdsApplication;
Expand Down Expand Up @@ -50,11 +54,44 @@ public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(
this,
SystemBarStyle.light(
android.graphics.Color.TRANSPARENT,
android.graphics.Color.TRANSPARENT
)
);

prefs = new UserPrefs(this);
setContentView(R.layout.activity_login);
setupWindowInsets();
initViews();
}

/**
* Setup window insets to handle edge-to-edge display.
* Adds system bar insets to existing padding to prevent content overlap.
*/
private void setupWindowInsets() {
View loginRoot = findViewById(R.id.login_root);
ViewCompat.setOnApplyWindowInsetsListener(loginRoot, (view, windowInsets) -> {
androidx.core.graphics.Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
// Add system bar insets to existing padding
int existingPaddingLeft = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
int existingPaddingTop = getResources().getDimensionPixelSize(R.dimen.activity_vertical_margin);
int existingPaddingRight = getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
int existingPaddingBottom = getResources().getDimensionPixelSize(R.dimen.activity_vertical_margin);

view.setPadding(
existingPaddingLeft + insets.left,
existingPaddingTop + insets.top,
existingPaddingRight + insets.right,
existingPaddingBottom + insets.bottom
);
return WindowInsetsCompat.CONSUMED;
});
}

private void initViews() {
mEmailView = findViewById(R.id.email);
mPasswordView = findViewById(R.id.password);
Expand Down Expand Up @@ -261,4 +298,3 @@ public void onEventMainThread(LoginResultEvent loginResult) {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ protected void onCreate(Bundle savedInstanceState) {
}
}

@Override
protected int getInsetContainerId() {
return R.id.container;
}

void createFragment() {
if (getSupportFragmentManager().findFragmentById(R.id.container) == null)
getSupportFragmentManager().beginTransaction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ public static Intent newIntent(Context context) {

private static final int REQUEST_FINISH_MONITORING = 1002;

@Override
protected int getInsetContainerId() {
return R.id.monitoring_root;
}

@NonNull
MapProvider.ProviderType providerType = MapProvider.ProviderType.GOOGLE;
@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class MonitoringListActivity extends BaseActivity implements MonitoringLi

MonitoringListFragment listFragment;

@Override
protected int getInsetContainerId() {
return R.id.monitoring_list_container;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public class NewMonitoringEntryActivity extends BaseActivity implements ServiceC

EEventBus eventBus = EEventBus.getInstance();

@Override
protected int getInsetContainerId() {
return R.id.container;
}

public static Intent newIntent(Context context, EntryType entryType) {
return new Intent(context, NewMonitoringEntryActivity.class)
.putExtra(EXTRA_TYPE, entryType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class StartMonitoringActivity extends BaseActivity {
EEventBus bus = EEventBus.getInstance();
CurrentMonitoringCommonFormFragment formFragment;

@Override
protected int getInsetContainerId() {
return R.id.container;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

public class StatsActivity extends BaseActivity {

@Override
protected int getInsetContainerId() {
return R.id.container;
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ open class BrowseMonitoringCommonFormActivity : BaseActivity() {

protected lateinit var monitoringCode: String

override fun getInsetContainerId(): Int = R.id.container

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_start_monitoring)
Expand Down
Loading
Loading