From e2c4112277efe46c62a1c114265881fe4070fab8 Mon Sep 17 00:00:00 2001 From: Lyla Fujiwara <3414789+ceruleanotter@users.noreply.github.com> Date: Thu, 17 Oct 2019 00:26:57 -0700 Subject: [PATCH 1/6] End of codelab 1 --- app/build.gradle | 12 +++ .../todoapp/statistics/StatisticsUtils.kt | 17 ++-- .../blueprints/todoapp/LiveDataTestUtil.kt | 62 +++++++++++++ .../todoapp/statistics/StatisticsUtilsTest.kt | 92 +++++++++++++++++++ .../todoapp/tasks/TasksViewModelTest.kt | 69 ++++++++++++++ 5 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 app/src/test/java/com/example/android/architecture/blueprints/todoapp/LiveDataTestUtil.kt create mode 100644 app/src/test/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtilsTest.kt create mode 100644 app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt diff --git a/app/build.gradle b/app/build.gradle index ba6af3761..10f901f90 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,11 @@ android { enabled = true enabledForTests = true } + + // Always show the result of every unit test when running via command line, even if it passes. + testOptions.unitTests { + includeAndroidResources = true + } } dependencies { @@ -54,6 +59,13 @@ dependencies { // Dependencies for local unit tests testImplementation "junit:junit:$junitVersion" + testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion" + testImplementation "androidx.arch.core:core-testing:$archTestingVersion" + testImplementation "org.robolectric:robolectric:$robolectricVersion" + + // AndroidX Test - JVM testing + testImplementation "androidx.test:core-ktx:$androidXTestCoreVersion" + testImplementation "androidx.test.ext:junit:$androidXTestExtKotlinRunnerVersion" // AndroidX Test - Instrumented testing androidTestImplementation "androidx.test.ext:junit:$androidXTestExtKotlinRunnerVersion" diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtils.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtils.kt index 968b8f144..c56edfb80 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtils.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtils.kt @@ -22,12 +22,17 @@ import com.example.android.architecture.blueprints.todoapp.data.Task * Function that does some trivial computation. Used to showcase unit tests. */ internal fun getActiveAndCompletedStats(tasks: List?): StatsResult { - val totalTasks = tasks!!.size - val numberOfActiveTasks = tasks.count { it.isActive } - return StatsResult( - activeTasksPercent = 100f * numberOfActiveTasks / tasks.size, - completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size - ) + + return if (tasks == null || tasks.isEmpty()) { + StatsResult(0f, 0f) + } else { + val totalTasks = tasks.size + val numberOfActiveTasks = tasks.count { it.isActive } + StatsResult( + activeTasksPercent = 100f * numberOfActiveTasks / tasks.size, + completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size + ) + } } data class StatsResult(val activeTasksPercent: Float, val completedTasksPercent: Float) diff --git a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/LiveDataTestUtil.kt b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/LiveDataTestUtil.kt new file mode 100644 index 000000000..33ab49f1d --- /dev/null +++ b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/LiveDataTestUtil.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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 + * + * http://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. + */ +package com.example.android.architecture.blueprints.todoapp + +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException + +/** + * Gets the value of a [LiveData] or waits for it to have one, with a timeout. + * + * Use this extension from host-side (JVM) tests. It's recommended to use it alongside + * `InstantTaskExecutorRule` or a similar mechanism to execute tasks synchronously. + */ +@VisibleForTesting(otherwise = VisibleForTesting.NONE) +fun LiveData.getOrAwaitValue( + time: Long = 2, + timeUnit: TimeUnit = TimeUnit.SECONDS, + afterObserve: () -> Unit = {} +): T { + var data: T? = null + val latch = CountDownLatch(1) + val observer = object : Observer { + override fun onChanged(o: T?) { + data = o + latch.countDown() + this@getOrAwaitValue.removeObserver(this) + } + } + this.observeForever(observer) + + try { + afterObserve.invoke() + + // Don't wait indefinitely if the LiveData is not set. + if (!latch.await(time, timeUnit)) { + throw TimeoutException("LiveData value was never set.") + } + + } finally { + this.removeObserver(observer) + } + + @Suppress("UNCHECKED_CAST") + return data as T +} diff --git a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtilsTest.kt b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtilsTest.kt new file mode 100644 index 000000000..90ef00a9c --- /dev/null +++ b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsUtilsTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +package com.example.android.architecture.blueprints.todoapp.statistics + +import com.example.android.architecture.blueprints.todoapp.data.Task +import org.hamcrest.core.Is.`is` +import org.junit.Assert.assertThat +import org.junit.Test + +/** + * Unit tests for [getActiveAndCompletedStats]. + */ +class StatisticsUtilsTest { + + @Test + fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() { + val tasks = listOf( + Task("title", "desc", isCompleted = false) + ) + // When the list of tasks is computed with an active task + val result = getActiveAndCompletedStats(tasks) + + // Then the percentages are 100 and 0 + assertThat(result.activeTasksPercent, `is`(100f)) + assertThat(result.completedTasksPercent, `is`(0f)) + } + + @Test + fun getActiveAndCompletedStats_noActive_returnsZeroHundred() { + val tasks = listOf( + Task("title", "desc", isCompleted = true) + ) + // When the list of tasks is computed with a completed task + val result = getActiveAndCompletedStats(tasks) + + // Then the percentages are 0 and 100 + assertThat(result.activeTasksPercent, `is`(0f)) + assertThat(result.completedTasksPercent, `is`(100f)) + } + + @Test + fun getActiveAndCompletedStats_both_returnsFortySixty() { + // Given 3 completed tasks and 2 active tasks + val tasks = listOf( + Task("title", "desc", isCompleted = true), + Task("title", "desc", isCompleted = true), + Task("title", "desc", isCompleted = true), + Task("title", "desc", isCompleted = false), + Task("title", "desc", isCompleted = false) + ) + // When the list of tasks is computed + val result = getActiveAndCompletedStats(tasks) + + // Then the result is 40-60 + assertThat(result.activeTasksPercent, `is`(40f)) + assertThat(result.completedTasksPercent, `is`(60f)) + } + + @Test + fun getActiveAndCompletedStats_error_returnsZeros() { + // When there's an error loading stats + val result = getActiveAndCompletedStats(null) + + // Both active and completed tasks are 0 + assertThat(result.activeTasksPercent, `is`(0f)) + assertThat(result.completedTasksPercent, `is`(0f)) + } + + @Test + fun getActiveAndCompletedStats_empty_returnsZeros() { + // When there are no tasks + val result = getActiveAndCompletedStats(emptyList()) + + // Both active and completed tasks are 0 + assertThat(result.activeTasksPercent, `is`(0f)) + assertThat(result.completedTasksPercent, `is`(0f)) + } +} diff --git a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt new file mode 100644 index 000000000..d3156296d --- /dev/null +++ b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +package com.example.android.architecture.blueprints.todoapp.tasks + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.example.android.architecture.blueprints.todoapp.getOrAwaitValue +import org.hamcrest.CoreMatchers.* +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(AndroidJUnit4::class) +class TasksViewModelTest { + + // Subject under test + private lateinit var tasksViewModel: TasksViewModel + + // Executes each task synchronously using Architecture Components. + @get:Rule + var instantExecutorRule = InstantTaskExecutorRule() + + @Before + fun setupViewModel() { + tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext()) + } + + + @Test + fun addNewTask_setsNewTaskEvent() { + // When adding a new task + tasksViewModel.addNewTask() + + // Then the new task event is triggered + val value = tasksViewModel.newTaskEvent.getOrAwaitValue() + + assertThat(value.getContentIfNotHandled(), not(nullValue())) + + + } + + @Test + fun setFilterAllTasks_tasksAddViewVisible() { + // When the filter type is ALL_TASKS + tasksViewModel.setFiltering(TasksFilterType.ALL_TASKS) + + // Then the "Add task" action is visible + assertThat(tasksViewModel.tasksAddViewVisible.getOrAwaitValue(), `is`(true)) + } + +} From 7f9704d4a5a4b6ccff9b938ef40e3fae0282a5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Alc=C3=A9rreca?= Date: Mon, 14 Jun 2021 13:01:45 +0000 Subject: [PATCH 2/6] Bumps versions and makes project compatible with AS 4.2.1 --- app/build.gradle | 3 +- build.gradle | 57 +++++++++++------------- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.properties | 6 +-- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 10f901f90..a265a6e3c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,7 +50,8 @@ dependencies { implementation "androidx.room:room-runtime:$roomVersion" kapt "androidx.room:room-compiler:$roomVersion" implementation "androidx.room:room-ktx:$roomVersion" - implementation "androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$archLifecycleVersion" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$archLifecycleVersion" kapt "androidx.lifecycle:lifecycle-compiler:$archLifecycleVersion" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$archLifecycleVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$archLifecycleVersion" diff --git a/build.gradle b/build.gradle index a477355e7..dfe1b541a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlinVersion = '1.3.31' - ext.navigationVersion = "2.1.0-alpha06" + ext.kotlinVersion = '1.5.10' + ext.navigationVersion = '2.3.5' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion" @@ -18,46 +18,41 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } -task clean(type: Delete) { - delete rootProject.buildDir -} - // Define versions in a single place ext { // Sdk and tools - // Support library and architecture components support minSdk 14 and above. - minSdkVersion = 14 - targetSdkVersion = 28 - compileSdkVersion = 28 + minSdkVersion = 21 + targetSdkVersion = 30 + compileSdkVersion = 30 // App dependencies androidXVersion = '1.0.0' - androidXTestCoreVersion = '1.2.0' - androidXTestExtKotlinRunnerVersion = '1.1.1' - androidXTestRulesVersion = '1.2.0-beta01' - androidXAnnotations = '1.0.1' + androidXTestCoreVersion = '1.3.0' + androidXTestExtKotlinRunnerVersion = '1.1.2' + androidXTestRulesVersion = '1.2.0' + androidXAnnotations = '1.2.0' androidXLegacySupport = '1.0.0' - appCompatVersion = '1.0.2' - archLifecycleVersion = '2.2.0-alpha01' - archTestingVersion = '2.0.0' + appCompatVersion = '1.3.0' + archLifecycleVersion = '2.3.1' + archTestingVersion = '2.1.0' cardVersion = '1.0.0' - coroutinesVersion = '1.2.1' + coroutinesVersion = '1.5.0' dexMakerVersion = '2.12.1' - espressoVersion = '3.2.0-beta01' - fragmentVersion = '1.1.0-alpha07' - fragmentKtxVersion = '1.1.0-rc01' + espressoVersion = '3.3.0' + fragmentVersion = '1.3.4' + fragmentKtxVersion = '1.3.4' hamcrestVersion = '1.3' - junitVersion = '4.12' - materialVersion = '1.0.0' - mockitoVersion = '2.8.9' - recyclerViewVersion = '1.0.0' - robolectricVersion = '4.3.1' - roomVersion = '2.1.0' + junitVersion = '4.13.1' + materialVersion = '1.3.0' + multiDexVersion = '2.0.1' + recyclerViewVersion = '1.2.0' + robolectricVersion = '4.5.1' + roomVersion = '2.3.0' rulesVersion = '1.0.1' timberVersion = '4.7.1' - truthVersion = '0.44' + truthVersion = '1.1.2' } diff --git a/gradle.properties b/gradle.properties index 94c4d55e0..acf164f6c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,3 @@ # org.gradle.parallel=true android.enableJetifier=true android.useAndroidX=true -android.enableUnitTestBinaryResources=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 464ed4166..f9e29c73b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Apr 04 11:20:54 PDT 2019 +#Mon Jun 14 12:47:31 UTC 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +zipStoreBase=GRADLE_USER_HOME From d9574e4f6c14e77bc36f4d88fd557e57dbb2ddc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Alc=C3=A9rreca?= Date: Wed, 1 Dec 2021 13:14:30 +0000 Subject: [PATCH 3/6] Bumps versions for Studio AFox (codelab 1) --- app/build.gradle | 5 +-- app/src/main/AndroidManifest.xml | 3 +- .../addedittask/AddEditTaskFragment.kt | 5 ++- .../todoapp/statistics/StatisticsFragment.kt | 3 +- .../todoapp/taskdetail/TaskDetailFragment.kt | 5 ++- .../blueprints/todoapp/tasks/TasksActivity.kt | 2 +- .../blueprints/todoapp/tasks/TasksFragment.kt | 6 ++-- .../todoapp/tasks/TasksViewModelTest.kt | 3 +- build.gradle | 33 +++++++++---------- gradle/wrapper/gradle-wrapper.properties | 2 +- 10 files changed, 30 insertions(+), 37 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a265a6e3c..e93a7cb74 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,15 +36,12 @@ dependencies { // App dependencies implementation "androidx.appcompat:appcompat:$appCompatVersion" - implementation "androidx.cardview:cardview:$cardVersion" + implementation "androidx.swiperefreshlayout:swiperefreshlayout:$swipeRefreshLayoutVersion" implementation "com.google.android.material:material:$materialVersion" implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion" implementation "androidx.annotation:annotation:$androidXAnnotations" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" implementation "com.jakewharton.timber:timber:$timberVersion" - implementation "androidx.legacy:legacy-support-v4:$androidXLegacySupport" - implementation "androidx.room:room-runtime:$roomVersion" - kapt "androidx.room:room-compiler:$roomVersion" // Architecture Components implementation "androidx.room:room-runtime:$roomVersion" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e85b438cf..36723a569 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,7 +28,8 @@ + android:theme="@style/AppTheme.OverlapSystemBar" + android:exported="true"> diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskFragment.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskFragment.kt index a6b99fd4f..881886173 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskFragment.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskFragment.kt @@ -45,7 +45,7 @@ class AddEditTaskFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { val root = inflater.inflate(R.layout.addtask_frag, container, false) viewDataBinding = AddtaskFragBinding.bind(root).apply { this.viewmodel = viewModel @@ -55,8 +55,7 @@ class AddEditTaskFragment : Fragment() { return viewDataBinding.root } - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setupSnackbar() setupNavigation() this.setupRefreshLayout(viewDataBinding.refreshLayout) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsFragment.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsFragment.kt index 80cdc8dda..05f5977cd 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsFragment.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsFragment.kt @@ -46,8 +46,7 @@ class StatisticsFragment : Fragment() { return viewDataBinding.root } - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewDataBinding.viewmodel = viewModel viewDataBinding.lifecycleOwner = this.viewLifecycleOwner this.setupRefreshLayout(viewDataBinding.refreshLayout) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailFragment.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailFragment.kt index 7581cbf1e..399436588 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailFragment.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailFragment.kt @@ -44,10 +44,9 @@ class TaskDetailFragment : Fragment() { private val viewModel by viewModels() - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setupFab() - view?.setupSnackbar(this, viewModel.snackbarText, Snackbar.LENGTH_SHORT) + view.setupSnackbar(this, viewModel.snackbarText, Snackbar.LENGTH_SHORT) setupNavigation() this.setupRefreshLayout(viewDataBinding.refreshLayout) } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksActivity.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksActivity.kt index 28013552e..46e259cdd 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksActivity.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksActivity.kt @@ -45,7 +45,7 @@ class TasksActivity : AppCompatActivity() { val navController: NavController = findNavController(R.id.nav_host_fragment) appBarConfiguration = AppBarConfiguration.Builder(R.id.tasks_fragment_dest, R.id.statistics_fragment_dest) - .setDrawerLayout(drawerLayout) + .setOpenableLayout(drawerLayout) .build() setupActionBarWithNavController(navController, appBarConfiguration) findViewById(R.id.nav_view) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt index 272fd3538..344b31f33 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt @@ -54,7 +54,7 @@ class TasksFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { viewDataBinding = TasksFragBinding.inflate(inflater, container, false).apply { viewmodel = viewModel } @@ -83,9 +83,7 @@ class TasksFragment : Fragment() { inflater.inflate(R.menu.tasks_fragment_menu, menu) } - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // Set the lifecycle owner to the lifecycle of the view viewDataBinding.lifecycleOwner = this.viewLifecycleOwner setupSnackbar() diff --git a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt index d3156296d..bc9e1ce19 100644 --- a/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt +++ b/app/src/test/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModelTest.kt @@ -26,8 +26,9 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.robolectric.annotation.Config - +@Config(sdk = [30]) // https://github.com/robolectric/robolectric/pull/6776 @RunWith(AndroidJUnit4::class) class TasksViewModelTest { diff --git a/build.gradle b/build.gradle index dfe1b541a..5ee3fda1c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlinVersion = '1.5.10' + ext.kotlinVersion = '1.5.31' ext.navigationVersion = '2.3.5' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.0.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion" @@ -26,33 +26,32 @@ allprojects { ext { // Sdk and tools minSdkVersion = 21 - targetSdkVersion = 30 - compileSdkVersion = 30 + targetSdkVersion = 31 + compileSdkVersion = 31 // App dependencies androidXVersion = '1.0.0' - androidXTestCoreVersion = '1.3.0' - androidXTestExtKotlinRunnerVersion = '1.1.2' + androidXTestCoreVersion = '1.4.0' + androidXTestExtKotlinRunnerVersion = '1.1.3' androidXTestRulesVersion = '1.2.0' - androidXAnnotations = '1.2.0' - androidXLegacySupport = '1.0.0' - appCompatVersion = '1.3.0' - archLifecycleVersion = '2.3.1' + androidXAnnotations = '1.3.0' + appCompatVersion = '1.4.0' + archLifecycleVersion = '2.4.0' archTestingVersion = '2.1.0' + coroutinesVersion = '1.5.2' cardVersion = '1.0.0' coroutinesVersion = '1.5.0' dexMakerVersion = '2.12.1' - espressoVersion = '3.3.0' - fragmentVersion = '1.3.4' - fragmentKtxVersion = '1.3.4' + espressoVersion = '3.4.0' + fragmentKtxVersion = '1.4.0' hamcrestVersion = '1.3' - junitVersion = '4.13.1' - materialVersion = '1.3.0' - multiDexVersion = '2.0.1' - recyclerViewVersion = '1.2.0' + junitVersion = '4.13.2' + materialVersion = '1.4.0' + recyclerViewVersion = '1.2.1' robolectricVersion = '4.5.1' roomVersion = '2.3.0' rulesVersion = '1.0.1' + swipeRefreshLayoutVersion = '1.1.0' timberVersion = '4.7.1' truthVersion = '1.1.2' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f9e29c73b..e228a385f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Jun 14 12:47:31 UTC 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 838e15bbd1694634e2f77edd3c513f61bb6a2ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Alc=C3=A9rreca?= Date: Wed, 1 Dec 2021 16:04:51 +0000 Subject: [PATCH 4/6] Use view binding in TasksFragment --- .../architecture/blueprints/todoapp/tasks/TasksFragment.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt index 344b31f33..0fd7e724e 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.kt @@ -129,10 +129,8 @@ class TasksFragment : Fragment() { } private fun setupFab() { - activity?.findViewById(R.id.add_task_fab)?.let { - it.setOnClickListener { - navigateToAddNewTask() - } + viewDataBinding.addTaskFab.setOnClickListener { + navigateToAddNewTask() } } From 640acf7b829a27a6f7dabef1e1ae3fcd9068db1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Alc=C3=A9rreca?= Date: Fri, 20 Jan 2023 18:21:40 +0100 Subject: [PATCH 5/6] Delete .circleci directory --- .circleci/config.yml | 92 -------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 7c071b76a..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,92 +0,0 @@ -version: 2 -config_android: - docker: - - image: circleci/android:api-28 - working_directory: ~/project - environment: - JAVA_TOOL_OPTIONS: "-Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" - GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2 -Djava.util.concurrent.ForkJoinPool.common.parallelism=2 -Dkotlin.incremental=false" - TERM: dumb -setup_ftl: -- run: - name: Authorize gcloud and set config defaults - command: | - echo $GCLOUD_SERVICE_KEY | base64 -di > ${HOME}/gcloud-service-key.json - sudo gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json - sudo gcloud --quiet config set project ${GOOGLE_PROJECT_ID} -jobs: - build_and_setup: - docker: - - image: circleci/android:api-28 - working_directory: ~/project - environment: - - JAVA_TOOL_OPTIONS: "-Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" - - GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2 -Djava.util.concurrent.ForkJoinPool.common.parallelism=2 -Dkotlin.incremental=false" - - TERM: dumb - steps: - - checkout - - run: - name: Build test and lint - command: | - ./gradlew assembleMockDebug assembleProdDebug assembleMockDebugAndroidTest testMockDebug testProdDebug lintMockDebug lintProdDebug - - run: - name: Save test results - command: | - mkdir -p ~/junit/ - find . -type f -regex "./.*/build/test-results/.*xml" -exec cp {} ~/junit/ \; - when: always - - store_test_results: - path: ~/junit - - store_artifacts: - path: ~/junit - destination: tests - - store_artifacts: - path: ./app/build/reports - destination: reports/ - - persist_to_workspace: - root: . - paths: - - ./app/build - run_ftl: - docker: - - image: circleci/android:api-28 - working_directory: ~/project - environment: - - JAVA_TOOL_OPTIONS: -Xmx1024m - - GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2 -Dkotlin.incremental=false - - TERM: dumb - steps: - - attach_workspace: - at: . - - run: - name: Authorize gcloud and set config defaults - command: | - echo $GCLOUD_SERVICE_KEY | base64 -di > ${HOME}/gcloud-service-key.json - sudo gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json - sudo gcloud --quiet config set project ${GOOGLE_PROJECT_ID} - - run: - name: Test with Firebase Test Lab - command: | - BUILD_DIR=build_${CIRCLE_BUILD_NUM} - sudo gcloud firebase test android run \ - --app app/build/outputs/apk/mock/debug/app-mock-debug.apk \ - --test app/build/outputs/apk/androidTest/mock/debug/app-mock-debug-androidTest.apk \ - --results-bucket cloud-test-${GOOGLE_PROJECT_ID}-testingcodelab \ - --results-dir=${BUILD_DIR} - - run: - name: Download results - command: | - BUILD_DIR=build_${CIRCLE_BUILD_NUM} - sudo pip install -U crcmod - mkdir firebase_test_results - sudo gsutil -m mv -r -U `sudo gsutil ls gs://cloud-test-${GOOGLE_PROJECT_ID}-testingcodelab/${BUILD_DIR} | tail -1` firebase_test_results/ | true - - store_artifacts: - path: firebase_test_results -workflows: - version: 2 - build_and_test: - jobs: - - build_and_setup - - run_ftl: - requires: - - build_and_setup From b9f92a4a27634a654153cb4bc0898f5e842ace05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Alc=C3=A9rreca?= Date: Tue, 10 Dec 2024 10:02:59 +0100 Subject: [PATCH 6/6] Update and rename blueprints.yaml to build_test.yaml --- .github/workflows/blueprints.yaml | 85 ------------------------------- .github/workflows/build_test.yaml | 61 ++++++++++++++++++++++ 2 files changed, 61 insertions(+), 85 deletions(-) delete mode 100644 .github/workflows/blueprints.yaml create mode 100644 .github/workflows/build_test.yaml diff --git a/.github/workflows/blueprints.yaml b/.github/workflows/blueprints.yaml deleted file mode 100644 index 5f2711b96..000000000 --- a/.github/workflows/blueprints.yaml +++ /dev/null @@ -1,85 +0,0 @@ -name: testingcodelabs - -on: - push: - branches: - - starter_code - - end_codelab_1 - - end_codelab_2 - - end_codelab_3 - pull_request: - branches: - - starter_code - - end_codelab_1 - - end_codelab_2 - - end_codelab_3 - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Copy CI gradle.properties - run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches/modules-* - ~/.gradle/caches/jars-* - ~/.gradle/caches/build-cache-* - key: gradle-${{ hashFiles('checksum.txt') }} - - - name: Build project - run: ./gradlew build test --stacktrace - - - name: Upload build reports - if: always() - uses: actions/upload-artifact@v2 - with: - name: build-reports - path: app/build/reports/ - - test: - needs: build - runs-on: macOS-latest # enables hardware acceleration in the virtual machine - timeout-minutes: 30 - strategy: - matrix: - api-level: [23, 29] - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Copy CI gradle.properties - run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - - name: Run instrumentation tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ matrix.api-level }} - arch: x86 - disable-animations: true - script: ./gradlew app:cC --stacktrace - - - name: Upload test reports - if: always() - uses: actions/upload-artifact@v2 - with: - name: test-reports - path: app/build/reports/ diff --git a/.github/workflows/build_test.yaml b/.github/workflows/build_test.yaml new file mode 100644 index 000000000..210fcd83a --- /dev/null +++ b/.github/workflows/build_test.yaml @@ -0,0 +1,61 @@ +name: testingcodelabs + +on: + push: + branches: + - starter_code + - end_codelab_1 + - end_codelab_2 + - end_codelab_3 + pull_request: + branches: + - starter_code + - end_codelab_1 + - end_codelab_2 + - end_codelab_3 + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + matrix: + api-level: [29] + + steps: + - uses: actions/checkout@v4 + + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + ls /dev/kvm + + - name: Set Up JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' # See 'Supported distributions' for available options + java-version: '17' + cache: 'gradle' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Run instrumentation tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + arch: x86 + disable-animations: true + script: ./gradlew connectedCheck --stacktrace + + - name: Upload test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-reports-${{ matrix.api-level }} + path: ./app/build/reports/androidTests