Skip to content

Commit 9b95718

Browse files
authored
Merge branch 'main' into a11y-ptz
2 parents d3350b2 + 0a80c6c commit 9b95718

File tree

11 files changed

+638
-71
lines changed

11 files changed

+638
-71
lines changed

compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleSupportingPaneScaffold.kt

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@
1717
package com.example.compose.snippets.adaptivelayouts
1818

1919
import androidx.compose.foundation.background
20+
import androidx.compose.foundation.layout.Column
21+
import androidx.compose.foundation.layout.padding
2022
import androidx.compose.foundation.layout.safeContentPadding
2123
import androidx.compose.foundation.layout.wrapContentSize
24+
import androidx.compose.material.icons.Icons
25+
import androidx.compose.material.icons.filled.Close
2226
import androidx.compose.material3.Button
27+
import androidx.compose.material3.Icon
28+
import androidx.compose.material3.IconButton
2329
import androidx.compose.material3.Text
2430
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
2531
import androidx.compose.material3.adaptive.layout.AnimatedPane
@@ -30,13 +36,17 @@ import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope
3036
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole
3137
import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior
3238
import androidx.compose.material3.adaptive.navigation.NavigableSupportingPaneScaffold
39+
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
3340
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldPredictiveBackHandler
3441
import androidx.compose.material3.adaptive.navigation.rememberSupportingPaneScaffoldNavigator
3542
import androidx.compose.runtime.Composable
3643
import androidx.compose.runtime.rememberCoroutineScope
44+
import androidx.compose.ui.Alignment
3745
import androidx.compose.ui.Modifier
3846
import androidx.compose.ui.graphics.Color
47+
import androidx.compose.ui.tooling.preview.Devices.TABLET
3948
import androidx.compose.ui.tooling.preview.Preview
49+
import androidx.compose.ui.unit.dp
4050
import kotlinx.coroutines.launch
4151

4252
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@@ -57,13 +67,20 @@ fun SampleNavigableSupportingPaneScaffoldParts() {
5767
// [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_params]
5868
}
5969

