Skip to content

Commit e257f2c

Browse files
committed
Merge remote-tracking branch 'origin/main' into patch-2
2 parents 8b7f630 + 48041fc commit e257f2c

File tree

17 files changed

+246
-89
lines changed

17 files changed

+246
-89
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ plugins {
2929
android {
3030
defaultConfig {
3131
applicationId = "com.google.samples.apps.nowinandroid"
32-
versionCode = 5
33-
versionName = "0.0.5" // X.Y.Z; X = Major, Y = minor, Z = Patch level
32+
versionCode = 7
33+
versionName = "0.1.1" // X.Y.Z; X = Major, Y = minor, Z = Patch level
3434

3535
// Custom test runner to set up Hilt dependency graph
3636
testInstrumentationRunner = "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"

app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class NiaAppStateTest {
183183
@Composable
184184
private fun rememberTestNavController(): TestNavHostController {
185185
val context = LocalContext.current
186-
val navController = remember {
186+
return remember<TestNavHostController> {
187187
TestNavHostController(context).apply {
188188
navigatorProvider.addNavigator(ComposeNavigator())
189189
graph = createGraph(startDestination = "a") {
@@ -193,5 +193,4 @@ private fun rememberTestNavController(): TestNavHostController {
193193
}
194194
}
195195
}
196-
return navController
197196
}

benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,17 @@ fun MacrobenchmarkScope.forYouScrollFeedDownUp() {
8888
val feedList = device.findObject(By.res("forYou:feed"))
8989
device.flingElementDownUp(feedList)
9090
}
91+
92+
fun MacrobenchmarkScope.setAppTheme(isDark: Boolean) {
93+
when (isDark) {
94+
true -> device.findObject(By.text("Dark")).click()
95+
false -> device.findObject(By.text("Light")).click()
96+
}
97+
device.waitForIdle()
98+
device.findObject(By.text("OK")).click()
99+
100+
// Wait until the top app bar is visible on screen
101+
device.wait(Until.hasObject(By.res("niaTopAppBar")), 2_000)
102+
val topAppBar = device.findObject(By.res("niaTopAppBar"))
103+
topAppBar.wait(Until.hasObject(By.text("Now in Android")), 2_000)
104+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2023 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.samples.apps.nowinandroid.interests
18+
19+
import android.os.Build.VERSION_CODES
20+
import androidx.annotation.RequiresApi
21+
import androidx.benchmark.macro.CompilationMode
22+
import androidx.benchmark.macro.ExperimentalMetricApi
23+
import androidx.benchmark.macro.FrameTimingMetric
24+
import androidx.benchmark.macro.PowerCategory
25+
import androidx.benchmark.macro.PowerCategoryDisplayLevel
26+
import androidx.benchmark.macro.PowerMetric
27+
import androidx.benchmark.macro.StartupMode
28+
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
29+
import androidx.test.ext.junit.runners.AndroidJUnit4
30+
import androidx.test.uiautomator.By
31+
import com.google.samples.apps.nowinandroid.PACKAGE_NAME
32+
import com.google.samples.apps.nowinandroid.allowNotifications
33+
import com.google.samples.apps.nowinandroid.foryou.forYouScrollFeedDownUp
34+
import com.google.samples.apps.nowinandroid.foryou.forYouSelectTopics
35+
import com.google.samples.apps.nowinandroid.foryou.forYouWaitForContent
36+
import com.google.samples.apps.nowinandroid.foryou.setAppTheme
37+
import org.junit.Rule
38+
import org.junit.Test
39+
import org.junit.runner.RunWith
40+
41+
@OptIn(ExperimentalMetricApi::class)
42+
@RequiresApi(VERSION_CODES.Q)
43+
@RunWith(AndroidJUnit4::class)
44+
class ScrollTopicListPowerMetricsBenchmark {
45+
@get:Rule
46+
val benchmarkRule = MacrobenchmarkRule()
47+
48+
private val categories = PowerCategory.values()
49+
.associateWith { PowerCategoryDisplayLevel.TOTAL }
50+
51+
@Test
52+
fun benchmarkStateChangeCompilationLight() =
53+
benchmarkStateChangeWithTheme(CompilationMode.Partial(), false)
54+
55+
@Test
56+
fun benchmarkStateChangeCompilationDark() =
57+
benchmarkStateChangeWithTheme(CompilationMode.Partial(), true)
58+
59+
private fun benchmarkStateChangeWithTheme(compilationMode: CompilationMode, isDark: Boolean) =
60+
benchmarkRule.measureRepeated(
61+
packageName = PACKAGE_NAME,
62+
metrics = listOf(FrameTimingMetric(), PowerMetric(PowerMetric.Energy(categories))),
63+
compilationMode = compilationMode,
64+
iterations = 2,
65+
startupMode = StartupMode.WARM,
66+
setupBlock = {
67+
// Start the app
68+
pressHome()
69+
startActivityAndWait()
70+
allowNotifications()
71+
// Navigate to Settings
72+
device.findObject(By.desc("Settings")).click()
73+
device.waitForIdle()
74+
setAppTheme(isDark)
75+
},
76+
) {
77+
forYouWaitForContent()
78+
forYouSelectTopics()
79+
repeat(3) {
80+
forYouScrollFeedDownUp()
81+
}
82+
}
83+
}

benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.benchmark.macro.StartupTimingMetric
2727
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
2828
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
2929
import com.google.samples.apps.nowinandroid.PACKAGE_NAME
30+
import com.google.samples.apps.nowinandroid.allowNotifications
3031
import com.google.samples.apps.nowinandroid.foryou.forYouWaitForContent
3132
import org.junit.Rule
3233
import org.junit.Test
@@ -86,6 +87,7 @@ abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
8687
},
8788
) {
8889
startActivityAndWait()
90+
allowNotifications()
8991
// Waits until the content is ready to capture Time To Full Display
9092
forYouWaitForContent()
9193
}

build_android_release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
2222
APP_OUT=$DIR/app/build/outputs
2323

24-
export JAVA_HOME="$(cd $DIR/../../../prebuilts/studio/jdk/jdk11/linux && pwd )"
24+
export JAVA_HOME="$(cd $DIR/../nowinandroid-prebuilts/jdk17/linux && pwd )"
2525
echo "JAVA_HOME=$JAVA_HOME"
2626

2727
export ANDROID_HOME="$(cd $DIR/../../../prebuilts/fullsdk/linux && pwd )"

core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,14 @@ class OfflineFirstNewsRepository @Inject constructor(
8080
val hasOnboarded = userData.shouldHideOnboarding
8181
val followedTopicIds = userData.followedTopics
8282

83-
// TODO: Make this more efficient, there is no need to retrieve populated
84-
// news resources when all that's needed are the ids
8583
val existingNewsResourceIdsThatHaveChanged = when {
86-
hasOnboarded -> newsResourceDao.getNewsResources(
84+
hasOnboarded -> newsResourceDao.getNewsResourceIds(
8785
useFilterTopicIds = true,
8886
filterTopicIds = followedTopicIds,
8987
useFilterNewsIds = true,
9088
filterNewsIds = changedIds.toSet(),
9189
)
9290
.first()
93-
.map { it.entity.id }
9491
.toSet()
9592
// No need to retrieve anything if notifications won't be sent
9693
else -> emptySet()

core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,33 @@ class TestNewsResourceDao : NewsResourceDao {
6767
result
6868
}
6969

70+
override fun getNewsResourceIds(
71+
useFilterTopicIds: Boolean,
72+
filterTopicIds: Set<String>,
73+
useFilterNewsIds: Boolean,
74+
filterNewsIds: Set<String>,
75+
): Flow<List<String>> =
76+
entitiesStateFlow
77+
.map { newsResourceEntities ->
78+
newsResourceEntities.map { entity ->
79+
entity.asPopulatedNewsResource(topicCrossReferences)
80+
}
81+
}
82+
.map { resources ->
83+
var result = resources
84+
if (useFilterTopicIds) {
85+
result = result.filter { resource ->
86+
resource.topics.any { it.id in filterTopicIds }
87+
}
88+
}
89+
if (useFilterNewsIds) {
90+
result = result.filter { resource ->
91+
resource.entity.id in filterNewsIds
92+
}
93+
}
94+
result.map { it.entity.id }
95+
}
96+
7097
override suspend fun insertOrIgnoreNewsResources(
7198
entities: List<NewsResourceEntity>,
7299
): List<Long> {

core/database/src/main/java/com/google/samples/apps/nowinandroid/core/database/dao/NewsResourceDao.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,37 @@ interface NewsResourceDao {
6565
filterNewsIds: Set<String> = emptySet(),
6666
): Flow<List<PopulatedNewsResource>>
6767

68+
/**
69+
* Fetches ids of news resources that match the query parameters
70+
*/
71+
@Transaction
72+
@Query(
73+
value = """
74+
SELECT id FROM news_resources
75+
WHERE
76+
CASE WHEN :useFilterNewsIds
77+
THEN id IN (:filterNewsIds)
78+
ELSE 1
79+
END
80+
AND
81+
CASE WHEN :useFilterTopicIds
82+
THEN id IN
83+
(
84+
SELECT news_resource_id FROM news_resources_topics
85+
WHERE topic_id IN (:filterTopicIds)
86+
)
87+
ELSE 1
88+
END
89+
ORDER BY publish_date DESC
90+
""",
91+
)
92+
fun getNewsResourceIds(
93+
useFilterTopicIds: Boolean = false,
94+
filterTopicIds: Set<String> = emptySet(),
95+
useFilterNewsIds: Boolean = false,
96+
filterNewsIds: Set<String> = emptySet(),
97+
): Flow<List<String>>
98+
6899
/**
69100
* Inserts [entities] into the db if they don't exist, and ignores those that do
70101
*/

core/datastore/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ protobuf {
5252
}
5353
}
5454

55+
androidComponents.beforeVariants {
56+
android.sourceSets.register(it.name) {
57+
java.srcDir(buildDir.resolve("generated/source/proto/${it.name}/java"))
58+
kotlin.srcDir(buildDir.resolve("generated/source/proto/${it.name}/kotlin"))
59+
}
60+
}
61+
5562
dependencies {
5663
implementation(project(":core:common"))
5764
implementation(project(":core:model"))

0 commit comments

Comments
 (0)