fix: 处理引用依赖问题

This commit is contained in:
2024-12-11 15:28:11 +08:00
parent df105485bd
commit 8454e55c4b
246 changed files with 14884 additions and 100 deletions

View File

@@ -0,0 +1,31 @@
//
// Build the setup design - lottie_loading_layout.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "external_setupdesign_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["external_setupdesign_license"],
}
android_library {
name: "setupdesign-lottie-loading-layout",
manifest: "AndroidManifest.xml",
static_libs: [
"androidx.annotation_annotation",
"lottie",
"setupcompat",
"setupdesign",
],
srcs: [
"src/**/*.java",
],
resource_dirs: [
"res",
],
min_sdk_version: "16",
sdk_version: "current"
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.setupdesign.lottieloadinglayout">
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
</manifest>

View File

@@ -0,0 +1,43 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.google.android.setupdesign.lottieloadinglayout"
compileSdk 34
defaultConfig {
minSdk 31
targetSdk 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
sourceSets {
main {
java.srcDirs = ['src']
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['res']
}
}
lint {
abortOnError false
}
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
dependencies {
// compileOnly files('../libs/framework.jar')
implementation libs.androidx.annotation.annotation
implementation libs.lottie
implementation project(':setupdesign')
implementation project(':setupcompat')
}

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/sud_landscape_header_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/sud_glif_land_header_area_weight"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/sud_landscape_content_area"
style="@style/SudLandContentContianerStyle"
android:focusedByDefault="false"
android:orientation="vertical">
<FrameLayout
android:id="@+id/sud_layout_loading_content"
android:paddingTop="?attr/sudGlifContentPaddingTop"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_lottie_layout" />
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_fullscreen_lottie_layout" />
<LinearLayout
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/sud_landscape_header_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/sud_glif_land_header_area_weight"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/sud_landscape_content_area"
style="@style/SudLandContentContianerStyle"
android:paddingTop="?attr/sudGlifContentPaddingTop"
android:focusedByDefault="false"
android:orientation="vertical">
<FrameLayout
android:id="@+id/sud_layout_loading_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_fullscreen_loading_template_content" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_fullscreen_lottie_layout" />
<LinearLayout
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Ignore UnusedAttribute: scrollIndicators is new in M. Default to no indicators in older
versions. -->
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="?attr/sudLoadingHeaderHeight"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/sud_lottie_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:layout_gravity="start|bottom"
android:scaleType="fitStart"
app:lottie_autoPlay="false"
app:lottie_loop="true" />
</LinearLayout>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Ignore UnusedAttribute: scrollIndicators is new in M. Default to no indicators in older
versions. -->
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="?attr/sudLoadingHeaderHeight"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_lottie_layout" />
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/SudLoadingContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.setupdesign.view.FillContentLayout
android:orientation="vertical"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/sud_progress_bar"
android:visibility="gone"
style="@style/SudFourColorIndeterminateProgressBar"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.setupdesign.view.IllustrationVideoView
android:id="@+id/sud_progress_illustration"
android:visibility="gone"
style="@style/SudContentIllustration"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.setupdesign.view.FillContentLayout>
</LinearLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/SudLoadingContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/sud_lottie_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
style="@style/SudContentIllustration"
app:lottie_autoPlay="false"
app:lottie_loop="true" />
</LinearLayout>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2024 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.
-->
<!-- Please keep filterTouchesWhenObscured=true; it's to prevent tapjacking.
See https://developer.android.com/privacy-and-security/risks/tapjacking -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_fullscreen_loading_template_content_two_pane" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<!-- Please keep filterTouchesWhenObscured=true; it's to prevent tapjacking.
See https://developer.android.com/privacy-and-security/risks/tapjacking -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_fullscreen_lottie_layout" />
<LinearLayout
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/sud_landscape_header_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/sud_glif_land_header_area_weight"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/sud_landscape_content_area"
style="@style/SudLandContentContianerStyle"
android:paddingTop="?attr/sudGlifContentPaddingTop"
android:focusedByDefault="false"
android:orientation="vertical">
<FrameLayout
android:id="@+id/sud_layout_loading_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<!-- Please keep filterTouchesWhenObscured=true; it's to prevent tapjacking.
See https://developer.android.com/privacy-and-security/risks/tapjacking -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_loading_template_content_two_pane" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2024 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.
-->
<!-- Please keep filterTouchesWhenObscured=true; it's to prevent tapjacking.
See https://developer.android.com/privacy-and-security/risks/tapjacking -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/sud_landscape_header_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/sud_glif_land_header_area_weight"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/sud_landscape_content_area"
style="@style/SudLandContentContianerStyle"
android:focusedByDefault="false"
android:orientation="vertical">
<FrameLayout
android:id="@+id/sud_layout_loading_content"
android:paddingTop="?attr/sudGlifContentPaddingTop"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_lottie_layout" />
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2022 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_fullscreen_loading_embedded_template_content" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2022 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_fullscreen_lottie_layout" />
<LinearLayout
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Ignore UnusedAttribute: scrollIndicators is new in M. Default to no indicators in older
versions. -->
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="?attr/sudLoadingHeaderHeight"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2022 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_loading_embedded_template_content" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2022 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.
-->
<com.google.android.setupcompat.view.StatusBarBackgroundLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/sud_glif_loading_embedded_template_content" />
</com.google.android.setupcompat.view.StatusBarBackgroundLayout>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2022 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- Ignore UnusedAttribute: scrollIndicators is new in M. Default to no indicators in older
versions. -->
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/sud_glif_header" />
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_lottie_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</com.google.android.setupdesign.view.BottomScrollView>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
style="@style/SudGlifCardBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<com.google.android.setupdesign.view.IntrinsicSizeFrameLayout
android:id="@+id/suc_intrinsic_size_layout"
style="@style/SudGlifCardContainer"
android:layout_width="@dimen/sud_glif_card_width"
android:layout_height="wrap_content"
android:height="@dimen/sud_glif_card_height">
<include layout="@layout/sud_glif_loading_template_content" />
</com.google.android.setupdesign.view.IntrinsicSizeFrameLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<com.google.android.setupcompat.view.StatusBarBackgroundLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/sud_glif_loading_template_content" />
</com.google.android.setupcompat.view.StatusBarBackgroundLayout>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- Ignore UnusedAttribute: scrollIndicators is new in M. Default to no indicators in older
versions. -->
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/sud_glif_header" />
<ViewStub
android:id="@+id/sud_loading_layout_illustration_stub"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_loading_illustration_layout" />
<ViewStub
android:id="@+id/sud_loading_layout_lottie_stub"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inflatedId="@+id/sud_layout_lottie_illustration"
android:layout="@layout/sud_loading_lottie_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</com.google.android.setupdesign.view.BottomScrollView>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.setupdesign.view.FillContentLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/sud_progress_bar"
android:visibility="gone"
style="@style/SudFourColorIndeterminateProgressBar"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.setupdesign.view.IllustrationVideoView
android:id="@+id/sud_progress_illustration"
android:visibility="gone"
style="@style/SudContentIllustration"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.setupdesign.view.FillContentLayout>
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.setupdesign.view.FillContentLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/sud_lottie_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
style="@style/SudContentIllustration"
app:lottie_autoPlay="false"
app:lottie_loop="true" />
</com.google.android.setupdesign.view.FillContentLayout>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="sud_glif_loading_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_card</item>
<item name="sud_glif_loading_embedded_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_embedded_template_card</item>
<item name="sud_glif_fullscreen_loading_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_fullscreen_loading_template_card</item>
<item name="sud_glif_fullscreen_loading_embedded_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_fullscreen_loading_embedded_template_card</item>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="sud_glif_loading_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_card</item>
<item name="sud_glif_loading_embedded_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_embedded_template_card</item>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2024 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="sud_glif_loading_template_two_pane" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_compat</item>
<item name="sud_glif_fullscreen_loading_template_two_pane" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_compat</item>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2024 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="sud_glif_loading_template_two_pane" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_card_two_pane</item>
<item name="sud_glif_fullscreen_loading_template_two_pane" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_fullscreen_loading_template_card_two_pane</item>
</resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<declare-styleable name="SudGlifLoadingLayout">
<attr name="sudIllustrationType" format="string" />
<attr name="sudLottieRes" format="reference" />
<attr name="sudUsePartnerHeavyTheme" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="sud_glif_loading_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_compat</item>
<item name="sud_glif_loading_embedded_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_embedded_template_compat</item>
<item name="sud_glif_fullscreen_loading_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_template_compat</item>
<item name="sud_glif_fullscreen_loading_embedded_template" type="layout" tools:ignore="UnusedResources">@layout/sud_glif_loading_embedded_template_compat</item>
</resources>

View File

@@ -0,0 +1,843 @@
/*
* Copyright (C) 2021 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.google.android.setupdesign;
import static com.google.android.setupcompat.partnerconfig.Util.isNightMode;
import static java.lang.Math.min;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.ColorFilter;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.StringDef;
import androidx.annotation.VisibleForTesting;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.value.LottieValueCallback;
import com.airbnb.lottie.value.SimpleLottieValueCallback;
import com.google.android.setupcompat.partnerconfig.PartnerConfig;
import com.google.android.setupcompat.partnerconfig.PartnerConfig.ResourceType;
import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
import com.google.android.setupcompat.partnerconfig.ResourceEntry;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.util.BuildCompatUtils;
import com.google.android.setupcompat.util.ForceTwoPaneHelper;
import com.google.android.setupdesign.lottieloadinglayout.R;
import com.google.android.setupdesign.util.LayoutStyler;
import com.google.android.setupdesign.util.LottieAnimationHelper;
import com.google.android.setupdesign.view.IllustrationVideoView;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* A GLIF themed layout with a {@link com.airbnb.lottie.LottieAnimationView} to showing lottie
* illustration and a substitute {@link com.google.android.setupdesign.view.IllustrationVideoView}
* to showing mp4 illustration. {@code app:sudIllustrationType} can also be used to specify one of
* the set including "default", "account", "connection", "update", and "final_hold". {@code
* app:sudLottieRes} can assign the json file of Lottie resource.
*/
public class GlifLoadingLayout extends GlifLayout {
private static final String TAG = "GlifLoadingLayout";
View inflatedView;
@VisibleForTesting @IllustrationType String illustrationType = IllustrationType.DEFAULT;
@VisibleForTesting LottieAnimationConfig animationConfig = LottieAnimationConfig.CONFIG_DEFAULT;
@VisibleForTesting @RawRes int customLottieResource = 0;
private AnimatorListener animatorListener;
private Runnable nextActionRunnable;
private boolean workFinished;
protected static final String GLIF_LAYOUT_TYPE = "GlifLayoutType";
protected static final String LOADING_LAYOUT = "LoadingLayout";
@VisibleForTesting public boolean runRunnable;
@VisibleForTesting
public List<LottieAnimationFinishListener> animationFinishListeners = new ArrayList<>();
public GlifLoadingLayout(Context context) {
this(context, 0, 0);
}
public GlifLoadingLayout(Context context, int template) {
this(context, template, 0);
}
public GlifLoadingLayout(Context context, int template, int containerId) {
super(context, template, containerId);
init(null, com.google.android.setupdesign.R.attr.sudLayoutTheme);
}
public GlifLoadingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, com.google.android.setupdesign.R.attr.sudLayoutTheme);
}
public GlifLoadingLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int defStyleAttr) {
registerMixin(FooterBarMixin.class, new LoadingFooterBarMixin(this, attrs, defStyleAttr));
TypedArray a =
getContext()
.obtainStyledAttributes(attrs, R.styleable.SudGlifLoadingLayout, defStyleAttr, 0);
customLottieResource = a.getResourceId(R.styleable.SudGlifLoadingLayout_sudLottieRes, 0);
String illustrationType = a.getString(R.styleable.SudGlifLoadingLayout_sudIllustrationType);
a.recycle();
if (customLottieResource != 0) {
inflateLottieView();
ViewGroup container = findContainer(0);
container.setVisibility(View.VISIBLE);
} else {
if (illustrationType != null) {
setIllustrationType(illustrationType);
}
if (BuildCompatUtils.isAtLeastS()) {
inflateLottieView();
} else {
inflateIllustrationStub();
}
}
View view = findManagedViewById(R.id.sud_layout_loading_content);
if (view != null) {
if (shouldApplyPartnerResource()) {
LayoutStyler.applyPartnerCustomizationExtraPaddingStyle(view);
}
tryApplyPartnerCustomizationContentPaddingTopStyle(view);
}
updateHeaderHeight();
updateLandscapeMiddleHorizontalSpacing();
workFinished = false;
runRunnable = true;
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
/*
* add the listener used to log animation end and check whether the
* work in background finish when repeated.
*/
animatorListener =
new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// Do nothing.
}
@Override
public void onAnimationEnd(Animator animation) {
Log.i(TAG, "Animate enable:" + isAnimateEnable() + ". Animation end.");
}
@Override
public void onAnimationCancel(Animator animation) {
// Do nothing.
}
@Override
public void onAnimationRepeat(Animator animation) {
if (workFinished) {
Log.i(TAG, "Animation repeat but work finished, run the register runnable.");
finishRunnable(nextActionRunnable);
workFinished = false;
}
}
};
lottieAnimationView.addAnimatorListener(animatorListener);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (inflatedView instanceof LinearLayout) {
updateContentPadding((LinearLayout) inflatedView);
}
}
private boolean isAnimateEnable() {
try {
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
return Settings.Global.getFloat(
getContext().getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE)
!= 0f;
} else {
return true;
}
} catch (SettingNotFoundException e) {
return true;
}
}
public void setIllustrationType(@IllustrationType String type) {
if (customLottieResource != 0) {
throw new IllegalStateException(
"custom illustration already applied, should not set illustration.");
}
if (!illustrationType.equals(type)) {
illustrationType = type;
}
switch (type) {
case IllustrationType.ACCOUNT:
animationConfig = LottieAnimationConfig.CONFIG_ACCOUNT;
break;
case IllustrationType.CONNECTION:
animationConfig = LottieAnimationConfig.CONFIG_CONNECTION;
break;
case IllustrationType.UPDATE:
animationConfig = LottieAnimationConfig.CONFIG_UPDATE;
break;
case IllustrationType.FINAL_HOLD:
animationConfig = LottieAnimationConfig.CONFIG_FINAL_HOLD;
break;
default:
animationConfig = LottieAnimationConfig.CONFIG_DEFAULT;
break;
}
updateAnimationView();
}
// TODO: [GlifLoadingLayout] Should add testcase. LottieAnimationView was auto
// generated not able to mock. So we have no idea how to detected is the api pass to
// LottiAnimationView correctly.
public boolean setAnimation(InputStream inputStream, String keyCache) {
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
lottieAnimationView.setAnimation(inputStream, keyCache);
return true;
} else {
return false;
}
}
public boolean setAnimation(String assetName) {
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
lottieAnimationView.setAnimation(assetName);
return true;
} else {
return false;
}
}
public boolean setAnimation(@RawRes int rawRes) {
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
lottieAnimationView.setAnimation(rawRes);
return true;
} else {
return false;
}
}
private void updateAnimationView() {
if (BuildCompatUtils.isAtLeastS()) {
setLottieResource();
} else {
setIllustrationResource();
}
}
/**
* Call this when your activity is done and should be closed. The activity will be finished while
* animation finished.
*/
public void finish(@NonNull Activity activity) {
if (activity == null) {
throw new NullPointerException("activity should not be null");
}
registerAnimationFinishRunnable(activity::finish);
}
private void updateHeaderHeight() {
View headerView = findManagedViewById(R.id.sud_header_scroll_view);
Configuration currentConfig = getResources().getConfiguration();
if (headerView != null
&& PartnerConfigHelper.get(getContext())
.isPartnerConfigAvailable(PartnerConfig.CONFIG_LOADING_LAYOUT_HEADER_HEIGHT)
&& currentConfig.orientation != Configuration.ORIENTATION_LANDSCAPE) {
float configHeaderHeight =
PartnerConfigHelper.get(getContext())
.getDimension(getContext(), PartnerConfig.CONFIG_LOADING_LAYOUT_HEADER_HEIGHT);
headerView.getLayoutParams().height = (int) configHeaderHeight;
}
}
private void updateContentPadding(LinearLayout linearLayout) {
int paddingTop = linearLayout.getPaddingTop();
int paddingLeft = linearLayout.getPaddingLeft();
int paddingRight = linearLayout.getPaddingRight();
int paddingBottom = linearLayout.getPaddingBottom();
if (PartnerConfigHelper.get(getContext())
.isPartnerConfigAvailable(PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_TOP)) {
float configPaddingTop =
PartnerConfigHelper.get(getContext())
.getDimension(getContext(), PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_TOP);
if (configPaddingTop >= 0) {
paddingTop = (int) configPaddingTop;
}
}
if (PartnerConfigHelper.get(getContext())
.isPartnerConfigAvailable(PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_START)) {
float configPaddingLeft =
PartnerConfigHelper.get(getContext())
.getDimension(getContext(), PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_START);
if (configPaddingLeft >= 0) {
paddingLeft = (int) configPaddingLeft;
}
}
if (PartnerConfigHelper.get(getContext())
.isPartnerConfigAvailable(PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_END)) {
float configPaddingRight =
PartnerConfigHelper.get(getContext())
.getDimension(getContext(), PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_END);
if (configPaddingRight >= 0) {
paddingRight = (int) configPaddingRight;
}
}
if (PartnerConfigHelper.get(getContext())
.isPartnerConfigAvailable(PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_BOTTOM)) {
float configPaddingBottom =
PartnerConfigHelper.get(getContext())
.getDimension(getContext(), PartnerConfig.CONFIG_LOADING_LAYOUT_PADDING_BOTTOM);
if (configPaddingBottom >= 0) {
FooterBarMixin footerBarMixin = getMixin(FooterBarMixin.class);
if (footerBarMixin == null || footerBarMixin.getButtonContainer() == null) {
paddingBottom = (int) configPaddingBottom;
} else {
paddingBottom =
(int) configPaddingBottom
- (int)
min(
configPaddingBottom,
getButtonContainerHeight(footerBarMixin.getButtonContainer()));
}
}
}
linearLayout.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
private static int getButtonContainerHeight(View view) {
view.measure(
MeasureSpec.makeMeasureSpec(view.getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), MeasureSpec.EXACTLY));
return view.getMeasuredHeight();
}
private void inflateLottieView() {
final View lottieLayout = peekLottieLayout();
if (lottieLayout == null) {
ViewStub viewStub = findManagedViewById(R.id.sud_loading_layout_lottie_stub);
if (viewStub != null) {
inflatedView = viewStub.inflate();
if (inflatedView instanceof LinearLayout) {
updateContentPadding((LinearLayout) inflatedView);
}
setLottieResource();
}
}
}
private void inflateIllustrationStub() {
final View progressLayout = peekProgressIllustrationLayout();
if (progressLayout == null) {
ViewStub viewStub = findManagedViewById(R.id.sud_loading_layout_illustration_stub);
if (viewStub != null) {
inflatedView = viewStub.inflate();
if (inflatedView instanceof LinearLayout) {
updateContentPadding((LinearLayout) inflatedView);
}
setIllustrationResource();
}
}
}
private void setLottieResource() {
LottieAnimationView lottieView = findViewById(R.id.sud_lottie_view);
if (lottieView == null) {
Log.w(TAG, "Lottie view not found, skip set resource. Wait for layout inflated.");
return;
}
if (customLottieResource != 0) {
InputStream inputRaw = getResources().openRawResource(customLottieResource);
lottieView.setAnimation(inputRaw, null);
lottieView.playAnimation();
} else {
PartnerConfigHelper partnerConfigHelper = PartnerConfigHelper.get(getContext());
ResourceEntry resourceEntry =
partnerConfigHelper.getIllustrationResourceEntry(
getContext(), animationConfig.getLottieConfig());
if (resourceEntry != null) {
InputStream inputRaw =
resourceEntry.getResources().openRawResource(resourceEntry.getResourceId());
lottieView.setAnimation(inputRaw, null);
lottieView.playAnimation();
setLottieLayoutVisibility(View.VISIBLE);
setIllustrationLayoutVisibility(View.GONE);
LottieAnimationHelper.get()
.applyColor(
getContext(),
findLottieAnimationView(),
isNightMode(getResources().getConfiguration())
? animationConfig.getDarkThemeCustomization()
: animationConfig.getLightThemeCustomization());
} else {
setLottieLayoutVisibility(View.GONE);
setIllustrationLayoutVisibility(View.VISIBLE);
inflateIllustrationStub();
}
}
}
private void setIllustrationLayoutVisibility(int visibility) {
View illustrationLayout = findViewById(R.id.sud_layout_progress_illustration);
if (illustrationLayout != null) {
illustrationLayout.setVisibility(visibility);
}
}
private void setLottieLayoutVisibility(int visibility) {
View lottieLayout = findViewById(R.id.sud_layout_lottie_illustration);
if (lottieLayout != null) {
lottieLayout.setVisibility(visibility);
}
}
@VisibleForTesting
boolean isLottieLayoutVisible() {
View lottieLayout = findViewById(R.id.sud_layout_lottie_illustration);
return lottieLayout != null && lottieLayout.getVisibility() == View.VISIBLE;
}
private void setIllustrationResource() {
View illustrationLayout = findViewById(R.id.sud_layout_progress_illustration);
if (illustrationLayout == null) {
Log.i(TAG, "Illustration stub not inflated, skip set resource");
return;
}
IllustrationVideoView illustrationVideoView =
findManagedViewById(R.id.sud_progress_illustration);
ProgressBar progressBar = findManagedViewById(R.id.sud_progress_bar);
PartnerConfigHelper partnerConfigHelper = PartnerConfigHelper.get(getContext());
ResourceEntry resourceEntry =
partnerConfigHelper.getIllustrationResourceEntry(
getContext(), animationConfig.getIllustrationConfig());
if (resourceEntry != null) {
progressBar.setVisibility(GONE);
illustrationVideoView.setVisibility(VISIBLE);
illustrationVideoView.setVideoResourceEntry(resourceEntry);
} else {
progressBar.setVisibility(VISIBLE);
illustrationVideoView.setVisibility(GONE);
}
}
private LottieAnimationView findLottieAnimationView() {
return findViewById(R.id.sud_lottie_view);
}
private IllustrationVideoView findIllustrationVideoView() {
return findManagedViewById(R.id.sud_progress_illustration);
}
public void playAnimation() {
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
lottieAnimationView.setRepeatCount(LottieDrawable.INFINITE);
lottieAnimationView.playAnimation();
}
}
/** Returns whether the layout is waiting for animation finish or not. */
public boolean isFinishing() {
LottieAnimationView lottieAnimationView = findLottieAnimationView();
if (lottieAnimationView != null) {
return !animationFinishListeners.isEmpty() && lottieAnimationView.getRepeatCount() == 0;
} else {
return false;
}
}
@AnimationType
public int getAnimationType() {
if (findLottieAnimationView() != null && isLottieLayoutVisible()) {
return AnimationType.LOTTIE;
} else if (findIllustrationVideoView() != null) {
return AnimationType.ILLUSTRATION;
} else {
return AnimationType.PROGRESS_BAR;
}
}
// TODO: Should add testcase with mocked LottieAnimationView.
/** Add an animator listener to {@link LottieAnimationView}. */
public void addAnimatorListener(Animator.AnimatorListener listener) {
LottieAnimationView animationView = findLottieAnimationView();
if (animationView != null) {
animationView.addAnimatorListener(listener);
}
}
/** Remove the listener from {@link LottieAnimationView}. */
public void removeAnimatorListener(AnimatorListener listener) {
LottieAnimationView animationView = findLottieAnimationView();
if (animationView != null) {
animationView.removeAnimatorListener(listener);
}
}
/** Remove all {@link AnimatorListener} from {@link LottieAnimationView}. */
public void removeAllAnimatorListener() {
LottieAnimationView animationView = findLottieAnimationView();
if (animationView != null) {
animationView.removeAllAnimatorListeners();
}
}
/** Add a value callback with property {@link LottieProperty.COLOR_FILTER}. */
public void addColorCallback(KeyPath keyPath, LottieValueCallback<ColorFilter> callback) {
LottieAnimationView animationView = findLottieAnimationView();
if (animationView != null) {
animationView.addValueCallback(keyPath, LottieProperty.COLOR_FILTER, callback);
}
}
/** Add a simple value callback with property {@link LottieProperty.COLOR_FILTER}. */
public void addColorCallback(KeyPath keyPath, SimpleLottieValueCallback<ColorFilter> callback) {
LottieAnimationView animationView = findLottieAnimationView();
if (animationView != null) {
animationView.addValueCallback(keyPath, LottieProperty.COLOR_FILTER, callback);
}
}
@Nullable
private View peekLottieLayout() {
return findViewById(R.id.sud_layout_lottie_illustration);
}
@Nullable
private View peekProgressIllustrationLayout() {
return findViewById(R.id.sud_layout_progress_illustration);
}
@Override
protected View onInflateTemplate(LayoutInflater inflater, int template) {
Context context = getContext();
if (template == 0) {
boolean useFullScreenIllustration =
PartnerConfigHelper.get(context)
.getBoolean(
context,
PartnerConfig.CONFIG_LOADING_LAYOUT_FULL_SCREEN_ILLUSTRATION_ENABLED,
false);
if (useFullScreenIllustration) {
template = R.layout.sud_glif_fullscreen_loading_template;
// if the activity is embedded should apply an embedded layout.
if (isEmbeddedActivityOnePaneEnabled(context)) {
template = R.layout.sud_glif_fullscreen_loading_embedded_template;
} else if (ForceTwoPaneHelper.isForceTwoPaneEnable(getContext())) {
template = ForceTwoPaneHelper.getForceTwoPaneStyleLayout(getContext(), template);
}
} else {
template = R.layout.sud_glif_loading_template;
// if the activity is embedded should apply an embedded layout.
if (isEmbeddedActivityOnePaneEnabled(context)) {
template = R.layout.sud_glif_loading_embedded_template;
} else if (ForceTwoPaneHelper.isForceTwoPaneEnable(getContext())) {
template = ForceTwoPaneHelper.getForceTwoPaneStyleLayout(getContext(), template);
}
}
}
return inflateTemplate(
inflater, com.google.android.setupdesign.R.style.SudThemeGlif_Light, template);
}
@Override
protected ViewGroup findContainer(int containerId) {
if (containerId == 0) {
containerId = R.id.sud_layout_content;
}
return super.findContainer(containerId);
}
@Override
protected void onDetachedFromWindow() {
if (VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
PersistableBundle bundle = new PersistableBundle();
bundle.putString(GLIF_LAYOUT_TYPE, LOADING_LAYOUT);
setLayoutTypeMetrics(bundle);
super.onDetachedFromWindow();
}
}
/** The progress config used to maps to different animation */
public enum LottieAnimationConfig {
CONFIG_DEFAULT(
PartnerConfig.CONFIG_PROGRESS_ILLUSTRATION_DEFAULT,
PartnerConfig.CONFIG_LOADING_LOTTIE_DEFAULT,
PartnerConfig.CONFIG_LOTTIE_LIGHT_THEME_CUSTOMIZATION_DEFAULT,
PartnerConfig.CONFIG_LOTTIE_DARK_THEME_CUSTOMIZATION_DEFAULT),
CONFIG_ACCOUNT(
PartnerConfig.CONFIG_PROGRESS_ILLUSTRATION_ACCOUNT,
PartnerConfig.CONFIG_LOADING_LOTTIE_ACCOUNT,
PartnerConfig.CONFIG_LOTTIE_LIGHT_THEME_CUSTOMIZATION_ACCOUNT,
PartnerConfig.CONFIG_LOTTIE_DARK_THEME_CUSTOMIZATION_ACCOUNT),
CONFIG_CONNECTION(
PartnerConfig.CONFIG_PROGRESS_ILLUSTRATION_CONNECTION,
PartnerConfig.CONFIG_LOADING_LOTTIE_CONNECTION,
PartnerConfig.CONFIG_LOTTIE_LIGHT_THEME_CUSTOMIZATION_CONNECTION,
PartnerConfig.CONFIG_LOTTIE_DARK_THEME_CUSTOMIZATION_CONNECTION),
CONFIG_UPDATE(
PartnerConfig.CONFIG_PROGRESS_ILLUSTRATION_UPDATE,
PartnerConfig.CONFIG_LOADING_LOTTIE_UPDATE,
PartnerConfig.CONFIG_LOTTIE_LIGHT_THEME_CUSTOMIZATION_UPDATE,
PartnerConfig.CONFIG_LOTTIE_DARK_THEME_CUSTOMIZATION_UPDATE),
CONFIG_FINAL_HOLD(
PartnerConfig.CONFIG_PROGRESS_ILLUSTRATION_FINAL_HOLD,
PartnerConfig.CONFIG_LOADING_LOTTIE_FINAL_HOLD,
PartnerConfig.CONFIG_LOTTIE_LIGHT_THEME_CUSTOMIZATION_FINAL_HOLD,
PartnerConfig.CONFIG_LOTTIE_DARK_THEME_CUSTOMIZATION_FINAL_HOLD);
private final PartnerConfig illustrationConfig;
private final PartnerConfig lottieConfig;
private final PartnerConfig lightThemeCustomization;
private final PartnerConfig darkThemeCustomization;
LottieAnimationConfig(
PartnerConfig illustrationConfig,
PartnerConfig lottieConfig,
PartnerConfig lightThemeCustomization,
PartnerConfig darkThemeCustomization) {
if (illustrationConfig.getResourceType() != ResourceType.ILLUSTRATION
|| lottieConfig.getResourceType() != ResourceType.ILLUSTRATION) {
throw new IllegalArgumentException(
"Illustration progress only allow illustration resource");
}
this.illustrationConfig = illustrationConfig;
this.lottieConfig = lottieConfig;
this.lightThemeCustomization = lightThemeCustomization;
this.darkThemeCustomization = darkThemeCustomization;
}
PartnerConfig getIllustrationConfig() {
return illustrationConfig;
}
PartnerConfig getLottieConfig() {
return lottieConfig;
}
PartnerConfig getLightThemeCustomization() {
return lightThemeCustomization;
}
PartnerConfig getDarkThemeCustomization() {
return darkThemeCustomization;
}
}
/**
* Register the {@link Runnable} as a callback that will be performed when the animation finished.
*/
public void registerAnimationFinishRunnable(Runnable runnable) {
workFinished = true;
nextActionRunnable = runnable;
synchronized (this) {
runRunnable = true;
animationFinishListeners.add(
new LottieAnimationFinishListener(this, () -> finishRunnable(runnable)));
}
}
@VisibleForTesting
public synchronized void finishRunnable(Runnable runnable) {
// to avoid run the runnable twice.
if (runRunnable) {
runnable.run();
}
runRunnable = false;
}
/** The listener that to indicate the playing status for lottie animation. */
@VisibleForTesting
public static class LottieAnimationFinishListener {
private final Runnable runnable;
private final GlifLoadingLayout glifLoadingLayout;
private final LottieAnimationView lottieAnimationView;
@VisibleForTesting
AnimatorListener animatorListener =
new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// Do nothing.
}
@Override
public void onAnimationEnd(Animator animation) {
onAnimationFinished();
}
@Override
public void onAnimationCancel(Animator animation) {
// Do nothing.
}
@Override
public void onAnimationRepeat(Animator animation) {
// Do nothing.
}
};
@VisibleForTesting
LottieAnimationFinishListener(GlifLoadingLayout glifLoadingLayout, Runnable runnable) {
if (runnable == null) {
throw new NullPointerException("Runnable can not be null");
}
this.glifLoadingLayout = glifLoadingLayout;
this.runnable = runnable;
this.lottieAnimationView = glifLoadingLayout.findLottieAnimationView();
boolean shouldAnimationBeFinished =
PartnerConfigHelper.get(glifLoadingLayout.getContext())
.getBoolean(
glifLoadingLayout.getContext(),
PartnerConfig.CONFIG_LOADING_LAYOUT_WAIT_FOR_ANIMATION_FINISHED,
true);
// TODO: add test case for verify the case which isAnimating returns true.
if (glifLoadingLayout.isLottieLayoutVisible()
&& lottieAnimationView.isAnimating()
&& !isZeroAnimatorDurationScale()
&& shouldAnimationBeFinished) {
Log.i(TAG, "Register animation finish.");
lottieAnimationView.addAnimatorListener(animatorListener);
lottieAnimationView.setRepeatCount(0);
} else {
onAnimationFinished();
}
}
@VisibleForTesting
boolean isZeroAnimatorDurationScale() {
try {
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
return Settings.Global.getFloat(
glifLoadingLayout.getContext().getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE)
== 0f;
} else {
return false;
}
} catch (SettingNotFoundException e) {
return false;
}
}
@VisibleForTesting
public void onAnimationFinished() {
runnable.run();
if (lottieAnimationView != null) {
lottieAnimationView.removeAnimatorListener(animatorListener);
}
glifLoadingLayout.animationFinishListeners.remove(this);
}
}
/** Annotates the state for the illustration. */
@Retention(RetentionPolicy.SOURCE)
@StringDef({
IllustrationType.ACCOUNT,
IllustrationType.CONNECTION,
IllustrationType.DEFAULT,
IllustrationType.UPDATE,
IllustrationType.FINAL_HOLD
})
public @interface IllustrationType {
String DEFAULT = "default";
String ACCOUNT = "account";
String CONNECTION = "connection";
String UPDATE = "update";
String FINAL_HOLD = "final_hold";
}
/** Annotates the type for the illustration. */
@Retention(RetentionPolicy.SOURCE)
@IntDef({AnimationType.LOTTIE, AnimationType.ILLUSTRATION, AnimationType.PROGRESS_BAR})
public @interface AnimationType {
int LOTTIE = 1;
int ILLUSTRATION = 2;
int PROGRESS_BAR = 3;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2021 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.google.android.setupdesign;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.google.android.setupcompat.internal.TemplateLayout;
import com.google.android.setupcompat.template.FooterBarMixin;
/** A {@link Mixin} to get the container of footer bar for usage. */
public class LoadingFooterBarMixin extends FooterBarMixin {
/**
* Creates a mixin for managing buttons on the footer.
*
* @param layout The {@link TemplateLayout} containing this mixin.
* @param attrs XML attributes given to the layout.
* @param defStyleAttr The default style attribute as given to the constructor of the layout.
*/
public LoadingFooterBarMixin(
TemplateLayout layout, @Nullable AttributeSet attrs, int defStyleAttr) {
super(layout, attrs, defStyleAttr);
}
@Override
public LinearLayout getButtonContainer() {
return super.getButtonContainer();
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2022 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.google.android.setupdesign.util;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.SimpleColorFilter;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.value.LottieValueCallback;
import com.google.android.setupcompat.partnerconfig.PartnerConfig;
import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** A helper to help apply color on lottie animation */
public class LottieAnimationHelper {
private static final String TAG = "LottieAnimationHelper";
private static LottieAnimationHelper instance = null;
@VisibleForTesting public final Map<String, Integer> colorResourceMapping;
public static LottieAnimationHelper get() {
if (instance == null) {
instance = new LottieAnimationHelper();
}
return instance;
}
private LottieAnimationHelper() {
colorResourceMapping = new HashMap<>();
}
/**
* The color resource is from PartnerConfig, which is a string array and each string will be
* {key_path_name}:@{color_reference} or {key_path_name}:{color code}
*/
public void applyColor(
@NonNull Context context, LottieAnimationView lottieView, PartnerConfig partnerConfig) {
applyColor(
context,
lottieView,
PartnerConfigHelper.get(context).getStringArray(context, partnerConfig));
}
/**
* The color resource is from list of string and each string will be
* {key_path_name}:@{color_reference} or {key_path_name}:#{color code}
*/
public void applyColor(
@NonNull Context context, LottieAnimationView lottieView, List<String> colorMappings) {
applyColor(context, lottieView, parseColorMapping(context, colorMappings));
}
/**
* The color resource is from a color mapping table and the key is the keypath, and value is color
* Integer.
*/
public void applyColor(
@NonNull Context context,
LottieAnimationView lottieView,
Map<KeyPath, Integer> colorMappings) {
for (KeyPath keyPath : colorMappings.keySet()) {
lottieView.addValueCallback(
keyPath,
LottieProperty.COLOR_FILTER,
new LottieValueCallback<>(new SimpleColorFilter(colorMappings.get(keyPath))));
}
}
private Map<KeyPath, Integer> parseColorMapping(
@NonNull Context context, List<String> colorMappings) {
Map<KeyPath, Integer> customizationMap = new HashMap<>();
for (String colorMapping : colorMappings) {
String[] splitItem = colorMapping.split(":");
if (splitItem.length == 2) {
if (splitItem[1].charAt(0) == '#') { // color code
try {
customizationMap.put(
new KeyPath("**", splitItem[0], "**"), Color.parseColor(splitItem[1]));
} catch (IllegalArgumentException exception) {
Log.e(TAG, "Unknown color, value=" + colorMapping);
}
} else if (splitItem[1].charAt(0) == '@') { // color resource
int colorResourceId;
if (colorResourceMapping.containsKey(splitItem[1])) {
colorResourceId = colorResourceMapping.get(splitItem[1]);
} else {
colorResourceId =
context
.getResources()
.getIdentifier(splitItem[1].substring(1), "color", context.getPackageName());
colorResourceMapping.put(splitItem[1], colorResourceId);
}
try {
customizationMap.put(
new KeyPath("**", splitItem[0], "**"),
context.getResources().getColor(colorResourceId, null));
} catch (Resources.NotFoundException exception) {
Log.e(TAG, "Resource Not found, resource value=" + colorMapping);
}
} else {
Log.w(TAG, "incorrect format customization, value=" + colorMapping);
}
} else {
Log.w(TAG, "incorrect format customization, value=" + colorMapping);
}
}
return customizationMap;
}
}