commit e63250e25bbf67acacf57152284fd8f841e09f6f
Author: purifetchi <0xlunaric@gmail.com>
Date: Tue Jun 10 23:36:41 2025 +0200
android
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7914c3d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+#built application files
+*.apk
+*.ap_
+*.aab
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+gen/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Windows thumbnail db
+Thumbs.db
+
+# OSX files
+.DS_Store
+
+# Android Studio
+*.iml
+.idea
+#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
+.gradle
+build/
+.navigation
+captures/
+output.json
+
+#NDK
+obj/
+.externalNativeBuild
\ No newline at end of file
diff --git a/lab1/.gitignore b/lab1/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/lab1/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/lab1/.kotlin/errors/errors-1749574013288.log b/lab1/.kotlin/errors/errors-1749574013288.log
new file mode 100644
index 0000000..1219b50
--- /dev/null
+++ b/lab1/.kotlin/errors/errors-1749574013288.log
@@ -0,0 +1,4 @@
+kotlin version: 2.0.21
+error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
+ 1. Kotlin compile daemon is ready
+
diff --git a/lab1/app/.gitignore b/lab1/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lab1/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lab1/app/build.gradle.kts b/lab1/app/build.gradle.kts
new file mode 100644
index 0000000..d39e277
--- /dev/null
+++ b/lab1/app/build.gradle.kts
@@ -0,0 +1,63 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "com.example.lab1"
+ compileSdk = 35
+
+ defaultConfig {
+ applicationId = "com.example.lab1"
+ minSdk = 27
+ targetSdk = 35
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+ buildFeatures {
+ compose = true
+ }
+}
+
+dependencies {
+
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.activity.compose)
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.ui)
+ implementation(libs.androidx.ui.graphics)
+ implementation(libs.androidx.ui.tooling.preview)
+ implementation(libs.androidx.material3)
+ implementation(libs.androidx.appcompat)
+ implementation(libs.material)
+ implementation(libs.androidx.activity)
+ implementation(libs.androidx.constraintlayout)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(platform(libs.androidx.compose.bom))
+ androidTestImplementation(libs.androidx.ui.test.junit4)
+ debugImplementation(libs.androidx.ui.tooling)
+ debugImplementation(libs.androidx.ui.test.manifest)
+}
\ No newline at end of file
diff --git a/lab1/app/proguard-rules.pro b/lab1/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lab1/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/lab1/app/src/androidTest/java/com/example/lab1/ExampleInstrumentedTest.kt b/lab1/app/src/androidTest/java/com/example/lab1/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..d5d5740
--- /dev/null
+++ b/lab1/app/src/androidTest/java/com/example/lab1/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.lab1
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.example.lab1", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/lab1/app/src/main/AndroidManifest.xml b/lab1/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bcbfa47
--- /dev/null
+++ b/lab1/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/java/com/example/lab1/GradeAdapter.java b/lab1/app/src/main/java/com/example/lab1/GradeAdapter.java
new file mode 100644
index 0000000..708399d
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/GradeAdapter.java
@@ -0,0 +1,75 @@
+package com.example.lab1;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+public class GradeAdapter extends RecyclerView.Adapter {
+ public static class GradeViewHolder extends RecyclerView.ViewHolder {
+ TextView tvSubject;
+ RadioGroup rgGrade;
+
+ GradeViewHolder(@NonNull View itemView) {
+ super(itemView);
+ tvSubject = itemView.findViewById(R.id.tvSubject);
+ rgGrade = itemView.findViewById(R.id.rgGrade);
+ }
+ }
+
+ private final List subjects;
+ private final int[] gradeOptions = {2,3,4,5};
+
+ public GradeAdapter(List subjects) {
+ this.subjects = subjects;
+ }
+
+ @NonNull
+ @Override
+ public GradeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.grades_row, parent, false);
+ return new GradeViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull GradeViewHolder holder, int position) {
+ Subject item = subjects.get(position);
+ holder.tvSubject.setText(item.name);
+ holder.rgGrade.removeAllViews();
+
+ for (double grade : gradeOptions) {
+ RadioButton rb = new RadioButton(holder.itemView.getContext());
+ rb.setText(String.valueOf(grade));
+ rb.setId(View.generateViewId());
+ rb.setTag(grade);
+
+ rb.setChecked(item.grade == grade);
+
+ holder.rgGrade.addView(rb);
+ }
+
+ holder.rgGrade.setOnCheckedChangeListener((group, checkedId) -> {
+ RadioButton selected = group.findViewById(checkedId);
+ if (selected != null) {
+ item.grade = (double)selected.getTag();
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return subjects.size();
+ }
+
+ public List getGradeItems() {
+ return subjects;
+ }
+}
diff --git a/lab1/app/src/main/java/com/example/lab1/GradesActivity.java b/lab1/app/src/main/java/com/example/lab1/GradesActivity.java
new file mode 100644
index 0000000..e266aa8
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/GradesActivity.java
@@ -0,0 +1,100 @@
+package com.example.lab1;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GradesActivity extends AppCompatActivity {
+
+ private GradeAdapter gradeAdapter;
+ private List subjects;
+ private RecyclerView recyclerView;
+
+ private static final String KEY_GRADES = "key_grades";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_grades);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.mainGrades), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
+ return insets;
+ });
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ subjects = new ArrayList<>();
+ var subjectArray = getResources().getStringArray(R.array.przedmioty);
+ var subjectCount = getIntent().getIntExtra("gradeCount", 5);
+ for (var i = 0; i < subjectCount; i++) {
+ subjects.add(new Subject(subjectArray[i]));
+ }
+
+ if (savedInstanceState != null && savedInstanceState.containsKey(KEY_GRADES)) {
+ double[] savedGrades = savedInstanceState.getDoubleArray(KEY_GRADES);
+ if (savedGrades != null) {
+ for (int i = 0; i < savedGrades.length && i < subjects.size(); i++) {
+ subjects.get(i).grade = savedGrades[i];
+ }
+ }
+ }
+
+ recyclerView = findViewById(R.id.rvListaOcen);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ gradeAdapter = new GradeAdapter(subjects);
+ recyclerView.setAdapter(gradeAdapter);
+
+ var calculateButton = findViewById(R.id.btOblicz);
+ calculateButton.setOnClickListener(v -> calculateAverage());
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ double[] savedGrades = new double[subjects.size()];
+ for (int i = 0; i < subjects.size(); i++) {
+ Double grade = subjects.get(i).grade;
+ savedGrades[i] = grade;
+ }
+ outState.putDoubleArray(KEY_GRADES, savedGrades);
+ }
+
+ @Override
+ public void onBackPressed() {
+ Intent resultIntent = new Intent();
+ setResult(RESULT_CANCELED, resultIntent);
+ super.onBackPressed();
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ onBackPressed(); // ustawia wynik i kończy aktywność
+ return true;
+ }
+
+ private void calculateAverage() {
+ double sum = 0;
+ var items = gradeAdapter.getGradeItems();
+ for (Subject item : items) {
+ sum += item.grade;
+ }
+
+ double average = sum / items.size();
+ Intent resultIntent = new Intent();
+ resultIntent.putExtra("average", average);
+ setResult(RESULT_OK, resultIntent);
+ finish();
+ }
+}
diff --git a/lab1/app/src/main/java/com/example/lab1/MainActivity.java b/lab1/app/src/main/java/com/example/lab1/MainActivity.java
new file mode 100644
index 0000000..3d71b0b
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/MainActivity.java
@@ -0,0 +1,149 @@
+package com.example.lab1;
+
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.*;
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class MainActivity extends AppCompatActivity {
+
+ final int GRADE_ACTIVITY_REQUEST_CODE = 2420;
+
+ EditText etImie, etNazwisko, etOceny;
+ Button btOceny;
+
+ boolean isNameValid = false, isSurnameValid = false, isGradeValid = false, isResults = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ etImie = findViewById(R.id.etImie);
+ etNazwisko = findViewById(R.id.etNazwisko);
+ etOceny = findViewById(R.id.etOceny);
+ btOceny = findViewById(R.id.btOceny);
+
+ setupValidation(etImie, getString(R.string.imie_invalid), (s) -> {
+ isNameValid = !s.trim().isEmpty();
+ return isNameValid;
+ });
+
+ setupValidation(etNazwisko, getString(R.string.nazwisko_invalid), (s) -> {
+ isSurnameValid = !s.trim().isEmpty();
+ return isSurnameValid;
+ });
+
+ setupValidation(etOceny, getString(R.string.oceny_invalid), (s) -> {
+ try {
+ int num = Integer.parseInt(s);
+ isGradeValid = num >= 5 && num <= 15;
+ } catch (NumberFormatException e) {
+ isGradeValid = false;
+ }
+ return isGradeValid;
+ });
+
+ btOceny.setOnClickListener(v -> {
+ Toast.makeText(this, getString(R.string.dane_poprawne), Toast.LENGTH_SHORT).show();
+
+ Intent intent = new Intent(MainActivity.this, GradesActivity.class);
+ intent.putExtra("gradeCount", Integer.parseInt(etOceny.getText().toString()));
+ startActivityForResult(intent, GRADE_ACTIVITY_REQUEST_CODE);
+ });
+ }
+
+ private void setupValidation(EditText editText, String errorMsg, Validator validator) {
+ editText.setOnFocusChangeListener((v, hasFocus) -> {
+ if (!hasFocus) {
+ String value = editText.getText().toString();
+ if (!validator.validate(value)) {
+ editText.setError(errorMsg);
+ Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();
+ }
+ updateButtonState();
+ }
+ });
+
+ editText.addTextChangedListener(new TextWatcher() {
+ public void afterTextChanged(Editable s) {
+ validator.validate(s.toString());
+ updateButtonState();
+ }
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+ });
+ }
+
+ private void updateButtonState() {
+ var visibility = isNameValid && isSurnameValid && isGradeValid && !isResults
+ ? View.VISIBLE
+ : View.GONE;
+
+ btOceny.setVisibility(visibility);
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString("name", etImie.getText().toString());
+ outState.putString("surname", etNazwisko.getText().toString());
+ outState.putString("gradeCount", etOceny.getText().toString());
+ }
+
+ @Override
+ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ etImie.setText(savedInstanceState.getString("name", ""));
+ etNazwisko.setText(savedInstanceState.getString("surname", ""));
+ etOceny.setText(savedInstanceState.getString("gradeCount", ""));
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == GRADE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
+ isResults = true;
+ updateButtonState();
+
+ var average = data.getDoubleExtra("average", 0.0);
+ showAverageResult(average);
+ }
+ }
+
+ private void showAverageResult(double average) {
+ TextView tvAverage = findViewById(R.id.tvAverage);
+ tvAverage.setText(String.format(getString(R.string.srednia_format), average));
+ tvAverage.setVisibility(View.VISIBLE);
+
+ var averageAboveThree = average >= 3.0;
+ Button btAverage = findViewById(R.id.btAverage);
+ if (averageAboveThree) {
+ btAverage.setText(R.string.superasnie);
+ } else {
+ btAverage.setText(R.string.nie_poszlo);
+ }
+
+ btAverage.setVisibility(View.VISIBLE);
+ btAverage.setOnClickListener(v -> {
+ String message;
+ if (averageAboveThree) {
+ message = getString(R.string.gratulacje_zaliczenie);
+ } else {
+ message = getString(R.string.zaliczenie_warunkowe);
+ }
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+ finish();
+ });
+ }
+
+ interface Validator {
+ boolean validate(String input);
+ }
+}
diff --git a/lab1/app/src/main/java/com/example/lab1/Subject.java b/lab1/app/src/main/java/com/example/lab1/Subject.java
new file mode 100644
index 0000000..f291eb8
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/Subject.java
@@ -0,0 +1,10 @@
+package com.example.lab1;
+public class Subject {
+ public String name;
+ public Double grade;
+
+ public Subject(String subjectName) {
+ this.name = subjectName;
+ this.grade = 2.0;
+ }
+}
diff --git a/lab1/app/src/main/java/com/example/lab1/ui/theme/Color.kt b/lab1/app/src/main/java/com/example/lab1/ui/theme/Color.kt
new file mode 100644
index 0000000..9916ecc
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.example.lab1.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
diff --git a/lab1/app/src/main/java/com/example/lab1/ui/theme/Theme.kt b/lab1/app/src/main/java/com/example/lab1/ui/theme/Theme.kt
new file mode 100644
index 0000000..8cf2ba2
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/ui/theme/Theme.kt
@@ -0,0 +1,58 @@
+package com.example.lab1.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun Lab1Theme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/lab1/app/src/main/java/com/example/lab1/ui/theme/Type.kt b/lab1/app/src/main/java/com/example/lab1/ui/theme/Type.kt
new file mode 100644
index 0000000..6a3879a
--- /dev/null
+++ b/lab1/app/src/main/java/com/example/lab1/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.example.lab1.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/lab1/app/src/main/res/drawable/ic_launcher_background.xml b/lab1/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lab1/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab1/app/src/main/res/drawable/ic_launcher_foreground.xml b/lab1/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lab1/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/layout/activity_grades.xml b/lab1/app/src/main/res/layout/activity_grades.xml
new file mode 100644
index 0000000..953142e
--- /dev/null
+++ b/lab1/app/src/main/res/layout/activity_grades.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
diff --git a/lab1/app/src/main/res/layout/activity_main.xml b/lab1/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..9ff205c
--- /dev/null
+++ b/lab1/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab1/app/src/main/res/layout/grades_row.xml b/lab1/app/src/main/res/layout/grades_row.xml
new file mode 100644
index 0000000..bf6bc49
--- /dev/null
+++ b/lab1/app/src/main/res/layout/grades_row.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/lab1/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/lab1/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab1/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/lab1/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab1/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/lab1/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lab1/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lab1/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lab1/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/lab1/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lab1/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lab1/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/lab1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lab1/app/src/main/res/values/colors.xml b/lab1/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/lab1/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/values/strings.xml b/lab1/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..929f4c1
--- /dev/null
+++ b/lab1/app/src/main/res/values/strings.xml
@@ -0,0 +1,40 @@
+
+ lab1
+ Imię:
+ Imię nie może być puste
+ Podaj swoje imię
+ Wpisz poprawne dane
+ Nazwisko:
+ Nazwisko nie może być puste
+ Podaj swoje nazwisko
+ Liczba ocen:
+ Wpisz liczbę ocen (5–15)
+ Liczba ocen musi być z przedziału 5 do 15
+ Dane poprawne
+ OCENY
+ Oblicz srednia
+
+ - Matematyka
+ - Fizyka
+ - Chemia
+ - Biologia
+ - Historia
+ - Geografia
+ - Informatyka
+ - Język polski
+ - Język angielski
+ - Wiedza o społeczeństwie
+ - Religia
+ - Wychowanie fizyczne
+ - Muzyka
+ - Plastyka
+ - Technika
+
+ Przedmiot
+ Super :)
+ Tym razem mi nie poszło
+ Gratulacje! Otrzymujesz zaliczenie!
+ Wysyłam podanie o zaliczenie warunkowe
+ Twoja średnia to %.2f
+ Wprowadź przynajmniej jedną ocenę
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/values/themes.xml b/lab1/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..1194ab9
--- /dev/null
+++ b/lab1/app/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/xml/backup_rules.xml b/lab1/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/lab1/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/main/res/xml/data_extraction_rules.xml b/lab1/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/lab1/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab1/app/src/test/java/com/example/lab1/ExampleUnitTest.kt b/lab1/app/src/test/java/com/example/lab1/ExampleUnitTest.kt
new file mode 100644
index 0000000..c2b26d2
--- /dev/null
+++ b/lab1/app/src/test/java/com/example/lab1/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.lab1
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/lab1/build.gradle.kts b/lab1/build.gradle.kts
new file mode 100644
index 0000000..952b930
--- /dev/null
+++ b/lab1/build.gradle.kts
@@ -0,0 +1,6 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.android) apply false
+ alias(libs.plugins.kotlin.compose) apply false
+}
\ No newline at end of file
diff --git a/lab1/gradle.properties b/lab1/gradle.properties
new file mode 100644
index 0000000..20e2a01
--- /dev/null
+++ b/lab1/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/lab1/gradle/libs.versions.toml b/lab1/gradle/libs.versions.toml
new file mode 100644
index 0000000..67c90ee
--- /dev/null
+++ b/lab1/gradle/libs.versions.toml
@@ -0,0 +1,40 @@
+[versions]
+agp = "8.10.1"
+kotlin = "2.0.21"
+coreKtx = "1.10.1"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+lifecycleRuntimeKtx = "2.9.1"
+activityCompose = "1.10.1"
+composeBom = "2024.09.00"
+appcompat = "1.7.1"
+material = "1.12.0"
+activity = "1.10.1"
+constraintlayout = "2.1.4"
+
+[libraries]
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
+androidx-ui = { group = "androidx.compose.ui", name = "ui" }
+androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
+androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
+androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
+androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
+androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
+androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+
diff --git a/lab1/gradle/wrapper/gradle-wrapper.jar b/lab1/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/lab1/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lab1/gradle/wrapper/gradle-wrapper.properties b/lab1/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c7fb49e
--- /dev/null
+++ b/lab1/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jun 10 18:41:08 CEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/lab1/gradlew b/lab1/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/lab1/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/lab1/gradlew.bat b/lab1/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/lab1/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lab1/settings.gradle.kts b/lab1/settings.gradle.kts
new file mode 100644
index 0000000..998a086
--- /dev/null
+++ b/lab1/settings.gradle.kts
@@ -0,0 +1,23 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "lab1"
+include(":app")
diff --git a/lab2/.gitignore b/lab2/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/lab2/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/lab2/app/.gitignore b/lab2/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lab2/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lab2/app/build.gradle.kts b/lab2/app/build.gradle.kts
new file mode 100644
index 0000000..fdc8e81
--- /dev/null
+++ b/lab2/app/build.gradle.kts
@@ -0,0 +1,56 @@
+plugins {
+ alias(libs.plugins.android.application)
+}
+
+android {
+ namespace = "com.example.lab2"
+ compileSdk = 35
+
+ defaultConfig {
+ applicationId = "com.example.lab2"
+ minSdk = 27
+ targetSdk = 35
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
+
+dependencies {
+ implementation(libs.appcompat)
+ implementation(libs.material)
+ implementation(libs.activity)
+ implementation(libs.constraintlayout)
+
+ // Room
+ implementation("androidx.room:room-runtime:2.6.1")
+ testImplementation("androidx.room:room-testing:2.6.1")
+ annotationProcessor("androidx.room:room-compiler:2.6.1")
+
+
+ // Lifecycle
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
+ implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
+
+ // Testy
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.ext.junit)
+ androidTestImplementation(libs.espresso.core)
+}
diff --git a/lab2/app/proguard-rules.pro b/lab2/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lab2/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/lab2/app/src/androidTest/java/com/example/lab2/ExampleInstrumentedTest.java b/lab2/app/src/androidTest/java/com/example/lab2/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..9ce59e3
--- /dev/null
+++ b/lab2/app/src/androidTest/java/com/example/lab2/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.lab2;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.lab2", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/lab2/app/src/main/AndroidManifest.xml b/lab2/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2ae6be9
--- /dev/null
+++ b/lab2/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/java/com/example/lab2/AddPhoneActivity.java b/lab2/app/src/main/java/com/example/lab2/AddPhoneActivity.java
new file mode 100644
index 0000000..8726d1a
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/AddPhoneActivity.java
@@ -0,0 +1,56 @@
+package com.example.lab2;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+public class AddPhoneActivity extends AppCompatActivity {
+
+ private EditText manufacturerInput;
+ private EditText modelInput;
+ private EditText androidVersionInput;
+ private EditText websiteInput;
+ private Button saveButton;
+ private Button cancelButton;
+ private Button websiteButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_add_phone);
+
+ manufacturerInput = findViewById(R.id.editManufacturer);
+ modelInput = findViewById(R.id.editModel);
+ androidVersionInput = findViewById(R.id.editAndroidVersion);
+ websiteInput = findViewById(R.id.editWebsite);
+ saveButton = findViewById(R.id.buttonSave);
+ cancelButton = findViewById(R.id.buttonCancel);
+ websiteButton = findViewById(R.id.buttonWebsite);
+
+ websiteButton.setOnClickListener(view -> {
+ String url = websiteInput.getText().toString();
+ if (!url.startsWith("http")) {
+ url = "http://" + url;
+ }
+ Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(browserIntent);
+ });
+
+ cancelButton.setOnClickListener(view -> finish());
+
+ saveButton.setOnClickListener(view -> {
+ Intent resultIntent = new Intent();
+ resultIntent.putExtra("manufacturer", manufacturerInput.getText().toString());
+ resultIntent.putExtra("model", modelInput.getText().toString());
+ resultIntent.putExtra("androidVersion", androidVersionInput.getText().toString());
+ resultIntent.putExtra("website", websiteInput.getText().toString());
+ setResult(RESULT_OK, resultIntent);
+ finish();
+ });
+ }
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/MainActivity.java b/lab2/app/src/main/java/com/example/lab2/MainActivity.java
new file mode 100644
index 0000000..eadca82
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/MainActivity.java
@@ -0,0 +1,48 @@
+package com.example.lab2;
+
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import androidx.activity.EdgeToEdge;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MainActivity extends AppCompatActivity {
+ private PhoneViewModel mPhoneViewModel;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ RecyclerView recyclerView = findViewById(R.id.recyclerView);
+ PhoneListAdapter adapter = new PhoneListAdapter(this);
+ recyclerView.setAdapter(adapter);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+
+ mPhoneViewModel = new ViewModelProvider(this).get(PhoneViewModel.class);
+ mPhoneViewModel.getAllPhones().observe(this, adapter::setPhones);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == R.id.clear_data) {
+ mPhoneViewModel.deleteAll();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/Phone.java b/lab2/app/src/main/java/com/example/lab2/Phone.java
new file mode 100644
index 0000000..8f22d7e
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/Phone.java
@@ -0,0 +1,25 @@
+package com.example.lab2;
+
+import androidx.annotation.NonNull;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "phones")
+public class Phone {
+ @PrimaryKey(autoGenerate = true)
+ public int id;
+
+ @NonNull
+ public String producer;
+ @NonNull
+ public String model;
+ public String version;
+ public String website;
+
+ public Phone(@NonNull String producer, @NonNull String model, String version, String website) {
+ this.producer = producer;
+ this.model = model;
+ this.version = version;
+ this.website = website;
+ }
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/PhoneDao.java b/lab2/app/src/main/java/com/example/lab2/PhoneDao.java
new file mode 100644
index 0000000..e3091bf
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/PhoneDao.java
@@ -0,0 +1,21 @@
+package com.example.lab2;
+
+import androidx.lifecycle.LiveData;
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+
+import java.util.List;
+
+@Dao
+public interface PhoneDao {
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insert(Phone phone);
+
+ @Query("DELETE FROM phones")
+ void deleteAll();
+
+ @Query("SELECT * FROM phones ORDER BY producer ASC")
+ LiveData> getAllPhones();
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/PhoneDatabase.java b/lab2/app/src/main/java/com/example/lab2/PhoneDatabase.java
new file mode 100644
index 0000000..a42e7d7
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/PhoneDatabase.java
@@ -0,0 +1,56 @@
+package com.example.lab2;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.sqlite.db.SupportSQLiteDatabase;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Database(entities = {Phone.class}, version = 1, exportSchema = false)
+public abstract class PhoneDatabase extends RoomDatabase {
+ public abstract PhoneDao phoneDao();
+
+ private static volatile PhoneDatabase INSTANCE;
+ private static final int NUMBER_OF_THREADS = 4;
+ static final ExecutorService databaseWriteExecutor =
+ Executors.newFixedThreadPool(NUMBER_OF_THREADS);
+
+ public static PhoneDatabase getDatabase(final Context context) {
+ if (INSTANCE == null) {
+ synchronized (PhoneDatabase.class) {
+ if (INSTANCE == null) {
+ context.deleteDatabase("phone_database");
+ Log.i("tag", "deleted db");
+ INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
+ PhoneDatabase.class, "phone_database")
+ .addCallback(sRoomDatabaseCallback)
+ .fallbackToDestructiveMigration()
+ .build();
+ }
+ }
+ }
+ return INSTANCE;
+ }
+
+ private static final RoomDatabase.Callback sRoomDatabaseCallback =
+ new RoomDatabase.Callback() {
+ @Override
+ public void onCreate(@NonNull SupportSQLiteDatabase db) {
+ super.onCreate(db);
+ databaseWriteExecutor.execute(() -> {
+ PhoneDao dao = INSTANCE.phoneDao();
+ dao.deleteAll();
+ dao.insert(new Phone("Google", "Pixel 4", "11", "https://google.com"));
+ dao.insert(new Phone("Samsung", "Galaxy S21", "12", "https://samsung.com"));
+ });
+ Log.i("", "remake");
+ }
+ };
+}
+
diff --git a/lab2/app/src/main/java/com/example/lab2/PhoneListAdapter.java b/lab2/app/src/main/java/com/example/lab2/PhoneListAdapter.java
new file mode 100644
index 0000000..4da4ab8
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/PhoneListAdapter.java
@@ -0,0 +1,56 @@
+package com.example.lab2;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PhoneListAdapter extends RecyclerView.Adapter {
+ private List mPhones = new ArrayList<>();
+ private final LayoutInflater mInflater;
+
+ public PhoneListAdapter(Context context) {
+ mInflater = LayoutInflater.from(context);
+ }
+
+ static class PhoneViewHolder extends RecyclerView.ViewHolder {
+ private final TextView phoneItemView;
+
+ public PhoneViewHolder(View itemView) {
+ super(itemView);
+ phoneItemView = itemView.findViewById(R.id.textView);
+ }
+
+ public void bind(String text) {
+ phoneItemView.setText(text);
+ }
+ }
+
+ @Override
+ public PhoneViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View itemView = mInflater.inflate(R.layout.phone_list_item, parent, false);
+ return new PhoneViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(PhoneViewHolder holder, int position) {
+ Phone current = mPhones.get(position);
+ holder.bind(current.producer + " " + current.model);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPhones.size();
+ }
+
+ public void setPhones(List phones) {
+ mPhones = phones;
+ notifyDataSetChanged();
+ }
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/PhoneRepository.java b/lab2/app/src/main/java/com/example/lab2/PhoneRepository.java
new file mode 100644
index 0000000..cb58401
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/PhoneRepository.java
@@ -0,0 +1,26 @@
+package com.example.lab2;
+
+import android.app.Application;
+
+import androidx.lifecycle.LiveData;
+
+import java.util.List;
+
+public class PhoneRepository {
+ private final PhoneDao mPhoneDao;
+ private final LiveData> mAllPhones;
+
+ public PhoneRepository(Application application) {
+ PhoneDatabase db = PhoneDatabase.getDatabase(application);
+ mPhoneDao = db.phoneDao();
+ mAllPhones = mPhoneDao.getAllPhones();
+ }
+
+ public LiveData> getAllPhones() {
+ return mAllPhones;
+ }
+
+ public void deleteAll() {
+ PhoneDatabase.databaseWriteExecutor.execute(mPhoneDao::deleteAll);
+ }
+}
diff --git a/lab2/app/src/main/java/com/example/lab2/PhoneViewModel.java b/lab2/app/src/main/java/com/example/lab2/PhoneViewModel.java
new file mode 100644
index 0000000..982b9f2
--- /dev/null
+++ b/lab2/app/src/main/java/com/example/lab2/PhoneViewModel.java
@@ -0,0 +1,28 @@
+package com.example.lab2;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.List;
+
+public class PhoneViewModel extends AndroidViewModel {
+ private final PhoneRepository mRepository;
+ private final LiveData> mAllPhones;
+
+ public PhoneViewModel(@NonNull Application application) {
+ super(application);
+ mRepository = new PhoneRepository(application);
+ mAllPhones = mRepository.getAllPhones();
+ }
+
+ public LiveData> getAllPhones() {
+ return mAllPhones;
+ }
+
+ public void deleteAll() {
+ mRepository.deleteAll();
+ }
+}
diff --git a/lab2/app/src/main/res/drawable/ic_launcher_background.xml b/lab2/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lab2/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab2/app/src/main/res/drawable/ic_launcher_foreground.xml b/lab2/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lab2/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/layout/activity_add_phone.xml b/lab2/app/src/main/res/layout/activity_add_phone.xml
new file mode 100644
index 0000000..1be30f5
--- /dev/null
+++ b/lab2/app/src/main/res/layout/activity_add_phone.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab2/app/src/main/res/layout/activity_main.xml b/lab2/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..618c153
--- /dev/null
+++ b/lab2/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/layout/phone_list_item.xml b/lab2/app/src/main/res/layout/phone_list_item.xml
new file mode 100644
index 0000000..26890f1
--- /dev/null
+++ b/lab2/app/src/main/res/layout/phone_list_item.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/lab2/app/src/main/res/menu/main_menu.xml b/lab2/app/src/main/res/menu/main_menu.xml
new file mode 100644
index 0000000..24f6059
--- /dev/null
+++ b/lab2/app/src/main/res/menu/main_menu.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/lab2/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/lab2/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab2/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/lab2/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab2/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/lab2/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lab2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lab2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lab2/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/lab2/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lab2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lab2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/lab2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lab2/app/src/main/res/values-night/themes.xml b/lab2/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..c5bbf13
--- /dev/null
+++ b/lab2/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/values/colors.xml b/lab2/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..c8524cd
--- /dev/null
+++ b/lab2/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/values/strings.xml b/lab2/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..d884592
--- /dev/null
+++ b/lab2/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ lab2
+ Wyczyść dane
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/values/themes.xml b/lab2/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..cb07ca7
--- /dev/null
+++ b/lab2/app/src/main/res/values/themes.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/xml/backup_rules.xml b/lab2/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/lab2/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/main/res/xml/data_extraction_rules.xml b/lab2/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/lab2/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab2/app/src/test/java/com/example/lab2/ExampleUnitTest.java b/lab2/app/src/test/java/com/example/lab2/ExampleUnitTest.java
new file mode 100644
index 0000000..082bf81
--- /dev/null
+++ b/lab2/app/src/test/java/com/example/lab2/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.lab2;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/lab2/build.gradle.kts b/lab2/build.gradle.kts
new file mode 100644
index 0000000..b4457db
--- /dev/null
+++ b/lab2/build.gradle.kts
@@ -0,0 +1,3 @@
+plugins {
+ alias(libs.plugins.android.application) apply false
+}
\ No newline at end of file
diff --git a/lab2/gradle.properties b/lab2/gradle.properties
new file mode 100644
index 0000000..4387edc
--- /dev/null
+++ b/lab2/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/lab2/gradle/libs.versions.toml b/lab2/gradle/libs.versions.toml
new file mode 100644
index 0000000..12a2082
--- /dev/null
+++ b/lab2/gradle/libs.versions.toml
@@ -0,0 +1,21 @@
+[versions]
+agp = "8.10.1"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+appcompat = "1.7.1"
+material = "1.12.0"
+activity = "1.10.1"
+constraintlayout = "2.2.1"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version = "8.4.0" }
diff --git a/lab2/gradle/wrapper/gradle-wrapper.jar b/lab2/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/lab2/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lab2/gradle/wrapper/gradle-wrapper.properties b/lab2/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..31fbe70
--- /dev/null
+++ b/lab2/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jun 10 21:13:26 CEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/lab2/gradlew b/lab2/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/lab2/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/lab2/gradlew.bat b/lab2/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/lab2/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lab2/settings.gradle.kts b/lab2/settings.gradle.kts
new file mode 100644
index 0000000..cc510c3
--- /dev/null
+++ b/lab2/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "lab2"
+include(":app")
+
\ No newline at end of file
diff --git a/lab3/.gitignore b/lab3/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/lab3/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/lab3/app/.gitignore b/lab3/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lab3/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lab3/app/build.gradle.kts b/lab3/app/build.gradle.kts
new file mode 100644
index 0000000..1ef3d87
--- /dev/null
+++ b/lab3/app/build.gradle.kts
@@ -0,0 +1,43 @@
+plugins {
+ alias(libs.plugins.android.application)
+}
+
+android {
+ namespace = "com.example.lab3"
+ compileSdk = 35
+
+ defaultConfig {
+ applicationId = "com.example.lab3"
+ minSdk = 27
+ targetSdk = 35
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
+
+dependencies {
+
+ implementation(libs.appcompat)
+ implementation(libs.material)
+ implementation(libs.activity)
+ implementation(libs.constraintlayout)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.ext.junit)
+ androidTestImplementation(libs.espresso.core)
+}
\ No newline at end of file
diff --git a/lab3/app/proguard-rules.pro b/lab3/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lab3/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/lab3/app/src/androidTest/java/com/example/lab3/ExampleInstrumentedTest.java b/lab3/app/src/androidTest/java/com/example/lab3/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..f9f8800
--- /dev/null
+++ b/lab3/app/src/androidTest/java/com/example/lab3/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.lab3;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.lab3", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/lab3/app/src/main/AndroidManifest.xml b/lab3/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e274777
--- /dev/null
+++ b/lab3/app/src/main/AndroidManifest.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/java/com/example/lab3/DownloadService.java b/lab3/app/src/main/java/com/example/lab3/DownloadService.java
new file mode 100644
index 0000000..58cf12e
--- /dev/null
+++ b/lab3/app/src/main/java/com/example/lab3/DownloadService.java
@@ -0,0 +1,160 @@
+package com.example.lab3;
+
+import android.app.*;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.core.app.NotificationCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import java.io.*;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+
+public class DownloadService extends IntentService {
+ private static final String TAG = "DownloadService";
+
+ private static final String ACTION_DOWNLOAD = "com.example.lab3.action.download_file";
+ private static final String URL_KEY = "url";
+
+ public static final String BROADCAST_PROGRESS = "com.example.lab3.broadcast.download_progress";
+ public static final String PROGRESS_KEY = "progressInfo";
+
+ private static final int NOTIFICATION_ID = 1;
+ private static final String CHANNEL_ID = "download_channel";
+ private static final int BUFFER_SIZE = 4096;
+
+ private NotificationManager notificationManager;
+ private ProgressInfo progressInfo;
+
+ public DownloadService() {
+ super("DownloadService");
+ }
+
+ public static void startDownload(Context context, String url) {
+ Intent intent = new Intent(context, DownloadService.class);
+ intent.setAction(ACTION_DOWNLOAD);
+ intent.putExtra(URL_KEY, url);
+ context.startService(intent);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (intent == null) return;
+
+ if (ACTION_DOWNLOAD.equals(intent.getAction())) {
+ String url = intent.getStringExtra(URL_KEY);
+ if (url != null) {
+ initService();
+ startForeground(NOTIFICATION_ID, buildNotification());
+ downloadFile(url);
+ }
+ }
+ }
+
+ private void initService() {
+ progressInfo = new ProgressInfo();
+ notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ createNotificationChannel();
+ }
+
+ private void createNotificationChannel() {
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ getString(R.string.app_name),
+ NotificationManager.IMPORTANCE_LOW
+ );
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ private Notification buildNotification() {
+ Intent intent = new Intent(this, MainActivity.class);
+ PendingIntent pendingIntent = TaskStackBuilder.create(this)
+ .addNextIntentWithParentStack(intent)
+ .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
+ .setContentTitle(getString(R.string.app_name))
+ .setSmallIcon(android.R.drawable.ic_menu_save)
+ .setContentIntent(pendingIntent)
+ .setOngoing(true)
+ .setChannelId(CHANNEL_ID);
+
+ if (progressInfo.fileSize > 0) {
+ int progress = (int) (progressInfo.downloadedBytes * 100 / progressInfo.fileSize);
+ builder.setProgress(100, progress, false)
+ .setContentText(progress + "%");
+ } else {
+ builder.setProgress(0, 0, true)
+ .setContentText(getString(R.string.powiadomienie_pobieranie));
+ }
+
+ return builder.build();
+ }
+
+ private void downloadFile(String urlString) {
+ HttpsURLConnection connection = null;
+ DataInputStream input = null;
+ FileOutputStream output = null;
+
+ try {
+ URL url = new URL(urlString);
+ File outputFile = new File(getExternalFilesDir(null), new File(url.getFile()).getName());
+
+ if (outputFile.exists()) outputFile.delete();
+
+ connection = (HttpsURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.connect();
+
+ progressInfo.fileSize = connection.getContentLength();
+
+ input = new DataInputStream(connection.getInputStream());
+ output = new FileOutputStream(outputFile);
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bytesRead;
+
+ while ((bytesRead = input.read(buffer)) != -1) {
+ output.write(buffer, 0, bytesRead);
+ progressInfo.downloadedBytes += bytesRead;
+
+ updateNotification();
+ broadcastProgress();
+ Log.d(TAG, "Pobrano " + progressInfo.downloadedBytes + " z " + progressInfo.fileSize);
+ }
+
+ progressInfo.status = ProgressInfo.STATUS_COMPLETED;
+ Log.d(TAG, "Pobrano plik: " + outputFile.getPath());
+
+ } catch (Exception e) {
+ progressInfo.status = ProgressInfo.STATUS_ERROR;
+ Log.e(TAG, "Błąd podczas pobierania pliku", e);
+ } finally {
+ broadcastProgress();
+ closeQuietly(input);
+ closeQuietly(output);
+ if (connection != null) connection.disconnect();
+ }
+ }
+
+ private void updateNotification() {
+ notificationManager.notify(NOTIFICATION_ID, buildNotification());
+ }
+
+ private void broadcastProgress() {
+ Intent intent = new Intent(BROADCAST_PROGRESS);
+ intent.putExtra(PROGRESS_KEY, progressInfo);
+ LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+ }
+
+ private void closeQuietly(Closeable stream) {
+ try {
+ if (stream != null) stream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Błąd zamykania strumienia", e);
+ }
+ }
+}
diff --git a/lab3/app/src/main/java/com/example/lab3/MainActivity.java b/lab3/app/src/main/java/com/example/lab3/MainActivity.java
new file mode 100644
index 0000000..4ac8b9d
--- /dev/null
+++ b/lab3/app/src/main/java/com/example/lab3/MainActivity.java
@@ -0,0 +1,205 @@
+package com.example.lab3;
+
+import android.Manifest;
+import android.content.*;
+import android.content.pm.PackageManager;
+import android.os.*;
+import android.util.Log;
+import android.widget.*;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String TAG = "MainActivity";
+ private static final int REQUEST_WRITE_PERMISSION = 1;
+
+ private EditText etAddress;
+ private TextView tvFileSizeValue, tvFileTypeValue, tvDownloadProgressValue;
+ private ProgressBar pbDownload;
+
+ private FileInfo fileInfo = new FileInfo();
+ private ProgressInfo progressInfo = new ProgressInfo();
+
+ private final BroadcastReceiver progressReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ progressInfo = intent.getParcelableExtra(DownloadService.PROGRESS_KEY);
+ updateProgress();
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ initUI();
+ restoreState(savedInstanceState);
+ }
+
+ private void initUI() {
+ etAddress = findViewById(R.id.etAddress);
+ tvFileSizeValue = findViewById(R.id.tvFileSizeValue);
+ tvFileTypeValue = findViewById(R.id.tvFileTypeValue);
+ tvDownloadProgressValue = findViewById(R.id.tvDownloadProgressValue);
+ pbDownload = findViewById(R.id.pbDownload);
+
+ findViewById(R.id.btnDownloadInfo).setOnClickListener(v -> fetchFileInfo());
+ findViewById(R.id.btnDownloadFile).setOnClickListener(v -> tryDownload());
+ }
+
+ private void fetchFileInfo() {
+ String url = etAddress.getText().toString().trim();
+ if (url.isEmpty()) {
+ showToast(R.string.podaj_url);
+ } else {
+ new FileInfoTask().execute(url);
+ }
+ }
+
+ private void tryDownload() {
+ String url = etAddress.getText().toString().trim();
+ if (url.isEmpty()) {
+ showToast(R.string.podaj_url);
+ return;
+ }
+
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ == PackageManager.PERMISSION_GRANTED) {
+ startDownload(url);
+ } else {
+ requestStoragePermission();
+ }
+ }
+
+ private void requestStoragePermission() {
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ showToast(R.string.dodaj_uprawnienia);
+ }
+
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ REQUEST_WRITE_PERMISSION);
+ }
+
+ private void startDownload(String url) {
+ DownloadService.startDownload(this, url);
+ showToast(R.string.pobieranie_niewiadomo);
+ }
+
+ private void showToast(int resId) {
+ Toast.makeText(this, getText(resId), Toast.LENGTH_SHORT).show();
+ }
+
+ private void updateProgress() {
+ if (progressInfo == null) return;
+
+ if (progressInfo.fileSize > 0) {
+ int percent = (int) (progressInfo.downloadedBytes * 100 / progressInfo.fileSize);
+ pbDownload.setIndeterminate(false);
+ pbDownload.setProgress(percent);
+ tvDownloadProgressValue.setText(percent + "%");
+ } else {
+ pbDownload.setIndeterminate(true);
+ tvDownloadProgressValue.setText(R.string.pobieranie_niewiadomo);
+ }
+
+ switch (progressInfo.status) {
+ case ProgressInfo.STATUS_COMPLETED:
+ tvDownloadProgressValue.setText(R.string.pobrano_plik);
+ break;
+ case ProgressInfo.STATUS_ERROR:
+ tvDownloadProgressValue.setText(R.string.blad_pobierania);
+ break;
+ }
+ }
+
+ private void updateFileInfo() {
+ tvFileSizeValue.setText(String.valueOf(Math.max(fileInfo.contentLength, 0)));
+ tvFileTypeValue.setText(fileInfo.contentType != null ? fileInfo.contentType : "");
+ }
+
+ private void restoreState(Bundle state) {
+ if (state == null) return;
+
+ etAddress.setText(state.getString("url", ""));
+ fileInfo.contentLength = state.getInt("contentLength", 0);
+ fileInfo.contentType = state.getString("contentType", "");
+ progressInfo = state.getParcelable("progressInfo");
+
+ updateFileInfo();
+ updateProgress();
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putString("url", etAddress.getText().toString());
+ outState.putInt("contentLength", fileInfo.contentLength);
+ outState.putString("contentType", fileInfo.contentType);
+ outState.putParcelable("progressInfo", progressInfo);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ LocalBroadcastManager.getInstance(this).registerReceiver(
+ progressReceiver, new IntentFilter(DownloadService.BROADCAST_PROGRESS));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(progressReceiver);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] results) {
+ super.onRequestPermissionsResult(requestCode, permissions, results);
+ if (requestCode == REQUEST_WRITE_PERMISSION &&
+ results.length > 0 &&
+ results[0] == PackageManager.PERMISSION_GRANTED) {
+ startDownload(etAddress.getText().toString());
+ } else {
+ showToast(R.string.dodaj_uprawnienia);
+ }
+ }
+
+ private static class FileInfo {
+ int contentLength;
+ String contentType;
+ }
+
+ private class FileInfoTask extends AsyncTask {
+ @Override
+ protected FileInfo doInBackground(String... urls) {
+ FileInfo info = new FileInfo();
+ try {
+ HttpURLConnection conn = (HttpURLConnection) new URL(urls[0]).openConnection();
+ conn.setRequestMethod("GET");
+ conn.connect();
+ info.contentLength = conn.getContentLength();
+ info.contentType = conn.getContentType();
+ conn.disconnect();
+ } catch (Exception e) {
+ Log.e(TAG, "Błąd pobierania informacji o pliku", e);
+ info.contentLength = -1;
+ info.contentType = "err";
+ }
+ return info;
+ }
+
+ @Override
+ protected void onPostExecute(FileInfo result) {
+ fileInfo = result;
+ updateFileInfo();
+ }
+ }
+}
diff --git a/lab3/app/src/main/java/com/example/lab3/ProgressInfo.java b/lab3/app/src/main/java/com/example/lab3/ProgressInfo.java
new file mode 100644
index 0000000..e3a6837
--- /dev/null
+++ b/lab3/app/src/main/java/com/example/lab3/ProgressInfo.java
@@ -0,0 +1,47 @@
+package com.example.lab3;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class ProgressInfo implements Parcelable {
+
+ public static final int STATUS_IN_PROGRESS = 0;
+ public static final int STATUS_COMPLETED = 1;
+ public static final int STATUS_ERROR = -1;
+
+ public long downloadedBytes = 0;
+ public int fileSize = 0;
+ public int status = STATUS_IN_PROGRESS;
+
+ public ProgressInfo() {}
+
+ protected ProgressInfo(Parcel in) {
+ downloadedBytes = in.readLong();
+ fileSize = in.readInt();
+ status = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(downloadedBytes);
+ dest.writeInt(fileSize);
+ dest.writeInt(status);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ProgressInfo createFromParcel(Parcel in) {
+ return new ProgressInfo(in);
+ }
+
+ @Override
+ public ProgressInfo[] newArray(int size) {
+ return new ProgressInfo[size];
+ }
+ };
+}
diff --git a/lab3/app/src/main/res/drawable/ic_launcher_background.xml b/lab3/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lab3/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab3/app/src/main/res/drawable/ic_launcher_foreground.xml b/lab3/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lab3/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/layout/activity_main.xml b/lab3/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..2135309
--- /dev/null
+++ b/lab3/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab3/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/lab3/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab3/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/lab3/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab3/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/lab3/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lab3/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lab3/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lab3/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/lab3/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lab3/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lab3/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/lab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lab3/app/src/main/res/values-night/themes.xml b/lab3/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..9c4962b
--- /dev/null
+++ b/lab3/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/values/colors.xml b/lab3/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..c8524cd
--- /dev/null
+++ b/lab3/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/values/strings.xml b/lab3/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..2eb7274
--- /dev/null
+++ b/lab3/app/src/main/res/values/strings.xml
@@ -0,0 +1,18 @@
+
+ lab3
+ Adres:
+ https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.36.tar.xz
+ POBIERZ INFORMACJE
+ Rozmiar pliku:
+ 0
+ Typ pliku:
+ -
+ POBIERZ PLIK
+ Pobrano bajtów:
+ Pobieranie...
+ Podaj URL
+ Pobieranie pliku...
+ Pobrano plik!
+ Błąd pobierania pliku!
+ Proszę dodać uprawnienia aplikacji.
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/values/themes.xml b/lab3/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..33d51d1
--- /dev/null
+++ b/lab3/app/src/main/res/values/themes.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/xml/backup_rules.xml b/lab3/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/lab3/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/main/res/xml/data_extraction_rules.xml b/lab3/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/lab3/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab3/app/src/test/java/com/example/lab3/ExampleUnitTest.java b/lab3/app/src/test/java/com/example/lab3/ExampleUnitTest.java
new file mode 100644
index 0000000..77dbbcd
--- /dev/null
+++ b/lab3/app/src/test/java/com/example/lab3/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.lab3;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/lab3/build.gradle.kts b/lab3/build.gradle.kts
new file mode 100644
index 0000000..3756278
--- /dev/null
+++ b/lab3/build.gradle.kts
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+}
\ No newline at end of file
diff --git a/lab3/gradle.properties b/lab3/gradle.properties
new file mode 100644
index 0000000..4387edc
--- /dev/null
+++ b/lab3/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/lab3/gradle/libs.versions.toml b/lab3/gradle/libs.versions.toml
new file mode 100644
index 0000000..434a764
--- /dev/null
+++ b/lab3/gradle/libs.versions.toml
@@ -0,0 +1,22 @@
+[versions]
+agp = "8.10.1"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+appcompat = "1.7.1"
+material = "1.12.0"
+activity = "1.10.1"
+constraintlayout = "2.2.1"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+
diff --git a/lab3/gradle/wrapper/gradle-wrapper.jar b/lab3/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/lab3/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lab3/gradle/wrapper/gradle-wrapper.properties b/lab3/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a9d71c7
--- /dev/null
+++ b/lab3/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jun 10 22:37:59 CEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/lab3/gradlew b/lab3/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/lab3/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/lab3/gradlew.bat b/lab3/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/lab3/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lab3/settings.gradle.kts b/lab3/settings.gradle.kts
new file mode 100644
index 0000000..09dac4d
--- /dev/null
+++ b/lab3/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "lab3"
+include(":app")
+
\ No newline at end of file
diff --git a/lab4/.gitignore b/lab4/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/lab4/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/lab4/app/.gitignore b/lab4/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/lab4/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lab4/app/build.gradle.kts b/lab4/app/build.gradle.kts
new file mode 100644
index 0000000..b58a94e
--- /dev/null
+++ b/lab4/app/build.gradle.kts
@@ -0,0 +1,43 @@
+plugins {
+ alias(libs.plugins.android.application)
+}
+
+android {
+ namespace = "com.example.lab4"
+ compileSdk = 35
+
+ defaultConfig {
+ applicationId = "com.example.lab4"
+ minSdk = 27
+ targetSdk = 35
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
+
+dependencies {
+
+ implementation(libs.appcompat)
+ implementation(libs.material)
+ implementation(libs.activity)
+ implementation(libs.constraintlayout)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.ext.junit)
+ androidTestImplementation(libs.espresso.core)
+}
\ No newline at end of file
diff --git a/lab4/app/proguard-rules.pro b/lab4/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/lab4/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/lab4/app/src/androidTest/java/com/example/lab4/ExampleInstrumentedTest.java b/lab4/app/src/androidTest/java/com/example/lab4/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..be72a82
--- /dev/null
+++ b/lab4/app/src/androidTest/java/com/example/lab4/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.lab4;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.lab4", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/lab4/app/src/main/AndroidManifest.xml b/lab4/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3954aed
--- /dev/null
+++ b/lab4/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/java/com/example/lab4/DrawingView.java b/lab4/app/src/main/java/com/example/lab4/DrawingView.java
new file mode 100644
index 0000000..43f5835
--- /dev/null
+++ b/lab4/app/src/main/java/com/example/lab4/DrawingView.java
@@ -0,0 +1,115 @@
+package com.example.lab4;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class DrawingView extends View {
+
+ private Bitmap mBitmap;
+ private Canvas mBitmapCanvas;
+ private Paint mPaintLine;
+ private Paint mPaintCircle;
+
+ private Path mPath;
+ private float mStartX, mStartY;
+
+ private int currentColor = 0xFFFF0000;
+
+ private final List strokeEndpoints = new ArrayList<>();
+
+ public DrawingView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintLine.setStyle(Paint.Style.STROKE);
+ mPaintLine.setStrokeWidth(5);
+
+ mPaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintCircle.setStyle(Paint.Style.FILL);
+
+ mPath = new Path();
+ }
+
+ public void setCurrentColor(int color) {
+ currentColor = color;
+ }
+
+ public void clearCanvas() {
+ if (mBitmap != null) {
+ strokeEndpoints.clear();
+ mBitmap.eraseColor(0xFFFFFFFF);
+ mPath.reset();
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ if (mBitmap != null) mBitmap.recycle();
+ mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ mBitmap.eraseColor(0xFFFFFFFF); // biało
+ mBitmapCanvas = new Canvas(mBitmap);
+ super.onSizeChanged(w, h, oldw, oldh);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ float x = event.getX();
+ float y = event.getY();
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mPath = new Path();
+ mPath.moveTo(x, y);
+ mStartX = x;
+ mStartY = y;
+ invalidate();
+ return true;
+
+ case MotionEvent.ACTION_MOVE:
+ mPath.lineTo(x, y);
+ invalidate();
+ return true;
+
+ case MotionEvent.ACTION_UP:
+ mPaintLine.setColor(currentColor);
+ mBitmapCanvas.drawPath(mPath, mPaintLine);
+
+ strokeEndpoints.add(new float[]{mStartX, mStartY, x, y, currentColor});
+ mPath.reset();
+ invalidate();
+ return true;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0, 0, null);
+ }
+
+ if (!mPath.isEmpty()) {
+ mPaintLine.setColor(currentColor);
+ canvas.drawPath(mPath, mPaintLine);
+ }
+
+ for (float[] data : strokeEndpoints) {
+ mPaintCircle.setColor((int) data[4]);
+ canvas.drawCircle(data[0], data[1], 15, mPaintCircle);
+ canvas.drawCircle(data[2], data[3], 15, mPaintCircle);
+ }
+ }
+}
diff --git a/lab4/app/src/main/java/com/example/lab4/MainActivity.java b/lab4/app/src/main/java/com/example/lab4/MainActivity.java
new file mode 100644
index 0000000..1caaab5
--- /dev/null
+++ b/lab4/app/src/main/java/com/example/lab4/MainActivity.java
@@ -0,0 +1,28 @@
+package com.example.lab4;
+
+import android.os.Bundle;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class MainActivity extends AppCompatActivity {
+
+ private DrawingView drawingView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ drawingView = findViewById(R.id.powierzchnia_rysunku);
+
+ findViewById(R.id.btn_red).setOnClickListener(v ->
+ drawingView.setCurrentColor(0xFFFF0000));
+ findViewById(R.id.btn_orange).setOnClickListener(v ->
+ drawingView.setCurrentColor(0xFFFFA500));
+ findViewById(R.id.btn_blue).setOnClickListener(v ->
+ drawingView.setCurrentColor(0xFF0000FF));
+ findViewById(R.id.btn_green).setOnClickListener(v ->
+ drawingView.setCurrentColor(0xFF008000));
+ findViewById(R.id.btn_clear).setOnClickListener(v ->
+ drawingView.clearCanvas());
+ }
+}
diff --git a/lab4/app/src/main/res/drawable/ic_launcher_background.xml b/lab4/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/lab4/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab4/app/src/main/res/drawable/ic_launcher_foreground.xml b/lab4/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/lab4/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/layout/activity_main.xml b/lab4/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..16b6e8c
--- /dev/null
+++ b/lab4/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lab4/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/lab4/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab4/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/lab4/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/lab4/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/lab4/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lab4/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lab4/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lab4/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/lab4/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lab4/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lab4/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/lab4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lab4/app/src/main/res/values-night/themes.xml b/lab4/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..c03477c
--- /dev/null
+++ b/lab4/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/values/colors.xml b/lab4/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..c8524cd
--- /dev/null
+++ b/lab4/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/values/strings.xml b/lab4/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..28b6b31
--- /dev/null
+++ b/lab4/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ lab4
+ X
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/values/themes.xml b/lab4/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..d4c3f93
--- /dev/null
+++ b/lab4/app/src/main/res/values/themes.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/xml/backup_rules.xml b/lab4/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/lab4/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/main/res/xml/data_extraction_rules.xml b/lab4/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/lab4/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab4/app/src/test/java/com/example/lab4/ExampleUnitTest.java b/lab4/app/src/test/java/com/example/lab4/ExampleUnitTest.java
new file mode 100644
index 0000000..ff3d735
--- /dev/null
+++ b/lab4/app/src/test/java/com/example/lab4/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.lab4;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/lab4/build.gradle.kts b/lab4/build.gradle.kts
new file mode 100644
index 0000000..3756278
--- /dev/null
+++ b/lab4/build.gradle.kts
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+}
\ No newline at end of file
diff --git a/lab4/gradle.properties b/lab4/gradle.properties
new file mode 100644
index 0000000..4387edc
--- /dev/null
+++ b/lab4/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/lab4/gradle/libs.versions.toml b/lab4/gradle/libs.versions.toml
new file mode 100644
index 0000000..434a764
--- /dev/null
+++ b/lab4/gradle/libs.versions.toml
@@ -0,0 +1,22 @@
+[versions]
+agp = "8.10.1"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+appcompat = "1.7.1"
+material = "1.12.0"
+activity = "1.10.1"
+constraintlayout = "2.2.1"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+
diff --git a/lab4/gradle/wrapper/gradle-wrapper.jar b/lab4/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/lab4/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lab4/gradle/wrapper/gradle-wrapper.properties b/lab4/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..418649e
--- /dev/null
+++ b/lab4/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jun 10 20:46:05 CEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/lab4/gradlew b/lab4/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/lab4/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/lab4/gradlew.bat b/lab4/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/lab4/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lab4/settings.gradle.kts b/lab4/settings.gradle.kts
new file mode 100644
index 0000000..b053ee6
--- /dev/null
+++ b/lab4/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "lab4"
+include(":app")
+
\ No newline at end of file