70+
@Composable
71+
@Preview(device = TABLET)
72+
fun SampleNavigationSupportingPaneScaffoldFullTabletPreview() {
73+
SampleNavigableSupportingPaneScaffoldFull()
74+
}
75+
6076
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
6177
@Composable
6278
@Preview
6379
fun SampleNavigableSupportingPaneScaffoldFull() {
6480
// [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_full]
6581
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
6682
val scope = rememberCoroutineScope()
83+
val backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
6784

6885
NavigableSupportingPaneScaffold(
6986
navigator = scaffoldNavigator,
@@ -92,7 +109,26 @@ fun SampleNavigableSupportingPaneScaffoldFull() {
92109
},
93110
supportingPane = {
94111
AnimatedPane(modifier = Modifier.safeContentPadding()) {
95-
Text("Supporting pane")
112+
Column {
113+
// Allow users to dismiss the supporting pane. Use back navigation to
114+
// hide an expanded supporting pane.
115+
if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) {
116+
// Material design principles promote the usage of a right-aligned
117+
// close (X) button.
118+
IconButton(
119+
modifier = Modifier.align(Alignment.End).padding(16.dp),
120+
onClick = {
121+
scope.launch {
122+
scaffoldNavigator.navigateBack(backNavigationBehavior)
123+
}
124+
}
125+
) {
126+
Icon(Icons.Default.Close, contentDescription = "Close")
127+
}
128+
}
129+
Text("Supporting pane")
130+
}
131+
96132
}
97133
}
98134
)
@@ -124,11 +160,32 @@ fun ThreePaneScaffoldPaneScope.MainPane(
124160
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
125161
@Composable
126162
fun ThreePaneScaffoldPaneScope.SupportingPane(
163+
scaffoldNavigator: ThreePaneScaffoldNavigator<Any>,
127164
modifier: Modifier = Modifier,
165+
backNavigationBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange,
128166
) {
129-
AnimatedPane(modifier = modifier.safeContentPadding()) {
130-
// Supporting pane content
131-
Text("This is the supporting pane")
167+
val scope = rememberCoroutineScope()
168+
AnimatedPane(modifier = Modifier.safeContentPadding()) {
169+
Column {
170+
// Allow users to dismiss the supporting pane. Use back navigation to
171+
// hide an expanded supporting pane.
172+
if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) {
173+
// Material design principles promote the usage of a right-aligned
174+
// close (X) button.
175+
IconButton(
176+
modifier = modifier.align(Alignment.End).padding(16.dp),
177+
onClick = {
178+
scope.launch {
179+
scaffoldNavigator.navigateBack(backNavigationBehavior)
180+
}
181+
}
182+
) {
183+
Icon(Icons.Default.Close, contentDescription = "Close")
184+
}
185+
}
186+
Text("Supporting pane")
187+
}
188+
132189
}
133190
}
134191
// [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_extracted_panes]
@@ -152,7 +209,7 @@ fun SampleNavigableSupportingPaneScaffoldSimplified() {
152209
}
153210
)
154211
},
155-
supportingPane = { SupportingPane() },
212+
supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) },
156213
)
157214
// [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified]
158215
}
@@ -182,7 +239,7 @@ fun SampleSupportingPaneScaffoldSimplifiedWithPredictiveBackHandler() {
182239
}
183240
)
184241
},
185-
supportingPane = { SupportingPane() },
242+
supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) },
186243
)
187244
// [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified_with_predictive_back_handler]
188245
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright 2025 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.example.compose.snippets.modifiers
18+
19+
import androidx.annotation.DrawableRes
20+
import androidx.compose.foundation.Image
21+
import androidx.compose.foundation.background
22+
import androidx.compose.foundation.border
23+
import androidx.compose.foundation.layout.Box
24+
import androidx.compose.foundation.layout.fillMaxSize
25+
import androidx.compose.foundation.layout.fillMaxWidth
26+
import androidx.compose.foundation.layout.height
27+
import androidx.compose.foundation.layout.padding
28+
import androidx.compose.foundation.lazy.LazyColumn
29+
import androidx.compose.material3.Card
30+
import androidx.compose.material3.Text
31+
import androidx.compose.runtime.Composable
32+
import androidx.compose.runtime.getValue
33+
import androidx.compose.runtime.mutableStateOf
34+
import androidx.compose.runtime.remember
35+
import androidx.compose.runtime.setValue
36+
import androidx.compose.ui.Alignment
37+
import androidx.compose.ui.Modifier
38+
import androidx.compose.ui.graphics.Color
39+
import androidx.compose.ui.layout.onFirstVisible
40+
import androidx.compose.ui.layout.onVisibilityChanged
41+
import androidx.compose.ui.res.painterResource
42+
import androidx.compose.ui.unit.dp
43+
44+
private object OnVisibilityChangedSample {
45+
46+
@Composable
47+
fun OnVisibilityChangedExample(modifier: Modifier = Modifier) {
48+
// [START android_compose_modifiers_onVisibilityChanged]
49+
Text(
50+
text = "Some text",
51+
modifier = Modifier
52+
.onVisibilityChanged { visible ->
53+
if (visible) {
54+
// Do something if visible
55+
} else {
56+
// Do something if not visible
57+
}
58+
}
59+
.padding(vertical = 8.dp)
60+
)
61+
// [END android_compose_modifiers_onVisibilityChanged]
62+
}
63+
}
64+
65+
private object OnVisibilityChangedMinFractionVisible {
66+
67+
@Composable
68+
fun OnVisibilityChangedModifierMinFractionExample(modifier: Modifier = Modifier) {
69+
// [START android_compose_modifiers_onVisibilityChangedMinFraction]
70+
LazyColumn(
71+
modifier = modifier.fillMaxSize()
72+
) {
73+
item {
74+
Box(
75+
modifier = Modifier
76+
// [START_EXCLUDE]
77+
.fillParentMaxWidth()
78+
.border(0.5.dp, Color.Gray)
79+
// [END_EXCLUDE]
80+
// Here the visible callback gets triggered when 20% of the composable is visible
81+
.onVisibilityChanged(
82+
minFractionVisible = 0.2f,
83+
) { visible ->
84+
if (visible) {
85+
// Call specific logic here
86+
// viewModel.fetchDataFromNetwork()
87+
}
88+
}
89+
.padding(vertical = 16.dp)
90+
) {
91+
Text(
92+
text = "Sample Text",
93+
modifier = Modifier.padding(horizontal = 16.dp)
94+
)
95+
}
96+
}
97+
}
98+
// [END android_compose_modifiers_onVisibilityChangedMinFraction]
99+
}
100+
}
101+
102+
private object onVisibilityChangedMinDuration {
103+
104+
val MutedPlum = Color(0xFF7B4B6B)
105+
val PalePink = Color(0xFFF3E9EB)
106+
107+
@Composable
108+
fun OnVisibilityChangedMinDurationExample(
109+
@DrawableRes imageRes: Int,
110+
modifier: Modifier = Modifier,
111+
) {
112+
// [START android_compose_modifiers_onVisibilityChangedMinDuration]
113+
var background by remember { mutableStateOf(PalePink) }
114+
Card(
115+
modifier = modifier
116+
// [START_EXCLUDE]
117+
.height(300.dp)
118+
.fillMaxWidth()
119+
// [END_EXCLUDE]
120+
.onVisibilityChanged(minDurationMs = 3000) {
121+
if (it) {
122+
background = MutedPlum
123+
}
124+
}
125+
) {
126+
127+
Box(
128+
modifier = Modifier
129+
// [START_EXCLUDE]
130+
.fillMaxSize()
131+
// [END_EXCLUDE]
132+
.background(background),
133+
contentAlignment = Alignment.Center,
134+
) {
135+
// [START_EXCLUDE]
136+
Image(
137+
painter = painterResource(id = imageRes),
138+
contentDescription = "Androidify Bot",
139+
)
140+
// [END_EXCLUDE]
141+
}
142+
}
143+
// [END android_compose_modifiers_onVisibilityChangedMinDuration]
144+
}
145+
}
146+
147+
148+
private object OnFirstVisibleSample {
149+
150+
@Composable
151+
fun OnFirstVisibleExample(id: Int, modifier: Modifier = Modifier) {
152+
Card(
153+
modifier = modifier
154+
.fillMaxWidth()
155+
.padding(8.dp)
156+
) {
157+
// [START android_compose_modifiers_onFirstVisible]
158+
Text(
159+
modifier = Modifier
160+
.fillMaxSize()
161+
.onFirstVisible {
162+
println("OnFirstVisible : ProductCard: $id is visible")
163+
}
164+
.padding(8.dp),
165+
text = "Product $id"
166+
)
167+
// [END android_compose_modifiers_onFirstVisible]
168+
}
169+
}
170+
}

gradle/libs.versions.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ androidx-constraintlayout = "2.2.1"
1212
androidx-constraintlayout-compose = "1.1.1"
1313
androidx-coordinator-layout = "1.3.0"
1414
androidx-corektx = "1.17.0"
15-
androidx-credentials = "1.5.0"
16-
androidx-credentials-play-services-auth = "1.5.0"
15+
androidx-credentials = "1.6.0-beta03"
16+
androidx-credentials-play-services-auth = "1.6.0-beta03"
1717
androidx-emoji2-views = "1.6.0"
1818
androidx-fragment-ktx = "1.8.9"
1919
androidx-glance-appwidget = "1.1.1"
@@ -28,9 +28,9 @@ androidx-test-junit = "1.3.0"
2828
androidx-window = "1.5.0"
2929
androidx-window-core = "1.5.0"
3030
androidx-window-java = "1.5.0"
31-
androidx-xr-arcore = "1.0.0-alpha06"
32-
androidx-xr-compose = "1.0.0-alpha07"
33-
androidx-xr-scenecore = "1.0.0-alpha07"
31+
androidx-xr-arcore = "1.0.0-alpha07"
32+
androidx-xr-compose = "1.0.0-alpha08"
33+
androidx-xr-scenecore = "1.0.0-alpha08"
3434
androidxHiltNavigationCompose = "1.3.0"
3535
appcompat = "1.7.1"
3636
coil = "2.7.0"

identity/credentialmanager/src/main/java/com/example/identity/credentialmanager/PasskeyAndPasswordFunctions.kt

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,23 @@ class PasskeyAndPasswordFunctions(
7070
) {
7171
val requestJson = creationResult.toString()
7272
// [START android_identity_get_password_passkey_options]
73-
// Retrieves the user's saved password for your app from their
74-
// password provider.
73+
// Get password logins from the credential provider on the user's device.
7574
val getPasswordOption = GetPasswordOption()
7675

77-
// Get passkey from the user's public key credential provider.
76+
// Get passkeys from the credential provider on the user's device.
7877
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
7978
requestJson = requestJson
8079
)
8180
// [END android_identity_get_password_passkey_options]
8281
var result: GetCredentialResponse
82+
var preferImmediatelyAvailableCredentials: Boolean = false
8383
// [START android_identity_get_credential_request]
8484
val credentialRequest = GetCredentialRequest(
85+
// Include all the sign-in options that your app supports.
8586
listOf(getPasswordOption, getPublicKeyCredentialOption),
87+
// Defines whether you prefer to use only immediately available
88+
// credentials or hybrid credentials.
89+
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
8690
)
8791
// [END android_identity_get_credential_request]
8892
runBlocking {
@@ -92,7 +96,8 @@ class PasskeyAndPasswordFunctions(
9296
val response = credentialManager.prepareGetCredential(
9397
GetCredentialRequest(
9498
listOf(
95-
getPublicKeyCredentialOption,
99+
// Include all the sign-in options that your app supports
100+
getPublicKeyCredentialOption,
96101
getPasswordOption
97102
)
98103
)
@@ -230,19 +235,19 @@ class PasskeyAndPasswordFunctions(
230235

231236
// [START android_identity_create_passkey]
232237
suspend fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) {
238+
var isConditional: Boolean = false
233239
val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
234-
// Contains the request in JSON format. Uses the standard WebAuthn
235-
// web JSON spec.
240+
// Contains the request in JSON format.
236241
requestJson = requestJson,
237-
// Defines whether you prefer to use only immediately available
238-
// credentials, not hybrid credentials, to fulfill this request.
239-
// This value is false by default.
242+
// Defines whether you prefer to use only locally-available
243+
// credentials or hybrid credentials.
240244
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
245+
// Automatically create a passkey if the user does not have one.
246+
isConditional = isConditional
241247
)
242248

243-
// Execute CreateCredentialRequest asynchronously to register credentials
244-
// for a user account. Handle success and failure cases with the result and
245-
// exceptions, respectively.
249+
// Execute createCredential asynchronously to register credentials
250+
// for a user account.
246251
coroutineScope {
247252
try {
248253
val result = credentialManager.createCredential(

0 commit comments

Comments
 (0)