Merge "Move ShadowBluetoothUtils.java to tests/robotests/testutils." into main
diff --git a/Android.bp b/Android.bp
index ca4971e..0271b2f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,6 +112,7 @@
"androidx.room_room-runtime",
"SystemUIUnfoldLib",
"aconfig_settings_flags_lib",
+ "android.content.pm.flags-aconfig-java",
],
plugins: [
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c64187f..a15b4ea 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -645,6 +645,7 @@
<activity android:name="Settings$FaceSettingsActivity"
android:label="@string/security_settings_face_preference_title"
android:exported="true"
+ android:theme="@style/Theme.Settings.NoActionBar"
android:icon="@drawable/ic_face_header">
<intent-filter>
<action android:name="android.settings.FACE_SETTINGS" />
@@ -659,6 +660,7 @@
<activity android:name="Settings$FaceSettingsInternalActivity"
android:label="@string/security_settings_face_preference_title"
android:exported="false"
+ android:theme="@style/Theme.Settings.NoActionBar"
android:icon="@drawable/ic_face_header"
android:taskAffinity="com.android.settings.root">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
@@ -1577,6 +1579,20 @@
android:value="@string/menu_key_apps"/>
</activity>
+ <activity android:name="Settings$UserAspectRatioAppActivity"
+ android:exported="true"
+ android:label="@string/aspect_ratio_title">
+ <intent-filter>
+ <action android:name="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="package" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.applications.appcompat.UserAspectRatioDetails" />
+ <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+ android:value="@string/menu_key_apps"/>
+ </activity>
+
<activity
android:name="Settings$ManageDomainUrlsActivity"
android:exported="true"
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index d4960c2..d0a8afe 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -9,6 +9,7 @@
"settings_connecteddevice_flag_declarations.aconfig",
"settings_globalintl_flag_declarations.aconfig",
"settings_apn_flag_declarations.aconfig",
+ "settings_onboarding_experience_flag_declarations.aconfig"
],
}
diff --git a/aconfig/settings_onboarding_experience_flag_declarations.aconfig b/aconfig/settings_onboarding_experience_flag_declarations.aconfig
new file mode 100644
index 0000000..6fb5377
--- /dev/null
+++ b/aconfig/settings_onboarding_experience_flag_declarations.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.settings.flags"
+
+flag {
+ name: "enable_sound_backup"
+ namespace: "onboarding_experience"
+ description: "Feature flag for B&R sound settings."
+ bug: "278975761"
+}
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index 63ab6ac..0e1713c 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -738,4 +738,11 @@
<string name="daltonizer_feature_summary" product="default">Adjust how colors display on your phone</string>
<!-- The daltonizer feature summary display as a subtext as an item in a list. -->
<string name="daltonizer_feature_summary" product="tablet">Adjust how colors display on your tablet</string>
+
+ <!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
+ <string name="spatial_audio_speaker" product="default">Phone speakers</string>
+ <!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
+ <string name="spatial_audio_speaker" product="tablet">Tablet speakers</string>
+ <!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
+ <string name="spatial_audio_speaker" product="device">Device speakers</string>
</resources>
diff --git a/res/drawable/battery_hints_chip_bg.xml b/res/drawable/battery_hints_chip_bg.xml
new file mode 100644
index 0000000..e7d1d0f
--- /dev/null
+++ b/res/drawable/battery_hints_chip_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/settingslib_dialog_background" />
+ <corners android:radius="@dimen/battery_hints_chip_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/battery_hints_chip_bg_ripple.xml b/res/drawable/battery_hints_chip_bg_ripple.xml
new file mode 100644
index 0000000..a8bd0b37
--- /dev/null
+++ b/res/drawable/battery_hints_chip_bg_ripple.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@drawable/battery_hints_chip_bg"/>
+</ripple>
\ No newline at end of file
diff --git a/res/layout/anomaly_app_item_preference.xml b/res/layout/anomaly_app_item_preference.xml
new file mode 100644
index 0000000..0a19849
--- /dev/null
+++ b/res/layout/anomaly_app_item_preference.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <include layout="@layout/preference_app"/>
+
+ <LinearLayout
+ android:id="@+id/warning_chip"
+ android:visibility="gone"
+ android:clickable="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <Space
+ android:layout_width="@dimen/secondary_app_icon_size"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="8dp"
+ android:layout_marginStart="16dp"
+ android:background="@drawable/battery_hints_chip_bg_ripple">
+
+ <ImageView
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:layout_gravity="center_vertical|start"
+ android:contentDescription="@string/battery_hints_warning_icon_a11y"
+ android:src="@drawable/ic_battery_tips_warning_icon" />
+
+ <TextView
+ android:id="@+id/warning_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="8dp"
+ android:layout_gravity="center_vertical|start"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/raw/fold_setting_selective_stay_awake_lottie.json b/res/raw/fold_setting_selective_stay_awake_lottie.json
new file mode 100644
index 0000000..5271145
--- /dev/null
+++ b/res/raw/fold_setting_selective_stay_awake_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":244,"w":412,"h":300,"nm":"Foldable_FoldingSetting_EDU_02_412x300","ddd":0,"assets":[{"id":"comp_0","nm":"Folded Youtube UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle 3470505","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[195.532,168,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[29,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470505","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 3470502","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,148.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,9],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470502","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"▽ Group 24","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.647,94.93,0],"ix":2,"l":2},"a":{"a":0,"k":[19,5.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":38,"h":11,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Vector 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[194.532,63,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.87,0],[0,-4.431],[0,0],[-2.777,0],[-1.047,-0.656]],"o":[[4.917,0],[0,0],[0.956,-2.133],[1.411,0],[1.184,-3.118]],"v":[[4.621,-4],[13.5,4],[-13.5,3.959],[-7.444,0.267],[-3.711,1.333]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"▽ Group 23","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[227.627,73.222,0],"ix":2,"l":2},"a":{"a":0,"k":[23,6,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":46,"h":12,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"▽ Group 21","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[222.901,108.93,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"▽ Group 18","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.405,106.27,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,14,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":28,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,89.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,69],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"▽ Group 17","refId":"comp_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.262,132.883,0],"ix":2,"l":2},"a":{"a":0,"k":[2,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":4,"h":8,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Vector 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.282,133,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36.25,0],[-36.25,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Vector 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[233.032,133,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[22,0],[-22,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Ellipse 7581","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[168.032,164,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14,14],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7581","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Rectangle 3470507","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,210.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,69],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470507","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_1","nm":"▽ Group 24","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[19.069,5.305,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.951,0],[0,-5.239],[0.044,-0.4],[0,0],[-2.087,0],[-0.755,-0.355],[-3.241,0],[-1.376,-1.465]],"o":[[5.194,0],[0,0.4],[0,0],[0.932,-1.687],[0.844,0],[1.154,-2.886],[2.175,0],[1.465,-3.374]],"v":[[9.656,-5.305],[19.069,4.107],[19.024,5.305],[-19.069,5.305],[-14.229,2.464],[-11.832,2.997],[-4.64,-1.887],[0.91,0.466]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_2","nm":"▽ Group 23","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22.865,6.238,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.376,-5.239],[-1.288,0],[-0.71,-2.619],[0,0],[-3.774,0],[-1.421,-0.977],[-5.372,0]],"o":[[0.977,-0.71],[2.841,0],[0,0],[1.199,-3.374],[1.82,0],[1.598,-4.795],[5.638,0]],"v":[[13.408,2.864],[16.915,1.798],[22.865,6.238],[-22.865,6.238],[-14.696,0.466],[-9.723,2.064],[1.731,-6.238]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_3","nm":"▽ Group 21","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 22","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_4","nm":"▽ Group 22","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-9.264,11.313],[9.264,11.313],[3.421,1.621],[7.839,1.621],[0,-11.313],[-7.839,1.621],[-3.421,1.621]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[8.017,10.6],[-7.981,10.6],[-2.102,0.909],[-6.52,0.909],[0.036,-9.959],[6.592,0.909],[2.173,0.909]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_5","nm":"▽ Group 18","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 20","refId":"comp_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"▽ Group 19","refId":"comp_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.265,25.197,0],"ix":2,"l":2},"a":{"a":0,"k":[3,3,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":6,"h":6,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_6","nm":"▽ Group 20","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-9.264,11.313],[9.264,11.313],[3.421,1.621],[7.839,1.621],[0,-11.313],[-7.839,1.621],[-3.421,1.621]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[8.017,10.6],[-7.981,10.6],[-2.102,0.909],[-6.52,0.909],[0.036,-9.959],[6.592,0.909],[2.173,0.909]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_7","nm":"▽ Group 19","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[2.957,2.779,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-2.957,2.779],[2.957,2.779],[2.957,-2.779],[2.245,-2.779],[2.245,2.067],[-2.245,2.067],[-2.245,-2.779],[-2.957,-2.779]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_8","nm":"▽ Group 17","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.46,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_9","nm":"Unfolded YouTube UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 9","refId":"comp_10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[156.94,145.03,0],"ix":2,"l":2},"a":{"a":0,"k":[43,12,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":86,"h":24,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.64,71.83,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.5,0],[0,-10.8],[0,0],[-6.1,0],[-2.3,-1.6]],"o":[[10.8,0],[0,0],[2.1,-5.2],[3.1,0],[2.6,-7.6]],"v":[[10.15,-9.75],[29.65,9.75],[-29.65,9.65],[-16.35,0.65],[-8.15,3.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"▽ Group 8","refId":"comp_11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.49,96.13,0],"ix":2,"l":2},"a":{"a":0,"k":[51.5,14,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":103,"h":28,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"▽ Group 7","refId":"comp_12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111.22,226.963,0],"ix":2,"l":2},"a":{"a":0,"k":[2,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":4,"h":8,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Vector 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[166.369,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44,0],[-44,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Vector 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.869,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.5,0],[-46.5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"▽ Group 5","refId":"comp_13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[240.856,176.561,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"▽ Group 2","refId":"comp_15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[282.536,170.581,0],"ix":2,"l":2},"a":{"a":0,"k":[21,31.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":63,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.99,132.58,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[216,155],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_10","nm":"▽ Group 9","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[42.95,11.95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.9,0],[0,-11.8],[0.1,-0.9],[0,0],[-4.7,0],[-1.7,-0.8],[-7.3,0],[-3.1,-3.3]],"o":[[11.7,0],[0,0.9],[0,0],[2.1,-3.8],[1.9,0],[2.6,-6.5],[4.9,0],[3.3,-7.6]],"v":[[21.75,-11.95],[42.95,9.25],[42.85,11.95],[-42.95,11.95],[-32.05,5.55],[-26.65,6.75],[-10.45,-4.25],[2.05,1.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_11","nm":"▽ Group 8","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[51.5,14.05,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.1,-11.8],[-2.9,0],[-1.6,-5.9],[0,0],[-8.5,0],[-3.2,-2.2],[-12.1,0]],"o":[[2.2,-1.6],[6.4,0],[0,0],[2.7,-7.6],[4.1,0],[3.6,-10.8],[12.7,0]],"v":[[30.2,6.45],[38.1,4.05],[51.5,14.05],[-51.5,14.05],[-33.1,1.05],[-21.9,4.65],[3.9,-14.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_12","nm":"▽ Group 7","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.46,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_13","nm":"▽ Group 5","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 6","refId":"comp_14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_14","nm":"▽ Group 6","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_15","nm":"▽ Group 2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 4","refId":"comp_16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"▽ Group 3","refId":"comp_17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.863,56.741,0],"ix":2,"l":2},"a":{"a":0,"k":[6.5,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":13,"h":13,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_16","nm":"▽ Group 4","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_17","nm":"▽ Group 3","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6.661,6.26,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.661,6.26],[6.661,6.26],[6.661,-6.26],[5.056,-6.26],[5.056,4.655],[-5.056,4.655],[-5.056,-6.26],[-6.661,-6.26]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[88,88,100],"ix":6,"l":2}},"ao":0,"ip":-6,"op":630,"st":30,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":40,"s":[0,0,0],"to":[-10.833,0,0],"ti":[10.833,0,0]},{"t":80,"s":[-65,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":244,"st":40,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.839],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.495,137.576],[54.264,146.808],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.282,-146.679],[63.915,-137.047]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-9.436]],"o":[[0,8.464],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.623,136.911],[54.466,146.518],[-54.319,117.62],[-59.648,109.223],[-59.708,-109.282],[-54.594,-117.179],[54.309,-145.697],[63.951,-135.939]],"c":true}]},{"t":80,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.599,105.138],[54.368,114.37],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.31,-114.429],[63.943,-104.797]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".black 2","cl":"black","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Folded Youtube UI","parent":2,"tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[0]},{"t":90,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":51,"op":651,"st":51,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[206,150,0],"to":[1.444,0,0],"ti":[-2,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":49,"s":[214.667,150,0],"to":[2,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[218,150,0],"to":[1.083,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[221.167,150,0],"to":[1.083,0,0],"ti":[-1.111,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[224.5,150,0],"to":[1.111,0,0],"ti":[-1.333,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[227.833,150,0],"to":[1.333,0,0],"ti":[-1.528,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":54,"s":[232.5,150,0],"to":[1.528,0,0],"ti":[-1.583,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[237,150,0],"to":[1.583,0,0],"ti":[-1.889,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[242,150,0],"to":[1.889,0,0],"ti":[-2.167,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":57,"s":[248.333,150,0],"to":[2.167,0,0],"ti":[-2.278,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[255,150,0],"to":[2.278,0,0],"ti":[-2.5,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[262,150,0],"to":[2.5,0,0],"ti":[-3.556,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[270,150,0],"to":[3.556,0,0],"ti":[-2.222,0,0]},{"t":61,"s":[283.333,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[311.96,210.22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.52,5.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630,"st":30,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Unfolded YouTube UI","parent":2,"tt":1,"refId":"comp_9","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"t":50,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"t":61,"s":[0,100,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-2.282,113.897],[-17.976,113.897],[-121.273,113.897],[-130.36,105.242],[-130.36,-104.809],[-121.273,-113.897],[-1.197,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-8.034,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.243],[118.937,113.897],[20.423,113.897],[-1.182,113.897],[-16.193,117.028],[-121.36,141.834],[-130.185,134.804],[-130.289,-134.192],[-121.277,-142.03],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"t":61,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-1.125,113.897],[-16.101,117.189],[-121.089,144.98],[-130.176,136.326],[-130.286,-135.704],[-121.198,-144.793],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[99,99,100]},{"t":61,"s":[-1,99,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey601","cl":"grey601","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[116.74,102.33,0],"ix":1,"l":2},"s":{"a":0,"k":[114.5,114.5,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[115.717,-109.174],[-119.283,-109.174],[-119.283,299.701],[115.717,299.701]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.17,0],[0,0],[0,4.18],[0,0],[-4.17,0],[0,0],[0,-4.18]],"o":[[0,4.18],[0,0],[-4.18,0],[0,0],[0,-4.18],[0,0],[4.18,0],[0,0]],"v":[[112.07,92.13],[104.12,99.71],[-106.16,99.71],[-114.11,92.13],[-114.11,-91.75],[-106.16,-99.71],[104.12,-99.71],[112.07,-91.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.055,2.749],[0,0],[5.7,0],[0,0],[1.89,-1.05],[0.88,0.35],[0,0],[2.17,0],[0,0],[0,-5.7],[0,0],[-5.7,0],[0,0],[-1.89,1.05],[-0.85,-0.29],[0,0],[-2.17,0],[0,0],[0,5.7],[0,0],[0.055,2.493]],"o":[[0,0],[0,0],[0,-5.71],[0,0],[-2.17,0],[-0.88,0.35],[0,0],[-1.89,-1.06],[0,0],[-5.71,0],[0,0],[0,5.71],[0,0],[2.17,0],[0.83,-0.33],[0,0],[1.89,1.05],[0,0],[5.71,0],[0,0],[-0.069,-5.452],[0,0]],"v":[[114.45,-15.54],[114.45,-36.12],[114.45,-91.75],[104.12,-102.08],[6.42,-102.08],[0.23,-100.48],[-2.52,-100.47],[-2.55,-100.47],[-8.74,-102.08],[-106.16,-102.08],[-116.49,-91.75],[-116.49,91.75],[-106.16,102.08],[-8.54,102.08],[-2.35,100.48],[0.25,100.42],[0.35,100.48],[7.83,102.08],[104.12,102.08],[114.45,91.75],[114.45,31.38],[114.45,-0.88]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.74,102.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":254,"st":30,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":244,"st":40,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.291,0],[0,0],[0,15.652],[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0]],"o":[[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0],[15.185,0],[0,0],[0,15.544]],"v":[[178.179,150],[-178.179,150],[-206,121.522],[-206,-121.522],[-178.179,-150],[178.286,-150],[206,-121.522],[206,121.63]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":245,"st":10,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/fold_setting_sleep_on_fold_lottie.json b/res/raw/fold_setting_sleep_on_fold_lottie.json
new file mode 100644
index 0000000..0030e11
--- /dev/null
+++ b/res/raw/fold_setting_sleep_on_fold_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":244,"w":412,"h":300,"nm":"Foldable_FoldingSetting_EDU_03_412x300","ddd":0,"assets":[{"id":"comp_0","nm":"Unfolded YouTube UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 9","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[156.94,145.03,0],"ix":2,"l":2},"a":{"a":0,"k":[43,12,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":86,"h":24,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.64,71.83,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.5,0],[0,-10.8],[0,0],[-6.1,0],[-2.3,-1.6]],"o":[[10.8,0],[0,0],[2.1,-5.2],[3.1,0],[2.6,-7.6]],"v":[[10.15,-9.75],[29.65,9.75],[-29.65,9.65],[-16.35,0.65],[-8.15,3.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"▽ Group 8","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.49,96.13,0],"ix":2,"l":2},"a":{"a":0,"k":[51.5,14,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":103,"h":28,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"▽ Group 7","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111.22,226.963,0],"ix":2,"l":2},"a":{"a":0,"k":[2,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":4,"h":8,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Vector 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[166.369,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44,0],[-44,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Vector 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.869,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.5,0],[-46.5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"▽ Group 5","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[240.856,176.561,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"▽ Group 2","refId":"comp_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[282.536,170.581,0],"ix":2,"l":2},"a":{"a":0,"k":[21,31.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":63,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.99,132.58,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[216,155],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_1","nm":"▽ Group 9","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[42.95,11.95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.9,0],[0,-11.8],[0.1,-0.9],[0,0],[-4.7,0],[-1.7,-0.8],[-7.3,0],[-3.1,-3.3]],"o":[[11.7,0],[0,0.9],[0,0],[2.1,-3.8],[1.9,0],[2.6,-6.5],[4.9,0],[3.3,-7.6]],"v":[[21.75,-11.95],[42.95,9.25],[42.85,11.95],[-42.95,11.95],[-32.05,5.55],[-26.65,6.75],[-10.45,-4.25],[2.05,1.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_2","nm":"▽ Group 8","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[51.5,14.05,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.1,-11.8],[-2.9,0],[-1.6,-5.9],[0,0],[-8.5,0],[-3.2,-2.2],[-12.1,0]],"o":[[2.2,-1.6],[6.4,0],[0,0],[2.7,-7.6],[4.1,0],[3.6,-10.8],[12.7,0]],"v":[[30.2,6.45],[38.1,4.05],[51.5,14.05],[-51.5,14.05],[-33.1,1.05],[-21.9,4.65],[3.9,-14.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_3","nm":"▽ Group 7","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.46,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_4","nm":"▽ Group 5","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 6","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_5","nm":"▽ Group 6","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_6","nm":"▽ Group 2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 4","refId":"comp_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"▽ Group 3","refId":"comp_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.863,56.741,0],"ix":2,"l":2},"a":{"a":0,"k":[6.5,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":13,"h":13,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_7","nm":"▽ Group 4","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_8","nm":"▽ Group 3","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6.661,6.26,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.661,6.26],[6.661,6.26],[6.661,-6.26],[5.056,-6.26],[5.056,4.655],[-5.056,4.655],[-5.056,-6.26],[-6.661,-6.26]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[88,88,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":630,"st":30,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":40,"s":[0,0,0],"to":[-10.833,0,0],"ti":[10.833,0,0]},{"t":80,"s":[-65,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":244,"st":40,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.839],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.495,137.576],[54.264,146.808],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.282,-146.679],[63.915,-137.047]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-9.436]],"o":[[0,8.464],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.623,136.911],[54.466,146.518],[-54.319,117.62],[-59.648,109.223],[-59.708,-109.282],[-54.594,-117.179],[54.309,-145.697],[63.951,-135.939]],"c":true}]},{"t":80,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.599,105.138],[54.368,114.37],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.31,-114.429],[63.943,-104.797]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".black 2","cl":"black","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Vector","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[0]},{"t":90,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.918,-0.923],[-1.289,0],[0,0],[-0.918,0.923],[0,1.296],[0,0],[0.918,0.923],[1.289,0],[0,0],[0,0],[2.891,2.911],[4.109,0],[2.896,-2.911],[0,-4.13],[0,0],[0,0],[0.918,-0.923],[0,-1.296],[0,0]],"o":[[0.918,0.923],[0,0],[1.289,0],[0.918,-0.923],[0,0],[0,-1.296],[-0.918,-0.923],[0,0],[0,0],[0,-4.13],[-2.891,-2.911],[-4.109,0],[-2.896,2.911],[0,0],[0,0],[-1.289,0],[-0.918,0.923],[0,0],[0,1.296]],"v":[[-23.623,31.615],[-20.312,33],[20.312,33],[23.623,31.615],[25,28.286],[25,-5.814],[23.623,-9.144],[20.312,-10.529],[14.844,-10.529],[14.844,-18.071],[10.508,-28.633],[0.008,-33],[-10.5,-28.633],[-14.844,-18.071],[-14.844,-10.529],[-20.312,-10.529],[-23.623,-9.144],[-25,-5.814],[-25,28.286]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[20.312,28.286],[-20.312,28.286],[-20.312,-5.814],[20.312,-5.814]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[1.172,-1.154],[1.658,0],[1.181,1.152],[0,1.598],[-1.172,1.283],[-1.658,0],[-1.181,-1.283],[0,-1.571]],"o":[[-1.172,1.154],[-1.658,0],[-1.181,-1.152],[0,-1.598],[1.172,-1.283],[1.658,0],[1.181,1.283],[0,1.621]],"v":[[4.258,15.555],[0.013,17.286],[-4.245,15.557],[-6.016,11.432],[-4.258,7.111],[-0.013,5.186],[4.245,7.111],[6.016,11.393]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-1.979,1.986],[-2.819,0],[-1.973,-1.986],[0,-2.837]],"o":[[0,0],[0,0],[0,-2.837],[1.979,-1.986],[2.819,0],[1.973,1.986],[0,0]],"v":[[10.156,-10.529],[-10.156,-10.529],[-10.156,-18.071],[-7.188,-25.307],[0.009,-28.286],[7.197,-25.307],[10.156,-18.071]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630,"st":30,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":245,"st":39,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[206,150,0],"to":[1.444,0,0],"ti":[-2,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":49,"s":[214.667,150,0],"to":[2,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[218,150,0],"to":[1.083,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[221.167,150,0],"to":[1.083,0,0],"ti":[-1.111,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[224.5,150,0],"to":[1.111,0,0],"ti":[-1.333,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[227.833,150,0],"to":[1.333,0,0],"ti":[-1.528,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":54,"s":[232.5,150,0],"to":[1.528,0,0],"ti":[-1.583,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[237,150,0],"to":[1.583,0,0],"ti":[-1.889,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[242,150,0],"to":[1.889,0,0],"ti":[-2.167,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":57,"s":[248.333,150,0],"to":[2.167,0,0],"ti":[-2.278,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[255,150,0],"to":[2.278,0,0],"ti":[-2.5,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[262,150,0],"to":[2.5,0,0],"ti":[-3.556,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[270,150,0],"to":[3.556,0,0],"ti":[-2.222,0,0]},{"t":61,"s":[283.333,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[311.96,210.22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.52,5.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630,"st":30,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"Unfolded YouTube UI","parent":2,"tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"t":50,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"t":61,"s":[0,100,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-2.282,113.897],[-17.976,113.897],[-121.273,113.897],[-130.36,105.242],[-130.36,-104.809],[-121.273,-113.897],[-1.197,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-8.034,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.243],[118.937,113.897],[20.423,113.897],[-1.182,113.897],[-16.193,117.028],[-121.36,141.834],[-130.185,134.804],[-130.289,-134.192],[-121.277,-142.03],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"t":61,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-1.125,113.897],[-16.101,117.189],[-121.089,144.98],[-130.176,136.326],[-130.286,-135.704],[-121.198,-144.793],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[99,99,100]},{"t":61,"s":[-1,99,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey601","cl":"grey601","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[116.74,102.33,0],"ix":1,"l":2},"s":{"a":0,"k":[114.5,114.5,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[115.717,-109.174],[-119.283,-109.174],[-119.283,299.701],[115.717,299.701]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.17,0],[0,0],[0,4.18],[0,0],[-4.17,0],[0,0],[0,-4.18]],"o":[[0,4.18],[0,0],[-4.18,0],[0,0],[0,-4.18],[0,0],[4.18,0],[0,0]],"v":[[112.07,92.13],[104.12,99.71],[-106.16,99.71],[-114.11,92.13],[-114.11,-91.75],[-106.16,-99.71],[104.12,-99.71],[112.07,-91.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.055,2.749],[0,0],[5.7,0],[0,0],[1.89,-1.05],[0.88,0.35],[0,0],[2.17,0],[0,0],[0,-5.7],[0,0],[-5.7,0],[0,0],[-1.89,1.05],[-0.85,-0.29],[0,0],[-2.17,0],[0,0],[0,5.7],[0,0],[0.055,2.493]],"o":[[0,0],[0,0],[0,-5.71],[0,0],[-2.17,0],[-0.88,0.35],[0,0],[-1.89,-1.06],[0,0],[-5.71,0],[0,0],[0,5.71],[0,0],[2.17,0],[0.83,-0.33],[0,0],[1.89,1.05],[0,0],[5.71,0],[0,0],[-0.069,-5.452],[0,0]],"v":[[114.45,-15.54],[114.45,-36.12],[114.45,-91.75],[104.12,-102.08],[6.42,-102.08],[0.23,-100.48],[-2.52,-100.47],[-2.55,-100.47],[-8.74,-102.08],[-106.16,-102.08],[-116.49,-91.75],[-116.49,91.75],[-106.16,102.08],[-8.54,102.08],[-2.35,100.48],[0.25,100.42],[0.35,100.48],[7.83,102.08],[104.12,102.08],[114.45,91.75],[114.45,31.38],[114.45,-0.88]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.74,102.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":247,"st":30,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":244,"st":40,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.291,0],[0,0],[0,15.652],[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0]],"o":[[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0],[15.185,0],[0,0],[0,15.544]],"v":[[178.179,150],[-178.179,150],[-206,121.522],[-206,-121.522],[-178.179,-150],[178.286,-150],[206,-121.522],[206,121.63]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":244,"st":40,"bm":0}],"markers":[]}
diff --git a/res/raw/fold_setting_stay_awake_on_fold_lottie.json b/res/raw/fold_setting_stay_awake_on_fold_lottie.json
new file mode 100644
index 0000000..53b2ff0
--- /dev/null
+++ b/res/raw/fold_setting_stay_awake_on_fold_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":332,"w":412,"h":300,"nm":"Foldable_FoldingSetting_EDU_01_412x300","ddd":0,"assets":[{"id":"comp_0","nm":"Folded Youtube UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle 3470505","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[195.532,168,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[29,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470505","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 3470502","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,148.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,9],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470502","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"▽ Group 24","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.647,94.93,0],"ix":2,"l":2},"a":{"a":0,"k":[19,5.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":38,"h":11,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Vector 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[194.532,63,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.87,0],[0,-4.431],[0,0],[-2.777,0],[-1.047,-0.656]],"o":[[4.917,0],[0,0],[0.956,-2.133],[1.411,0],[1.184,-3.118]],"v":[[4.621,-4],[13.5,4],[-13.5,3.959],[-7.444,0.267],[-3.711,1.333]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"▽ Group 23","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[227.627,73.222,0],"ix":2,"l":2},"a":{"a":0,"k":[23,6,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":46,"h":12,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"▽ Group 21","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[222.901,108.93,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"▽ Group 18","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[241.405,106.27,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,14,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":28,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,89.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,69],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"▽ Group 17","refId":"comp_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.262,132.883,0],"ix":2,"l":2},"a":{"a":0,"k":[2,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":4,"h":8,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Vector 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.282,133,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36.25,0],[-36.25,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Vector 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[233.032,133,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[22,0],[-22,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Ellipse 7581","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[168.032,164,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14,14],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7581","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Rectangle 3470507","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.032,210.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,69],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470507","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_1","nm":"▽ Group 24","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[19.069,5.305,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.951,0],[0,-5.239],[0.044,-0.4],[0,0],[-2.087,0],[-0.755,-0.355],[-3.241,0],[-1.376,-1.465]],"o":[[5.194,0],[0,0.4],[0,0],[0.932,-1.687],[0.844,0],[1.154,-2.886],[2.175,0],[1.465,-3.374]],"v":[[9.656,-5.305],[19.069,4.107],[19.024,5.305],[-19.069,5.305],[-14.229,2.464],[-11.832,2.997],[-4.64,-1.887],[0.91,0.466]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_2","nm":"▽ Group 23","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22.865,6.238,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.376,-5.239],[-1.288,0],[-0.71,-2.619],[0,0],[-3.774,0],[-1.421,-0.977],[-5.372,0]],"o":[[0.977,-0.71],[2.841,0],[0,0],[1.199,-3.374],[1.82,0],[1.598,-4.795],[5.638,0]],"v":[[13.408,2.864],[16.915,1.798],[22.865,6.238],[-22.865,6.238],[-14.696,0.466],[-9.723,2.064],[1.731,-6.238]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_3","nm":"▽ Group 21","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 22","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_4","nm":"▽ Group 22","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-9.264,11.313],[9.264,11.313],[3.421,1.621],[7.839,1.621],[0,-11.313],[-7.839,1.621],[-3.421,1.621]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[8.017,10.6],[-7.981,10.6],[-2.102,0.909],[-6.52,0.909],[0.036,-9.959],[6.592,0.909],[2.173,0.909]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_5","nm":"▽ Group 18","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 20","refId":"comp_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[9.5,11.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":19,"h":23,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"▽ Group 19","refId":"comp_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.265,25.197,0],"ix":2,"l":2},"a":{"a":0,"k":[3,3,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":6,"h":6,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_6","nm":"▽ Group 20","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[9.264,11.313,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-9.264,11.313],[9.264,11.313],[3.421,1.621],[7.839,1.621],[0,-11.313],[-7.839,1.621],[-3.421,1.621]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[8.017,10.6],[-7.981,10.6],[-2.102,0.909],[-6.52,0.909],[0.036,-9.959],[6.592,0.909],[2.173,0.909]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_7","nm":"▽ Group 19","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[2.957,2.779,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-2.957,2.779],[2.957,2.779],[2.957,-2.779],[2.245,-2.779],[2.245,2.067],[-2.245,2.067],[-2.245,-2.779],[-2.957,-2.779]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_8","nm":"▽ Group 17","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.46,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_9","nm":"Unfolded YouTube UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 9","refId":"comp_10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[156.94,145.03,0],"ix":2,"l":2},"a":{"a":0,"k":[43,12,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":86,"h":24,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.64,71.83,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.5,0],[0,-10.8],[0,0],[-6.1,0],[-2.3,-1.6]],"o":[[10.8,0],[0,0],[2.1,-5.2],[3.1,0],[2.6,-7.6]],"v":[[10.15,-9.75],[29.65,9.75],[-29.65,9.65],[-16.35,0.65],[-8.15,3.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"▽ Group 8","refId":"comp_11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.49,96.13,0],"ix":2,"l":2},"a":{"a":0,"k":[51.5,14,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":103,"h":28,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"▽ Group 7","refId":"comp_12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111.22,226.963,0],"ix":2,"l":2},"a":{"a":0,"k":[2,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":4,"h":8,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Vector 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[166.369,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[44,0],[-44,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Vector 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256.869,227.275,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.5,0],[-46.5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"▽ Group 5","refId":"comp_13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[240.856,176.561,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"▽ Group 2","refId":"comp_15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[282.536,170.581,0],"ix":2,"l":2},"a":{"a":0,"k":[21,31.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":63,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.99,132.58,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[216,155],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_10","nm":"▽ Group 9","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[42.95,11.95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.9,0],[0,-11.8],[0.1,-0.9],[0,0],[-4.7,0],[-1.7,-0.8],[-7.3,0],[-3.1,-3.3]],"o":[[11.7,0],[0,0.9],[0,0],[2.1,-3.8],[1.9,0],[2.6,-6.5],[4.9,0],[3.3,-7.6]],"v":[[21.75,-11.95],[42.95,9.25],[42.85,11.95],[-42.95,11.95],[-32.05,5.55],[-26.65,6.75],[-10.45,-4.25],[2.05,1.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_11","nm":"▽ Group 8","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[51.5,14.05,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.1,-11.8],[-2.9,0],[-1.6,-5.9],[0,0],[-8.5,0],[-3.2,-2.2],[-12.1,0]],"o":[[2.2,-1.6],[6.4,0],[0,0],[2.7,-7.6],[4.1,0],[3.6,-10.8],[12.7,0]],"v":[[30.2,6.45],[38.1,4.05],[51.5,14.05],[-51.5,14.05],[-33.1,1.05],[-21.9,4.65],[3.9,-14.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_12","nm":"▽ Group 7","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.46,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,3.883,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,3.883],[0,-3.883]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_13","nm":"▽ Group 5","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 6","refId":"comp_14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_14","nm":"▽ Group 6","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_15","nm":"▽ Group 2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"▽ Group 4","refId":"comp_16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[21,25.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":42,"h":51,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"▽ Group 3","refId":"comp_17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.863,56.741,0],"ix":2,"l":2},"a":{"a":0,"k":[6.5,6.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":13,"h":13,"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_16","nm":"▽ Group 4","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[20.866,25.481,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-20.866,25.481],[20.866,25.481],[7.704,3.652],[17.656,3.652],[0,-25.481],[-17.656,3.652],[-7.704,3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[18.057,23.876],[-17.977,23.876],[-4.735,2.046],[-14.687,2.046],[0.08,-22.431],[14.847,2.046],[4.896,2.046]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_17","nm":"▽ Group 3","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6.661,6.26,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.661,6.26],[6.661,6.26],[6.661,-6.26],[5.056,-6.26],[5.056,4.655],[-5.056,4.655],[-5.056,-6.26],[-6.661,-6.26]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_18","nm":"Folded Gmail UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Ellipse 7590","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[86,6,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7590","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Ellipse 7594","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6,160,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7594","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse 7593","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6,128,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7593","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Ellipse 7592","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6,96,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7592","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Ellipse 7591","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6,64,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7591","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Ellipse 7589","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[6,32,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[12,12],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7589","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Rectangle 3470513","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,162.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470513","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Rectangle 3470511","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,130.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470511","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Rectangle 3470509","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,98.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470509","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Rectangle 3470507","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,66.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470507","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Rectangle 3470505","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,34.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470505","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Rectangle 3470512","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.5,156,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470512","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Rectangle 3470510","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.5,124,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470510","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Rectangle 3470508","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.5,92,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Rectangle 3470506","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.5,60,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470506","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Rectangle 3470504","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.5,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470504","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Rectangle 3470503","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[37,6.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[74,13],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470503","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]},{"id":"comp_19","nm":"Unfolded Gmail UI","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle 3470520","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,141.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470520","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 3470519","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,132.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470519","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle 3470518","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,123.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470518","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Rectangle 3470517","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,114.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470517","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rectangle 3470516","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,105.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470516","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Rectangle 3470515","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[114.994,96.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470515","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Ellipse 7584","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[296.494,74.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7584","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Ellipse 7598","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[154.494,209.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7598","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Ellipse 7597","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[154.494,182.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7597","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Ellipse 7596","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[154.494,155.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7596","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Ellipse 7595","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[154.494,128.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7595","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Ellipse 7579","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[154.494,101.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7579","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Rectangle 3470514","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[212.994,74.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470514","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Rectangle 3470502","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.994,74.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[32,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470502","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Rectangle 3470530","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.994,210.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470530","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Rectangle 3470528","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.994,183.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470528","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Rectangle 3470526","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.994,156.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470526","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Rectangle 3470524","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.994,129.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470524","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Rectangle 3470522","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.994,102.582,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470522","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Rectangle 3470529","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.494,204.082,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470529","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Rectangle 3470527","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.494,177.082,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470527","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Rectangle 3470525","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.494,150.082,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470525","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"Rectangle 3470523","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.494,123.082,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470523","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"Rectangle 3470521","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.494,96.082,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[17,4],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.23137255013,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 3470521","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[88,88,100],"ix":6,"l":2}},"ao":0,"ip":181,"op":781,"st":181,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":191,"s":[0,0,0],"to":[-10.833,0,0],"ti":[10.833,0,0]},{"t":231,"s":[-65,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":181,"op":395,"st":191,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey603","cl":"grey603","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":211,"s":[0,100,100]},{"t":231,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":211,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.839],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.495,137.576],[54.264,146.808],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.282,-146.679],[63.915,-137.047]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":212,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-9.436]],"o":[[0,8.464],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.623,136.911],[54.466,146.518],[-54.319,117.62],[-59.648,109.223],[-59.708,-109.282],[-54.594,-117.179],[54.309,-145.697],[63.951,-135.939]],"c":true}]},{"t":231,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.599,105.138],[54.368,114.37],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.31,-114.429],[63.943,-104.797]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":211,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":212,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":231,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":212,"op":396,"st":190,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".black 6","cl":"black","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":211,"s":[0,100,100]},{"t":231,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":211,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":212,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":231,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":212,"op":396,"st":190,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Folded Youtube UI","parent":2,"tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":231,"s":[0]},{"t":241,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":202,"op":802,"st":202,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".black 5","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":211,"s":[0,100,100]},{"t":231,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":211,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":212,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":231,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":212,"op":396,"st":190,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":199,"s":[206,150,0],"to":[1.444,0,0],"ti":[-2,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":200,"s":[214.667,150,0],"to":[2,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":201,"s":[218,150,0],"to":[1.083,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":202,"s":[221.167,150,0],"to":[1.083,0,0],"ti":[-1.111,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":203,"s":[224.5,150,0],"to":[1.111,0,0],"ti":[-1.333,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":204,"s":[227.833,150,0],"to":[1.333,0,0],"ti":[-1.528,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":205,"s":[232.5,150,0],"to":[1.528,0,0],"ti":[-1.583,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":206,"s":[237,150,0],"to":[1.583,0,0],"ti":[-1.889,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":207,"s":[242,150,0],"to":[1.889,0,0],"ti":[-2.167,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":208,"s":[248.333,150,0],"to":[2.167,0,0],"ti":[-2.278,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":209,"s":[255,150,0],"to":[2.278,0,0],"ti":[-2.5,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":210,"s":[262,150,0],"to":[2.5,0,0],"ti":[-3.556,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":211,"s":[270,150,0],"to":[3.556,0,0],"ti":[-2.222,0,0]},{"t":212,"s":[283.333,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[311.96,210.22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.52,5.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":151,"op":781,"st":181,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Unfolded YouTube UI","parent":2,"tt":1,"refId":"comp_9","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":191,"s":[100]},{"t":201,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":151,"op":751,"st":151,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey602","cl":"grey602","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":191,"s":[100,100,100]},{"t":212,"s":[0,100,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":191,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-2.282,113.897],[-17.976,113.897],[-121.273,113.897],[-130.36,105.242],[-130.36,-104.809],[-121.273,-113.897],[-1.197,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-8.034,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.243],[118.937,113.897],[20.423,113.897],[-1.182,113.897],[-16.193,117.028],[-121.36,141.834],[-130.185,134.804],[-130.289,-134.192],[-121.277,-142.03],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"t":212,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-1.125,113.897],[-16.101,117.189],[-121.089,144.98],[-130.176,136.326],[-130.286,-135.704],[-121.198,-144.793],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":191,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":207,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":211,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":212,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":151,"op":212,"st":191,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".black 4","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":191,"s":[99,99,100]},{"t":212,"s":[-1,99,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":191,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":207,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":210,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":211,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":212,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":151,"op":212,"st":191,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey604","cl":"grey604","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[116.74,102.33,0],"ix":1,"l":2},"s":{"a":0,"k":[114.5,114.5,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[115.717,-109.174],[-119.283,-109.174],[-119.283,299.701],[115.717,299.701]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.17,0],[0,0],[0,4.18],[0,0],[-4.17,0],[0,0],[0,-4.18]],"o":[[0,4.18],[0,0],[-4.18,0],[0,0],[0,-4.18],[0,0],[4.18,0],[0,0]],"v":[[112.07,92.13],[104.12,99.71],[-106.16,99.71],[-114.11,92.13],[-114.11,-91.75],[-106.16,-99.71],[104.12,-99.71],[112.07,-91.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.055,2.749],[0,0],[5.7,0],[0,0],[1.89,-1.05],[0.88,0.35],[0,0],[2.17,0],[0,0],[0,-5.7],[0,0],[-5.7,0],[0,0],[-1.89,1.05],[-0.85,-0.29],[0,0],[-2.17,0],[0,0],[0,5.7],[0,0],[0.055,2.493]],"o":[[0,0],[0,0],[0,-5.71],[0,0],[-2.17,0],[-0.88,0.35],[0,0],[-1.89,-1.06],[0,0],[-5.71,0],[0,0],[0,5.71],[0,0],[2.17,0],[0.83,-0.33],[0,0],[1.89,1.05],[0,0],[5.71,0],[0,0],[-0.069,-5.452],[0,0]],"v":[[114.45,-15.54],[114.45,-36.12],[114.45,-91.75],[104.12,-102.08],[6.42,-102.08],[0.23,-100.48],[-2.52,-100.47],[-2.55,-100.47],[-8.74,-102.08],[-106.16,-102.08],[-116.49,-91.75],[-116.49,91.75],[-106.16,102.08],[-8.54,102.08],[-2.35,100.48],[0.25,100.42],[0.35,100.48],[7.83,102.08],[104.12,102.08],[114.45,91.75],[114.45,31.38],[114.45,-0.88]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.74,102.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":151,"op":419,"st":181,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".black 3","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":151,"op":395,"st":191,"bm":0},{"ddd":0,"ind":15,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[88,88,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":151,"st":30,"bm":0},{"ddd":0,"ind":16,"ty":3,"nm":"Null 1","parent":15,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":40,"s":[0,0,0],"to":[-10.833,0,0],"ti":[10.833,0,0]},{"t":80,"s":[-65,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":151,"st":40,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".grey600","cl":"grey600","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.839],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.495,137.576],[54.264,146.808],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.282,-146.679],[63.915,-137.047]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-9.436]],"o":[[0,8.464],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.623,136.911],[54.466,146.518],[-54.319,117.62],[-59.648,109.223],[-59.708,-109.282],[-54.594,-117.179],[54.309,-145.697],[63.951,-135.939]],"c":true}]},{"t":80,"s":[{"i":[[0,0],[5.09,0],[0,0],[0,2.838],[0,0],[-2.838,0],[0,0],[0,-5.089]],"o":[[0,5.09],[0,0],[-2.838,0],[0,0],[0,-2.838],[0,0],[5.089,0],[0,0]],"v":[[63.599,105.138],[54.368,114.37],[-54.501,114.37],[-59.648,109.223],[-59.708,-109.282],[-54.56,-114.429],[54.31,-114.429],[63.943,-104.797]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":151,"st":39,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".black 2","cl":"black","parent":16,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":151,"st":39,"bm":0},{"ddd":0,"ind":19,"ty":0,"nm":"Folded Gmail UI","parent":16,"tt":1,"refId":"comp_18","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[0]},{"t":90,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[67.273,-5.682,0],"ix":2,"l":2},"a":{"a":0,"k":[46,83,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":92,"h":166,"ip":51,"op":151,"st":51,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".black","cl":"black","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.971,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-68.471,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":60,"s":[0,100,100]},{"t":80,"s":[99,99,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.001,"y":0},"t":60,"s":[{"i":[[0,1.789],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-1.339]],"v":[[66.136,-9.414],[66.108,-137.044],[54.305,-148.847],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.23,149.034],[66.032,137.232],[66.136,27.401]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0},"t":61,"s":[{"i":[[0,2.744],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,14.182],[0,0]],"o":[[0,0],[0,-14.188],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-2.275]],"v":[[76.36,-9.414],[76.369,-135.937],[54.341,-147.74],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.359,148.37],[76.385,136.568],[76.36,27.401]],"c":true}]},{"t":80,"s":[{"i":[[0,4.914],[0,0],[6.519,0],[0,0],[0,-2.523],[0,0],[-2.523,0],[0,0],[0,6.518],[0,0]],"o":[[0,0],[0,-6.519],[0,0],[-2.523,0],[0,0],[0,2.523],[0,0],[6.518,0],[0,0],[0,-4.401]],"v":[[66.136,-9.414],[66.136,-104.794],[54.333,-116.597],[-63.903,-116.597],[-68.471,-112.028],[-68.471,112.028],[-63.903,116.597],[54.334,116.597],[66.136,104.795],[66.136,27.401]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":61,"op":151,"st":39,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Mask","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[206,150,0],"to":[1.444,0,0],"ti":[-2,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":49,"s":[214.667,150,0],"to":[2,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[218,150,0],"to":[1.083,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[221.167,150,0],"to":[1.083,0,0],"ti":[-1.111,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":52,"s":[224.5,150,0],"to":[1.111,0,0],"ti":[-1.333,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[227.833,150,0],"to":[1.333,0,0],"ti":[-1.528,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":54,"s":[232.5,150,0],"to":[1.528,0,0],"ti":[-1.583,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55,"s":[237,150,0],"to":[1.583,0,0],"ti":[-1.889,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[242,150,0],"to":[1.889,0,0],"ti":[-2.167,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":57,"s":[248.333,150,0],"to":[2.167,0,0],"ti":[-2.278,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[255,150,0],"to":[2.278,0,0],"ti":[-2.5,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[262,150,0],"to":[2.5,0,0],"ti":[-3.556,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[270,150,0],"to":[3.556,0,0],"ti":[-2.222,0,0]},{"t":61,"s":[283.333,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[311.96,210.22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.52,5.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":151,"st":30,"bm":0},{"ddd":0,"ind":22,"ty":0,"nm":"Unfolded Gmail UI","parent":16,"tt":1,"refId":"comp_19","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"t":50,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[113.636,113.636,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":151,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey600","cl":"grey600","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"t":61,"s":[0,100,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-2.282,113.897],[-17.976,113.897],[-121.273,113.897],[-130.36,105.242],[-130.36,-104.809],[-121.273,-113.897],[-1.197,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-8.034,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.243],[118.937,113.897],[20.423,113.897],[-1.182,113.897],[-16.193,117.028],[-121.36,141.834],[-130.185,134.804],[-130.289,-134.192],[-121.277,-142.03],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]},{"t":61,"s":[{"i":[[0,0],[4.771,0],[0,0],[0,0],[0,0],[0,0],[0,4.772],[0,0],[-4.771,0],[0,0],[0,0],[0,-4.772]],"o":[[0,4.772],[0,0],[0,0],[0,0],[0,0],[-4.771,0],[0,0],[0,-4.772],[0,0],[0,0],[4.771,0],[0,0]],"v":[[128.025,105.242],[118.937,113.897],[20.423,113.897],[-1.125,113.897],[-16.101,117.189],[-121.089,144.98],[-130.176,136.326],[-130.286,-135.704],[-121.198,-144.793],[-1.188,-113.897],[118.937,-113.897],[128.025,-104.809]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".black","cl":"black","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":40,"s":[99,99,100]},{"t":61,"s":[-1,99,100]}],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":40,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.495,0.571],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.733,0.815],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.787,-0.915],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.2,-0.463],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-115.408],[-10,-118.046],[-124.313,-139.448],[-136.266,-129.393],[-136.179,129.543],[-124.572,138.847],[-9.85,117.863],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.498,0.671],[7.261,0],[0,-6.52],[0,0],[-17.913,0],[0,0],[0,0],[-2.833,0.748],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.896,-0.865],[0,0],[-23.138,0],[0,0],[0,6.52],[10.232,0],[0,0],[2.152,-0.545],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-12.716,-117.624],[-123.042,-143.651],[-144.273,-133.721],[-144.17,133.897],[-128.267,144.577],[-10.465,117.238],[-8.936,116.926],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.499,0.698],[0,0],[0,-12.135],[0,0],[-34.442,0],[0,0],[0,0],[-2.859,0.73],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.925,-0.851],[0,0],[-32.058,0],[0,0],[0,11.078],[0,0],[0,0],[2.14,-0.566],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.836],[-126.224,-145.794],[-160.39,-134.865],[-160.283,135.047],[-126.011,146.227],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.938,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]},{"t":61,"s":[{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.5,0.717],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.879,0.717],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.946,-0.842],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.13,-0.582],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.842],[-121.197,-147.509],[-133.002,-135.704],[-132.892,135.892],[-121.088,147.697],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":40,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":".grey600","cl":"grey600","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[116.74,102.33,0],"ix":1,"l":2},"s":{"a":0,"k":[114.5,114.5,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[115.717,-109.174],[-119.283,-109.174],[-119.283,299.701],[115.717,299.701]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.17,0],[0,0],[0,4.18],[0,0],[-4.17,0],[0,0],[0,-4.18]],"o":[[0,4.18],[0,0],[-4.18,0],[0,0],[0,-4.18],[0,0],[4.18,0],[0,0]],"v":[[112.07,92.13],[104.12,99.71],[-106.16,99.71],[-114.11,92.13],[-114.11,-91.75],[-106.16,-99.71],[104.12,-99.71],[112.07,-91.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.055,2.749],[0,0],[5.7,0],[0,0],[1.89,-1.05],[0.88,0.35],[0,0],[2.17,0],[0,0],[0,-5.7],[0,0],[-5.7,0],[0,0],[-1.89,1.05],[-0.85,-0.29],[0,0],[-2.17,0],[0,0],[0,5.7],[0,0],[0.055,2.493]],"o":[[0,0],[0,0],[0,-5.71],[0,0],[-2.17,0],[-0.88,0.35],[0,0],[-1.89,-1.06],[0,0],[-5.71,0],[0,0],[0,5.71],[0,0],[2.17,0],[0.83,-0.33],[0,0],[1.89,1.05],[0,0],[5.71,0],[0,0],[-0.069,-5.452],[0,0]],"v":[[114.45,-15.54],[114.45,-36.12],[114.45,-91.75],[104.12,-102.08],[6.42,-102.08],[0.23,-100.48],[-2.52,-100.47],[-2.55,-100.47],[-8.74,-102.08],[-106.16,-102.08],[-116.49,-91.75],[-116.49,91.75],[-106.16,102.08],[-8.54,102.08],[-2.35,100.48],[0.25,100.42],[0.35,100.48],[7.83,102.08],[104.12,102.08],[114.45,91.75],[114.45,31.38],[114.45,-0.88]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.74,102.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":151,"st":30,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":".black","cl":"black","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,0,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-2,-197],[-237,-197],[-237,211.874],[-2,211.874]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.295,0.044],[0,0],[6.52,0],[0,0],[2.164,-1.2],[1.012,0.395],[0,0],[2.474,0],[0,0],[0,-6.52],[0,0],[-6.52,0],[0,0],[0,0],[-2.164,1.2],[-0.966,-0.33],[0,0],[-2.474,0],[0,0],[0,0],[0,6.519],[0,0],[0,1.668],[0,0]],"o":[[0,0],[0,-6.52],[0,0],[-2.474,0],[-1.008,0.404],[0,0],[-2.164,-1.2],[0,0],[-6.52,0],[0,0],[0,6.52],[0,0],[0,0],[2.474,0],[0.951,-0.381],[0,0],[2.163,1.2],[0,0],[0,0],[6.519,0],[0,0],[1.295,-0.044],[0,0],[0,-1.668]],"v":[[130.741,-9.416],[130.741,-104.809],[118.936,-116.613],[7.323,-116.613],[0.252,-114.783],[-2.892,-114.769],[-2.929,-114.783],[-10,-116.613],[-121.272,-116.613],[-133.077,-104.809],[-133.077,104.809],[-121.272,116.613],[-9.85,116.613],[-9.755,116.613],[-2.684,114.783],[0.286,114.719],[0.401,114.783],[8.942,116.613],[9.038,116.613],[118.937,116.613],[130.741,104.81],[130.741,27.405],[133.077,24.344],[133.077,-6.354]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":151,"st":40,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.291,0],[0,0],[0,15.652],[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0]],"o":[[0,0],[-15.291,0],[0,0],[0,-15.652],[0,0],[15.185,0],[0,0],[0,15.544]],"v":[[178.179,150],[-178.179,150],[-206,121.522],[-206,-121.522],[-178.179,-150],[178.286,-150],[206,-121.522],[206,121.63]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":332,"st":40,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 1723d17..f454954 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1420,20 +1420,49 @@
<item>color_battery_anomaly_yellow_selector</item>
</string-array>
- <!-- The following 3 arrays are for power anomaly tips card. Please keep them the same size. -->
- <string-array name="power_anomaly_titles">
- <item>Turn on adaptive brightness to extend battery life</item>
- <item>Reduce screen timeout to extend battery life</item>
+ <!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
+ <string-array name="power_anomaly_title_ids" translatable="false">
+ <item>battery_tips_settings_summary_brightness</item>
+ <item>battery_tips_settings_summary_screen_timeout</item>
+ <item>battery_tips_apps_summary_always_high</item>
+ <item>battery_tips_apps_summary_higher_than_usual</item>
+ <item>battery_tips_apps_summary_always_high_in_background</item>
+ <item>battery_tips_apps_summary_higher_than_usual_in_background</item>
+ <item>battery_tips_apps_summary_always_high_in_foreground</item>
+ <item>battery_tips_apps_summary_higher_than_usual_in_foreground</item>
</string-array>
<string-array name="power_anomaly_main_btn_strings" translatable="false">
<item>@string/battery_tips_card_action_button</item>
<item>@string/battery_tips_card_action_button</item>
+ <item>@string/battery_tips_card_action_button_check</item>
+ <item>@string/battery_tips_card_action_button_check</item>
+ <item>@string/battery_tips_card_action_button_check</item>
+ <item>@string/battery_tips_card_action_button_check</item>
+ <item>@string/battery_tips_card_action_button_check</item>
+ <item>@string/battery_tips_card_action_button_check</item>
</string-array>
<string-array name="power_anomaly_dismiss_btn_strings" translatable="false">
<item>@string/battery_tips_card_dismiss_button</item>
<item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ <item>@string/battery_tips_card_dismiss_button</item>
+ </string-array>
+
+ <string-array name="power_anomaly_hint_messages" translatable="false">
+ <item></item>
+ <item></item>
+ <item>@string/battery_app_item_hint</item>
+ <item>@string/battery_app_item_hint</item>
+ <item>@string/battery_app_item_hint_in_bg</item>
+ <item>@string/battery_app_item_hint_in_bg</item>
+ <item>@string/battery_app_item_hint_in_fg</item>
+ <item>@string/battery_app_item_hint_in_fg</item>
</string-array>
<!-- A list of not supporting Terms of Address. [DO NOT TRANSLATE] -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a8ad434..205e2a3 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -403,6 +403,7 @@
<!-- Battery tips card view component -->
<dimen name="battery_tips_card_corner_radius_small">4dp</dimen>
<dimen name="battery_tips_card_corner_radius_normal">24dp</dimen>
+ <dimen name="battery_hints_chip_corner_radius">8dp</dimen>
<!-- Dimensions for Dream settings cards -->
<dimen name="dream_item_min_column_width">174dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e4b68d0..f8eaaff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7387,7 +7387,7 @@
<string name="vibrate_when_ringing_option_ramping_ringer">Vibrate first then ring gradually</string>
<!-- Sound: Title for the option enabling spatializer effect. [CHAR LIMIT=30] -->
- <string name="spatial_audio_title">Spatial audio</string>
+ <string name="spatial_audio_title">Spatial Audio</string>
<!-- Sound: Other sounds: Title for the option enabling touch sounds for dial pad tones. [CHAR LIMIT=30] -->
<string name="dial_pad_tones_title">Dial pad tones</string>
@@ -7434,9 +7434,6 @@
<!-- Setting summary for controlling how caption text display in real time [CHAR LIMIT=NONE]-->
<string name="live_caption_summary">Automatically caption media</string>
- <!-- Output device type for the phone speaker that is available for spatializer effect. [CHAR LIMIT=NONE]-->
- <string name="spatial_audio_speaker">Phone speaker</string>
-
<!-- Output device type for the wired headphones that is available for spatializer effect. [CHAR LIMIT=NONE]-->
<string name="spatial_audio_wired_headphones">Wired headphones</string>
@@ -9821,12 +9818,51 @@
<!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
<string name="battery_tips_card_action_button">View Settings</string>
+ <!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
+ <string name="battery_tips_card_action_button_check">Check</string>
+
<!-- Label of dismiss button in battery tips card [CHAR LIMIT=50] -->
<string name="battery_tips_card_dismiss_button">Got it</string>
<!-- Feedback card message in battery tips card [CHAR LIMIT=NONE] -->
<string name="battery_tips_card_feedback_info">Is this message helpful?</string>
+ <!-- Content description for battery hints warning icon of app anomaly [CHAR LIMIT=NONE] -->
+ <string name="battery_hints_warning_icon_a11y">Battery tips warning icon</string>
+
+ <!-- Summary of settings anomaly for adaptive brightness [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_settings_summary_brightness">Turn on adaptive brightness to extend battery life</string>
+
+ <!-- Summary of settings anomaly for screen timeout [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_settings_summary_screen_timeout">Reduce screen timeout to extend battery life</string>
+
+ <!-- Summary of apps anomaly for always high [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_always_high"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery</string>
+
+ <!-- Summary of apps anomaly for higher than usual [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_higher_than_usual"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual</string>
+
+ <!-- Summary of apps anomaly for always high in background [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_always_high_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the background</string>
+
+ <!-- Summary of apps anomaly for higher than usual in background [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_higher_than_usual_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the background</string>
+
+ <!-- Summary of apps anomaly for always high in foreground [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_always_high_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the foreground</string>
+
+ <!-- Summary of apps anomaly for higher than usual in foreground [CHAR LIMIT=NONE] -->
+ <string name="battery_tips_apps_summary_higher_than_usual_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the foreground</string>
+
+ <!-- Label of hint for apps anomaly in battery usage [CHAR LIMIT=NONE] -->
+ <string name="battery_app_item_hint">High battery usage</string>
+
+ <!-- Label of hint for apps background anomaly in battery usage [CHAR LIMIT=NONE] -->
+ <string name="battery_app_item_hint_in_bg">High battery usage in the background</string>
+
+ <!-- Label of hint for apps foreground anomaly in battery usage [CHAR LIMIT=NONE] -->
+ <string name="battery_app_item_hint_in_fg">High battery usage in the foreground</string>
+
<!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
<string name="filter_battery_unrestricted_title">Unrestricted</string>
@@ -12434,4 +12470,7 @@
<string name="grammatical_gender_title">Grammatical gender</string>
<!-- Developer settings: select Grammatical gender dialog title [CHAR LIMIT=50]-->
<string name="grammatical_gender_dialog_title">Select Grammatical gender</string>
+
+ <!-- Developer settings: Title for the screen allowing user to control Quarantined apps [CHAR LIMIT=50] -->
+ <string name="quarantined_apps_title">Quarantined Apps</string>
</resources>
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index db46a1a..90c40a6 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -116,7 +116,7 @@
<Preference
android:key="aspect_ratio_apps"
- android:title="@string/aspect_ratio_title"
+ android:title="@string/aspect_ratio_experimental_title"
android:summary="@string/summary_placeholder"
android:order="22"
settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
diff --git a/res/xml/data_usage_list.xml b/res/xml/data_usage_list.xml
index 28f09c6..791fc86 100644
--- a/res/xml/data_usage_list.xml
+++ b/res/xml/data_usage_list.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="usage_amount"
@@ -32,6 +33,7 @@
<PreferenceCategory
android:key="apps_group"
- android:layout="@layout/preference_category_no_label" />
+ android:layout="@layout/preference_category_no_label"
+ settings:controller="com.android.settings.datausage.DataUsageListAppsController" />
</PreferenceScreen>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index ab1ee41..4135750 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -736,6 +736,12 @@
android:title="@string/enable_notes_role_title"
android:summary="@string/enable_notes_role_summary" />
+ <Preference
+ android:key="quarantined_apps"
+ android:title="@string/quarantined_apps_title"
+ settings:controller="com.android.settings.development.quarantine.QuarantinedAppsPreferenceController"
+ android:fragment="com.android.settings.development.quarantine.QuarantinedAppsFragment" />
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/quarantined_apps.xml b/res/xml/quarantined_apps.xml
new file mode 100644
index 0000000..69a90d6
--- /dev/null
+++ b/res/xml/quarantined_apps.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="quarantined_apps_screen"
+ android:title="@string/quarantined_apps_title"
+ settings:controller="com.android.settings.development.quarantine.QuarantinedAppsScreenController"
+ settings:searchable="true">
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml
index ec76caa..f95b678 100644
--- a/res/xml/user_aspect_ratio_details.xml
+++ b/res/xml/user_aspect_ratio_details.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:title="@string/aspect_ratio_title">
+ android:title="@string/aspect_ratio_experimental_title">
<com.android.settingslib.widget.ActionButtonsPreference
android:key="header_view" />
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 7cd4493..ab55bec 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -362,6 +362,8 @@
public static class ClonedAppsListActivity extends SettingsActivity { /* empty */ }
/** Activity to manage Aspect Ratio app list page */
public static class UserAspectRatioAppListActivity extends SettingsActivity { /* empty */ }
+ /** Activity to manage Aspect Ratio app page */
+ public static class UserAspectRatioAppActivity extends SettingsActivity { /* empty */ }
public static class NotificationReviewPermissionsActivity extends SettingsActivity { /* empty */ }
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ChannelNotificationSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/HearingAidUtils.java b/src/com/android/settings/accessibility/HearingAidUtils.java
index 4734c55..edf2d9f 100644
--- a/src/com/android/settings/accessibility/HearingAidUtils.java
+++ b/src/com/android/settings/accessibility/HearingAidUtils.java
@@ -42,9 +42,10 @@
*/
public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
@NonNull CachedBluetoothDevice device, int launchPage) {
- // No need to show the pair another ear dialog if the device supports and enables CSIP.
+ // No need to show the pair another ear dialog if the device supports CSIP.
// CSIP will pair other devices in the same set automatically.
- if (isCsipSupportedAndEnabled(device)) {
+ if (device.getProfiles().stream().anyMatch(
+ profile -> profile instanceof CsipSetCoordinatorProfile)) {
return;
}
if (device.isConnectedAshaHearingAidDevice()
@@ -63,10 +64,4 @@
HearingAidPairingDialogFragment.newInstance(device.getAddress(), launchPage)
.show(fragmentManager, HearingAidPairingDialogFragment.TAG);
}
-
- private static boolean isCsipSupportedAndEnabled(@NonNull CachedBluetoothDevice device) {
- return device.getProfiles().stream().anyMatch(
- profile -> (profile instanceof CsipSetCoordinatorProfile)
- && (profile.isEnabled(device.getDevice())));
- }
}
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 182e5ae..98d56cc 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -159,6 +159,16 @@
return CONDITIONALLY_UNAVAILABLE;
}
+ // If we are in work profile mode and there is no user then we
+ // should hide for now. We use CONDITIONALLY_UNAVAILABLE
+ // because it is possible for the user to be set later.
+ if (mIsWorkProfile) {
+ UserHandle workProfile = getWorkProfileUserHandle();
+ if (workProfile == null) {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+ }
+
return AVAILABLE;
}
@@ -186,12 +196,17 @@
fragment.getSettingsLifecycle().addObserver(this);
mFragmentManager = fragmentManager;
mIsWorkProfile = isWorkProfile;
+
setDelegate(delegate);
verifyReceivedIntent(launchIntent);
// Recreate the content observers because the user might have changed.
mSettingsContentObserver.unregister();
mSettingsContentObserver.register();
+
+ // When we set the mIsWorkProfile above we should try and force a refresh
+ // so we can get the correct data.
+ delegate.forceDelegateRefresh();
}
/**
@@ -302,10 +317,15 @@
null);
}
- private Set<ComponentName> buildComponentNameSet(List<CredentialProviderInfo> providers) {
+ private Set<ComponentName> buildComponentNameSet(
+ List<CredentialProviderInfo> providers, boolean removeNonPrimary) {
Set<ComponentName> output = new HashSet<>();
for (CredentialProviderInfo cpi : providers) {
+ if (removeNonPrimary && !cpi.isPrimary()) {
+ continue;
+ }
+
output.add(cpi.getComponentName());
}
@@ -321,13 +341,16 @@
List<CredentialProviderInfo> newProviders =
mCredentialManager.getCredentialProviderServices(
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
- Set<ComponentName> newComponents = buildComponentNameSet(newProviders);
+ Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
+ Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);
// Get the list of old components
- Set<ComponentName> oldComponents = buildComponentNameSet(mServices);
+ Set<ComponentName> oldComponents = buildComponentNameSet(mServices, false);
+ Set<ComponentName> oldPrimaryComponents = buildComponentNameSet(mServices, true);
// If the sets are equal then don't update the UI.
- if (oldComponents.equals(newComponents)) {
+ if (oldComponents.equals(newComponents)
+ && oldPrimaryComponents.equals(newPrimaryComponents)) {
return;
}
@@ -698,12 +721,22 @@
protected int getUser() {
if (mIsWorkProfile) {
- UserHandle workProfile = Utils.getManagedProfile(UserManager.get(mContext));
- return workProfile.getIdentifier();
+ UserHandle workProfile = getWorkProfileUserHandle();
+ if (workProfile != null) {
+ return workProfile.getIdentifier();
+ }
}
return UserHandle.myUserId();
}
+ private @Nullable UserHandle getWorkProfileUserHandle() {
+ if (mIsWorkProfile) {
+ return Utils.getManagedProfile(UserManager.get(mContext));
+ }
+
+ return null;
+ }
+
/** Called when the dialog button is clicked. */
private static interface DialogHost {
void onDialogClick(int whichButton);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
index d65e057..155ced5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java
@@ -30,10 +30,10 @@
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
-import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/** Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment. */
@@ -95,7 +95,7 @@
return dialog;
}
- public static void showErrorDialog(BiometricEnrollBase host, int errMsgId, boolean isSetup) {
+ public static void showErrorDialog(FragmentActivity host, int errMsgId, boolean isSetup) {
if (host.isFinishing()) {
return;
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
index 1f57198..2c8ee8f 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
@@ -27,12 +27,18 @@
import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.EnrollReason
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerEnrollStateViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.toOriginalReason
import com.android.settings.password.ChooseLockSettingsHelper
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.channels.onFailure
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
@@ -67,6 +73,16 @@
suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray>
/**
+ * Runs [FingerprintManager.enroll] with the [hardwareAuthToken] and [EnrollReason] for this
+ * enrollment. Returning the [FingerEnrollStateViewModel] that represents this fingerprint
+ * enrollment state.
+ */
+ suspend fun enroll(
+ hardwareAuthToken: ByteArray?,
+ enrollReason: EnrollReason,
+ ): Flow<FingerEnrollStateViewModel>
+
+ /**
* Removes the given fingerprint, returning true if it was successfully removed and false
* otherwise
*/
@@ -133,6 +149,51 @@
override val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
+ override suspend fun enroll(
+ hardwareAuthToken: ByteArray?,
+ enrollReason: EnrollReason,
+ ): Flow<FingerEnrollStateViewModel> = callbackFlow {
+ var streamEnded = false
+ val enrollmentCallback =
+ object : FingerprintManager.EnrollmentCallback() {
+ override fun onEnrollmentProgress(remaining: Int) {
+ trySend(FingerEnrollStateViewModel.EnrollProgress(remaining)).onFailure { error ->
+ Log.d(TAG, "onEnrollmentProgress($remaining) failed to send, due to $error")
+ }
+ if (remaining == 0) {
+ streamEnded = true
+ }
+ }
+
+ override fun onEnrollmentHelp(helpMsgId: Int, helpString: CharSequence?) {
+ trySend(FingerEnrollStateViewModel.EnrollHelp(helpMsgId, helpString.toString()))
+ .onFailure { error -> Log.d(TAG, "onEnrollmentHelp failed to send, due to $error") }
+ }
+
+ override fun onEnrollmentError(errMsgId: Int, errString: CharSequence?) {
+ trySend(FingerEnrollStateViewModel.EnrollError(errMsgId, errString.toString()))
+ .onFailure { error -> Log.d(TAG, "onEnrollmentError failed to send, due to $error") }
+ streamEnded = true
+ }
+ }
+
+ val cancellationSignal = CancellationSignal()
+ fingerprintManager.enroll(
+ hardwareAuthToken,
+ cancellationSignal,
+ applicationContext.userId,
+ enrollmentCallback,
+ enrollReason.toOriginalReason()
+ )
+ awaitClose {
+ // If the stream has not been ended, and the user has stopped collecting the flow
+ // before it was over, send cancel.
+ if (!streamEnded) {
+ cancellationSignal.cancel()
+ }
+ }
+ }
+
override suspend fun removeFingerprint(fp: FingerprintViewModel): Boolean = suspendCoroutine {
val callback =
object : RemovalCallback() {
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
index f6d20ae..31afcb7 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
@@ -20,11 +20,13 @@
import android.app.Activity
import android.content.Intent
import android.content.res.ColorStateList
+import android.content.res.Configuration
import android.graphics.Color
import android.hardware.fingerprint.FingerprintManager
import android.os.Bundle
import android.provider.Settings
import android.util.Log
+import android.view.accessibility.AccessibilityManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
@@ -43,18 +45,22 @@
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollmentIntroV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Confirmation
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Education
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Enrollment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Finish
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Intro
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.LaunchConfirmDeviceCredential
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
import com.android.settings.password.ChooseLockGeneric
import com.android.settings.password.ChooseLockSettingsHelper
import com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE
@@ -70,8 +76,12 @@
* children fragments.
*/
class FingerprintEnrollmentV2Activity : FragmentActivity() {
- private lateinit var navigationViewModel: FingerprintEnrollmentNavigationViewModel
+ private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
+ private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
+ private lateinit var accessibilityViewModel: AccessibilityViewModel
+ private lateinit var foldStateViewModel: FoldStateViewModel
+ private lateinit var orientationStateViewModel: OrientationStateViewModel
private val coroutineDispatcher = Dispatchers.Default
/** Result listener for ChooseLock activity flow. */
@@ -94,6 +104,11 @@
super.onAttachedToWindow()
}
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ foldStateViewModel.onConfigurationChange(newConfig)
+ }
+
@ColorInt
private fun getBackgroundColor(): Int {
val stateList: ColorStateList? =
@@ -170,24 +185,61 @@
navigationViewModel =
ViewModelProvider(
this,
- FingerprintEnrollmentNavigationViewModel.FingerprintEnrollmentNavigationViewModelFactory(
+ FingerprintEnrollNavigationViewModel.FingerprintEnrollNavigationViewModelFactory(
backgroundDispatcher,
interactor,
gatekeeperViewModel,
gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo, /* canSkipConfirm */
)
- )[FingerprintEnrollmentNavigationViewModel::class.java]
+ )[FingerprintEnrollNavigationViewModel::class.java]
+
+ // Initialize FoldStateViewModel
+ foldStateViewModel =
+ ViewModelProvider(this, FoldStateViewModel.FoldStateViewModelFactory(context))[
+ FoldStateViewModel::class.java]
+ foldStateViewModel.onConfigurationChange(resources.configuration)
// Initialize FingerprintViewModel
- ViewModelProvider(
- this,
- FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(interactor)
- )[FingerprintEnrollViewModel::class.java]
+ fingerprintEnrollViewModel =
+ ViewModelProvider(
+ this,
+ FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
+ interactor,
+ backgroundDispatcher
+ )
+ )[FingerprintEnrollViewModel::class.java]
// Initialize scroll view model
ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[
FingerprintScrollViewModel::class.java]
+ // Initialize AccessibilityViewModel
+ accessibilityViewModel =
+ ViewModelProvider(
+ this,
+ AccessibilityViewModel.AccessibilityViewModelFactory(
+ getSystemService(AccessibilityManager::class.java)!!
+ )
+ )[AccessibilityViewModel::class.java]
+
+ // Initialize OrientationViewModel
+ orientationStateViewModel =
+ ViewModelProvider(this, OrientationStateViewModel.OrientationViewModelFactory(context))[
+ OrientationStateViewModel::class.java]
+
+ // Initialize FingerprintEnrollFindSensorViewModel
+ ViewModelProvider(
+ this,
+ FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory(
+ navigationViewModel,
+ fingerprintEnrollViewModel,
+ gatekeeperViewModel,
+ accessibilityViewModel,
+ foldStateViewModel,
+ orientationStateViewModel
+ )
+ )[FingerprintEnrollFindSensorViewModel::class.java]
+
lifecycleScope.launch {
navigationViewModel.navigationViewModel.filterNotNull().collect {
Log.d(TAG, "navigationStep $it")
@@ -198,7 +250,7 @@
Confirmation -> FingerprintEnrollConfirmationV2Fragment::class.java as Class<Fragment>
Education -> FingerprintEnrollFindSensorV2Fragment::class.java as Class<Fragment>
Enrollment -> FingerprintEnrollEnrollingV2Fragment::class.java as Class<Fragment>
- Intro -> FingerprintEnrollmentIntroV2Fragment::class.java as Class<Fragment>
+ Intro -> FingerprintEnrollIntroV2Fragment::class.java as Class<Fragment>
else -> null
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
index df4cf72..b12491f 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
@@ -19,7 +19,7 @@
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
/**
* A fragment to indicate that fingerprint enrollment has been completed.
@@ -33,7 +33,7 @@
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
val navigationViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollmentNavigationViewModel::class.java]
+ ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
}
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
index 915aa1f..0140d57 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
@@ -19,16 +19,17 @@
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.R
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
/** A fragment that is responsible for enrolling a users fingerprint. */
-class FingerprintEnrollEnrollingV2Fragment : Fragment() {
+class FingerprintEnrollEnrollingV2Fragment : Fragment(R.layout.fingerprint_enroll_enrolling) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
val navigationViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollmentNavigationViewModel::class.java]
+ ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
}
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
index e9e1db2..dcdcccf 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
@@ -17,26 +17,197 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.Surface
+import android.view.View
+import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.airbnb.lottie.LottieAnimationView
import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog
+import com.android.settings.biometrics.fingerprint.FingerprintFindSensorAnimation
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.google.android.setupcompat.template.FooterBarMixin
+import com.google.android.setupcompat.template.FooterButton
+import com.google.android.setupdesign.GlifLayout
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+private const val TAG = "FingerprintEnrollFindSensorV2Fragment"
/**
* A fragment that is used to educate the user about the fingerprint sensor on this device.
*
+ * If the sensor is not a udfps sensor, this fragment listens to fingerprint enrollment for
+ * proceeding to the enroll enrolling.
+ *
* The main goals of this page are
* 1. Inform the user where the fingerprint sensor is on their device
* 2. Explain to the user how the enrollment process shown by [FingerprintEnrollEnrollingV2Fragment]
* will work.
*/
-class FingerprintEnrollFindSensorV2Fragment : Fragment(R.layout.fingerprint_v2_enroll_find_sensor) {
+class FingerprintEnrollFindSensorV2Fragment : Fragment() {
+ // This is only for non-udfps or non-sfps sensor. For udfps and sfps, we show lottie.
+ private var animation: FingerprintFindSensorAnimation? = null
+
+ private var contentLayoutId: Int = -1
+ private lateinit var viewModel: FingerprintEnrollFindSensorViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (savedInstanceState == null) {
- val navigationViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollmentNavigationViewModel::class.java]
+ viewModel =
+ ViewModelProvider(requireActivity())[FingerprintEnrollFindSensorViewModel::class.java]
+ lifecycleScope.launch {
+ viewModel.sensorType.collect {
+ contentLayoutId =
+ when (it) {
+ FingerprintSensorType.UDFPS_OPTICAL,
+ FingerprintSensorType.UDFPS_ULTRASONIC -> R.layout.udfps_enroll_find_sensor_layout
+ FingerprintSensorType.POWER_BUTTON -> R.layout.sfps_enroll_find_sensor_layout
+ else -> R.layout.fingerprint_v2_enroll_find_sensor
+ }
+ }
}
}
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(contentLayoutId, container, false).also { it ->
+ val view = it!! as GlifLayout
+
+ // Set up header and description
+ lifecycleScope.launch { viewModel.sensorType.collect { setTexts(it, view) } }
+
+ // Set up footer bar
+ val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
+ setupSecondaryButton(footerBarMixin)
+ lifecycleScope.launch {
+ viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
+ }
+
+ // Set up lottie or animation
+ lifecycleScope.launch {
+ viewModel.showSfpsLottie.collect { (isFolded, rotation) ->
+ setupLottie(view, getSfpsIllustrationLottieAnimation(isFolded, rotation))
+ }
+ }
+ lifecycleScope.launch {
+ viewModel.showUdfpsLottie.collect { isAccessibilityEnabled ->
+ val lottieAnimation =
+ if (isAccessibilityEnabled) R.raw.udfps_edu_a11y_lottie else R.raw.udfps_edu_lottie
+ setupLottie(view, lottieAnimation) { viewModel.proceedToEnrolling() }
+ }
+ }
+ lifecycleScope.launch {
+ viewModel.showRfpsAnimation.collect {
+ animation = view.findViewById(R.id.fingerprint_sensor_location_animation)
+ animation!!.startAnimation()
+ }
+ }
+
+ lifecycleScope.launch {
+ viewModel.showErrorDialog.collect { (errMsgId, isSetup) ->
+ // TODO: Covert error dialog kotlin as well
+ FingerprintErrorDialog.showErrorDialog(requireActivity(), errMsgId, isSetup)
+ }
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ animation?.stopAnimation()
+ super.onDestroy()
+ }
+
+ private fun setupSecondaryButton(footerBarMixin: FooterBarMixin) {
+ footerBarMixin.secondaryButton =
+ FooterButton.Builder(requireActivity())
+ .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
+ .setListener {
+ run {
+ // TODO: Show the dialog for suw
+ Log.d(TAG, "onSkipClicked")
+ // TODO: Finish activity in the root activity instead.
+ requireActivity().finish()
+ }
+ }
+ .setButtonType(FooterButton.ButtonType.SKIP)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
+ .build()
+ }
+
+ private fun setupPrimaryButton(footerBarMixin: FooterBarMixin) {
+ footerBarMixin.primaryButton =
+ FooterButton.Builder(requireActivity())
+ .setText(R.string.security_settings_udfps_enroll_find_sensor_start_button)
+ .setListener {
+ run {
+ Log.d(TAG, "onStartButtonClick")
+ viewModel.proceedToEnrolling()
+ }
+ }
+ .setButtonType(FooterButton.ButtonType.NEXT)
+ .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
+ .build()
+ }
+
+ private fun setupLottie(
+ view: View,
+ lottieAnimation: Int,
+ lottieClickListener: View.OnClickListener? = null
+ ) {
+ val illustrationLottie: LottieAnimationView? = view.findViewById(R.id.illustration_lottie)
+ illustrationLottie?.setAnimation(lottieAnimation)
+ illustrationLottie?.playAnimation()
+ illustrationLottie?.setOnClickListener(lottieClickListener)
+ illustrationLottie?.visibility = View.VISIBLE
+ }
+
+ private fun setTexts(sensorType: FingerprintSensorType, view: GlifLayout) {
+ when (sensorType) {
+ FingerprintSensorType.UDFPS_OPTICAL,
+ FingerprintSensorType.UDFPS_ULTRASONIC -> {
+ view.setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title)
+ view.setDescriptionText(R.string.security_settings_udfps_enroll_find_sensor_message)
+ }
+ FingerprintSensorType.POWER_BUTTON -> {
+ view.setHeaderText(R.string.security_settings_sfps_enroll_find_sensor_title)
+ view.setDescriptionText(R.string.security_settings_sfps_enroll_find_sensor_message)
+ }
+ else -> {
+ view.setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title)
+ view.setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message)
+ }
+ }
+ }
+
+ private fun getSfpsIllustrationLottieAnimation(isFolded: Boolean, rotation: Int): Int {
+ val animation: Int
+ when (rotation) {
+ Surface.ROTATION_90 ->
+ animation =
+ (if (isFolded) R.raw.fingerprint_edu_lottie_folded_top_left
+ else R.raw.fingerprint_edu_lottie_portrait_top_left)
+ Surface.ROTATION_180 ->
+ animation =
+ (if (isFolded) R.raw.fingerprint_edu_lottie_folded_bottom_left
+ else R.raw.fingerprint_edu_lottie_landscape_bottom_left)
+ Surface.ROTATION_270 ->
+ animation =
+ (if (isFolded) R.raw.fingerprint_edu_lottie_folded_bottom_right
+ else R.raw.fingerprint_edu_lottie_portrait_bottom_right)
+ else ->
+ animation =
+ (if (isFolded) R.raw.fingerprint_edu_lottie_folded_top_right
+ else R.raw.fingerprint_edu_lottie_landscape_top_right)
+ }
+ return animation
+ }
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
similarity index 96%
rename from src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
index f2f925b..dbf6d12 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
@@ -33,8 +33,8 @@
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.android.settings.R
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Unicorn
@@ -72,10 +72,10 @@
* 2. How the data will be stored
* 3. How the user can access and remove their data
*/
-class FingerprintEnrollmentIntroV2Fragment : Fragment(R.layout.fingerprint_v2_enroll_introduction) {
+class FingerprintEnrollIntroV2Fragment : Fragment(R.layout.fingerprint_v2_enroll_introduction) {
private lateinit var footerBarMixin: FooterBarMixin
private lateinit var textModel: TextModel
- private lateinit var navigationViewModel: FingerprintEnrollmentNavigationViewModel
+ private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
@@ -83,7 +83,7 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigationViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollmentNavigationViewModel::class.java]
+ ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
fingerprintEnrollViewModel =
ViewModelProvider(requireActivity())[FingerprintEnrollViewModel::class.java]
fingerprintScrollViewModel =
@@ -180,7 +180,10 @@
scrollView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
// Next button responsible for starting the next fragment.
val onNextButtonClick: View.OnClickListener =
- View.OnClickListener { Log.d(TAG, "OnNextClicked") }
+ View.OnClickListener {
+ Log.d(TAG, "OnNextClicked")
+ navigationViewModel.nextStep()
+ }
val layout: GlifLayout = requireActivity().requireViewById(R.id.setup_wizard_layout)
footerBarMixin = layout.getMixin(FooterBarMixin::class.java)
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/AccessibilityViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/AccessibilityViewModel.kt
new file mode 100644
index 0000000..a86ad5d
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/AccessibilityViewModel.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.view.accessibility.AccessibilityManager
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.stateIn
+
+/** Represents all of the information on accessibility state. */
+class AccessibilityViewModel(accessibilityManager: AccessibilityManager) : ViewModel() {
+ /** A flow that contains whether or not accessibility is enabled */
+ val isAccessibilityEnabled: Flow<Boolean> =
+ callbackFlow {
+ val listener =
+ AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
+ accessibilityManager.addAccessibilityStateChangeListener(listener)
+
+ // This clause will be called when no one is listening to the flow
+ awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
+ }
+ .stateIn(
+ viewModelScope, // This is going to tied to the view model scope
+ SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
+ false
+ )
+
+ class AccessibilityViewModelFactory(private val accessibilityManager: AccessibilityManager) :
+ ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ ): T {
+ return AccessibilityViewModel(accessibilityManager) as T
+ }
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/EnrollReason.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/EnrollReason.kt
new file mode 100644
index 0000000..87deeb3
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/EnrollReason.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.hardware.fingerprint.FingerprintManager
+
+/**
+ * The reason for enrollment. Represents [FingerprintManager.EnrollReason]
+ */
+enum class EnrollReason {
+ /** The enroll happens on education screen. */
+ FindSensor,
+ /** The enroll happens on enrolling screen. */
+ EnrollEnrolling
+}
+
+/** Convert EnrollReason to original [FingerprintManager.EnrollReason]. */
+fun EnrollReason.toOriginalReason(): Int {
+ return when (this) {
+ EnrollReason.EnrollEnrolling -> FingerprintManager.ENROLL_ENROLL
+ EnrollReason.FindSensor -> FingerprintManager.ENROLL_FIND_SENSOR
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerEnrollStateViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerEnrollStateViewModel.kt
new file mode 100644
index 0000000..73343bd
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerEnrollStateViewModel.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.annotation.StringRes
+
+/**
+ * Represents a fingerprint enrollment state. See [FingerprintManager.EnrollmentCallback] for more
+ * information
+ */
+sealed class FingerEnrollStateViewModel {
+ /** Represents enrollment step progress. */
+ data class EnrollProgress(
+ val remainingSteps: Int,
+ ) : FingerEnrollStateViewModel()
+ /** Represents that recoverable error has been encountered during enrollment. */
+ data class EnrollHelp(
+ @StringRes val helpMsgId: Int,
+ val helpString: String,
+ ) : FingerEnrollStateViewModel()
+ /** Represents that an unrecoverable error has been encountered and the operation is complete. */
+ data class EnrollError(
+ @StringRes val errMsgId: Int,
+ val errString: String,
+ ) : FingerEnrollStateViewModel()
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt
new file mode 100644
index 0000000..dbf6b33
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.hardware.fingerprint.FingerprintManager
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.combineTransform
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.transform
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+
+/** Models the UI state for [FingerprintEnrollFindSensorV2Fragment]. */
+class FingerprintEnrollFindSensorViewModel(
+ private val navigationViewModel: FingerprintEnrollNavigationViewModel,
+ private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
+ private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
+ accessibilityViewModel: AccessibilityViewModel,
+ foldStateViewModel: FoldStateViewModel,
+ orientationStateViewModel: OrientationStateViewModel
+) : ViewModel() {
+ /** Represents the stream of sensor type. */
+ val sensorType: Flow<FingerprintSensorType> =
+ fingerprintEnrollViewModel.sensorType.filterWhenEducationIsShown()
+ private val _isUdfps: Flow<Boolean> =
+ sensorType.map {
+ it == FingerprintSensorType.UDFPS_OPTICAL || it == FingerprintSensorType.UDFPS_ULTRASONIC
+ }
+ private val _isSfps: Flow<Boolean> = sensorType.map { it == FingerprintSensorType.POWER_BUTTON }
+ private val _isRearSfps: Flow<Boolean> =
+ combineTransform(_isSfps, _isUdfps) { v1, v2 -> !v1 && !v2 }
+
+ /** Represents the stream of showing primary button. */
+ val showPrimaryButton: Flow<Boolean> = _isUdfps.transform { if (it) emit(true) }
+
+ /** Represents the stream of showing sfps lottie, Pair(isFolded, rotation). */
+ val showSfpsLottie: Flow<Pair<Boolean, Int>> =
+ combineTransform(
+ _isSfps,
+ foldStateViewModel.isFolded,
+ orientationStateViewModel.rotation,
+ ) { isSfps, isFolded, rotation ->
+ if (isSfps) emit(Pair(isFolded, rotation))
+ }
+
+ /** Represents the stream of showing udfps lottie. */
+ val showUdfpsLottie: Flow<Boolean> =
+ combineTransform(
+ _isUdfps,
+ accessibilityViewModel.isAccessibilityEnabled,
+ ) { isUdfps, isAccessibilityEnabled ->
+ if (isUdfps) emit(isAccessibilityEnabled)
+ }
+
+ /** Represents the stream of showing rfps animation. */
+ val showRfpsAnimation: Flow<Boolean> = _isRearSfps.transform { if (it) emit(true) }
+
+ private val _showErrorDialog: MutableStateFlow<Pair<Int, Boolean>?> = MutableStateFlow(null)
+ /** Represents the stream of showing error dialog. */
+ val showErrorDialog = _showErrorDialog.filterNotNull()
+
+ init {
+ // Start or end enroll flow
+ viewModelScope.launch {
+ combine(
+ fingerprintEnrollViewModel.sensorType,
+ gatekeeperViewModel.hasValidGatekeeperInfo,
+ gatekeeperViewModel.gatekeeperInfo,
+ navigationViewModel.navigationViewModel
+ ) { sensorType, hasValidGatekeeperInfo, gatekeeperInfo, navigationViewModel ->
+ val shouldStartEnroll =
+ navigationViewModel.currStep == Education &&
+ sensorType != FingerprintSensorType.UDFPS_OPTICAL &&
+ sensorType != FingerprintSensorType.UDFPS_ULTRASONIC &&
+ hasValidGatekeeperInfo
+ if (shouldStartEnroll) (gatekeeperInfo as GatekeeperInfo.GatekeeperPasswordInfo).token
+ else null
+ }
+ .collect { token ->
+ if (token != null) {
+ fingerprintEnrollViewModel.startEnroll(token, EnrollReason.FindSensor)
+ } else {
+ fingerprintEnrollViewModel.stopEnroll()
+ }
+ }
+ }
+
+ // Enroll progress flow
+ viewModelScope.launch {
+ combine(
+ navigationViewModel.enrollType,
+ fingerprintEnrollViewModel.enrollFlow.filterNotNull()
+ ) { enrollType, enrollFlow ->
+ Pair(enrollType, enrollFlow)
+ }
+ .collect { (enrollType, enrollFlow) ->
+ when (enrollFlow) {
+ // TODO: Cancel the enroll() when EnrollProgress is received instead of proceeding to
+ // Enrolling page. Otherwise Enrolling page will receive the EnrollError.
+ is FingerEnrollStateViewModel.EnrollProgress -> proceedToEnrolling()
+ is FingerEnrollStateViewModel.EnrollError -> {
+ val errMsgId = enrollFlow.errMsgId
+ if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ proceedToEnrolling()
+ } else {
+ _showErrorDialog.update { Pair(errMsgId, enrollType == SetupWizard) }
+ }
+ }
+ is FingerEnrollStateViewModel.EnrollHelp -> {}
+ }
+ }
+ }
+ }
+
+ /** Proceed to EnrollEnrolling page. */
+ fun proceedToEnrolling() {
+ navigationViewModel.nextStep()
+ }
+
+ // TODO: If we decide to remove previous fragment from activity, then we don't need to check
+ // whether education is shown for the flows that are subscribed by
+ // [FingerprintEnrollFindSensorV2Fragment].
+ private fun <T> Flow<T>.filterWhenEducationIsShown() =
+ combineTransform(navigationViewModel.navigationViewModel) { value, navigationViewModel ->
+ if (navigationViewModel.currStep == Education) {
+ emit(value)
+ }
+ }
+
+ class FingerprintEnrollFindSensorViewModelFactory(
+ private val navigationViewModel: FingerprintEnrollNavigationViewModel,
+ private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
+ private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
+ private val accessibilityViewModel: AccessibilityViewModel,
+ private val foldStateViewModel: FoldStateViewModel,
+ private val orientationStateViewModel: OrientationStateViewModel
+ ) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ return FingerprintEnrollFindSensorViewModel(
+ navigationViewModel,
+ fingerprintEnrollViewModel,
+ gatekeeperViewModel,
+ accessibilityViewModel,
+ foldStateViewModel,
+ orientationStateViewModel
+ )
+ as T
+ }
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt
index 31fa03d..cb1beb9 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.ViewModel
@@ -21,13 +20,24 @@
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.toSensorType
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.transformLatest
+import kotlinx.coroutines.flow.update
-/** Represents all of the fingerprint information needed for fingerprint enrollment. */
-class FingerprintEnrollViewModel(fingerprintManagerInteractor: FingerprintManagerInteractor) :
- ViewModel() {
+private const val TAG = "FingerprintEnrollViewModel"
+
+/** Represents all of the fingerprint information needed for a fingerprint enrollment process. */
+class FingerprintEnrollViewModel(
+ private val fingerprintManagerInteractor: FingerprintManagerInteractor,
+ backgroundDispatcher: CoroutineDispatcher,
+) : ViewModel() {
/** Represents the stream of [FingerprintSensorType] */
val sensorType: Flow<FingerprintSensorType> =
@@ -35,14 +45,55 @@
it.sensorType.toSensorType()
}
- class FingerprintEnrollViewModelFactory(val interactor: FingerprintManagerInteractor) :
- ViewModelProvider.Factory {
+ private var _enrollReason: MutableStateFlow<EnrollReason> =
+ MutableStateFlow(EnrollReason.FindSensor)
+ private var _hardwareAuthToken: MutableStateFlow<ByteArray?> = MutableStateFlow(null)
+ private var _consumerShouldEnroll: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ /**
+ * A flow that contains a [FingerprintEnrollViewModel] which contains the relevant information for
+ * an enrollment process
+ */
+ val enrollFlow: Flow<FingerEnrollStateViewModel> =
+ combine(_consumerShouldEnroll, _hardwareAuthToken, _enrollReason) {
+ consumerShouldEnroll,
+ hardwareAuthToken,
+ enrollReason ->
+ Triple(consumerShouldEnroll, hardwareAuthToken, enrollReason)
+ }
+ .transformLatest {
+ // transformLatest() instead of transform() is used here for cancelling previous enroll()
+ // whenever |consumerShouldEnroll| is changed. Otherwise the latest value will be suspended
+ // since enroll() is an infinite callback flow.
+ (consumerShouldEnroll, hardwareAuthToken, enrollReason) ->
+ if (consumerShouldEnroll && hardwareAuthToken != null) {
+ fingerprintManagerInteractor.enroll(hardwareAuthToken, enrollReason).collect { emit(it) }
+ }
+ }
+ .flowOn(backgroundDispatcher)
+
+ /** Used to indicate the consumer of the view model is ready for an enrollment. */
+ fun startEnroll(hardwareAuthToken: ByteArray?, enrollReason: EnrollReason) {
+ _enrollReason.update { enrollReason }
+ _hardwareAuthToken.update { hardwareAuthToken }
+ // Update _consumerShouldEnroll after updating the other values.
+ _consumerShouldEnroll.update { true }
+ }
+
+ /** Used to indicate to stop the enrollment. */
+ fun stopEnroll() {
+ _consumerShouldEnroll.update { false }
+ }
+
+ class FingerprintEnrollViewModelFactory(
+ val interactor: FingerprintManagerInteractor,
+ val backgroundDispatcher: CoroutineDispatcher
+ ) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
): T {
- return FingerprintEnrollViewModel(interactor) as T
+ return FingerprintEnrollViewModel(interactor, backgroundDispatcher) as T
}
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
similarity index 95%
rename from src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
index 6a8a8c4..dafe545 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
@@ -29,7 +29,7 @@
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-const val TAG = "FingerprintEnrollmentNavigationViewModel"
+private const val TAG = "FingerprintEnrollNavigationViewModel"
/** Interface to validate a gatekeeper hat */
interface Validator {
@@ -54,7 +54,7 @@
* This class is responsible for sending a [NavigationStep] which indicates where the user is in the
* Fingerprint Enrollment flow
*/
-class FingerprintEnrollmentNavigationViewModel(
+class FingerprintEnrollNavigationViewModel(
private val dispatcher: CoroutineDispatcher,
private val validator: Validator,
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
@@ -131,7 +131,7 @@
}
}
- class FingerprintEnrollmentNavigationViewModelFactory(
+ class FingerprintEnrollNavigationViewModelFactory(
private val backgroundDispatcher: CoroutineDispatcher,
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
private val fingerprintGatekeeperViewModel: FingerprintGatekeeperViewModel,
@@ -143,7 +143,7 @@
modelClass: Class<T>,
): T {
- return FingerprintEnrollmentNavigationViewModel(
+ return FingerprintEnrollNavigationViewModel(
backgroundDispatcher,
object : Validator {
override fun validateGateKeeper(challenge: Long?): Boolean {
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
index 5486e7a..fa4463a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
@@ -29,6 +29,8 @@
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+private const val TAG = "FingerprintGatekeeperViewModel"
+
sealed interface GatekeeperInfo {
object Invalid : GatekeeperInfo
object Timeout : GatekeeperInfo
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FoldStateViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FoldStateViewModel.kt
new file mode 100644
index 0000000..a4c7ff2
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FoldStateViewModel.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.content.Context
+import android.content.res.Configuration
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.unfold.updates.FoldProvider
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+
+/** Represents all of the information on fold state. */
+class FoldStateViewModel(context: Context) : ViewModel() {
+
+ private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
+
+ /** A flow that contains the fold state info */
+ val isFolded: Flow<Boolean> = callbackFlow {
+ val foldStateListener =
+ object : FoldProvider.FoldCallback {
+ override fun onFoldUpdated(isFolded: Boolean) {
+ trySend(isFolded)
+ }
+ }
+ screenSizeFoldProvider.registerCallback(foldStateListener, context.mainExecutor)
+ awaitClose { screenSizeFoldProvider.unregisterCallback(foldStateListener) }
+ }
+
+ fun onConfigurationChange(newConfig: Configuration) {
+ screenSizeFoldProvider.onConfigurationChange(newConfig)
+ }
+
+ class FoldStateViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ ): T {
+ return FoldStateViewModel(context) as T
+ }
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/OrientationStateViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/OrientationStateViewModel.kt
new file mode 100644
index 0000000..2e5f734
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/OrientationStateViewModel.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
+
+import android.content.Context
+import android.view.OrientationEventListener
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import com.android.internal.R
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.stateIn
+
+/** Represents all of the information on orientation state and rotation state. */
+class OrientationStateViewModel(private val context: Context) : ViewModel() {
+
+ /** A flow that contains the orientation info */
+ val orientation: Flow<Int> = callbackFlow {
+ val orientationEventListener =
+ object : OrientationEventListener(context) {
+ override fun onOrientationChanged(orientation: Int) {
+ trySend(orientation)
+ }
+ }
+ orientationEventListener.enable()
+ awaitClose { orientationEventListener.disable() }
+ }
+
+ /** A flow that contains the rotation info */
+ val rotation: Flow<Int> =
+ callbackFlow {
+ val orientationEventListener =
+ object : OrientationEventListener(context) {
+ override fun onOrientationChanged(orientation: Int) {
+ trySend(getRotationFromDefault(context.display!!.rotation))
+ }
+ }
+ orientationEventListener.enable()
+ awaitClose { orientationEventListener.disable() }
+ }
+ .stateIn(
+ viewModelScope, // This is going to tied to the view model scope
+ SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
+ context.display!!.rotation
+ )
+
+ fun getRotationFromDefault(rotation: Int): Int {
+ val isReverseDefaultRotation =
+ context.resources.getBoolean(R.bool.config_reverseDefaultRotation)
+ return if (isReverseDefaultRotation) {
+ (rotation + 1) % 4
+ } else {
+ rotation
+ }
+ }
+
+ class OrientationViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ ): T {
+ return OrientationStateViewModel(context) as T
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsDataSyncController.java b/src/com/android/settings/bluetooth/BluetoothDetailsDataSyncController.java
index 5969ada..a8cd85f 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsDataSyncController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsDataSyncController.java
@@ -64,6 +64,7 @@
mCompanionDeviceManager = context.getSystemService(CompanionDeviceManager.class);
mCompanionDeviceManager.getAllAssociations().stream().filter(
+ a -> a.getDeviceMacAddress() != null).filter(
a -> Objects.equal(mCachedDevice.getAddress(),
a.getDeviceMacAddress().toString().toUpperCase())).max(
Comparator.comparingLong(AssociationInfo::getTimeApprovedMs)).ifPresent(
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
index 188b4ad..562a469 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
@@ -31,6 +31,8 @@
import com.google.common.annotations.VisibleForTesting;
+import java.util.Set;
+
/**
* This class handles button preference logic to display for hearing aid device.
*/
@@ -91,7 +93,11 @@
}
private boolean getButtonPreferenceVisibility(CachedBluetoothDevice cachedDevice) {
- return isBinauralMode(cachedDevice) && isOnlyOneSideConnected(cachedDevice);
+ // The device is not connected yet. Don't show the button.
+ if (!cachedDevice.isConnectedHearingAidDevice()) {
+ return false;
+ }
+ return isBinauralMode(cachedDevice) && !isOtherSideConnected(cachedDevice);
}
private void launchPairingDetail() {
@@ -106,16 +112,25 @@
return cachedDevice.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL;
}
- private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
- if (!cachedDevice.isConnectedAshaHearingAidDevice()) {
- return false;
+ private boolean isOtherSideConnected(CachedBluetoothDevice cachedDevice) {
+ // Check sub device for ASHA hearing aid
+ if (cachedDevice.isConnectedAshaHearingAidDevice()) {
+ final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
+ if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
+ return true;
+ }
}
- final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
- return false;
+ // Check member device for LE audio hearing aid
+ if (cachedDevice.isConnectedLeAudioHearingAidDevice()) {
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.isConnectedLeAudioHearingAidDevice()) {
+ return true;
+ }
+ }
}
- return true;
+ return false;
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 555868b..f473f2c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -69,7 +69,9 @@
private static final String ENABLE_DUAL_MODE_AUDIO =
"persist.bluetooth.enable_dual_mode_audio";
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
- private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
+ private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
+ private static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
+ "persist.bluetooth.leaudio.toggle_visible";
private LocalBluetoothManager mManager;
private LocalBluetoothProfileManager mProfileManager;
@@ -465,15 +467,13 @@
private void updateLeAudioConfig() {
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
- boolean isLeDeviceDetailEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
- LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+ boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
+ LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
boolean isLeEnabledByDefault = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
- mIsLeAudioToggleEnabled = isLeDeviceDetailEnabled || isLeEnabledByDefault;
+ mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
- + ", BT_LE_AUDIO_DEVICE_DETAIL_ENABLED:" + isLeDeviceDetailEnabled
+ + ", LE_AUDIO_TOGGLE_VISIBLE_PROPERTY:" + isLeAudioToggleVisible
+ ", CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT:" + isLeEnabledByDefault);
}
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 2401ff5..94074df 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -42,19 +42,4 @@
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
*/
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
- /**
- * {@code true} whether to show LE Audio toggle in device detail page. Default is false.
- */
- public static final String BT_LE_AUDIO_DEVICE_DETAIL_ENABLED =
- "bt_le_audio_device_detail_enabled";
- /**
- * {@code true} if press and hold nav handle to search is enabled.
- */
- public static final String PRESS_HOLD_NAV_HANDLE_TO_SEARCH =
- "press_hold_nav_handle_to_search";
- /**
- * {@code true} if long press home button to search is enabled.
- */
- public static final String LONG_PRESS_HOME_BUTTON_TO_SEARCH =
- "long_press_home_button_to_search";
}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index c00b8eb..e89f20e 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -42,6 +42,7 @@
import com.android.settings.applications.ProcessStatsSummary;
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.applications.UsageAccessDetails;
+import com.android.settings.applications.appcompat.UserAspectRatioDetails;
import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.AppLocaleDetails;
@@ -371,7 +372,8 @@
ColorAndMotionFragment.class.getName(),
LongBackgroundTasksDetails.class.getName(),
RegionalPreferencesEntriesFragment.class.getName(),
- BatteryInfoFragment.class.getName()
+ BatteryInfoFragment.class.getName(),
+ UserAspectRatioDetails.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/datausage/AppDataUsagePreference.java b/src/com/android/settings/datausage/AppDataUsagePreference.java
index 2805819..d8c7392 100644
--- a/src/com/android/settings/datausage/AppDataUsagePreference.java
+++ b/src/com/android/settings/datausage/AppDataUsagePreference.java
@@ -38,6 +38,7 @@
public AppDataUsagePreference(Context context, AppItem item, int percent,
UidDetailProvider provider) {
super(context);
+ setKey("app_data_usage_" + item.key);
mItem = item;
mPercent = percent;
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java
deleted file mode 100644
index 1bd2be8..0000000
--- a/src/com/android/settings/datausage/BillingCyclePreference.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 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.android.settings.datausage;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.content.Intent;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.TelephonyManager;
-import android.telephony.data.ApnSetting;
-import android.util.AttributeSet;
-
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.network.MobileDataEnabledListener;
-
-/**
- * Preference which displays billing cycle of subscription
- */
-public class BillingCyclePreference extends Preference
- implements TemplatePreference, MobileDataEnabledListener.Client {
-
- private NetworkTemplate mTemplate;
- private NetworkServices mServices;
- private int mSubId;
- private MobileDataEnabledListener mListener;
-
- /**
- * Preference constructor
- *
- * @param context Context of preference
- * @param arrts The attributes of the XML tag that is inflating the preference
- */
- public BillingCyclePreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- mListener = new MobileDataEnabledListener(context, this);
- }
-
- @Override
- public void onAttached() {
- super.onAttached();
- mListener.start(mSubId);
- }
-
- @Override
- public void onDetached() {
- mListener.stop();
- super.onDetached();
- }
-
- @Override
- public void setTemplate(NetworkTemplate template, int subId,
- NetworkServices services) {
- mTemplate = template;
- mSubId = subId;
- mServices = services;
- setSummary(null);
-
- setIntent(getIntent());
- }
-
- private void updateEnabled() {
- try {
- setEnabled(mServices.mNetworkService.isBandwidthControlEnabled()
- && mServices.mTelephonyManager.createForSubscriptionId(mSubId)
- .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
- && mServices.mUserManager.isAdminUser());
- } catch (RemoteException e) {
- setEnabled(false);
- }
- }
-
- @Override
- public Intent getIntent() {
- final Bundle args = new Bundle();
- args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
- return new SubSettingLauncher(getContext())
- .setDestination(BillingCycleSettings.class.getName())
- .setArguments(args)
- .setTitleRes(R.string.billing_cycle)
- .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
- .toIntent();
- }
-
- /**
- * Implementation of {@code MobileDataEnabledListener.Client}
- */
- public void onMobileDataEnabledChange() {
- updateEnabled();
- }
-}
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.kt b/src/com/android/settings/datausage/BillingCyclePreference.kt
new file mode 100644
index 0000000..619f7e9
--- /dev/null
+++ b/src/com/android/settings/datausage/BillingCyclePreference.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage
+
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.net.NetworkTemplate
+import android.os.Bundle
+import android.util.AttributeSet
+import androidx.preference.Preference
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.datausage.lib.BillingCycleRepository
+import com.android.settings.network.MobileDataEnabledListener
+
+/**
+ * Preference which displays billing cycle of subscription
+ *
+ * @param context Context of preference
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ */
+class BillingCyclePreference @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ private val repository: BillingCycleRepository = BillingCycleRepository(context),
+) : Preference(context, attrs), TemplatePreference {
+ private lateinit var template: NetworkTemplate
+ private var subId = 0
+
+ private val listener = MobileDataEnabledListener(context) {
+ updateEnabled()
+ }
+
+ override fun setTemplate(template: NetworkTemplate, subId: Int) {
+ this.template = template
+ this.subId = subId
+ summary = null
+ updateEnabled()
+ intent = intent
+ }
+
+ override fun onAttached() {
+ super.onAttached()
+ listener.start(subId)
+ }
+
+ override fun onDetached() {
+ listener.stop()
+ super.onDetached()
+ }
+
+ private fun updateEnabled() {
+ isEnabled = repository.isModifiable(subId)
+ }
+
+ override fun getIntent(): Intent {
+ val args = Bundle().apply {
+ putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
+ }
+ return SubSettingLauncher(context).apply {
+ setDestination(BillingCycleSettings::class.java.name)
+ setArguments(args)
+ setTitleRes(R.string.billing_cycle)
+ setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
+ }.toIntent()
+ }
+}
diff --git a/src/com/android/settings/datausage/BillingCyclePreferenceController.java b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
index 73216ab..8b55585 100644
--- a/src/com/android/settings/datausage/BillingCyclePreferenceController.java
+++ b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
@@ -17,20 +17,12 @@
package com.android.settings.datausage;
import android.content.Context;
-import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.os.INetworkManagementService;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.datausage.DataUsageUtils;
import com.android.settings.datausage.lib.DataUsageLib;
-import com.android.settingslib.NetworkPolicyEditor;
public class BillingCyclePreferenceController extends BasePreferenceController {
private int mSubscriptionId;
@@ -48,18 +40,9 @@
super.displayPreference(screen);
BillingCyclePreference preference = screen.findPreference(getPreferenceKey());
- TemplatePreference.NetworkServices services = new TemplatePreference.NetworkServices();
- services.mNetworkService = INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
- services.mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager);
- services.mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
- services.mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
- services.mUserManager = mContext.getSystemService(UserManager.class);
-
NetworkTemplate template = DataUsageLib.getMobileTemplate(mContext, mSubscriptionId);
- preference.setTemplate(template, mSubscriptionId, services);
+ preference.setTemplate(template, mSubscriptionId);
}
@Override
diff --git a/src/com/android/settings/datausage/CellDataPreference.java b/src/com/android/settings/datausage/CellDataPreference.java
index aa763ae..9374217 100644
--- a/src/com/android/settings/datausage/CellDataPreference.java
+++ b/src/com/android/settings/datausage/CellDataPreference.java
@@ -99,7 +99,7 @@
}
@Override
- public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) {
+ public void setTemplate(NetworkTemplate template, int subId) {
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
throw new IllegalArgumentException("CellDataPreference needs a SubscriptionInfo");
}
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index 12fb03b..e2a103e 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -56,8 +56,6 @@
private long mStart;
private long mEnd;
private NetworkCycleChartData mNetworkCycleChartData;
- private int mSecondaryColor;
- private int mSeriesColor;
public ChartDataUsagePreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -310,10 +308,4 @@
mEnd = data.getEndTime();
notifyChanged();
}
-
- public void setColors(int seriesColor, int secondaryColor) {
- mSeriesColor = seriesColor;
- mSecondaryColor = secondaryColor;
- notifyChanged();
- }
}
diff --git a/src/com/android/settings/datausage/DataUsageBaseFragment.java b/src/com/android/settings/datausage/DataUsageBaseFragment.java
index eee3228..5ddbab8 100644
--- a/src/com/android/settings/datausage/DataUsageBaseFragment.java
+++ b/src/com/android/settings/datausage/DataUsageBaseFragment.java
@@ -15,23 +15,13 @@
package com.android.settings.datausage;
import android.content.Context;
-import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.os.Bundle;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.NetworkPolicyEditor;
public abstract class DataUsageBaseFragment extends DashboardFragment {
- private static final String TAG = "DataUsageBase";
- private static final String ETHERNET = "ethernet";
protected final TemplatePreference.NetworkServices services =
new TemplatePreference.NetworkServices();
@@ -41,16 +31,10 @@
super.onCreate(icicle);
Context context = getContext();
- services.mNetworkService = INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
services.mPolicyManager = (NetworkPolicyManager) context
.getSystemService(Context.NETWORK_POLICY_SERVICE);
services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager);
-
- services.mTelephonyManager = context.getSystemService(TelephonyManager.class);
- services.mSubscriptionManager = SubscriptionManager.from(context);
- services.mUserManager = UserManager.get(context);
}
@Override
@@ -58,33 +42,4 @@
super.onResume();
services.mPolicyEditor.read();
}
-
- protected boolean isAdmin() {
- return services.mUserManager.isAdminUser();
- }
-
- protected boolean isMobileDataAvailable(int subId) {
- return services.mSubscriptionManager.getActiveSubscriptionInfo(subId) != null;
- }
-
- protected boolean isNetworkPolicyModifiable(NetworkPolicy policy, int subId) {
- return policy != null && isBandwidthControlEnabled() && services.mUserManager.isAdminUser()
- && isDataEnabled(subId);
- }
-
- private boolean isDataEnabled(int subId) {
- if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return true;
- }
- return services.mTelephonyManager.getDataEnabled(subId);
- }
-
- protected boolean isBandwidthControlEnabled() {
- try {
- return services.mNetworkService.isBandwidthControlEnabled();
- } catch (RemoteException e) {
- Log.w(TAG, "problem talking with INetworkManagementService: ", e);
- return false;
- }
- }
}
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index b030219..15a5603 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -15,19 +15,15 @@
package com.android.settings.datausage;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
-import android.app.usage.NetworkStats;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.NetworkPolicy;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.EventLog;
import android.util.Log;
@@ -36,7 +32,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ImageView;
import android.widget.Spinner;
import androidx.annotation.NonNull;
@@ -46,25 +41,19 @@
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
-import com.android.settings.datausage.lib.AppDataUsageRepository;
+import com.android.settings.datausage.lib.BillingCycleRepository;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.network.MobileNetworkRepository;
-import com.android.settings.network.ProxySubscriptionManager;
import com.android.settings.widget.LoadingViewController;
-import com.android.settingslib.AppItem;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
import com.android.settingslib.net.NetworkCycleChartData;
import com.android.settingslib.net.NetworkCycleChartDataLoader;
-import com.android.settingslib.net.NetworkStatsSummaryLoader;
-import com.android.settingslib.net.UidDetailProvider;
import com.android.settingslib.utils.ThreadUtils;
-import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -85,14 +74,11 @@
private static final String KEY_USAGE_AMOUNT = "usage_amount";
private static final String KEY_CHART_DATA = "chart_data";
- private static final String KEY_APPS_GROUP = "apps_group";
private static final String KEY_TEMPLATE = "template";
private static final String KEY_APP = "app";
@VisibleForTesting
static final int LOADER_CHART_DATA = 2;
- @VisibleForTesting
- static final int LOADER_SUMMARY = 3;
@VisibleForTesting
MobileDataEnabledListener mDataStateListener;
@@ -113,18 +99,16 @@
@Nullable
private List<NetworkCycleChartData> mCycleData;
- // Caches the cycles for startAppDataUsage usage, which need be cleared when resumed.
- private ArrayList<Long> mCycles;
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
// which need be cleared when resumed.
private CycleAdapter.CycleItem mLastDisplayedCycle;
- private UidDetailProvider mUidDetailProvider;
private CycleAdapter mCycleAdapter;
private Preference mUsageAmount;
- private PreferenceGroup mApps;
private View mHeader;
private MobileNetworkRepository mMobileNetworkRepository;
private SubscriptionInfoEntity mSubscriptionInfoEntity;
+ private DataUsageListAppsController mDataUsageListAppsController;
+ private BillingCycleRepository mBillingCycleRepository;
@Override
public int getMetricsCategory() {
@@ -142,20 +126,32 @@
}
final Activity activity = getActivity();
- if (!isBandwidthControlEnabled()) {
+ mBillingCycleRepository = createBillingCycleRepository();
+ if (!mBillingCycleRepository.isBandwidthControlEnabled()) {
Log.w(TAG, "No bandwidth control; leaving");
activity.finish();
return;
}
- mUidDetailProvider = new UidDetailProvider(activity);
mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
mChart = findPreference(KEY_CHART_DATA);
- mApps = findPreference(KEY_APPS_GROUP);
processArgument();
+ if (mTemplate == null) {
+ Log.e(TAG, "No template; leaving");
+ finish();
+ return;
+ }
updateSubscriptionInfoEntity();
mDataStateListener = new MobileDataEnabledListener(activity, this);
+ mDataUsageListAppsController = use(DataUsageListAppsController.class);
+ mDataUsageListAppsController.init(mTemplate);
+ }
+
+ @VisibleForTesting
+ @NonNull
+ BillingCycleRepository createBillingCycleRepository() {
+ return new BillingCycleRepository(requireContext());
}
@Override
@@ -216,7 +212,6 @@
super.onResume();
mLoadingViewController.showLoadingViewDelayed();
mDataStateListener.start(mSubId);
- mCycles = null;
mLastDisplayedCycle = null;
// kick off loader for network history
@@ -224,8 +219,6 @@
// network history when showing app detail.
getLoaderManager().restartLoader(LOADER_CHART_DATA,
buildArgs(mTemplate), mNetworkCycleDataCallbacks);
-
- updateBody();
}
@Override
@@ -234,16 +227,6 @@
mDataStateListener.stop();
getLoaderManager().destroyLoader(LOADER_CHART_DATA);
- getLoaderManager().destroyLoader(LOADER_SUMMARY);
- }
-
- @Override
- public void onDestroy() {
- if (mUidDetailProvider != null) {
- mUidDetailProvider.clearCache();
- mUidDetailProvider = null;
- }
- super.onDestroy();
}
@Override
@@ -295,33 +278,6 @@
updatePolicy();
}
- /**
- * Update body content based on current tab. Loads network cycle data from system, and
- * binds them to visible controls.
- */
- private void updateBody() {
- if (!isAdded()) return;
-
- final Context context = getActivity();
-
- // detail mode can change visible menus, invalidate
- getActivity().invalidateOptionsMenu();
-
- int seriesColor = context.getColor(R.color.sim_noitification);
- if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- final SubscriptionInfo sir = ProxySubscriptionManager.getInstance(context)
- .getActiveSubscriptionInfo(mSubId);
-
- if (sir != null) {
- seriesColor = sir.getIconTint();
- }
- }
-
- final int secondaryColor = Color.argb(127, Color.red(seriesColor), Color.green(seriesColor),
- Color.blue(seriesColor));
- mChart.setColors(seriesColor, secondaryColor);
- }
-
private Bundle buildArgs(NetworkTemplate template) {
final Bundle args = new Bundle();
args.putParcelable(KEY_TEMPLATE, template);
@@ -338,10 +294,9 @@
final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
final View configureButton = mHeader.findViewById(R.id.filter_settings);
//SUB SELECT
- if (isNetworkPolicyModifiable(policy, mSubId) && isMobileDataAvailable(mSubId)) {
+ if (policy != null && isMobileDataAvailable()) {
mChart.setNetworkPolicy(policy);
configureButton.setVisibility(View.VISIBLE);
- ((ImageView) configureButton).setColorFilter(android.R.color.white);
} else {
// controls are disabled; don't bind warning/limit sweeps
mChart.setNetworkPolicy(null);
@@ -352,9 +307,16 @@
if (mCycleData != null) {
mCycleAdapter.updateCycleList(mCycleData);
}
+ mDataUsageListAppsController.setCycleData(mCycleData);
updateSelectedCycle();
}
+ private boolean isMobileDataAvailable() {
+ return mBillingCycleRepository.isModifiable(mSubId)
+ && SubscriptionManager.from(requireContext())
+ .getActiveSubscriptionInfo(mSubId) != null;
+ }
+
/**
* Updates the chart and detail data when initial loaded or selected cycle changed.
*/
@@ -402,67 +364,18 @@
if (LOGD) Log.d(TAG, "updateDetailData()");
// kick off loader for detailed stats
- getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
- mNetworkStatsDetailCallbacks);
+ mDataUsageListAppsController.update(
+ mSubscriptionInfoEntity == null ? null : mSubscriptionInfoEntity.carrierId,
+ mChart.getInspectStart(),
+ mChart.getInspectEnd()
+ );
final long totalBytes = mCycleData != null && !mCycleData.isEmpty()
- ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
+ ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
}
- /**
- * Bind the given buckets.
- */
- private void bindStats(List<AppDataUsageRepository.Bucket> buckets) {
- mApps.removeAll();
- AppDataUsageRepository repository = new AppDataUsageRepository(
- requireContext(),
- ActivityManager.getCurrentUser(),
- mSubscriptionInfoEntity == null ? null : mSubscriptionInfoEntity.carrierId,
- appItem -> mUidDetailProvider.getUidDetail(appItem.key, true).packageName
- );
- for (var itemPercentPair : repository.getAppPercent(buckets)) {
- final AppDataUsagePreference preference = new AppDataUsagePreference(getContext(),
- itemPercentPair.getFirst(), itemPercentPair.getSecond(), mUidDetailProvider);
- preference.setOnPreferenceClickListener(p -> {
- AppDataUsagePreference pref = (AppDataUsagePreference) p;
- startAppDataUsage(pref.getItem());
- return true;
- });
- mApps.addPreference(preference);
- }
- }
-
- @VisibleForTesting
- void startAppDataUsage(AppItem item) {
- if (mCycleData == null) {
- return;
- }
- final Bundle args = new Bundle();
- args.putParcelable(AppDataUsage.ARG_APP_ITEM, item);
- args.putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, mTemplate);
- if (mCycles == null) {
- mCycles = new ArrayList<>();
- for (NetworkCycleChartData data : mCycleData) {
- if (mCycles.isEmpty()) {
- mCycles.add(data.getEndTime());
- }
- mCycles.add(data.getStartTime());
- }
- }
- args.putSerializable(AppDataUsage.ARG_NETWORK_CYCLES, mCycles);
- args.putLong(AppDataUsage.ARG_SELECTED_CYCLE,
- mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getEndTime());
-
- new SubSettingLauncher(getContext())
- .setDestination(AppDataUsage.class.getName())
- .setTitleRes(R.string.data_usage_app_summary_title)
- .setArguments(args)
- .setSourceMetricsCategory(getMetricsCategory())
- .launch();
- }
-
private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@@ -502,44 +415,6 @@
}
};
- private final LoaderCallbacks<NetworkStats> mNetworkStatsDetailCallbacks =
- new LoaderCallbacks<>() {
- @Override
- @NonNull
- public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
- return new NetworkStatsSummaryLoader.Builder(getContext())
- .setStartTime(mChart.getInspectStart())
- .setEndTime(mChart.getInspectEnd())
- .setNetworkTemplate(mTemplate)
- .build();
- }
-
- @Override
- public void onLoadFinished(
- @NonNull Loader<NetworkStats> loader, NetworkStats data) {
- bindStats(AppDataUsageRepository.Companion.convertToBuckets(data));
- updateEmptyVisible();
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader<NetworkStats> loader) {
- mApps.removeAll();
- updateEmptyVisible();
- }
-
- private void updateEmptyVisible() {
- if ((mApps.getPreferenceCount() != 0)
- != (getPreferenceScreen().getPreferenceCount() != 0)) {
- if (mApps.getPreferenceCount() != 0) {
- getPreferenceScreen().addPreference(mUsageAmount);
- getPreferenceScreen().addPreference(mApps);
- } else {
- getPreferenceScreen().removeAll();
- }
- }
- }
- };
-
private static boolean isGuestUser(Context context) {
if (context == null) return false;
final UserManager userManager = context.getSystemService(UserManager.class);
diff --git a/src/com/android/settings/datausage/DataUsageListAppsController.kt b/src/com/android/settings/datausage/DataUsageListAppsController.kt
new file mode 100644
index 0000000..c324407
--- /dev/null
+++ b/src/com/android/settings/datausage/DataUsageListAppsController.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage
+
+import android.app.ActivityManager
+import android.content.Context
+import android.net.NetworkTemplate
+import android.os.Bundle
+import androidx.annotation.OpenForTesting
+import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.LifecycleCoroutineScope
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceScreen
+import com.android.settings.R
+import com.android.settings.core.BasePreferenceController
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.datausage.lib.AppDataUsageRepository
+import com.android.settingslib.AppItem
+import com.android.settingslib.net.NetworkCycleChartData
+import com.android.settingslib.net.UidDetailProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+@OpenForTesting
+open class DataUsageListAppsController(context: Context, preferenceKey: String) :
+ BasePreferenceController(context, preferenceKey) {
+
+ private val uidDetailProvider = UidDetailProvider(context)
+ private lateinit var template: NetworkTemplate
+ private lateinit var repository: AppDataUsageRepository
+ private lateinit var preference: PreferenceGroup
+ private lateinit var lifecycleScope: LifecycleCoroutineScope
+
+ private var cycleData: List<NetworkCycleChartData>? = null
+
+ open fun init(template: NetworkTemplate) {
+ this.template = template
+ repository = AppDataUsageRepository(
+ context = mContext,
+ currentUserId = ActivityManager.getCurrentUser(),
+ template = template,
+ ) { appItem: AppItem -> uidDetailProvider.getUidDetail(appItem.key, true).packageName }
+ }
+
+ override fun getAvailabilityStatus() = AVAILABLE
+
+ override fun displayPreference(screen: PreferenceScreen) {
+ super.displayPreference(screen)
+ preference = screen.findPreference(preferenceKey)!!
+ }
+
+ override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
+ lifecycleScope = viewLifecycleOwner.lifecycleScope
+ }
+
+ fun setCycleData(cycleData: List<NetworkCycleChartData>?) {
+ this.cycleData = cycleData
+ }
+
+ fun update(carrierId: Int?, startTime: Long, endTime: Long) = lifecycleScope.launch {
+ val apps = withContext(Dispatchers.Default) {
+ repository.getAppPercent(carrierId, startTime, endTime).map { (appItem, percent) ->
+ AppDataUsagePreference(mContext, appItem, percent, uidDetailProvider).apply {
+ setOnPreferenceClickListener {
+ startAppDataUsage(appItem, endTime)
+ true
+ }
+ }
+ }
+ }
+ preference.removeAll()
+ for (app in apps) {
+ preference.addPreference(app)
+ }
+ }
+
+ @VisibleForTesting
+ fun startAppDataUsage(item: AppItem, endTime: Long) {
+ val cycleData = cycleData ?: return
+ val args = Bundle().apply {
+ putParcelable(AppDataUsage.ARG_APP_ITEM, item)
+ putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, template)
+ val cycles = ArrayList<Long>().apply {
+ for (data in cycleData) {
+ if (isEmpty()) add(data.endTime)
+ add(data.startTime)
+ }
+ }
+ putSerializable(AppDataUsage.ARG_NETWORK_CYCLES, cycles)
+ putLong(AppDataUsage.ARG_SELECTED_CYCLE, endTime)
+ }
+ SubSettingLauncher(mContext).apply {
+ setDestination(AppDataUsage::class.java.name)
+ setTitleRes(R.string.data_usage_app_summary_title)
+ setArguments(args)
+ setSourceMetricsCategory(metricsCategory)
+ }.launch()
+ }
+}
diff --git a/src/com/android/settings/datausage/DataUsagePreference.java b/src/com/android/settings/datausage/DataUsagePreference.java
index 0ed0ad3..0f7bf58 100644
--- a/src/com/android/settings/datausage/DataUsagePreference.java
+++ b/src/com/android/settings/datausage/DataUsagePreference.java
@@ -49,7 +49,7 @@
}
@Override
- public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) {
+ public void setTemplate(NetworkTemplate template, int subId) {
mTemplate = template;
mSubId = subId;
final DataUsageController controller = getDataUsageController();
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index d176402..4f876ab 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -103,7 +103,7 @@
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
mSummaryPreference = findPreference(KEY_STATUS_HEADER);
- if (!hasMobileData || !isAdmin()) {
+ if (!hasMobileData || !UserManager.get(context).isAdminUser()) {
removePreference(KEY_RESTRICT_BACKGROUND);
}
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
@@ -183,9 +183,8 @@
private void addMobileSection(int subId, SubscriptionInfo subInfo) {
TemplatePreferenceCategory category = (TemplatePreferenceCategory)
inflatePreferences(R.xml.data_usage_cellular);
- category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId),
- subId, services);
- category.pushTemplates(services);
+ category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId), subId);
+ category.pushTemplates();
final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
subInfo, getContext());
if (subInfo != null && !TextUtils.isEmpty(displayName)) {
@@ -198,15 +197,14 @@
void addWifiSection() {
TemplatePreferenceCategory category = (TemplatePreferenceCategory)
inflatePreferences(R.xml.data_usage_wifi);
- category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build(),
- 0, services);
+ category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build(), 0);
}
private void addEthernetSection() {
TemplatePreferenceCategory category = (TemplatePreferenceCategory)
inflatePreferences(R.xml.data_usage_ethernet);
- category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_ETHERNET).build(),
- 0, services);
+ category.setTemplate(
+ new NetworkTemplate.Builder(NetworkTemplate.MATCH_ETHERNET).build(), 0);
}
private Preference inflatePreferences(int resId) {
@@ -259,10 +257,10 @@
private void updateState() {
PreferenceScreen screen = getPreferenceScreen();
for (int i = 1; i < screen.getPreferenceCount(); i++) {
- Preference currentPreference = screen.getPreference(i);
- if (currentPreference instanceof TemplatePreferenceCategory) {
- ((TemplatePreferenceCategory) currentPreference).pushTemplates(services);
- }
+ Preference currentPreference = screen.getPreference(i);
+ if (currentPreference instanceof TemplatePreferenceCategory) {
+ ((TemplatePreferenceCategory) currentPreference).pushTemplates();
+ }
}
}
diff --git a/src/com/android/settings/datausage/NetworkRestrictionsPreference.java b/src/com/android/settings/datausage/NetworkRestrictionsPreference.java
deleted file mode 100644
index 9afc0c3..0000000
--- a/src/com/android/settings/datausage/NetworkRestrictionsPreference.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 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.android.settings.datausage;
-
-import android.content.Context;
-import android.net.NetworkTemplate;
-import android.util.AttributeSet;
-
-import androidx.preference.Preference;
-
-public class NetworkRestrictionsPreference extends Preference implements TemplatePreference {
-
- public NetworkRestrictionsPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public void setTemplate(NetworkTemplate template, int subId,
- NetworkServices services) {
- // TODO: Summary
- }
-}
diff --git a/src/com/android/settings/datausage/TemplatePreference.java b/src/com/android/settings/datausage/TemplatePreference.java
index 43dda0a..8e780db 100644
--- a/src/com/android/settings/datausage/TemplatePreference.java
+++ b/src/com/android/settings/datausage/TemplatePreference.java
@@ -16,23 +16,16 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.os.INetworkManagementService;
-import android.os.UserManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import com.android.settingslib.NetworkPolicyEditor;
public interface TemplatePreference {
- void setTemplate(NetworkTemplate template, int subId, NetworkServices services);
+ /** Sets the network template. */
+ void setTemplate(NetworkTemplate template, int subId);
class NetworkServices {
- INetworkManagementService mNetworkService;
NetworkPolicyManager mPolicyManager;
- TelephonyManager mTelephonyManager;
- SubscriptionManager mSubscriptionManager;
- UserManager mUserManager;
NetworkPolicyEditor mPolicyEditor;
}
diff --git a/src/com/android/settings/datausage/TemplatePreferenceCategory.java b/src/com/android/settings/datausage/TemplatePreferenceCategory.java
index d26b9b1..9173676 100644
--- a/src/com/android/settings/datausage/TemplatePreferenceCategory.java
+++ b/src/com/android/settings/datausage/TemplatePreferenceCategory.java
@@ -31,8 +31,7 @@
}
@Override
- public void setTemplate(NetworkTemplate template, int subId,
- NetworkServices services) {
+ public void setTemplate(NetworkTemplate template, int subId) {
mTemplate = template;
mSubId = subId;
}
@@ -46,12 +45,13 @@
return super.addPreference(preference);
}
- public void pushTemplates(NetworkServices services) {
+ /** Pushes the templates. */
+ public void pushTemplates() {
if (mTemplate == null) {
throw new RuntimeException("null mTemplate for " + getKey());
}
for (int i = 0; i < getPreferenceCount(); i++) {
- ((TemplatePreference) getPreference(i)).setTemplate(mTemplate, mSubId, services);
+ ((TemplatePreference) getPreference(i)).setTemplate(mTemplate, mSubId);
}
}
diff --git a/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt b/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
index 3813af5..074a555 100644
--- a/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
+++ b/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
@@ -17,11 +17,15 @@
package com.android.settings.datausage.lib
import android.app.usage.NetworkStats
+import android.app.usage.NetworkStatsManager
import android.content.Context
import android.net.NetworkPolicyManager
+import android.net.NetworkTemplate
import android.os.Process
import android.os.UserHandle
+import android.util.Log
import android.util.SparseArray
+import androidx.annotation.VisibleForTesting
import com.android.settings.R
import com.android.settingslib.AppItem
import com.android.settingslib.net.UidDetailProvider
@@ -30,15 +34,18 @@
class AppDataUsageRepository(
private val context: Context,
private val currentUserId: Int,
- private val carrierId: Int?,
- private val getPackageName: (AppItem) -> String,
+ private val template: NetworkTemplate,
+ private val getPackageName: (AppItem) -> String?,
) {
- data class Bucket(
- val uid: Int,
- val bytes: Long,
- )
+ private val networkStatsManager = context.getSystemService(NetworkStatsManager::class.java)!!
- fun getAppPercent(buckets: List<Bucket>): List<Pair<AppItem, Int>> {
+ fun getAppPercent(carrierId: Int?, startTime: Long, endTime: Long): List<Pair<AppItem, Int>> {
+ val networkStats = querySummary(startTime, endTime) ?: return emptyList()
+ return getAppPercent(carrierId, convertToBuckets(networkStats))
+ }
+
+ @VisibleForTesting
+ fun getAppPercent(carrierId: Int?, buckets: List<Bucket>): List<Pair<AppItem, Int>> {
val items = ArrayList<AppItem>()
val knownItems = SparseArray<AppItem>()
val profiles = context.userManager.userProfiles
@@ -61,7 +68,7 @@
item.restricted = true
}
- val filteredItems = filterItems(items).sorted()
+ val filteredItems = filterItems(carrierId, items).sorted()
val largest: Long = filteredItems.maxOfOrNull { it.total } ?: 0
return filteredItems.map { item ->
val percentTotal = if (largest > 0) (item.total * 100 / largest).toInt() else 0
@@ -69,7 +76,14 @@
}
}
- private fun filterItems(items: List<AppItem>): List<AppItem> {
+ private fun querySummary(startTime: Long, endTime: Long): NetworkStats? = try {
+ networkStatsManager.querySummary(template, startTime, endTime)
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Exception querying network detail.", e)
+ null
+ }
+
+ private fun filterItems(carrierId: Int?, items: List<AppItem>): List<AppItem> {
// When there is no specified SubscriptionInfo, Wi-Fi data usage will be displayed.
// In this case, the carrier service package also needs to be hidden.
if (carrierId != null && carrierId !in context.resources.getIntArray(
@@ -178,7 +192,15 @@
}
companion object {
- fun convertToBuckets(stats: NetworkStats): List<Bucket> {
+ private const val TAG = "AppDataUsageRepository"
+
+ @VisibleForTesting
+ data class Bucket(
+ val uid: Int,
+ val bytes: Long,
+ )
+
+ private fun convertToBuckets(stats: NetworkStats): List<Bucket> {
val buckets = mutableListOf<Bucket>()
stats.use {
val bucket = NetworkStats.Bucket()
diff --git a/src/com/android/settings/datausage/lib/BillingCycleRepository.kt b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
new file mode 100644
index 0000000..bd6aa27
--- /dev/null
+++ b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.ServiceManager
+import android.telephony.TelephonyManager
+import android.util.Log
+import androidx.annotation.OpenForTesting
+import com.android.settingslib.spaprivileged.framework.common.userManager
+
+@OpenForTesting
+open class BillingCycleRepository @JvmOverloads constructor(
+ context: Context,
+ private val networkService: INetworkManagementService =
+ INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
+ ),
+) {
+ private val userManager = context.userManager
+ private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+
+ fun isModifiable(subId: Int): Boolean =
+ isBandwidthControlEnabled() && userManager.isAdminUser && isDataEnabled(subId)
+
+ open fun isBandwidthControlEnabled(): Boolean = try {
+ networkService.isBandwidthControlEnabled
+ } catch (e: Exception) {
+ Log.w(TAG, "problem talking with INetworkManagementService: ", e)
+ false
+ }
+
+ private fun isDataEnabled(subId: Int): Boolean =
+ telephonyManager.createForSubscriptionId(subId)
+ .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+
+ companion object {
+ private const val TAG = "BillingCycleRepository"
+ }
+}
diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
index 298ced0..980bdaa 100644
--- a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
@@ -20,6 +20,7 @@
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import androidx.annotation.VisibleForTesting;
@@ -27,7 +28,6 @@
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
/**
@@ -40,9 +40,12 @@
private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
- private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
+ private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
+ static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
+ "persist.bluetooth.leaudio.toggle_visible";
+
@VisibleForTesting
BluetoothAdapter mBluetoothAdapter;
@@ -73,10 +76,7 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (Boolean) newValue;
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
- isEnabled ? "true" : "false", LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+ SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, Boolean.toString(isEnabled));
return true;
}
@@ -86,25 +86,13 @@
return;
}
- final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
- LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+ final boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
+ LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
mPreference.setEnabled(!leAudioEnabledByDefault);
- ((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled
+ ((SwitchPreference) mPreference).setChecked(isLeAudioToggleVisible
|| leAudioEnabledByDefault);
}
-
- @Override
- protected void onDeveloperOptionsSwitchDisabled() {
- super.onDeveloperOptionsSwitchDisabled();
- // Reset the toggle to null when the developer option is disabled
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null",
- LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
- }
}
diff --git a/src/com/android/settings/development/quarantine/OWNERS b/src/com/android/settings/development/quarantine/OWNERS
new file mode 100644
index 0000000..d4de31a
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 316234
+
+sudheersai@google.com
+yamasani@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java b/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java
new file mode 100644
index 0000000..6ad1f86
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppPreference.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.settingslib.widget.AppSwitchPreference;
+
+public class QuarantinedAppPreference extends AppSwitchPreference {
+ private final AppEntry mEntry;
+ private Drawable mCacheIcon;
+
+ public QuarantinedAppPreference(Context context, AppEntry entry) {
+ super(context);
+ mEntry = entry;
+ mCacheIcon = AppUtils.getIconFromCache(mEntry);
+
+ mEntry.ensureLabel(context);
+ setKey(generateKey(mEntry));
+ if (mCacheIcon != null) {
+ setIcon(mCacheIcon);
+ } else {
+ setIcon(R.drawable.empty_icon);
+ }
+ updateState();
+ }
+
+ static String generateKey(AppEntry entry) {
+ return entry.info.packageName + "|" + entry.info.uid;
+ }
+
+ public AppEntry getEntry() {
+ return mEntry;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ if (mCacheIcon == null) {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ final Drawable icon = AppUtils.getIcon(getContext(), mEntry);
+ ThreadUtils.postOnMainThread(() -> {
+ setIcon(icon);
+ mCacheIcon = icon;
+ });
+ });
+ }
+ super.onBindViewHolder(holder);
+ }
+
+ void updateState() {
+ setTitle(mEntry.label);
+ setChecked((boolean) mEntry.extraInfo);
+ notifyChanged();
+ }
+}
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java b/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java
new file mode 100644
index 0000000..206b922
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppStateBridge.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+
+public class QuarantinedAppStateBridge extends AppStateBaseBridge {
+ private Context mContext;
+
+ public QuarantinedAppStateBridge(Context context,
+ ApplicationsState appState, Callback callback) {
+ super(appState, callback);
+ mContext = context;
+ }
+
+ @Override
+ protected void loadAllExtraInfo() {
+ final ArrayList<AppEntry> apps = mAppSession.getAllApps();
+ for (int i = 0; i < apps.size(); i++) {
+ final AppEntry app = apps.get(i);
+ updateExtraInfo(app, app.info.packageName, app.info.uid);
+ }
+ }
+
+ @Override
+ protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+ app.extraInfo = isPackageQuarantined(pkg, uid);
+ }
+
+ private boolean isPackageQuarantined(String pkg, int uid) {
+ final PackageManager pm = mContext.createContextAsUser(
+ UserHandle.getUserHandleForUid(uid), 0).getPackageManager();
+ try {
+ return pm.isPackageQuarantined(pkg);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java b/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java
new file mode 100644
index 0000000..985e962
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppsFragment.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import static android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
+import static android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.SearchView;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.applications.AppIconCacheManager;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.search.SearchIndexable;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+// TODO: b/297934650 - Update this to use SPA framework
+@SearchIndexable
+public class QuarantinedAppsFragment extends DashboardFragment implements
+ SearchView.OnQueryTextListener, SearchView.OnCloseListener,
+ MenuItem.OnActionExpandListener {
+ private static final String TAG = "QuarantinedApps";
+
+ private static final int MENU_SEARCH_APPS = Menu.FIRST + 42;
+ private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 43;
+ private static final String EXTRA_SHOW_SYSTEM = "show_system";
+
+ private boolean mShowSystem;
+ private SearchView mSearchView;
+ private String mCurQuery;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mShowSystem = icicle != null && icicle.getBoolean(EXTRA_SHOW_SYSTEM);
+ use(QuarantinedAppsScreenController.class).setFilter(mCustomFilter);
+ use(QuarantinedAppsScreenController.class).setSession(getSettingsLifecycle());
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ mSearchView = new SearchView(getContext());
+ mSearchView.setOnQueryTextListener(this);
+ mSearchView.setOnCloseListener(this);
+ mSearchView.setIconifiedByDefault(true);
+
+ menu.add(Menu.NONE, MENU_SEARCH_APPS, Menu.NONE, R.string.search_settings)
+ .setIcon(R.drawable.ic_find_in_page_24px)
+ .setActionView(mSearchView)
+ .setOnActionExpandListener(this)
+ .setShowAsAction(SHOW_AS_ACTION_ALWAYS | SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
+ menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
+ mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == MENU_SHOW_SYSTEM) {
+ mShowSystem = !mShowSystem;
+ item.setTitle(mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system);
+ use(QuarantinedAppsScreenController.class).setFilter(mCustomFilter);
+ use(QuarantinedAppsScreenController.class).rebuild();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ mCurQuery = !TextUtils.isEmpty(newText) ? newText : null;
+ use(QuarantinedAppsScreenController.class).rebuild();
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ // Don't care about this.
+ return true;
+ }
+
+ @Override
+ public boolean onClose() {
+ if (!TextUtils.isEmpty(mSearchView.getQuery())) {
+ mSearchView.setQuery(null, true);
+ }
+ return true;
+ }
+
+ public final AppFilter mCustomFilter = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(ApplicationsState.AppEntry entry) {
+ final AppFilter defaultFilter = mShowSystem ? ApplicationsState.FILTER_ALL_ENABLED
+ : ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER;
+ return defaultFilter.filterApp(entry) && (mCurQuery == null
+ || entry.label.toLowerCase().contains(mCurQuery.toLowerCase()));
+ }
+ };
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ final AppBarLayout mAppBarLayout = getActivity().findViewById(R.id.app_bar);
+ // To prevent a large space on tool bar.
+ mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ final AppBarLayout mAppBarLayout = getActivity().findViewById(R.id.app_bar);
+ // To prevent a large space on tool bar.
+ mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
+ return true;
+ }
+
+ @Override
+ public int getPreferenceScreenResId() {
+ return R.xml.quarantined_apps;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.QUARANTINED_APPS_DEV_CONTROL;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ AppIconCacheManager.getInstance().release();
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.quarantined_apps);
+}
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java b/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java
new file mode 100644
index 0000000..de3b18b
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceController.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import android.content.Context;
+import android.content.pm.Flags;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class QuarantinedAppsPreferenceController extends BasePreferenceController {
+ public QuarantinedAppsPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return Flags.quarantinedEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java b/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java
new file mode 100644
index 0000000..e5373fd
--- /dev/null
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class QuarantinedAppsScreenController extends BasePreferenceController implements
+ LifecycleObserver, OnStart, OnStop, OnDestroy,
+ ApplicationsState.Callbacks, Preference.OnPreferenceChangeListener,
+ AppStateBaseBridge.Callback {
+ private final ApplicationsState mApplicationsState;
+ private final QuarantinedAppStateBridge mQuarantinedAppStateBridge;
+ private ApplicationsState.Session mSession;
+ private PreferenceScreen mScreen;
+ private AppFilter mFilter;
+ private boolean mExtraLoaded;
+
+ public QuarantinedAppsScreenController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mApplicationsState = ApplicationsState.getInstance(
+ (Application) context.getApplicationContext());
+ mQuarantinedAppStateBridge = new QuarantinedAppStateBridge(context,
+ mApplicationsState, this);
+ }
+
+ @Override
+ public void onStart() {
+ mQuarantinedAppStateBridge.resume(true /* forceLoadAllApps */);
+ }
+
+ @Override
+ public void onStop() {
+ mQuarantinedAppStateBridge.pause();
+ }
+
+ @Override
+ public void onDestroy() {
+ mQuarantinedAppStateBridge.release();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mScreen = screen;
+ }
+
+ public void setFilter(AppFilter filter) {
+ mFilter = filter;
+ }
+
+ public void setSession(Lifecycle lifecycle) {
+ mSession = mApplicationsState.newSession(this, lifecycle);
+ }
+
+ @Override
+ public void onExtraInfoUpdated() {
+ mExtraLoaded = true;
+ rebuild();
+ }
+
+ public void rebuild() {
+ if (!mExtraLoaded || mSession == null) {
+ return;
+ }
+
+ final ArrayList<AppEntry> apps = mSession.rebuild(mFilter,
+ ApplicationsState.ALPHA_COMPARATOR);
+ if (apps != null) {
+ onRebuildComplete(apps);
+ }
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
+ if (apps == null) {
+ return;
+ }
+
+ // Preload top visible icons of app list.
+ AppUtils.preloadTopIcons(mContext, apps,
+ mContext.getResources().getInteger(R.integer.config_num_visible_app_icons));
+
+ // Create apps key set for removing useless preferences
+ final Set<String> appsKeySet = new TreeSet<>();
+ // Add or update preferences
+ final int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ final AppEntry entry = apps.get(i);
+ if (!shouldAddPreference(entry)) {
+ continue;
+ }
+ final String prefkey = QuarantinedAppPreference.generateKey(entry);
+ appsKeySet.add(prefkey);
+ QuarantinedAppPreference preference = mScreen.findPreference(prefkey);
+ if (preference == null) {
+ preference = new QuarantinedAppPreference(mScreen.getContext(), entry);
+ preference.setOnPreferenceChangeListener(this);
+ mScreen.addPreference(preference);
+ } else {
+ preference.updateState();
+ }
+ preference.setOrder(i);
+ }
+
+ // Remove useless preferences
+ removeUselessPrefs(appsKeySet);
+ }
+
+ private void removeUselessPrefs(final Set<String> appsKeySet) {
+ final int prefCount = mScreen.getPreferenceCount();
+ String prefKey;
+ if (prefCount > 0) {
+ for (int i = prefCount - 1; i >= 0; i--) {
+ final Preference pref = mScreen.getPreference(i);
+ prefKey = pref.getKey();
+ if (!appsKeySet.isEmpty() && appsKeySet.contains(prefKey)) {
+ continue;
+ }
+ mScreen.removePreference(pref);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static boolean shouldAddPreference(AppEntry app) {
+ return app != null && UserHandle.isApp(app.info.uid);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof QuarantinedAppPreference) {
+ final QuarantinedAppPreference quarantinedPreference =
+ (QuarantinedAppPreference) preference;
+ final boolean quarantined = newValue == Boolean.TRUE;
+ setPackageQuarantined(quarantinedPreference.getEntry().info.packageName,
+ quarantinedPreference.getEntry().info.uid, quarantined);
+ quarantinedPreference.getEntry().extraInfo = quarantined;
+ return true;
+ }
+ return false;
+ }
+
+ private void setPackageQuarantined(String pkg, int uid, boolean quarantined) {
+ final PackageManager pm = mContext.createContextAsUser(
+ UserHandle.getUserHandleForUid(uid), 0).getPackageManager();
+ pm.setPackagesSuspended(new String[] {pkg}, quarantined, null /* appExtras */,
+ null /* launcherExtras */, null /* dialogInfo */,
+ PackageManager.FLAG_SUSPEND_QUARANTINED);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ }
+}
diff --git a/src/com/android/settings/display/FoldLockBehaviorSettings.java b/src/com/android/settings/display/FoldLockBehaviorSettings.java
index beda52e..e94b17e 100644
--- a/src/com/android/settings/display/FoldLockBehaviorSettings.java
+++ b/src/com/android/settings/display/FoldLockBehaviorSettings.java
@@ -48,18 +48,18 @@
public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key";
public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key";
public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key";
- private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
public static final String TAG = "FoldLockBehaviorSetting";
public static final HashSet<String> SETTING_VALUES = new HashSet<>(
Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD, SETTING_VALUE_SELECTIVE_STAY_AWAKE,
SETTING_VALUE_SLEEP_ON_FOLD));
-
+ private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
private Context mContext;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
+ setIllustrationLottieAnimation(getDefaultKey());
}
@Override
@@ -136,6 +136,31 @@
UserHandle.USER_CURRENT);
}
+ @Override
+ protected void onSelectionPerformed(boolean success) {
+ if (success) {
+ setIllustrationLottieAnimation(getDefaultKey());
+ updateCandidates();
+ }
+ }
+
+ private void setIllustrationLottieAnimation(String foldSettingValue) {
+ switch (foldSettingValue) {
+ case SETTING_VALUE_STAY_AWAKE_ON_FOLD:
+ setIllustration(R.raw.fold_setting_stay_awake_on_fold_lottie,
+ IllustrationType.LOTTIE_ANIMATION);
+ break;
+ case SETTING_VALUE_SELECTIVE_STAY_AWAKE:
+ setIllustration(R.raw.fold_setting_selective_stay_awake_lottie,
+ IllustrationType.LOTTIE_ANIMATION);
+ break;
+ case SETTING_VALUE_SLEEP_ON_FOLD:
+ setIllustration(R.raw.fold_setting_sleep_on_fold_lottie,
+ IllustrationType.LOTTIE_ANIMATION);
+ break;
+ }
+ }
+
private String resourceToString(int resource) {
return mContext.getText(resource).toString();
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
index ed8cc62..9e970d2 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
@@ -23,8 +23,6 @@
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
-import java.util.concurrent.TimeUnit;
-
/**
* Detect whether the battery is too low
*/
@@ -46,9 +44,7 @@
@Override
public BatteryTip detect() {
- final boolean lowBattery = mBatteryInfo.batteryLevel <= mWarningLevel
- || (mBatteryInfo.discharging && mBatteryInfo.remainingTimeUs != 0
- && mBatteryInfo.remainingTimeUs < TimeUnit.HOURS.toMicros(mPolicy.lowBatteryHour));
+ final boolean lowBattery = mBatteryInfo.batteryLevel <= mWarningLevel;
final boolean lowBatteryEnabled = mPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
final boolean dischargingLowBatteryState =
mPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java
new file mode 100644
index 0000000..2f139ec
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+class AnomalyAppItemPreference extends PowerGaugePreference {
+
+ private static final String TAG = "AnomalyAppItemPreference";
+
+ private CharSequence mAnomalyHintText;
+
+ AnomalyAppItemPreference(Context context) {
+ super(context, /* attrs */ null);
+ setLayoutResource(R.layout.anomaly_app_item_preference);
+ }
+
+ void setAnomalyHint(CharSequence anomalyHintText) {
+ if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
+ mAnomalyHintText = anomalyHintText;
+ notifyChanged();
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder viewHolder) {
+ super.onBindViewHolder(viewHolder);
+ final LinearLayout warningChipView =
+ (LinearLayout) viewHolder.findViewById(R.id.warning_chip);
+
+ if (!TextUtils.isEmpty(mAnomalyHintText)) {
+ ((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
+ warningChipView.setVisibility(View.VISIBLE);
+ } else {
+ warningChipView.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
new file mode 100644
index 0000000..d535490
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 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.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.SubSettingLauncher;
+
+import java.util.function.Function;
+
+final class AnomalyEventWrapper {
+ private static final String TAG = "AnomalyEventWrapper";
+
+ private final Context mContext;
+ private final PowerAnomalyEvent mPowerAnomalyEvent;
+
+ private final int mCardStyleId;
+ private final int mResourceIndex;
+
+ private SubSettingLauncher mSubSettingLauncher = null;
+ private Pair<Integer, Integer> mHighlightSlotPair = null;
+ private BatteryDiffEntry mRelatedBatteryDiffEntry = null;
+
+ AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent) {
+ mContext = context;
+ mPowerAnomalyEvent = powerAnomalyEvent;
+ // Set basic battery tips card info
+ mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
+ mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
+ }
+
+ private <T> T getInfo(Function<WarningBannerInfo, T> warningBannerInfoSupplier,
+ Function<WarningItemInfo, T> warningItemInfoSupplier) {
+ if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) {
+ return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo());
+ } else if (warningItemInfoSupplier != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
+ return warningItemInfoSupplier.apply(mPowerAnomalyEvent.getWarningItemInfo());
+ }
+ return null;
+ }
+
+ private int getResourceId(int resourceId, int resourceIndex, String defType) {
+ final String key = getStringFromArrayResource(resourceId, resourceIndex);
+ return TextUtils.isEmpty(key) ? 0
+ : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
+ }
+
+ private String getString(Function<WarningBannerInfo, String> warningBannerInfoSupplier,
+ Function<WarningItemInfo, String> warningItemInfoSupplier,
+ int resourceId, int resourceIndex) {
+ final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier);
+ return (!TextUtils.isEmpty(string) || resourceId <= 0) ? string
+ : getStringFromArrayResource(resourceId, resourceIndex);
+ }
+
+ private String getStringFromArrayResource(int resourceId, int resourceIndex) {
+ if (resourceId <= 0 || resourceIndex < 0) {
+ return null;
+ }
+ final String[] stringArray = mContext.getResources().getStringArray(resourceId);
+ return (resourceIndex >= 0 && resourceIndex < stringArray.length)
+ ? stringArray[resourceIndex] : null;
+ }
+
+ void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) {
+ mRelatedBatteryDiffEntry = batteryDiffEntry;
+ }
+
+ String getEventId() {
+ return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
+ }
+
+ int getIconResId() {
+ return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
+ }
+
+ int getColorResId() {
+ return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
+ }
+
+ String getTitleString() {
+ final String protoTitleString = getInfo(WarningBannerInfo::getTitleString,
+ WarningItemInfo::getTitleString);
+ if (!TextUtils.isEmpty(protoTitleString)) {
+ return protoTitleString;
+ }
+ final int titleFormatResId = getResourceId(R.array.power_anomaly_title_ids,
+ mResourceIndex, "string");
+ if (mPowerAnomalyEvent.hasWarningBannerInfo()) {
+ return mContext.getString(titleFormatResId);
+ } else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) {
+ final String appLabel = mRelatedBatteryDiffEntry.getAppLabel();
+ return mContext.getString(titleFormatResId, appLabel);
+ }
+ return null;
+ }
+
+ String getMainBtnString() {
+ return getString(WarningBannerInfo::getMainButtonString,
+ WarningItemInfo::getMainButtonString,
+ R.array.power_anomaly_main_btn_strings, mResourceIndex);
+ }
+
+ String getDismissBtnString() {
+ return getString(WarningBannerInfo::getCancelButtonString,
+ WarningItemInfo::getCancelButtonString,
+ R.array.power_anomaly_dismiss_btn_strings, mResourceIndex);
+ }
+
+ String getAnomalyHintString() {
+ return getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex);
+ }
+
+ String getDismissRecordKey() {
+ return mPowerAnomalyEvent.getDismissRecordKey();
+ }
+
+ boolean hasAnomalyEntryKey() {
+ return getAnomalyEntryKey() != null;
+ }
+
+ String getAnomalyEntryKey() {
+ return mPowerAnomalyEvent.hasWarningItemInfo()
+ && mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
+ ? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() : null;
+ }
+
+ boolean hasSubSettingLauncher() {
+ if (mSubSettingLauncher == null) {
+ mSubSettingLauncher = getSubSettingLauncher();
+ }
+ return mSubSettingLauncher != null;
+ }
+
+ SubSettingLauncher getSubSettingLauncher() {
+ if (mSubSettingLauncher != null) {
+ return mSubSettingLauncher;
+ }
+ final String destinationClassName = getInfo(
+ WarningBannerInfo::getMainButtonDestination, null);
+ if (!TextUtils.isEmpty(destinationClassName)) {
+ final Integer sourceMetricsCategory = getInfo(
+ WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
+ final String preferenceHighlightKey = getInfo(
+ WarningBannerInfo::getMainButtonSourceHighlightKey, null);
+ Bundle arguments = Bundle.EMPTY;
+ if (!TextUtils.isEmpty(preferenceHighlightKey)) {
+ arguments = new Bundle(1);
+ arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+ preferenceHighlightKey);
+ }
+ mSubSettingLauncher = new SubSettingLauncher(mContext)
+ .setDestination(destinationClassName)
+ .setSourceMetricsCategory(sourceMetricsCategory)
+ .setArguments(arguments);
+ }
+ return mSubSettingLauncher;
+ }
+
+ boolean hasHighlightSlotPair(BatteryLevelData batteryLevelData) {
+ if (mHighlightSlotPair == null) {
+ mHighlightSlotPair = getHighlightSlotPair(batteryLevelData);
+ }
+ return mHighlightSlotPair != null;
+ }
+
+ Pair<Integer, Integer> getHighlightSlotPair(BatteryLevelData batteryLevelData) {
+ if (mHighlightSlotPair != null) {
+ return mHighlightSlotPair;
+ }
+ if (!mPowerAnomalyEvent.hasWarningItemInfo()) {
+ return null;
+ }
+ final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
+ final Long startTimestamp = warningItemInfo.hasStartTimestamp()
+ ? warningItemInfo.getStartTimestamp() : null;
+ final Long endTimestamp = warningItemInfo.hasEndTimestamp()
+ ? warningItemInfo.getEndTimestamp() : null;
+ if (startTimestamp != null && endTimestamp != null) {
+ mHighlightSlotPair = batteryLevelData
+ .getIndexByTimestamps(startTimestamp, endTimestamp);
+ if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID
+ || mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
+ // Drop invalid mHighlightSlotPair index
+ mHighlightSlotPair = null;
+ }
+ }
+ return mHighlightSlotPair;
+ }
+
+ boolean updateTipsCardPreference(BatteryTipsCardPreference preference) {
+ final String titleString = getTitleString();
+ if (TextUtils.isEmpty(titleString)) {
+ return false;
+ }
+ preference.setTitle(titleString);
+ preference.setIconResourceId(getIconResId());
+ preference.setMainButtonStrokeColorResourceId(getColorResId());
+ preference.setMainButtonLabel(getMainBtnString());
+ preference.setDismissButtonLabel(getDismissBtnString());
+ return true;
+ }
+
+ boolean launchSubSetting() {
+ if (!hasSubSettingLauncher()) {
+ return false;
+ }
+ // Navigate to sub setting page
+ mSubSettingLauncher.launch();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 75b7c08..1ae3bef 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -221,14 +221,20 @@
refreshUi();
}
+ boolean isHighlightSlotFocused() {
+ return (mDailyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
+ && mDailyHighlightSlotIndex == mDailyChartIndex
+ && mHourlyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
+ && mHourlyHighlightSlotIndex == mHourlyChartIndex);
+ }
+
void onHighlightSlotIndexUpdate(int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
- if (mDailyHighlightSlotIndex == dailyHighlightSlotIndex
- && mHourlyHighlightSlotIndex == hourlyHighlightSlotIndex) {
- return;
- }
mDailyHighlightSlotIndex = dailyHighlightSlotIndex;
mHourlyHighlightSlotIndex = hourlyHighlightSlotIndex;
refreshUi();
+ if (mOnSelectedIndexUpdatedListener != null) {
+ mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
+ }
}
void selectHighlightSlotIndex() {
@@ -405,7 +411,7 @@
final String slotInformation = getSlotInformation();
return slotInformation == null
? mPrefContext.getString(
- R.string.battery_usage_breakdown_title_since_last_full_charge)
+ R.string.battery_usage_breakdown_title_since_last_full_charge)
: mPrefContext.getString(
R.string.battery_usage_breakdown_title_for_slot, slotInformation);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index e5cff20..2c799fa 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -120,12 +120,10 @@
public void onClick(View view) {
final int viewId = view.getId();
if (viewId == R.id.main_button || viewId == R.id.tips_card) {
- setVisible(false);
if (mOnConfirmListener != null) {
mOnConfirmListener.onConfirm();
}
} else if (viewId == R.id.dismiss_button) {
- setVisible(false);
if (mOnRejectListener != null) {
mOnRejectListener.onReject();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index b3a3508..44b2421 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -18,21 +18,15 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.os.Bundle;
import android.text.TextUtils;
import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.core.SubSettingLauncher;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import java.util.function.Function;
-
/** Controls the update for battery tips card */
public class BatteryTipsController extends BasePreferenceController {
@@ -59,6 +53,10 @@
@VisibleForTesting
BatteryTipsCardPreference mCardPreference;
+ @VisibleForTesting
+ AnomalyEventWrapper mAnomalyEventWrapper = null;
+ @VisibleForTesting
+ Boolean mIsAcceptable = false;
public BatteryTipsController(Context context) {
super(context, ROOT_PREFERENCE_KEY);
@@ -85,132 +83,56 @@
mOnAnomalyRejectListener = listener;
}
- private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
- Function<WarningBannerInfo, T> warningBannerInfoSupplier,
- Function<WarningItemInfo, T> warningItemInfoSupplier) {
- if (warningBannerInfoSupplier != null && powerAnomalyEvent.hasWarningBannerInfo()) {
- return warningBannerInfoSupplier.apply(powerAnomalyEvent.getWarningBannerInfo());
- } else if (warningItemInfoSupplier != null && powerAnomalyEvent.hasWarningItemInfo()) {
- return warningItemInfoSupplier.apply(powerAnomalyEvent.getWarningItemInfo());
+ void acceptTipsCard() {
+ if (mAnomalyEventWrapper == null || !mIsAcceptable) {
+ return;
}
- return null;
- }
-
- private String getStringFromResource(int resourceId, int resourceIndex) {
- if (resourceId < 0) {
- return null;
+ // For anomaly events with same record key, dismissed until next time full charged.
+ final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
+ if (!TextUtils.isEmpty(dismissRecordKey)) {
+ DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
- final String[] stringArray = mContext.getResources().getStringArray(resourceId);
- return (resourceIndex >= 0 && resourceIndex < stringArray.length)
- ? stringArray[resourceIndex] : null;
+ mCardPreference.setVisible(false);
+ mMetricsFeatureProvider.action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
+ mAnomalyEventWrapper.getEventId());
}
- private int getResourceId(int resourceId, int resourceIndex, String defType) {
- final String key = getStringFromResource(resourceId, resourceIndex);
- return TextUtils.isEmpty(key) ? 0
- : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
- }
-
- private String getString(PowerAnomalyEvent powerAnomalyEvent,
- Function<WarningBannerInfo, String> warningBannerInfoSupplier,
- Function<WarningItemInfo, String> warningItemInfoSupplier,
- int resourceId, int resourceIndex) {
- String string =
- getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier);
- return (!TextUtils.isEmpty(string) || resourceId < 0) ? string
- : getStringFromResource(resourceId, resourceIndex);
- }
-
- /** Generate a key string of current anomaly to record as dismissed in sharedPreferences. */
- public static String getDismissRecordKey(PowerAnomalyEvent event) {
- if (!event.hasKey()) {
- return null;
- }
- switch (event.getKey()){
- case KEY_APP:
- return event.hasWarningItemInfo()
- && event.getWarningItemInfo().hasDismissRecordKey()
- ? event.getWarningItemInfo().getDismissRecordKey() : null;
- default:
- return event.getKey().name();
- }
- }
-
- void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
- if (powerAnomalyEvent == null) {
+ void handleBatteryTipsCardUpdated(
+ AnomalyEventWrapper anomalyEventWrapper, boolean isAcceptable) {
+ mAnomalyEventWrapper = anomalyEventWrapper;
+ mIsAcceptable = isAcceptable;
+ if (mAnomalyEventWrapper == null) {
mCardPreference.setVisible(false);
return;
}
- // Get card icon and color styles
- final int cardStyleId = powerAnomalyEvent.getType().getNumber();
- final int iconResId = getResourceId(
- R.array.battery_tips_card_icons, cardStyleId, "drawable");
- final int colorResId = getResourceId(
- R.array.battery_tips_card_colors, cardStyleId, "color");
-
// Get card preference strings and navigate fragment info
- final String eventId = powerAnomalyEvent.hasEventId()
- ? powerAnomalyEvent.getEventId() : null;
- final PowerAnomalyKey powerAnomalyKey = powerAnomalyEvent.hasKey()
- ? powerAnomalyEvent.getKey() : null;
- final int resourceIndex = powerAnomalyKey != null ? powerAnomalyKey.getNumber() : -1;
+ final String eventId = mAnomalyEventWrapper.getEventId();
- final String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
- WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
- if (titleString.isEmpty()) {
+ // Update card & buttons preference
+ if (!mAnomalyEventWrapper.updateTipsCardPreference(mCardPreference)) {
mCardPreference.setVisible(false);
return;
}
- final String mainBtnString = getString(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
- R.array.power_anomaly_main_btn_strings, resourceIndex);
- final String dismissBtnString = getString(powerAnomalyEvent,
- WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
- R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
-
- final String destinationClassName = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonDestination, null);
- final Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
- final String preferenceHighlightKey = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonSourceHighlightKey, null);
-
- // Update card preference and main button fragment launcher
- mCardPreference.setTitle(titleString);
- mCardPreference.setIconResourceId(iconResId);
- mCardPreference.setMainButtonStrokeColorResourceId(colorResId);
- mCardPreference.setMainButtonLabel(mainBtnString);
- mCardPreference.setDismissButtonLabel(dismissBtnString);
-
// Set battery tips card listener
mCardPreference.setOnConfirmListener(() -> {
+ mCardPreference.setVisible(false);
if (mOnAnomalyConfirmListener != null) {
mOnAnomalyConfirmListener.onAnomalyConfirm();
- } else if (!TextUtils.isEmpty(destinationClassName)) {
- // Navigate to sub setting page
- Bundle arguments = Bundle.EMPTY;
- if (!TextUtils.isEmpty(preferenceHighlightKey)) {
- arguments = new Bundle(1);
- arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
- preferenceHighlightKey);
- }
- new SubSettingLauncher(mContext)
- .setDestination(destinationClassName)
- .setSourceMetricsCategory(sourceMetricsCategory)
- .setArguments(arguments)
- .launch();
+ } else if (mAnomalyEventWrapper.launchSubSetting()) {
+ mMetricsFeatureProvider.action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
}
- mMetricsFeatureProvider.action(
- mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
});
mCardPreference.setOnRejectListener(() -> {
+ mCardPreference.setVisible(false);
if (mOnAnomalyRejectListener != null) {
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full charged.
- final String dismissRecordKey = getDismissRecordKey(powerAnomalyEvent);
+ final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index d51485a..4db4d3b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -53,6 +53,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
/** Controller for battery usage breakdown preference group. */
@@ -93,6 +94,14 @@
BatteryDiffData mBatteryDiffData;
@VisibleForTesting
String mPercentLessThanThresholdText;
+ @VisibleForTesting
+ boolean mIsHighlightSlot;
+ @VisibleForTesting
+ String mAnomalyEventId;
+ @VisibleForTesting
+ String mAnomalyEntryKey;
+ @VisibleForTesting
+ String mAnomalyHintString;
public BatteryUsageBreakdownController(
Context context, Lifecycle lifecycle, SettingsActivity activity,
@@ -137,6 +146,12 @@
return false;
}
+ private String getActionKey(String packageName) {
+ final String actionKey = TextUtils.isEmpty(packageName)
+ ? PACKAGE_NAME_NONE : packageName;
+ return mAnomalyEventId == null ? actionKey : actionKey + "|" + mAnomalyEventId;
+ }
+
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!(preference instanceof PowerGaugePreference)) {
@@ -151,7 +166,7 @@
? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
: SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
- TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
+ getActionKey(packageName),
(int) Math.round(diffEntry.getPercentage()));
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
@@ -211,9 +226,23 @@
* used when showing the footer.
*/
void handleBatteryUsageUpdated(
- BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty) {
+ BatteryDiffData slotUsageData, String slotTimestamp,
+ boolean isAllUsageDataEmpty, boolean isHighlightSlot,
+ Optional<AnomalyEventWrapper> optionalAnomalyEventWrapper) {
mBatteryDiffData = slotUsageData;
mSlotTimestamp = slotTimestamp;
+ mIsHighlightSlot = isHighlightSlot;
+
+ if (optionalAnomalyEventWrapper != null) {
+ final AnomalyEventWrapper anomalyEventWrapper =
+ optionalAnomalyEventWrapper.orElse(null);
+ mAnomalyEventId = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getEventId() : null;
+ mAnomalyEntryKey = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getAnomalyEntryKey() : null;
+ mAnomalyHintString = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getAnomalyHintString() : null;
+ }
showCategoryTitle(slotTimestamp);
showSpinnerAndAppList();
@@ -278,15 +307,15 @@
continue;
}
final String prefKey = entry.getKey();
- PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
+ AnomalyAppItemPreference pref = mAppListPreferenceGroup.findPreference(prefKey);
if (pref != null) {
isAdded = true;
} else {
- pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
+ pref = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey);
}
- // Creates new innstance if cached preference is not found.
+ // Creates new instance if cached preference is not found.
if (pref == null) {
- pref = new PowerGaugePreference(mPrefContext);
+ pref = new AnomalyAppItemPreference(mPrefContext);
pref.setKey(prefKey);
mPreferenceCache.put(prefKey, pref);
}
@@ -294,6 +323,10 @@
pref.setTitle(appLabel);
pref.setOrder(prefIndex);
pref.setSingleLineTitle(true);
+ // Updates App item preference style
+ pref.setAnomalyHint(mIsHighlightSlot && mAnomalyEntryKey != null
+ && mAnomalyEntryKey.equals(entry.getKey())
+ ? mAnomalyHintString : null);
// Sets the BatteryDiffEntry to preference for launching detailed page.
pref.setBatteryDiffEntry(entry);
pref.setSelectable(entry.validForRestriction());
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index 1cbf2a3..4a336eb 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -116,8 +116,16 @@
final Handler handler = new Handler(Looper.getMainLooper());
final BatteryLevelData batteryLevelData = DataProcessManager.getBatteryLevelData(
context, handler, /*isFromPeriodJob=*/ true,
- batteryDiffDataMap -> DatabaseUtils.sendBatteryUsageSlotData(context,
- ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap)));
+ batteryDiffDataMap -> {
+ DatabaseUtils.sendBatteryUsageSlotData(context,
+ ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap));
+ if (batteryDiffDataMap.values().stream().anyMatch(data ->
+ data != null && (!data.getAppDiffEntryList().isEmpty()
+ || !data.getSystemDiffEntryList().isEmpty()))) {
+ FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider()
+ .detectSettingsAnomaly(context, /* displayDrain= */ 0);
+ }
+ });
if (batteryLevelData == null) {
Log.d(TAG, "preprocessBatteryUsageSlots() no new battery usage data.");
return;
@@ -139,8 +147,6 @@
// No app usage data or battery diff data at this time.
loadAppUsageData(context);
preprocessBatteryUsageSlots(context);
- FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider()
- .detectSettingsAnomaly(context, /* displayDrain= */ 0);
}
Log.d(TAG, String.format(
"loadUsageDataSafely() in %d/ms", System.currentTimeMillis() - start));
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index 283b742..fb83302 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -52,6 +52,7 @@
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.function.Predicate;
/** Advanced power usage. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -92,9 +93,9 @@
@VisibleForTesting
BatteryUsageBreakdownController mBatteryUsageBreakdownController;
@VisibleForTesting
- PowerAnomalyEvent mPowerAnomalyEvent;
- @VisibleForTesting
Optional<BatteryLevelData> mBatteryLevelData;
+ @VisibleForTesting
+ Optional<AnomalyEventWrapper> mHighlightEventWrapper;
@Override
public void onCreate(Bundle icicle) {
@@ -188,7 +189,7 @@
mIsChartDataLoaded = true;
mBatteryLevelData = null;
mBatteryUsageMap = null;
- mPowerAnomalyEvent = null;
+ mHighlightEventWrapper = null;
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
mBatteryLevelDataLoaderCallbacks);
}
@@ -239,8 +240,13 @@
mScreenOnTimeController.handleSceenOnTimeUpdated(
slotUsageData.getScreenOnTime(), slotInformation);
}
+ // Hide card tips if the related highlight slot was clicked.
+ if (isAppsAnomalyEventFocused()) {
+ mBatteryTipsController.acceptTipsCard();
+ }
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
- slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
+ slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty(),
+ isAppsAnomalyEventFocused(), mHighlightEventWrapper);
Log.d(TAG, String.format("Battery usage list shows in %d millis",
System.currentTimeMillis() - mResumeTimestamp));
}
@@ -261,49 +267,95 @@
return;
}
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
- final PowerAnomalyEvent displayEvent =
- getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
- onDisplayAnomalyEventUpdated(displayEvent);
+
+ final Set<String> dismissedPowerAnomalyKeys =
+ DatabaseUtils.getDismissedPowerAnomalyKeys(getContext());
+ Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
+
+ // Choose an app anomaly event with highest score to show highlight slot
+ final PowerAnomalyEvent highlightEvent =
+ getAnomalyEvent(anomalyEventList, PowerAnomalyEvent::hasWarningItemInfo);
+ // Choose an event never dismissed to show as card.
+ // If the slot is already highlighted, the tips card should be the corresponding app
+ // or settings anomaly event.
+ final PowerAnomalyEvent tipsCardEvent =
+ getAnomalyEvent(anomalyEventList,
+ event -> !dismissedPowerAnomalyKeys.contains(event.getDismissRecordKey())
+ && (event.equals(highlightEvent) || !event.hasWarningItemInfo()));
+ onDisplayAnomalyEventUpdated(tipsCardEvent, highlightEvent);
}
@VisibleForTesting
- void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
- mPowerAnomalyEvent = event;
+ void onDisplayAnomalyEventUpdated(
+ PowerAnomalyEvent tipsCardEvent, PowerAnomalyEvent highlightEvent) {
if (mBatteryTipsController == null
|| mBatteryChartPreferenceController == null
|| mBatteryUsageBreakdownController == null) {
return;
}
+ final boolean isSameAnomalyEvent = (tipsCardEvent == highlightEvent);
// Update battery tips card preference & behaviour
mBatteryTipsController.setOnAnomalyConfirmListener(null);
mBatteryTipsController.setOnAnomalyRejectListener(null);
- mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
+ final AnomalyEventWrapper tipsCardEventWrapper = (tipsCardEvent == null) ? null :
+ new AnomalyEventWrapper(getContext(), tipsCardEvent);
+ if (tipsCardEventWrapper != null) {
+ tipsCardEventWrapper.setRelatedBatteryDiffEntry(
+ findRelatedBatteryDiffEntry(tipsCardEventWrapper));
+ }
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ tipsCardEventWrapper, isSameAnomalyEvent);
// Update highlight slot effect in battery chart view
Pair<Integer, Integer> highlightSlotIndexPair = Pair.create(
BatteryChartViewModel.SELECTED_INDEX_INVALID,
BatteryChartViewModel.SELECTED_INDEX_INVALID);
- if (mPowerAnomalyEvent != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
- final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
- final Long startTimestamp = warningItemInfo.hasStartTimestamp()
- ? warningItemInfo.getStartTimestamp() : null;
- final Long endTimestamp = warningItemInfo.hasEndTimestamp()
- ? warningItemInfo.getEndTimestamp() : null;
- if (startTimestamp != null && endTimestamp != null) {
- highlightSlotIndexPair = mBatteryLevelData.map(levelData ->
- levelData.getIndexByTimestamps(startTimestamp, endTimestamp))
- .orElse(highlightSlotIndexPair);
- mBatteryTipsController.setOnAnomalyConfirmListener(
- mBatteryChartPreferenceController::selectHighlightSlotIndex);
- mBatteryTipsController.setOnAnomalyRejectListener(
- () -> onDisplayAnomalyEventUpdated(null));
+ mHighlightEventWrapper = Optional.ofNullable(isSameAnomalyEvent ? tipsCardEventWrapper :
+ ((highlightEvent != null)
+ ? new AnomalyEventWrapper(getContext(), highlightEvent) : null));
+ if (mBatteryLevelData != null && mBatteryLevelData.isPresent()
+ && mHighlightEventWrapper.isPresent()
+ && mHighlightEventWrapper.get().hasHighlightSlotPair(mBatteryLevelData.get())) {
+ highlightSlotIndexPair = mHighlightEventWrapper.get()
+ .getHighlightSlotPair(mBatteryLevelData.get());
+ if (isSameAnomalyEvent) {
+ // For main button, focus on highlight slot when clicked
+ mBatteryTipsController.setOnAnomalyConfirmListener(() -> {
+ mBatteryChartPreferenceController.selectHighlightSlotIndex();
+ mBatteryTipsController.acceptTipsCard();
+ });
}
}
mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
highlightSlotIndexPair.first, highlightSlotIndexPair.second);
}
+ @VisibleForTesting
+ BatteryDiffEntry findRelatedBatteryDiffEntry(AnomalyEventWrapper eventWrapper) {
+ if (eventWrapper == null
+ || mBatteryLevelData == null || mBatteryLevelData.isEmpty()
+ || !eventWrapper.hasHighlightSlotPair(mBatteryLevelData.get())
+ || !eventWrapper.hasAnomalyEntryKey()
+ || mBatteryUsageMap == null) {
+ return null;
+ }
+ final Pair<Integer, Integer> highlightSlotIndexPair =
+ eventWrapper.getHighlightSlotPair(mBatteryLevelData.get());
+ final BatteryDiffData relatedDiffData = mBatteryUsageMap
+ .get(highlightSlotIndexPair.first).get(highlightSlotIndexPair.second);
+ final String anomalyEntryKey = eventWrapper.getAnomalyEntryKey();
+ if (relatedDiffData == null || anomalyEntryKey == null) {
+ return null;
+ }
+ for (BatteryDiffEntry entry : relatedDiffData.getAppDiffEntryList()) {
+ if (anomalyEntryKey.equals(entry.getKey())) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
private void setBatteryChartPreferenceController() {
if (mHistPref != null && mBatteryChartPreferenceController != null) {
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
@@ -318,6 +370,11 @@
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
}
+ private boolean isAppsAnomalyEventFocused() {
+ return mBatteryChartPreferenceController != null
+ && mBatteryChartPreferenceController.isHighlightSlotFocused();
+ }
+
private void logScreenUsageTime() {
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
if (allBatteryDiffData == null) {
@@ -338,25 +395,22 @@
}
@VisibleForTesting
- static PowerAnomalyEvent getHighestScoreAnomalyEvent(
- Context context, PowerAnomalyEventList anomalyEventList) {
+ static PowerAnomalyEvent getAnomalyEvent(
+ PowerAnomalyEventList anomalyEventList, Predicate<PowerAnomalyEvent> predicate) {
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
return null;
}
- final Set<String> dismissedPowerAnomalyKeys =
- DatabaseUtils.getDismissedPowerAnomalyKeys(context);
- Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
- final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
+ final PowerAnomalyEvent filterAnomalyEvent = anomalyEventList.getPowerAnomalyEventsList()
.stream()
- .filter(event -> !dismissedPowerAnomalyKeys.contains(
- BatteryTipsController.getDismissRecordKey(event)))
+ .filter(predicate)
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
.orElse(null);
- Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
- return highestScoreEvent;
+ Log.d(TAG, "filterAnomalyEvent = " + filterAnomalyEvent);
+ return filterAnomalyEvent;
}
+
private static BatteryDiffData getAllBatteryDiffData(
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
return batteryUsageMap == null ? null : batteryUsageMap
diff --git a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
index 99df215..caa9c35 100644
--- a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -18,6 +18,7 @@
WarningBannerInfo warning_banner_info = 6;
WarningItemInfo warning_item_info = 7;
}
+ optional string dismiss_record_key = 8;
}
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
@@ -32,11 +33,16 @@
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
// The enum value will be used to decide pre-defined title and button labels.
//
-// Next id: 3
+// Next id: 8
enum PowerAnomalyKey{
KEY_BRIGHTNESS = 0;
KEY_SCREEN_TIMEOUT = 1;
- KEY_APP = 2;
+ KEY_APP_TOTAL_ALWAYS_HIGH = 2;
+ KEY_APP_TOTAL_HIGHER_THAN_USUAL = 3;
+ KEY_APP_BACKGROUND_ALWAYS_HIGH = 4;
+ KEY_APP_BACKGROUND_HIGHER_THAN_USUAL = 5;
+ KEY_APP_FOREGROUND_ALWAYS_HIGH = 6;
+ KEY_APP_FOREGROUND_HIGHER_THAN_USUAL = 7;
}
message WarningBannerInfo {
@@ -60,6 +66,5 @@
optional string description_string = 5;
optional string main_button_string = 6;
optional string cancel_button_string = 7;
- optional string dismiss_record_key = 8;
- optional string item_key = 9;
+ optional string item_key = 8;
}
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index ee398a4..f2688c6 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -329,7 +329,7 @@
mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
mDataUsagePreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI)
- .build(), 0 /*subId*/, null /*service*/);
+ .build(), 0 /*subId*/);
mResetInternetPreference = findPreference(PREF_KEY_RESET_INTERNET);
if (mResetInternetPreference != null) {
mResetInternetPreference.setVisible(false);
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 0cd12fe..9974ba2 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -18,7 +18,6 @@
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
-
import static com.android.internal.util.CollectionUtils.emptyIfNull;
import android.annotation.Nullable;
@@ -56,6 +55,8 @@
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -66,6 +67,9 @@
static final String SUB_ID = "sub_id";
@VisibleForTesting
static final String KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME = "unique_subscription_displayName";
+ private static final String REGEX_DISPLAY_NAME_PREFIXES = "^";
+ private static final String REGEX_DISPLAY_NAME_SUFFIXES = "\\s[0-9]+";
+
private static List<SubscriptionInfo> sAvailableResultsForTesting;
private static List<SubscriptionInfo> sActiveResultsForTesting;
@@ -281,8 +285,8 @@
String displayName = i.getDisplayName().toString();
info.originalName =
TextUtils.equals(displayName, PROFILE_GENERIC_DISPLAY_NAME)
- ? context.getResources().getString(R.string.sim_card)
- : displayName.trim();
+ ? context.getResources().getString(R.string.sim_card)
+ : displayName.trim();
return info;
});
@@ -298,12 +302,17 @@
// If a display name is duplicate, append the final 4 digits of the phone number.
// Creates a mapping of Subscription id to original display name + phone number display name
final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
+ int infoSubId = info.subscriptionInfo.getSubscriptionId();
String cachedDisplayName = getDisplayNameFromSharedPreference(
- context, info.subscriptionInfo.getSubscriptionId());
- if (!TextUtils.isEmpty(cachedDisplayName)) {
- Log.d(TAG, "use cached display name : " + cachedDisplayName);
+ context, infoSubId);
+ if (isValidCachedDisplayName(cachedDisplayName, info.originalName.toString())) {
+ Log.d(TAG, "use cached display name : for subId : " + infoSubId
+ + "cached display name : " + cachedDisplayName);
info.uniqueName = cachedDisplayName;
return info;
+ } else {
+ Log.d(TAG, "remove cached display name : " + infoSubId);
+ removeItemFromDisplayNameSharedPreference(context, infoSubId);
}
if (duplicateOriginalNames.contains(info.originalName)) {
@@ -320,9 +329,8 @@
} else {
info.uniqueName = info.originalName + " " + lastFourDigits;
Log.d(TAG, "Cache display name [" + info.uniqueName + "] for sub id "
- + info.subscriptionInfo.getSubscriptionId());
- saveDisplayNameToSharedPreference(
- context, info.subscriptionInfo.getSubscriptionId(), info.uniqueName);
+ + infoSubId);
+ saveDisplayNameToSharedPreference(context, infoSubId, info.uniqueName);
}
} else {
info.uniqueName = info.originalName;
@@ -404,10 +412,27 @@
.apply();
}
+ private static void removeItemFromDisplayNameSharedPreference(Context context, int subId) {
+ getDisplayNameSharedPreferenceEditor(context)
+ .remove(SUB_ID + subId)
+ .commit();
+ }
+
private static String getDisplayNameFromSharedPreference(Context context, int subid) {
return getDisplayNameSharedPreferences(context).getString(SUB_ID + subid, "");
}
+ @VisibleForTesting
+ static boolean isValidCachedDisplayName(String cachedDisplayName, String originalName) {
+ if (TextUtils.isEmpty(cachedDisplayName) || TextUtils.isEmpty(originalName)) {
+ return false;
+ }
+ String regex = REGEX_DISPLAY_NAME_PREFIXES + originalName + REGEX_DISPLAY_NAME_SUFFIXES;
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(cachedDisplayName);
+ return matcher.matches();
+ }
+
public static String getDisplayName(SubscriptionInfo info) {
final CharSequence name = info.getDisplayName();
if (name != null) {
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
new file mode 100644
index 0000000..90d96c6
--- /dev/null
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 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.android.settings.network.apn
+
+import android.net.Uri
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringArrayResource
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavType
+import androidx.navigation.navArgument
+import com.android.settings.R
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
+import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField
+import com.android.settingslib.spa.widget.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import java.util.Base64
+
+const val URI_TYPE = "uriType"
+const val URI = "uri"
+const val SUB_ID = "subId"
+const val MVNO_TYPE = "mvnoType"
+const val MVNO_MATCH_DATA = "mvnoMatchData"
+const val EDIT_URL = "editUrl"
+
+object ApnEditPageProvider : SettingsPageProvider {
+
+ override val name = "Apn"
+ const val TAG = "ApnPageProvider"
+
+ override val parameter = listOf(
+ navArgument(URI_TYPE) { type = NavType.StringType },
+ navArgument(URI) { type = NavType.StringType },
+ navArgument(SUB_ID) { type = NavType.IntType },
+ navArgument(MVNO_TYPE) { type = NavType.StringType },
+ navArgument(MVNO_MATCH_DATA) { type = NavType.StringType },
+ )
+
+ @Composable
+ override fun Page(arguments: Bundle?) {
+ val apnDataInit = ApnData()
+ val apnDataCur = remember {
+ mutableStateOf(apnDataInit)
+ }
+ ApnPage(apnDataCur)
+ }
+
+ fun getRoute(
+ uriType: String,
+ uri: Uri,
+ subId: Int,
+ mMvnoType: String,
+ mMvnoMatchData: String
+ ): String = "${name}/$uriType/${
+ Base64.getUrlEncoder().encodeToString(uri.toString().toByteArray())
+ }/$subId/$mMvnoType/$mMvnoMatchData"
+}
+
+@Composable
+fun ApnPage(apnDataCur: MutableState<ApnData>) {
+ var apnData by apnDataCur
+ val context = LocalContext.current
+ val authTypeOptions = stringArrayResource(R.array.apn_auth_entries).toList()
+ val apnProtocolOptions = stringArrayResource(R.array.apn_protocol_entries).toList()
+ val mvnoTypeOptions = stringArrayResource(R.array.mvno_type_entries).toList()
+
+ RegularScaffold(
+ title = stringResource(id = R.string.apn_edit),
+ ) {
+ Column() {
+ SettingsOutlinedTextField(
+ apnData.name,
+ stringResource(R.string.apn_name),
+ enabled = apnData.nameEnabled
+ ) { apnData = apnData.copy(name = it) }
+ SettingsOutlinedTextField(
+ apnData.apn,
+ stringResource(R.string.apn_apn),
+ enabled = apnData.apnEnabled
+ ) { apnData = apnData.copy(apn = it) }
+ SettingsOutlinedTextField(
+ apnData.proxy,
+ stringResource(R.string.apn_http_proxy),
+ enabled = apnData.proxyEnabled
+ ) { apnData = apnData.copy(proxy = it) }
+ SettingsOutlinedTextField(
+ apnData.port,
+ stringResource(R.string.apn_http_port),
+ enabled = apnData.portEnabled
+ ) { apnData = apnData.copy(port = it) }
+ SettingsOutlinedTextField(
+ apnData.userName,
+ stringResource(R.string.apn_user),
+ enabled = apnData.userNameEnabled
+ ) { apnData = apnData.copy(userName = it) }
+ // TODO: password
+ SettingsOutlinedTextField(
+ apnData.server,
+ stringResource(R.string.apn_server),
+ enabled = apnData.serverEnabled
+ ) { apnData = apnData.copy(server = it) }
+ SettingsOutlinedTextField(
+ apnData.mmsc,
+ stringResource(R.string.apn_mmsc),
+ enabled = apnData.mmscEnabled
+ ) { apnData = apnData.copy(mmsc = it) }
+ SettingsOutlinedTextField(
+ apnData.mmsProxy,
+ stringResource(R.string.apn_mms_proxy),
+ enabled = apnData.mmsProxyEnabled
+ ) { apnData = apnData.copy(mmsProxy = it) }
+ SettingsOutlinedTextField(
+ apnData.mmsPort,
+ stringResource(R.string.apn_mms_port),
+ enabled = apnData.mmsPortEnabled
+ ) { apnData = apnData.copy(mmsPort = it) }
+ SettingsOutlinedTextField(
+ apnData.mcc,
+ stringResource(R.string.apn_mcc),
+ enabled = apnData.mccEnabled
+ ) { apnData = apnData.copy(mcc = it) }
+ SettingsOutlinedTextField(
+ apnData.mnc,
+ stringResource(R.string.apn_mnc),
+ enabled = apnData.mncEnabled
+ ) { apnData = apnData.copy(mnc = it) }
+ // Warning: apnProtocol, apnRoaming, mvnoType string2Int
+ SettingsExposedDropdownMenuBox(
+ stringResource(R.string.apn_auth_type),
+ authTypeOptions,
+ apnData.authType,
+ apnData.authTypeEnabled,
+ ) { apnData = apnData.copy(authType = it) }
+ SettingsOutlinedTextField(
+ apnData.apnType,
+ stringResource(R.string.apn_type),
+ enabled = apnData.apnTypeEnabled
+ ) { apnData = apnData.copy(apn = it) } // TODO: updateApnType
+ SettingsExposedDropdownMenuBox(
+ stringResource(R.string.apn_protocol),
+ apnProtocolOptions,
+ apnData.apnProtocol,
+ apnData.apnProtocolEnabled
+ ) { apnData = apnData.copy(apnProtocol = it) }
+ SettingsExposedDropdownMenuBox(
+ stringResource(R.string.apn_roaming_protocol),
+ apnProtocolOptions,
+ apnData.apnRoaming,
+ apnData.apnRoamingEnabled
+ ) { apnData = apnData.copy(apnRoaming = it) }
+ SwitchPreference(
+ object : SwitchPreferenceModel {
+ override val title = context.resources.getString(R.string.carrier_enabled)
+ override val changeable =
+ stateOf(apnData.apnEnableEnabled)
+ override val checked =
+ stateOf(apnData.apnEnable)
+ override val onCheckedChange = { newChecked: Boolean ->
+ apnData = apnData.copy(apnEnable = newChecked)
+ }
+ }
+ )
+ SettingsExposedDropdownMenuBox(
+ stringResource(R.string.mvno_type),
+ mvnoTypeOptions,
+ apnData.mvnoType,
+ apnData.mvnoTypeEnabled
+ ) {
+ apnData = apnData.copy(mvnoType = it)
+ } // TODO: mvnoDescription
+ SettingsOutlinedTextField(
+ apnData.mvnoValue,
+ stringResource(R.string.mvno_match_data),
+ enabled = apnData.mvnoValueEnabled
+ ) { apnData = apnData.copy(mvnoValue = it) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/network/apn/ApnPreference.java b/src/com/android/settings/network/apn/ApnPreference.java
index f277db0..07d371a 100755
--- a/src/com/android/settings/network/apn/ApnPreference.java
+++ b/src/com/android/settings/network/apn/ApnPreference.java
@@ -16,6 +16,8 @@
package com.android.settings.network.apn;
+import static com.android.settings.network.apn.ApnEditPageProviderKt.EDIT_URL;
+
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
@@ -34,15 +36,21 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.flags.Flags;
+import com.android.settings.spa.SpaActivity;
/**
* Preference of APN UI entry
*/
-public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener,
- View.OnClickListener {
- private static final String TAG = "ApnPreference";
-
+public class ApnPreference extends Preference
+ implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+ private static final String TAG = "ApnPreference";
+ private static String sSelectedKey = null;
+ private static CompoundButton sCurrentChecked = null;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private boolean mProtectFromCheckedChange = false;
+ private boolean mSelectable = true;
+ private boolean mHideDetails = false;
/**
* Constructor of Preference
@@ -65,12 +73,6 @@
this(context, null);
}
- private static String sSelectedKey = null;
- private static CompoundButton sCurrentChecked = null;
- private boolean mProtectFromCheckedChange = false;
- private boolean mSelectable = true;
- private boolean mHideDetails = false;
-
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
@@ -147,25 +149,32 @@
}
if (mHideDetails) {
- Toast.makeText(context, context.getString(
- R.string.cannot_change_apn_toast), Toast.LENGTH_LONG).show();
+ Toast.makeText(context, context.getString(R.string.cannot_change_apn_toast),
+ Toast.LENGTH_LONG).show();
return;
}
- final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
- final Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
- editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
- editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- context.startActivity(editIntent);
- }
- public void setSelectable(boolean selectable) {
- mSelectable = selectable;
+ final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
+
+ if (Flags.newApnPageEnabled()) {
+ String route = ApnEditPageProvider.INSTANCE.getRoute(EDIT_URL, url, mSubId, "_", "_");
+ SpaActivity.startSpaActivity(context, route);
+ } else {
+ final Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
+ editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
+ editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ context.startActivity(editIntent);
+ }
}
public boolean getSelectable() {
return mSelectable;
}
+ public void setSelectable(boolean selectable) {
+ mSelectable = selectable;
+ }
+
public void setSubId(int subId) {
mSubId = subId;
}
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
new file mode 100644
index 0000000..7f4c297
--- /dev/null
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.android.settings.network.apn
+
+import android.provider.Telephony
+import android.telephony.TelephonyManager
+
+data class ApnData(
+ val name: String = "",
+ val apn: String = "",
+ val proxy: String = "",
+ val port: String = "",
+ val userName: String = "",
+ val passWord: String = "",
+ val server: String = "",
+ val mmsc: String = "",
+ val mmsProxy: String = "",
+ val mmsPort: String = "",
+ val mcc: String = "",
+ val mnc: String = "",
+ val authType: Int = -1,
+ val apnType: String = "",
+ val apnProtocol: Int = -1,
+ val apnRoaming: Int = -1,
+ val apnEnable: Boolean = true,
+ val bearer: Int = 0,
+ val mvnoType: Int = -1,
+ var mvnoValue: String = "",
+ val bearerBitmask: Int = 0,
+ val edited: Int = Telephony.Carriers.USER_EDITED,
+ val userEditable: Int = 1,
+ val carrierId: Int = TelephonyManager.UNKNOWN_CARRIER_ID
+) {
+ var nameEnabled = true
+ var apnEnabled = true
+ var proxyEnabled = true
+ var portEnabled = true
+ var userNameEnabled = true
+ var passWordEnabled = true
+ var serverEnabled = true
+ var mmscEnabled = true
+ var mmsProxyEnabled = true
+ var mmsPortEnabled = true
+ var mccEnabled = true
+ var mncEnabled = true
+ var authTypeEnabled = true
+ var apnTypeEnabled = true
+ var apnProtocolEnabled = true
+ var apnRoamingEnabled = true
+ var apnEnableEnabled = true
+ var bearerEnabled = true
+ var mvnoTypeEnabled = true
+ var mvnoValueEnabled = false
+}
\ No newline at end of file
diff --git a/src/com/android/settings/panel/PanelSlicesAdapter.java b/src/com/android/settings/panel/PanelSlicesAdapter.java
index 57d8aa4..a2360d8 100644
--- a/src/com/android/settings/panel/PanelSlicesAdapter.java
+++ b/src/com/android/settings/panel/PanelSlicesAdapter.java
@@ -61,15 +61,12 @@
private final List<LiveData<Slice>> mSliceLiveData;
private final int mMetricsCategory;
private final PanelFragment mPanelFragment;
- private final String mSliceClickActionLabel;
public PanelSlicesAdapter(
PanelFragment fragment, Map<Uri, LiveData<Slice>> sliceLiveData, int metricsCategory) {
mPanelFragment = fragment;
mSliceLiveData = new ArrayList<>(sliceLiveData.values());
mMetricsCategory = metricsCategory;
- mSliceClickActionLabel = mPanelFragment.getContext().getString(
- R.string.accessibility_action_label_panel_slice);
}
@NonNull
@@ -77,7 +74,7 @@
public SliceRowViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
final Context context = viewGroup.getContext();
final LayoutInflater inflater = LayoutInflater.from(context);
- View view;
+ final View view;
if (viewType == PanelContent.VIEW_TYPE_SLIDER) {
view = inflater.inflate(R.layout.panel_slice_slider_row, viewGroup, false);
} else {
@@ -189,7 +186,6 @@
return;
}
sliceView.setTag(ROW_VIEW_TAG, new Object());
-
sliceView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -208,15 +204,17 @@
* Update the action label for TalkBack to be more specific
* @param view the RowView within the Slice
*/
- private void setActionLabel(View view) {
+ @VisibleForTesting void setActionLabel(View view) {
view.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host,
AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
+
AccessibilityNodeInfo.AccessibilityAction customClick =
- new AccessibilityNodeInfo.AccessibilityAction(
- ACTION_CLICK, mSliceClickActionLabel);
+ new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, host
+ .getResources()
+ .getString(R.string.accessibility_action_label_panel_slice));
info.addAction(customClick);
}
});
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 737d1df..800adb0 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -1034,8 +1034,6 @@
getActivity().getWindow().getDecorView());
mPasswordEntryInputDisabler.setInputEnabled(false);
- setNextEnabled(false);
-
mSaveAndFinishWorker = new SaveAndFinishWorker();
mSaveAndFinishWorker
.setListener(this)
diff --git a/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java b/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java
index 9e1d0d5..f72bcd9 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceDashboardFragment.java
@@ -18,7 +18,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.util.FeatureFlagUtils;
+import android.os.Flags;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -56,13 +56,8 @@
new BaseSearchIndexProvider(R.xml.private_space_settings) {
@Override
protected boolean isPageSearchEnabled(Context context) {
- // Temporary workaround for hiding PS Settings until the trunk stable feature
- // flag is available.
- // TODO(b/295516544): Remove this workaround when trunk stable feature flag is
- // available.
return SafetyCenterManagerWrapper.get().isEnabled(context)
- && FeatureFlagUtils.isEnabled(context,
- FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS);
+ && Flags.allowPrivateProfile();
}
@Override
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
index b07c623..4910a7b 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
@@ -20,11 +20,11 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
+import android.os.Flags;
import android.os.UserManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceStatus;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.settings.R;
@@ -35,7 +35,7 @@
/** Private Space safety source for the Safety Center */
public final class PrivateSpaceSafetySource {
public static final String SAFETY_SOURCE_ID = "AndroidPrivateSpace";
- private static final String TAG = "PrivateSpaceSafetySource";
+ private static final String TAG = "PrivateSpaceSafetySrc";
private PrivateSpaceSafetySource() {}
@@ -54,10 +54,7 @@
return;
}
- // Temporary workaround to help prevent the PS Settings showing up in droidfood builds.
- // TODO(b/295516544): remove this when the trunk stable feature flag for PS is available.
- if (!FeatureFlagUtils.isEnabled(context,
- FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS)) {
+ if (!Flags.allowPrivateProfile()) {
// Setting null safetySourceData so that an old entry gets cleared out and this way
// provide a response since SC always expects one on rescan.
SafetyCenterManagerWrapper.get().setSafetySourceData(
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index 4e085c1..6960fc6 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -46,11 +46,11 @@
private static final int REQUEST_CODE_SCREEN_LOCK = 1;
private static final int REQUEST_CODE_SCREEN_LOCK_SETTINGS = 2;
- private LockScreenSafetySource() {
- }
+ private LockScreenSafetySource() {}
/** Sets lock screen safety data for Safety Center. */
- public static void setSafetySourceData(Context context,
+ public static void setSafetySourceData(
+ Context context,
ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils,
SafetyEvent safetyEvent) {
if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
@@ -63,59 +63,61 @@
}
if (!screenLockPreferenceDetailsUtils.isAvailable()) {
- SafetyCenterManagerWrapper.get().setSafetySourceData(
- context,
- SAFETY_SOURCE_ID,
- /* safetySourceData= */ null,
- safetyEvent
- );
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
return;
}
final int userId = UserHandle.myUserId();
- final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
- .checkIfPasswordQualityIsSet(context, userId);
- final PendingIntent pendingIntent = createPendingIntent(context,
- screenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent(
- SettingsEnums.SAFETY_CENTER), REQUEST_CODE_SCREEN_LOCK);
- final IconAction gearMenuIconAction = createGearMenuIconAction(context,
- screenLockPreferenceDetailsUtils);
- final boolean enabled =
+ final RestrictedLockUtils.EnforcedAdmin admin =
+ RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(context, userId);
+ final PendingIntent pendingIntent =
+ createPendingIntent(
+ context,
+ screenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent(
+ SettingsEnums.SAFETY_CENTER),
+ REQUEST_CODE_SCREEN_LOCK);
+ final IconAction gearMenuIconAction =
+ createGearMenuIconAction(context, screenLockPreferenceDetailsUtils);
+ final boolean lockScreenAllowedByAdmin =
!screenLockPreferenceDetailsUtils.isPasswordQualityManaged(userId, admin);
final boolean isLockPatternSecure = screenLockPreferenceDetailsUtils.isLockPatternSecure();
- final int severityLevel = enabled
- ? isLockPatternSecure
- ? SafetySourceData.SEVERITY_LEVEL_INFORMATION
- : SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
- : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
+ final int severityLevel =
+ lockScreenAllowedByAdmin
+ ? isLockPatternSecure
+ ? SafetySourceData.SEVERITY_LEVEL_INFORMATION
+ : SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
+ : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
-
- final SafetySourceStatus status = new SafetySourceStatus.Builder(
- context.getString(R.string.unlock_set_unlock_launch_picker_title),
- screenLockPreferenceDetailsUtils.getSummary(UserHandle.myUserId()),
- severityLevel)
- .setPendingIntent(pendingIntent)
- .setEnabled(enabled)
- .setIconAction(gearMenuIconAction).build();
+ final SafetySourceStatus status =
+ new SafetySourceStatus.Builder(
+ context.getString(R.string.unlock_set_unlock_launch_picker_title),
+ lockScreenAllowedByAdmin
+ ? screenLockPreferenceDetailsUtils.getSummary(
+ UserHandle.myUserId())
+ : context.getString(R.string.disabled_by_policy_title),
+ severityLevel)
+ .setPendingIntent(lockScreenAllowedByAdmin ? pendingIntent : null)
+ .setEnabled(lockScreenAllowedByAdmin)
+ .setIconAction(lockScreenAllowedByAdmin ? gearMenuIconAction : null)
+ .build();
final SafetySourceData.Builder safetySourceDataBuilder =
new SafetySourceData.Builder().setStatus(status);
- if (enabled && !isLockPatternSecure) {
+ if (lockScreenAllowedByAdmin && !isLockPatternSecure) {
safetySourceDataBuilder.addIssue(createNoScreenLockIssue(context, pendingIntent));
}
final SafetySourceData safetySourceData = safetySourceDataBuilder.build();
- SafetyCenterManagerWrapper.get().setSafetySourceData(
- context,
- SAFETY_SOURCE_ID,
- safetySourceData,
- safetyEvent
- );
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(context, SAFETY_SOURCE_ID, safetySourceData, safetyEvent);
}
/** Notifies Safety Center of a change in lock screen settings. */
public static void onLockScreenChange(Context context) {
setSafetySourceData(
- context, new ScreenLockPreferenceDetailsUtils(context),
+ context,
+ new ScreenLockPreferenceDetailsUtils(context),
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build());
// Also send refreshed safety center data for biometrics, since changing lockscreen settings
@@ -123,45 +125,45 @@
BiometricsSafetySource.onBiometricsChanged(context);
}
- private static IconAction createGearMenuIconAction(Context context,
- ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) {
- return screenLockPreferenceDetailsUtils.shouldShowGearMenu() ? new IconAction(
- IconAction.ICON_TYPE_GEAR,
- createPendingIntent(context,
- screenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent(
- SettingsEnums.SAFETY_CENTER),
- REQUEST_CODE_SCREEN_LOCK_SETTINGS))
+ private static IconAction createGearMenuIconAction(
+ Context context, ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) {
+ return screenLockPreferenceDetailsUtils.shouldShowGearMenu()
+ ? new IconAction(
+ IconAction.ICON_TYPE_GEAR,
+ createPendingIntent(
+ context,
+ screenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent(
+ SettingsEnums.SAFETY_CENTER),
+ REQUEST_CODE_SCREEN_LOCK_SETTINGS))
: null;
}
- private static PendingIntent createPendingIntent(Context context, Intent intent,
- int requestCode) {
- return PendingIntent
- .getActivity(
- context,
- requestCode,
- intent,
- PendingIntent.FLAG_IMMUTABLE);
+ private static PendingIntent createPendingIntent(
+ Context context, Intent intent, int requestCode) {
+ return PendingIntent.getActivity(
+ context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);
}
- private static SafetySourceIssue createNoScreenLockIssue(Context context,
- PendingIntent pendingIntent) {
- final SafetySourceIssue.Action action = new SafetySourceIssue.Action.Builder(
- SET_SCREEN_LOCK_ACTION_ID,
- context.getString(R.string.no_screen_lock_issue_action_label),
- pendingIntent).build();
+ private static SafetySourceIssue createNoScreenLockIssue(
+ Context context, PendingIntent pendingIntent) {
+ final SafetySourceIssue.Action action =
+ new SafetySourceIssue.Action.Builder(
+ SET_SCREEN_LOCK_ACTION_ID,
+ context.getString(R.string.no_screen_lock_issue_action_label),
+ pendingIntent)
+ .build();
// Custom notification deliberately has zero actions
final SafetySourceIssue.Notification customNotification =
- new SafetySourceIssue.Notification.Builder(
- context.getString(R.string.no_screen_lock_issue_notification_title),
- context.getString(R.string.no_screen_lock_issue_notification_text))
- .build();
+ new SafetySourceIssue.Notification.Builder(
+ context.getString(R.string.no_screen_lock_issue_notification_title),
+ context.getString(R.string.no_screen_lock_issue_notification_text))
+ .build();
return new SafetySourceIssue.Builder(
- NO_SCREEN_LOCK_ISSUE_ID,
- context.getString(R.string.no_screen_lock_issue_title),
- context.getString(R.string.no_screen_lock_issue_summary),
- SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
- NO_SCREEN_LOCK_ISSUE_TYPE_ID)
+ NO_SCREEN_LOCK_ISSUE_ID,
+ context.getString(R.string.no_screen_lock_issue_title),
+ context.getString(R.string.no_screen_lock_issue_summary),
+ SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
+ NO_SCREEN_LOCK_ISSUE_TYPE_ID)
.setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
.addAction(action)
.setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index f08a2de..40cc9a2 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.util.FeatureFlagUtils
+import com.android.settings.network.apn.ApnEditPageProvider
import com.android.settings.spa.about.AboutPhonePageProvider
import com.android.settings.spa.app.AllAppListPageProvider
import com.android.settings.spa.app.AppsMainPageProvider
@@ -34,8 +35,8 @@
import com.android.settings.spa.app.specialaccess.NfcTagAppsSettingsProvider
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
-import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.storage.StorageAppListPageProvider
import com.android.settings.spa.core.instrumentation.SpaLogProvider
import com.android.settings.spa.development.UsageStatsPageProvider
@@ -95,6 +96,7 @@
AboutPhonePageProvider,
StorageAppListPageProvider.Apps,
StorageAppListPageProvider.Games,
+ ApnEditPageProvider,
) + togglePermissionAppListTemplate.createPageProviders(),
rootPages = listOf(
HomePageProvider.createSettingsPage()
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
index 5206343..61098e8 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -41,7 +41,7 @@
if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
Preference(object : PreferenceModel {
- override val title = stringResource(R.string.aspect_ratio_title)
+ override val title = stringResource(R.string.aspect_ratio_experimental_title)
override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
initialValue = stringResource(R.string.summary_placeholder),
)
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index f403743..e74f1e3 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -82,7 +82,7 @@
@VisibleForTesting
fun EntryItem() =
Preference(object : PreferenceModel {
- override val title = stringResource(R.string.aspect_ratio_title)
+ override val title = stringResource(R.string.aspect_ratio_experimental_title)
override val summary = getSummary().toState()
override val onClick = navigator(name)
})
@@ -104,7 +104,7 @@
= { AppList() },
) {
AppListPage(
- title = stringResource(R.string.aspect_ratio_title),
+ title = stringResource(R.string.aspect_ratio_experimental_title),
listModel = rememberContext(::UserAspectRatioAppListModel),
appList = appList,
header = {
@@ -115,7 +115,8 @@
override val resId = R.raw.user_aspect_ratio_education
override val resourceType = ResourceType.LOTTIE
})
- }
+ },
+ noMoreOptions = true,
)
}
diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java
index 79c5b9f..678b675 100644
--- a/src/com/android/settings/system/SystemDashboardFragment.java
+++ b/src/com/android/settings/system/SystemDashboardFragment.java
@@ -16,9 +16,7 @@
package com.android.settings.system;
import android.app.settings.SettingsEnums;
-import android.content.Context;
import android.os.Bundle;
-import android.provider.SearchIndexableResource;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
@@ -29,9 +27,6 @@
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
-import java.util.Arrays;
-import java.util.List;
-
@SearchIndexable
public class SystemDashboardFragment extends DashboardFragment {
@@ -85,13 +80,5 @@
* For Search.
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.system_dashboard_fragment;
- return Arrays.asList(sir);
- }
- };
-}
\ No newline at end of file
+ new BaseSearchIndexProvider(R.xml.system_dashboard_fragment);
+}
diff --git a/src/com/android/settings/system/SystemUpdateManagerExt.kt b/src/com/android/settings/system/SystemUpdateManagerExt.kt
new file mode 100644
index 0000000..8ddf174
--- /dev/null
+++ b/src/com/android/settings/system/SystemUpdateManagerExt.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.android.settings.system
+
+import android.content.Context
+import android.os.Bundle
+import android.os.SystemUpdateManager
+import android.util.Log
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+private const val TAG = "SystemUpdateManagerExt"
+
+/**
+ * Gets the system update status.
+ *
+ * Note: [SystemUpdateManager.retrieveSystemUpdateInfo] must be called on worker thread to avoid
+ * StrictMode violation.
+ */
+suspend fun Context.getSystemUpdateInfo(): Bundle? = withContext(Dispatchers.Default) {
+ val updateManager = getSystemService(SystemUpdateManager::class.java)!!
+ try {
+ updateManager.retrieveSystemUpdateInfo()
+ } catch (e: Exception) {
+ Log.w(TAG, "Error getting system update info.")
+ null
+ }
+}
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.java b/src/com/android/settings/system/SystemUpdatePreferenceController.java
deleted file mode 100644
index b2a22ff..0000000
--- a/src/com/android/settings/system/SystemUpdatePreferenceController.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2016 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.android.settings.system;
-
-import static android.content.Context.CARRIER_CONFIG_SERVICE;
-import static android.content.Context.SYSTEM_UPDATE_SERVICE;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.os.SystemUpdateManager;
-import android.os.UserManager;
-import android.telephony.CarrierConfigManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-public class SystemUpdatePreferenceController extends BasePreferenceController {
-
- private static final String TAG = "SysUpdatePrefContr";
-
- private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
-
- private final UserManager mUm;
- private final SystemUpdateManager mUpdateManager;
-
- public SystemUpdatePreferenceController(Context context) {
- super(context, KEY_SYSTEM_UPDATE_SETTINGS);
- mUm = UserManager.get(context);
- mUpdateManager = (SystemUpdateManager) context.getSystemService(SYSTEM_UPDATE_SERVICE);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return mContext.getResources().getBoolean(R.bool.config_show_system_update_settings)
- && mUm.isAdminUser()
- ? AVAILABLE
- : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- if (isAvailable()) {
- Utils.updatePreferenceToSpecificActivityOrRemove(mContext, screen,
- getPreferenceKey(),
- Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
- }
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
- CarrierConfigManager configManager =
- (CarrierConfigManager) mContext.getSystemService(CARRIER_CONFIG_SERVICE);
- PersistableBundle b = configManager.getConfig();
- if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
- ciActionOnSysUpdate(b);
- }
- }
- // always return false here because this handler does not want to block other handlers.
- return false;
- }
-
- @Override
- public CharSequence getSummary() {
- CharSequence summary = mContext.getString(R.string.android_version_summary,
- Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY);
- final FutureTask<Bundle> bundleFutureTask = new FutureTask<>(
- // Put the API call in a future to avoid StrictMode violation.
- () -> mUpdateManager.retrieveSystemUpdateInfo());
- final Bundle updateInfo;
- try {
- bundleFutureTask.run();
- updateInfo = bundleFutureTask.get();
- } catch (InterruptedException | ExecutionException e) {
- Log.w(TAG, "Error getting system update info.");
- return summary;
- }
- switch (updateInfo.getInt(SystemUpdateManager.KEY_STATUS)) {
- case SystemUpdateManager.STATUS_WAITING_DOWNLOAD:
- case SystemUpdateManager.STATUS_IN_PROGRESS:
- case SystemUpdateManager.STATUS_WAITING_INSTALL:
- case SystemUpdateManager.STATUS_WAITING_REBOOT:
- summary = mContext.getText(R.string.android_version_pending_update_summary);
- break;
- case SystemUpdateManager.STATUS_UNKNOWN:
- Log.d(TAG, "Update statue unknown");
- // fall through to next branch
- case SystemUpdateManager.STATUS_IDLE:
- final String version = updateInfo.getString(SystemUpdateManager.KEY_TITLE);
- if (!TextUtils.isEmpty(version)) {
- summary = mContext.getString(R.string.android_version_summary, version);
- }
- break;
- }
- return summary;
- }
-
- /**
- * Trigger client initiated action (send intent) on system update
- */
- private void ciActionOnSysUpdate(PersistableBundle b) {
- String intentStr = b.getString(CarrierConfigManager.
- KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING);
- if (!TextUtils.isEmpty(intentStr)) {
- String extra = b.getString(CarrierConfigManager.
- KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING);
- String extraVal = b.getString(CarrierConfigManager.
- KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING);
-
- Intent intent = new Intent(intentStr);
- if (!TextUtils.isEmpty(extra)) {
- intent.putExtra(extra, extraVal);
- }
- Log.d(TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr +
- " with extra " + extra + ", " + extraVal);
- intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mContext.getApplicationContext().sendBroadcast(intent);
- }
- }
-}
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.kt b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
new file mode 100644
index 0000000..01df065
--- /dev/null
+++ b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 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.android.settings.system
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.PersistableBundle
+import android.os.SystemUpdateManager
+import android.os.UserManager
+import android.telephony.CarrierConfigManager
+import android.util.Log
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import com.android.settings.R
+import com.android.settings.Utils
+import com.android.settings.core.BasePreferenceController
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import kotlinx.coroutines.launch
+
+open class SystemUpdatePreferenceController(context: Context, preferenceKey: String) :
+ BasePreferenceController(context, preferenceKey) {
+ private val userManager: UserManager = context.userManager
+ private lateinit var preference: Preference
+
+ override fun getAvailabilityStatus() =
+ if (mContext.resources.getBoolean(R.bool.config_show_system_update_settings) &&
+ userManager.isAdminUser
+ ) AVAILABLE else UNSUPPORTED_ON_DEVICE
+
+ override fun displayPreference(screen: PreferenceScreen) {
+ super.displayPreference(screen)
+ preference = screen.findPreference(preferenceKey)!!
+ if (isAvailable) {
+ Utils.updatePreferenceToSpecificActivityOrRemove(
+ mContext,
+ screen,
+ preferenceKey,
+ Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY,
+ )
+ }
+ }
+
+ override fun handlePreferenceTreeClick(preference: Preference): Boolean {
+ if (preferenceKey == preference.key) {
+ val configManager = mContext.getSystemService(CarrierConfigManager::class.java)!!
+ configManager.getConfig(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)?.let {
+ if (it.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
+ ciActionOnSysUpdate(it)
+ }
+ }
+ }
+ // always return false here because this handler does not want to block other handlers.
+ return false
+ }
+
+ override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ preference.summary = calculateSummary()
+ }
+ }
+ }
+
+ private suspend fun calculateSummary(): String {
+ val updateInfo = mContext.getSystemUpdateInfo() ?: return getReleaseVersionSummary()
+
+ val status = updateInfo.getInt(SystemUpdateManager.KEY_STATUS)
+ if (status == SystemUpdateManager.STATUS_UNKNOWN) {
+ Log.d(TAG, "Update statue unknown")
+ }
+ when (status) {
+ SystemUpdateManager.STATUS_WAITING_DOWNLOAD,
+ SystemUpdateManager.STATUS_IN_PROGRESS,
+ SystemUpdateManager.STATUS_WAITING_INSTALL,
+ SystemUpdateManager.STATUS_WAITING_REBOOT -> {
+ return mContext.getString(R.string.android_version_pending_update_summary)
+ }
+
+ SystemUpdateManager.STATUS_IDLE,
+ SystemUpdateManager.STATUS_UNKNOWN -> {
+ val version = updateInfo.getString(SystemUpdateManager.KEY_TITLE)
+ if (!version.isNullOrEmpty()) {
+ return mContext.getString(R.string.android_version_summary, version)
+ }
+ }
+ }
+ return getReleaseVersionSummary()
+ }
+
+ private fun getReleaseVersionSummary(): String = mContext.getString(
+ R.string.android_version_summary,
+ Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY,
+ )
+
+ /**
+ * Trigger client initiated action (send intent) on system update
+ */
+ private fun ciActionOnSysUpdate(b: PersistableBundle) {
+ val intentStr = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING)
+ if (intentStr.isNullOrEmpty()) return
+ val extra = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING)
+ val extraVal =
+ b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING)
+ Log.d(
+ TAG,
+ "ciActionOnSysUpdate: broadcasting intent $intentStr with extra $extra, $extraVal"
+ )
+ val intent = Intent(intentStr).apply {
+ if (!extra.isNullOrEmpty()) putExtra(extra, extraVal)
+ addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND)
+ }
+ mContext.applicationContext.sendBroadcast(intent)
+ }
+
+ companion object {
+ private const val TAG = "SysUpdatePrefContr"
+ }
+}
diff --git a/src/com/android/settings/widget/HighlightablePreferenceGroupAdapter.java b/src/com/android/settings/widget/HighlightablePreferenceGroupAdapter.java
index a64ec89..a93a986 100644
--- a/src/com/android/settings/widget/HighlightablePreferenceGroupAdapter.java
+++ b/src/com/android/settings/widget/HighlightablePreferenceGroupAdapter.java
@@ -122,6 +122,9 @@
&& TextUtils.equals(mHighlightKey, getItem(position).getKey()))) {
// This position should be highlighted. If it's highlighted before - skip animation.
addHighlightBackground(holder, !mFadeInAnimated);
+ if (v != null) {
+ v.requestAccessibilityFocus();
+ }
} else if (Boolean.TRUE.equals(v.getTag(R.id.preference_highlighted))) {
// View with highlight is reused for a view that should not have highlight
removeHighlightBackground(holder, false /* animate */);
diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java
index 9450bb9..6d94fc9 100644
--- a/src/com/android/settings/widget/RadioButtonPickerFragment.java
+++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java
@@ -16,6 +16,7 @@
package com.android.settings.widget;
+import android.annotation.AnyRes;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
@@ -38,6 +39,7 @@
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import com.android.settingslib.widget.CandidateInfo;
+import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.xmlpull.v1.XmlPullParserException;
@@ -64,7 +66,7 @@
protected int mUserId;
private int mIllustrationId;
private int mIllustrationPreviewId;
- private VideoPreference mVideoPreference;
+ private IllustrationType mIllustrationType;
@Override
public void onAttach(Context context) {
@@ -252,18 +254,41 @@
/**
* Allows you to set an illustration at the top of this screen. Set the illustration id to 0
* if you want to remove the illustration.
- * @param illustrationId The res id for the raw of the illustration.
- * @param previewId The res id for the drawable of the illustration
+ *
+ * @param illustrationId The res id for the raw of the illustration.
+ * @param previewId The res id for the drawable of the illustration.
+ * @param illustrationType The illustration type for the raw of the illustration.
*/
- protected void setIllustration(int illustrationId, int previewId) {
+ protected void setIllustration(@AnyRes int illustrationId, @AnyRes int previewId,
+ IllustrationType illustrationType) {
mIllustrationId = illustrationId;
mIllustrationPreviewId = previewId;
+ mIllustrationType = illustrationType;
+ }
+
+ /**
+ * Allows you to set an illustration at the top of this screen. Set the illustration id to 0
+ * if you want to remove the illustration.
+ *
+ * @param illustrationId The res id for the raw of the illustration.
+ * @param illustrationType The illustration type for the raw of the illustration.
+ */
+ protected void setIllustration(@AnyRes int illustrationId, IllustrationType illustrationType) {
+ setIllustration(illustrationId, 0, illustrationType);
}
private void addIllustration(PreferenceScreen screen) {
- mVideoPreference = new VideoPreference(getContext());
- mVideoPreference.setVideo(mIllustrationId, mIllustrationPreviewId);
- screen.addPreference(mVideoPreference);
+ switch (mIllustrationType) {
+ case LOTTIE_ANIMATION:
+ IllustrationPreference illustrationPreference = new IllustrationPreference(
+ getContext());
+ illustrationPreference.setLottieAnimationResId(mIllustrationId);
+ screen.addPreference(illustrationPreference);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid illustration type: " + mIllustrationType);
+ }
}
protected abstract List<? extends CandidateInfo> getCandidates();
@@ -284,4 +309,8 @@
return 0;
}
+ protected enum IllustrationType {
+ LOTTIE_ANIMATION
+ }
+
}
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 82edea5..a5767e4 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -53,7 +53,6 @@
<bool name="config_show_pointer_speed">false</bool>
<bool name="config_show_vibrate_input_devices">false</bool>
<bool name="config_show_reset_dashboard">false</bool>
- <bool name="config_show_system_update_settings">false</bool>
<bool name="config_show_device_model">false</bool>
<bool name="config_show_top_level_accessibility">false</bool>
<bool name="config_show_top_level_battery">false</bool>
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
index 6d45af2..9368ec8 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
@@ -156,14 +156,13 @@
}
@Test
- public void launchHearingAidPairingDialog_deviceSupportsCsip_csipEnabled_noDialog() {
+ public void launchHearingAidPairingDialog_deviceSupportsCsip_noDialog() {
when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
HearingAidInfo.DeviceSide.SIDE_LEFT);
makeDeviceSupportCsip();
- makeDeviceEnableCsip(true);
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice,
TEST_LAUNCH_PAGE);
@@ -174,24 +173,6 @@
}
@Test
- public void launchHearingAidPairingDialog_deviceSupportsCsip_csipDisabled_dialogShown() {
- when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidInfo.DeviceMode.MODE_BINAURAL);
- when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidInfo.DeviceSide.SIDE_LEFT);
- makeDeviceSupportCsip();
- makeDeviceEnableCsip(false);
-
- HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice,
- TEST_LAUNCH_PAGE);
-
- shadowMainLooper().idle();
- final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(dialog.isShowing()).isTrue();
- }
-
- @Test
public void launchHearingAidPairingDialog_dialogShown() {
when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
@@ -213,11 +194,6 @@
when(mCachedBluetoothDevice.getProfiles()).thenReturn(uuids);
}
- private void makeDeviceEnableCsip(boolean enabled) {
- when(mCsipSetCoordinatorProfile.isEnabled(mCachedBluetoothDevice.getDevice()))
- .thenReturn(enabled);
- }
-
private void setupEnvironment() {
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
index 04b48c0..f3fa69d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
@@ -39,21 +39,21 @@
import android.graphics.Color;
import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.testing.FragmentScenario;
+import androidx.lifecycle.Lifecycle;
import com.android.settings.R;
import com.android.settings.testutils.FakeTimer;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.ShadowContextWrapper;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
-import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.function.Consumer;
@@ -61,7 +61,7 @@
@RunWith(RobolectricTestRunner.class)
public class ScreenFlashNotificationColorDialogFragmentTest {
- private ShadowContextWrapper mShadowContextWrapper;
+ private FragmentScenario<TestScreenFlashNotificationColorDialogFragment> mFragmentScenario;
private ScreenFlashNotificationColorDialogFragment mDialogFragment;
private AlertDialog mAlertDialog;
private ColorSelectorLayout mColorSelectorLayout;
@@ -69,35 +69,32 @@
@Before
public void setUp() {
- FragmentActivity fragmentActivity = Robolectric.setupActivity(FragmentActivity.class);
- mShadowContextWrapper = shadowOf(fragmentActivity);
-
mCurrentColor = ROSE.mColorInt;
- mDialogFragment = createFragment();
+ mFragmentScenario = FragmentScenario.launch(
+ TestScreenFlashNotificationColorDialogFragment.class,
+ /* fragmentArgs= */ null,
+ R.style.Theme_AlertDialog_SettingsLib,
+ Lifecycle.State.INITIALIZED);
+ setupFragment();
+ }
- mDialogFragment.show(fragmentActivity.getSupportFragmentManager(), "test");
-
- mAlertDialog = (AlertDialog) mDialogFragment.getDialog();
- if (mAlertDialog != null) {
- mColorSelectorLayout = mAlertDialog.findViewById(R.id.color_selector_preference);
- }
+ @After
+ public void cleanUp() {
+ mFragmentScenario.close();
}
@Test
- @Ignore
public void test_assertShow() {
assertThat(mAlertDialog.isShowing()).isTrue();
}
@Test
- @Ignore
public void clickNeutral_assertShow() {
performClickOnDialog(BUTTON_NEUTRAL);
assertThat(mAlertDialog.isShowing()).isTrue();
}
@Test
- @Ignore
public void clickNeutral_assertStartPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runOneTask();
@@ -106,7 +103,6 @@
}
@Test
- @Ignore
public void clickNeutral_flushAllScheduledTasks_assertStopPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runAllTasks();
@@ -115,31 +111,28 @@
}
@Test
- @Ignore
public void clickNegative_assertNotShow() {
performClickOnDialog(BUTTON_NEGATIVE);
assertThat(mAlertDialog.isShowing()).isFalse();
}
@Test
- @Ignore
public void clickPositive_assertNotShow() {
performClickOnDialog(BUTTON_POSITIVE);
assertThat(mAlertDialog.isShowing()).isFalse();
}
@Test
- @Ignore
public void clickNeutralAndPause_assertStopPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runOneTask();
- mDialogFragment.onPause();
+ // move the state from RESUMED to CREATED to make fragment's onPause() to be called
+ mFragmentScenario.moveToState(Lifecycle.State.CREATED);
assertStopPreview();
}
@Test
- @Ignore
public void clickNeutralAndClickNegative_assertStopPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runOneTask();
@@ -149,7 +142,6 @@
}
@Test
- @Ignore
public void clickNeutralAndClickPositive_assertStopPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runOneTask();
@@ -159,7 +151,6 @@
}
@Test
- @Ignore
public void clickNeutralAndClickColor_assertStartPreview() {
performClickOnDialog(BUTTON_NEUTRAL);
getTimerFromFragment().runOneTask();
@@ -177,7 +168,6 @@
}
@Test
- @Ignore
public void clickColorAndClickNegative_assertColor() {
checkColorButton(AZURE);
performClickOnDialog(BUTTON_NEGATIVE);
@@ -187,7 +177,6 @@
}
@Test
- @Ignore
public void clickColorAndClickPositive_assertColor() {
checkColorButton(BLUE);
performClickOnDialog(BUTTON_POSITIVE);
@@ -201,23 +190,32 @@
private void performClickOnDialog(int whichButton) {
mAlertDialog.getButton(whichButton).performClick();
+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
}
private Intent getLastCapturedIntent() {
- final List<Intent> capturedIntents = new ArrayList<>(
- mShadowContextWrapper.getBroadcastIntents());
+ final List<Intent> capturedIntents =
+ shadowOf(RuntimeEnvironment.getApplication()).getBroadcastIntents();
final int size = capturedIntents.size();
return capturedIntents.get(size - 1);
}
- private ScreenFlashNotificationColorDialogFragment createFragment() {
- ScreenFlashNotificationColorDialogFragmentWithFakeTimer fragment =
- new ScreenFlashNotificationColorDialogFragmentWithFakeTimer();
- ReflectionHelpers.setField(fragment, "mCurrentColor", mCurrentColor);
- ReflectionHelpers.setField(fragment, "mConsumer",
- (Consumer<Integer>) selectedColor -> mCurrentColor = selectedColor);
+ private void setupFragment() {
+ mFragmentScenario.onFragment(fragment -> {
+ ReflectionHelpers.setField(fragment, "mCurrentColor", mCurrentColor);
+ ReflectionHelpers.setField(fragment, "mConsumer",
+ (Consumer<Integer>) selectedColor -> mCurrentColor = selectedColor);
+ });
+ mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
- return fragment;
+ mFragmentScenario.onFragment(fragment -> {
+ assertThat(fragment.getDialog()).isNotNull();
+ assertThat(fragment.requireDialog().isShowing()).isTrue();
+ assertThat(fragment.requireDialog()).isInstanceOf(AlertDialog.class);
+ mAlertDialog = (AlertDialog) fragment.requireDialog();
+ mDialogFragment = fragment;
+ mColorSelectorLayout = mAlertDialog.findViewById(R.id.color_selector_preference);
+ });
}
private FakeTimer getTimerFromFragment() {
@@ -243,7 +241,7 @@
* A {@link ScreenFlashNotificationColorDialogFragment} that uses a fake timer so that it won't
* create unmanageable timer threads during test.
*/
- public static class ScreenFlashNotificationColorDialogFragmentWithFakeTimer extends
+ public static class TestScreenFlashNotificationColorDialogFragment extends
ScreenFlashNotificationColorDialogFragment {
@Override
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
index 090fb0c..2bd2d74 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
@@ -34,6 +34,9 @@
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
+import java.util.HashSet;
+import java.util.Set;
+
/** Tests for {@link BluetoothDetailsPairOtherController}. */
@RunWith(RobolectricTestRunner.class)
public class BluetoothDetailsPairOtherControllerTest extends BluetoothDetailsControllerTestBase {
@@ -60,8 +63,9 @@
mScreen.addPreference(mSpacePreference);
}
+ /** Test the pair other side button title during initialization. */
@Test
- public void init_leftSideDevice_rightSideButtonTitle() {
+ public void init_leftSideDevice_pairRightSideButtonTitle() {
when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_LEFT);
mController.init(mScreen);
@@ -70,8 +74,9 @@
mContext.getString(R.string.bluetooth_pair_right_ear_button));
}
+ /** Test the pair other side button title during initialization. */
@Test
- public void init_rightSideDevice_leftSideButtonTitle() {
+ public void init_rightSideDevice_pairLeftSideButtonTitle() {
when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
mController.init(mScreen);
@@ -80,9 +85,10 @@
mContext.getString(R.string.bluetooth_pair_left_ear_button));
}
+ /** Test the pair other side button visibility during initialization. */
@Test
- public void init_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
- when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
+ public void init_isNotConnectedHearingAidDevice_preferenceIsNotVisible() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
mController.init(mScreen);
@@ -90,23 +96,49 @@
assertThat(mSpacePreference.isVisible()).isFalse();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Hearing aids is not connected
+ * Expected result:
+ * The controller is not available. No need to show pair other side hint for
+ * not connected device.
+ */
@Test
- public void isAvailable_isNotConnectedAshaHearingAidDevice_notAvailable() {
- when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
+ public void isAvailable_isNotConnectedHearingAidDevice_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Monaural hearing aids
+ * Expected result:
+ * The controller is not available. No need to show pair other side hint for
+ * monaural device.
+ */
@Test
- public void isAvailable_isConnectedAshaHearingAidDevice_isMonaural_notAvailable() {
- when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+ public void isAvailable_isConnectedHearingAidDevice_isMonaural_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_MONAURAL);
assertThat(mController.isAvailable()).isFalse();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural ASHA hearing aids
+ * 2. Sub device is added
+ * 3. Sub device is connected
+ * Expected result:
+ * The controller is not available. Both sides are already paired and connected.
+ */
@Test
- public void isAvailable_subDeviceIsConnectedAshaHearingAidDevice_notAvailable() {
+ public void isAvailable_ashaDevice_otherDeviceIsConnected_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
@@ -115,8 +147,18 @@
assertThat(mController.isAvailable()).isFalse();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural ASHA hearing aids
+ * 2. Sub device is added
+ * 3. Sub device is not connected
+ * Expected result:
+ * The controller is available. Need to show the hint to pair the other side.
+ */
@Test
- public void isAvailable_subDeviceIsNotConnectedAshaHearingAidDevice_available() {
+ public void isAvailable_ashaDevice_otherDeviceIsNotConnected_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
@@ -125,8 +167,17 @@
assertThat(mController.isAvailable()).isTrue();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural ASHA hearing aids
+ * 2. No sub device added
+ * Expected result:
+ * The controller is available. Need to show the hint to pair the other side.
+ */
@Test
- public void isAvailable_subDeviceNotExist_available() {
+ public void isAvailable_ashaDevice_otherDeviceIsNotExist_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
when(mCachedDevice.getSubDevice()).thenReturn(null);
@@ -134,8 +185,67 @@
assertThat(mController.isAvailable()).isTrue();
}
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural LE Audio hearing aids
+ * 2. Member device is added
+ * 3. Member device is connected
+ * Expected result:
+ * The controller is not available. Both sides are already paired and connected.
+ */
@Test
- public void refresh_leftSideDevice_leftSideButtonTitle() {
+ public void isAvailable_leAudioDevice_otherDeviceIsConnected_notAvailable() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.isConnectedLeAudioHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedLeAudioHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mSubCachedDevice));
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural LE Audio hearing aids
+ * 2. Member device is added
+ * 3. Member device is not connected
+ * Expected result:
+ * The controller is available. Need to show the hint to pair the other side.
+ */
+ @Test
+ public void isAvailable_leAudioDevice_otherDeviceIsNotConnected_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.isConnectedLeAudioHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+ when(mSubCachedDevice.isConnectedLeAudioHearingAidDevice()).thenReturn(false);
+ when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mSubCachedDevice));
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ /**
+ * Test if the controller is available.
+ * Conditions:
+ * 1. Binaural LE Audio hearing aids
+ * 2. No member device added
+ * Expected result:
+ * The controller is available. Need to show the hint to pair the other side.
+ */
+ @Test
+ public void isAvailable_leAudioDevice_otherDeviceIsNotExist_available() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.isConnectedLeAudioHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+ when(mCachedDevice.getMemberDevice()).thenReturn(new HashSet<>());
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ /** Test the pair other side button title after refreshing. */
+ @Test
+ public void refresh_rightSideDevice_pairLeftSideButtonTitle() {
when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
mController.init(mScreen);
@@ -145,9 +255,10 @@
mContext.getString(R.string.bluetooth_pair_left_ear_button));
}
+ /** Test the pair other side button visibility after refreshing. */
@Test
- public void refresh_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
- when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
+ public void refresh_isNotConnectedHearingAidDevice_preferenceIsNotVisible() {
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
mController.init(mScreen);
mController.refresh();
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index 4640efe..5eee615 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -39,26 +39,28 @@
import android.widget.FrameLayout;
import android.widget.Spinner;
+import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager;
import androidx.preference.PreferenceManager;
import com.android.settings.R;
-import com.android.settings.SettingsActivity;
+import com.android.settings.datausage.lib.BillingCycleRepository;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.LoadingViewController;
-import com.android.settingslib.AppItem;
import com.android.settingslib.NetworkPolicyEditor;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
-import com.android.settingslib.net.NetworkCycleChartData;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
@@ -67,11 +69,10 @@
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers;
-import java.util.ArrayList;
-import java.util.List;
-
@RunWith(RobolectricTestRunner.class)
public class DataUsageListTest {
+ @Rule
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private MobileDataEnabledListener mMobileDataEnabledListener;
@@ -81,20 +82,23 @@
private LoaderManager mLoaderManager;
@Mock
private UserManager mUserManager;
+ @Mock
+ private BillingCycleRepository mBillingCycleRepository;
private Activity mActivity;
- private DataUsageList mDataUsageList;
+
+ @Spy
+ private TestDataUsageList mDataUsageList;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
final ActivityController<Activity> mActivityController =
Robolectric.buildActivity(Activity.class);
mActivity = spy(mActivityController.get());
mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class);
- mDataUsageList = spy(DataUsageList.class);
mDataUsageList.mDataStateListener = mMobileDataEnabledListener;
+ mDataUsageList.mTemplate = mock(NetworkTemplate.class);
doReturn(mActivity).when(mDataUsageList).getContext();
doReturn(mUserManager).when(mActivity).getSystemService(UserManager.class);
@@ -105,6 +109,7 @@
doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager();
mDataUsageList.mLoadingViewController = mock(LoadingViewController.class);
doNothing().when(mDataUsageList).updateSubscriptionInfoEntity();
+ when(mBillingCycleRepository.isBandwidthControlEnabled()).thenReturn(true);
}
@Test
@@ -196,34 +201,6 @@
}
@Test
- public void startAppDataUsage_shouldAddCyclesInfoToLaunchArguments() {
- final long startTime = 1521583200000L;
- final long endTime = 1521676800000L;
- final List<NetworkCycleChartData> data = new ArrayList<>();
- final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
- builder.setStartTime(startTime)
- .setEndTime(endTime);
- data.add(builder.build());
- ReflectionHelpers.setField(mDataUsageList, "mCycleData", data);
- final Spinner spinner = mock(Spinner.class);
- when(spinner.getSelectedItemPosition()).thenReturn(0);
- ReflectionHelpers.setField(mDataUsageList, "mCycleSpinner", spinner);
- final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
-
- mDataUsageList.startAppDataUsage(new AppItem());
-
- verify(mActivity).startActivity(intent.capture());
- final Bundle arguments =
- intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
- assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(endTime);
- final ArrayList<Long> cycles =
- (ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
- assertThat(cycles).hasSize(2);
- assertThat(cycles.get(0)).isEqualTo(endTime);
- assertThat(cycles.get(1)).isEqualTo(startTime);
- }
-
- @Test
public void onViewCreated_shouldHideCycleSpinner() {
final View view = new View(mActivity);
final View header = getHeader();
@@ -255,22 +232,19 @@
mDataUsageList.onPause();
verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_CHART_DATA);
- verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_SUMMARY);
}
private View getHeader() {
final View rootView = LayoutInflater.from(mActivity)
.inflate(R.layout.preference_list_fragment, null, false);
final FrameLayout pinnedHeader = rootView.findViewById(R.id.pinned_header);
- final View header = mActivity.getLayoutInflater()
- .inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
- return header;
+ return mActivity.getLayoutInflater()
+ .inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
}
private Spinner getSpinner(View header) {
- final Spinner spinner = header.findViewById(R.id.filter_spinner);
- return spinner;
+ return header.findViewById(R.id.filter_spinner);
}
@Implements(DataUsageBaseFragment.class)
@@ -279,10 +253,18 @@
public void onCreate(Bundle icicle) {
// do nothing
}
+ }
- @Implementation
- protected boolean isBandwidthControlEnabled() {
- return true;
+ public class TestDataUsageList extends DataUsageList {
+ @Override
+ protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
+ return mock(clazz);
+ }
+
+ @NonNull
+ @Override
+ BillingCycleRepository createBillingCycleRepository() {
+ return mBillingCycleRepository;
}
}
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
index 02f683a..4db2fe0 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
@@ -61,7 +61,7 @@
mPreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
.setMeteredness(NetworkStats.METERED_YES).build(),
- 5 /* subId */, null /* services */);
+ 5 /* subId */);
verify(mPreference).setEnabled(false);
verify(mPreference).setIntent(null);
@@ -73,7 +73,7 @@
mPreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
.setMeteredness(NetworkStats.METERED_YES).build(),
- 5 /* subId */, null /* services */);
+ 5 /* subId */);
verify(mPreference, never()).setEnabled(false);
verify(mPreference).setIntent(any(Intent.class));
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
index b405f9e..13bc6a4 100644
--- a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.development;
+import static com.android.settings.development.BluetoothLeAudioDeviceDetailsPreferenceController
+ .LE_AUDIO_TOGGLE_VISIBLE_PROPERTY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
@@ -25,12 +28,11 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
-import android.provider.DeviceConfig;
+import android.os.SystemProperties;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
-import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import org.junit.After;
@@ -77,9 +79,8 @@
public void onPreferenceChanged_settingEnabled_shouldTurnOnLeAudioDeviceDetailSetting() {
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
mController.onPreferenceChange(mPreference, true /* new value */);
- final boolean isEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+ final boolean isEnabled = SystemProperties.getBoolean(
+ LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, false);
assertThat(isEnabled).isTrue();
}
@@ -88,9 +89,8 @@
public void onPreferenceChanged_settingDisabled_shouldTurnOffLeAudioDeviceDetailSetting() {
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
mController.onPreferenceChange(mPreference, false /* new value */);
- final boolean isEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+ final boolean isEnabled = SystemProperties.getBoolean(
+ LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, true);
assertThat(isEnabled).isFalse();
}
@@ -98,18 +98,15 @@
@Test
public void updateState_settingEnabled_preferenceShouldBeChecked() {
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "true", false);
+ SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "true");
mController.updateState(mPreference);
-
verify(mPreference).setChecked(true);
}
@Test
public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
- SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "false", false);
+ SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "false");
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
diff --git a/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java b/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java
new file mode 100644
index 0000000..32ad0ad
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/quarantine/QuarantinedAppsScreenControllerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class QuarantinedAppsScreenControllerTest {
+ private static final String PREF_KEY = "quarantined_apps_screen";
+ private static final String TEST_PACKAGE = "com.example.test.pkg";
+ private static final int TEST_APP_ID = 1234;
+ private static final int TEST_USER_ID = 10;
+
+ private Context mContext;
+ private QuarantinedAppsScreenController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mController = new QuarantinedAppsScreenController(mContext, PREF_KEY);
+ }
+
+ @Test
+ public void testOnPreferenceChange() {
+ final Context userContext = mock(Context.class);
+ doReturn(userContext).when(mContext).createContextAsUser(
+ eq(UserHandle.of(TEST_USER_ID)), anyInt());
+ final PackageManager packageManager = mock(PackageManager.class);
+ doReturn(packageManager).when(userContext).getPackageManager();
+
+ final AppEntry entry = createAppEntry(TEST_PACKAGE, TEST_APP_ID, TEST_USER_ID);
+ final QuarantinedAppPreference preference = new QuarantinedAppPreference(mContext, entry);
+
+ mController.onPreferenceChange(preference, true);
+ verify(packageManager).setPackagesSuspended(aryEq(new String[] {TEST_PACKAGE}), eq(true),
+ any(), any(), any(),
+ eq(PackageManager.FLAG_SUSPEND_QUARANTINED));
+
+ mController.onPreferenceChange(preference, false);
+ verify(packageManager).setPackagesSuspended(aryEq(new String[] {TEST_PACKAGE}), eq(false),
+ any(), any(), any(),
+ eq(PackageManager.FLAG_SUSPEND_QUARANTINED));
+ }
+
+ private AppEntry createAppEntry(String packageName, int appId, int userId) {
+ final AppEntry entry = mock(AppEntry.class);
+ entry.info = createApplicationInfo(packageName, appId, userId);
+ entry.extraInfo = false;
+ return entry;
+ }
+
+ private ApplicationInfo createApplicationInfo(String packageName, int appId, int userId) {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.packageName = packageName;
+ info.uid = UserHandle.getUid(userId, appId);
+ return info;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
index 3ad14e5..19eac82 100644
--- a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
@@ -132,23 +132,23 @@
}
@Test
- public void isSliceableCorrectKey_returnsTrue() {
+ public void isPublicSliceCorrectKey_returnsTrue() {
final AmbientDisplayAlwaysOnPreferenceController controller =
new AmbientDisplayAlwaysOnPreferenceController(mContext,
"ambient_display_always_on");
- assertThat(controller.isSliceable()).isTrue();
+ assertThat(controller.isPublicSlice()).isTrue();
}
@Test
- public void isSliceableIncorrectKey_returnsFalse() {
+ public void isPublicSliceIncorrectKey_returnsFalse() {
final AmbientDisplayAlwaysOnPreferenceController controller =
new AmbientDisplayAlwaysOnPreferenceController(mContext, "bad_key");
- assertThat(controller.isSliceable()).isFalse();
+ assertThat(controller.isPublicSlice()).isFalse();
}
@Test
- public void isPublicSlice_returnTrue() {
- assertThat(mController.isPublicSlice()).isTrue();
+ public void isSliceable_returnTrue() {
+ assertThat(mController.isSliceable()).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/display/FoldLockBehaviorSettingsTest.java b/tests/robotests/src/com/android/settings/display/FoldLockBehaviorSettingsTest.java
index 37b9391..991f529 100644
--- a/tests/robotests/src/com/android/settings/display/FoldLockBehaviorSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/display/FoldLockBehaviorSettingsTest.java
@@ -24,13 +24,19 @@
import android.os.UserHandle;
import android.provider.Settings;
+import com.android.settings.testutils.shadow.ShadowSystemSettings;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowSystemSettings.class,
+})
public class FoldLockBehaviorSettingsTest {
private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
index 7104206..c9e201b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
@@ -53,7 +53,6 @@
mPolicy = spy(new BatteryTipPolicy(RuntimeEnvironment.application));
mContext = RuntimeEnvironment.application;
ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", true);
- ReflectionHelpers.setField(mPolicy, "lowBatteryHour", 3);
mBatteryInfo.discharging = true;
mLowBatteryDetector = new LowBatteryDetector(mContext, mPolicy, mBatteryInfo,
@@ -78,13 +77,9 @@
@Test
public void testDetect_lowBattery_tipNew() {
- mBatteryInfo.batteryLevel = 3;
+ mBatteryInfo.batteryLevel = 20;
mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMillis(1);
assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
-
- mBatteryInfo.batteryLevel = 50;
- mBatteryInfo.remainingTimeUs = TimeUnit.MINUTES.toMillis(1);
- assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
}
@Test
@@ -104,9 +99,9 @@
}
@Test
- public void testDetect_timeEstimationZero_tipInvisible() {
+ public void testDetect_lowTimeEstimation_tipInvisible() {
mBatteryInfo.batteryLevel = 50;
- mBatteryInfo.remainingTimeUs = 0;
+ mBatteryInfo.remainingTimeUs = TimeUnit.MINUTES.toMillis(1);
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java
new file mode 100644
index 0000000..60e0af0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.android.settings.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+
+import com.android.settings.testutils.BatteryTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public class AnomalyEventWrapperTest {
+ private AnomalyEventWrapper mAnomalyEventWrapper;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+ mContext = spy(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getDismissRecordKey_returnExpectedResult() {
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_BRIGHTNESS");
+
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_SCREEN_TIMEOUT");
+
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createAppAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_APP_1");
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
index 630ff45..63cb1b3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -58,13 +59,14 @@
private BatteryTipsCardPreference mBatteryTipsCardPreference;
private PowerUsageAdvanced mPowerUsageAdvanced;
private BatteryTipsController mBatteryTipsController;
+ private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Mock
private View mFakeView;
@Mock
- private BatteryChartPreferenceController mBatteryChartPreferenceController;
- @Mock
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
+ @Mock
+ private BatteryDiffEntry mFakeEntry;
@Before
public void setUp() {
@@ -73,8 +75,13 @@
mFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
mBatteryTipsController = new BatteryTipsController(mContext);
+ mBatteryChartPreferenceController =
+ spy(new BatteryChartPreferenceController(mContext, null, null));
+ mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
- mPowerUsageAdvanced = new PowerUsageAdvanced();
+
+ mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
+ doReturn(mContext).when(mPowerUsageAdvanced).getContext();
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
@@ -82,6 +89,7 @@
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
+ doReturn("TestEntriesKey").when(mFakeEntry).getKey();
}
@Test
@@ -99,7 +107,8 @@
when(mFakeView.getId()).thenReturn(R.id.main_button);
doNothing().when(mContext).startActivity(captor.capture());
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(adaptiveBrightnessAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
+ adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
@@ -110,18 +119,21 @@
assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
.isEqualTo(SettingsEnums.DISPLAY);
verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
+ verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "BrightnessAnomaly");
}
@Test
- public void onClick_dismissBtn_cardDismissAndLogged() {
+ public void onClick_dismissBtnOfSettingsAnomaly_cardDismissAndLogged() {
final PowerAnomalyEvent screenTimeoutAnomaly =
BatteryTestUtils.createScreenTimeoutAnomalyEvent();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(screenTimeoutAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
+ screenTimeoutAnomaly, screenTimeoutAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
@@ -129,6 +141,8 @@
assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext))
.contains(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name());
verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
+ verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
}
@@ -137,30 +151,40 @@
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.main_button);
+ doNothing().when(mBatteryChartPreferenceController).selectHighlightSlotIndex();
+ when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
verify(mContext, never()).startActivity(any(Intent.class));
+ verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
+ eq(1), eq(0));
verify(mBatteryChartPreferenceController).selectHighlightSlotIndex();
verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
+ verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "AppAnomaly");
}
@Test
- public void onClick_dismissBtnOfAppsAnomaly_removeHighlightSlotIndex() {
+ public void onClick_dismissBtnOfAppsAnomaly_keepHighlightSlotIndex() {
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
+ when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
+ verify(mContext, never()).startActivity(any(Intent.class));
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+ eq(1), eq(0));
+ verify(mBatteryChartPreferenceController, never()).selectHighlightSlotIndex();
+ verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "AppAnomaly");
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
index 913c00a..b8afe98 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -16,8 +16,6 @@
package com.android.settings.fuelgauge.batteryusage;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -70,30 +68,18 @@
@Test
public void handleBatteryTipsCardUpdated_null_hidePreference() {
- mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false);
verify(mBatteryTipsCardPreference).setVisible(false);
}
@Test
- public void getDismissRecordKey_returnExpectedResult() {
- assertThat(BatteryTipsController.getDismissRecordKey(
- BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent()))
- .isEqualTo("KEY_BRIGHTNESS");
- assertThat(BatteryTipsController.getDismissRecordKey(
- BatteryTestUtils.createScreenTimeoutAnomalyEvent()))
- .isEqualTo("KEY_SCREEN_TIMEOUT");
- assertThat(BatteryTipsController.getDismissRecordKey(
- BatteryTestUtils.createAppAnomalyEvent()))
- .isEqualTo("KEY_APP_1");
- }
-
- @Test
public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
// Check pre-defined string
verify(mBatteryTipsCardPreference).setTitle(
@@ -114,7 +100,8 @@
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
@@ -139,7 +126,8 @@
.build();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle(testTitle);
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
@@ -157,10 +145,13 @@
PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ AnomalyEventWrapper eventWrapper = new AnomalyEventWrapper(mContext, event);
+ eventWrapper.setRelatedBatteryDiffEntry(
+ new BatteryDiffEntry(mContext, "", "Chrome", 0));
+ mBatteryTipsController.handleBatteryTipsCardUpdated(eventWrapper, false);
verify(mBatteryTipsCardPreference).setTitle(
- "Chrome used more battery than usual in foreground");
+ "Chrome used more battery than usual");
verify(mBatteryTipsCardPreference).setIconResourceId(
R.drawable.ic_battery_tips_warning_icon);
verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index d89c06b..a721ad4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -69,7 +69,7 @@
@Mock
private BatteryHistEntry mBatteryHistEntry;
@Mock
- private PowerGaugePreference mPowerGaugePreference;
+ private AnomalyAppItemPreference mAnomalyAppItemPreference;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@@ -123,13 +123,14 @@
BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey",
new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
}
@Test
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
// Ensures the testing environment is correct.
mBatteryUsageBreakdownController.mPreferenceCache.put(
- PREF_KEY, mPowerGaugePreference);
+ PREF_KEY, mAnomalyAppItemPreference);
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
mBatteryUsageBreakdownController.onDestroy();
@@ -178,7 +179,6 @@
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
mBatteryUsageBreakdownController.addAllPreferences();
@@ -188,27 +188,25 @@
@Test
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
- doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
+ doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
// Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
- .isEqualTo(mPowerGaugePreference);
- verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference);
+ .isEqualTo(mAnomalyAppItemPreference);
+ verify(mAppListPreferenceGroup).removePreference(mAnomalyAppItemPreference);
}
@Test
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
- doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
+ doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
// Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
@@ -232,10 +230,10 @@
@Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+ doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
+ mAnomalyAppItemPreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
@@ -248,10 +246,10 @@
@Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+ doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
+ mAnomalyAppItemPreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index f06dc63..cd594d3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -72,6 +72,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mContext = spy(RuntimeEnvironment.application);
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
index 953c2d4..9753bd2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
@@ -20,8 +20,8 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -41,7 +41,9 @@
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.TimeZone;
+import java.util.function.Predicate;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
@@ -50,6 +52,9 @@
private Context mContext;
private PowerUsageAdvanced mPowerUsageAdvanced;
+ private Predicate<PowerAnomalyEvent> mCardFilterPredicate;
+ private Predicate<PowerAnomalyEvent> mSlotFilterPredicate;
+
@Mock
private BatteryTipsController mBatteryTipsController;
@Mock
@@ -65,7 +70,7 @@
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
mContext = spy(RuntimeEnvironment.application);
- mPowerUsageAdvanced = new PowerUsageAdvanced();
+ mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
@@ -74,43 +79,63 @@
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
+ doReturn(mContext).when(mPowerUsageAdvanced).getContext();
+ mSlotFilterPredicate = PowerAnomalyEvent::hasWarningItemInfo;
}
@Test
- public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
- assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
- assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
- mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
+ public void getFilterAnomalyEvent_withEmptyOrNullList_getNull() {
+ prepareCardFilterPredicate(null);
+ assertThat(PowerUsageAdvanced
+ .getAnomalyEvent(null, mCardFilterPredicate)).isNull();
+ assertThat(PowerUsageAdvanced
+ .getAnomalyEvent(null, mSlotFilterPredicate)).isNull();
+ assertThat(PowerUsageAdvanced.getAnomalyEvent(
+ BatteryTestUtils.createEmptyPowerAnomalyEventList(), mCardFilterPredicate))
+ .isNull();
+ assertThat(PowerUsageAdvanced.getAnomalyEvent(
+ BatteryTestUtils.createEmptyPowerAnomalyEventList(), mSlotFilterPredicate))
+ .isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
+ public void getFilterAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent)
- .isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(cardEvent).isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(slotEvent).isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
+ public void getFilterAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent)
- .isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(cardEvent).isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(slotEvent).isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
+ public void getFilterAnomalyEvent_withAllDismissed_getNull() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
@@ -118,20 +143,26 @@
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
}
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent).isNull();
+ assertThat(cardEvent).isNull();
+ assertThat(slotEvent).isNull();
}
@Test
public void onDisplayAnomalyEventUpdated_withSettingsAnomalyEvent_skipHighlightSlotEffect() {
final PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
- assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
- verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(event.getEventId());
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyRejectListener(isNull());
verify(mPowerUsageAdvanced.mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
@@ -140,46 +171,44 @@
}
@Test
- public void onDisplayAnomalyEventUpdated_withAppAnomalyEvent_setHighlightSlotEffect() {
+ public void onDisplayAnomalyEventUpdated_onlyAppAnomalyEvent_setHighlightSlotEffect() {
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
- assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
- verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(event.getEventId());
verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
-
- assertThat(event.getWarningItemInfo().hasStartTimestamp()).isTrue();
- assertThat(event.getWarningItemInfo().hasEndTimestamp()).isTrue();
assertThat(mPowerUsageAdvanced.mBatteryLevelData.get().getIndexByTimestamps(
event.getWarningItemInfo().getStartTimestamp(),
event.getWarningItemInfo().getEndTimestamp()
)).isEqualTo(Pair.create(1, 0));
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
- verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
}
@Test
- public void onDisplayAnomalyEventUpdated_withNull_removeHighlightSlotEffect() {
- final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
+ public void onDisplayAnomalyEventUpdated_withSettingsCardAndAppsSlotEvent_showExpected() {
+ final PowerAnomalyEvent settingsEvent =
+ BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
+ final PowerAnomalyEvent appsEvent =
+ BatteryTestUtils.createAppAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(null);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(settingsEvent, appsEvent);
- assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isNull();
- verify(mBatteryTipsController, times(2))
- .setOnAnomalyConfirmListener(isNull());
- verify(mBatteryTipsController, times(2))
- .setOnAnomalyRejectListener(isNull());
- verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
- verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
-
- verify(mBatteryChartPreferenceController)
- .onHighlightSlotIndexUpdate(eq(1), eq(0));
- verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(appsEvent.getEventId());
+ verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
+ verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
+ verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
}
-}
+
+ private void prepareCardFilterPredicate(PowerAnomalyEvent slotEvent) {
+ final Set<String> dismissedPowerAnomalyKeys =
+ DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
+ mCardFilterPredicate = event -> !dismissedPowerAnomalyKeys.contains(
+ event.getDismissRecordKey())
+ && (event.equals(slotEvent) || !event.hasWarningItemInfo());
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 643d364..a91af12 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -317,7 +317,7 @@
mNetworkProviderSettings.onCreate(Bundle.EMPTY);
verify(mDataUsagePreference).setVisible(true);
- verify(mDataUsagePreference).setTemplate(any(), eq(0) /*subId*/, eq(null) /*service*/);
+ verify(mDataUsagePreference).setTemplate(any(), eq(0) /*subId*/);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index c8cf290..54a6bd4 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -235,7 +236,7 @@
mPreferenceController.getDefaultNASIntent();
mPreferenceController.updateState(mPreference);
- verify(mPreference).setSwitchEnabled(eq(false));
+ verify(mPreference, atLeastOnce()).setSwitchEnabled(eq(false));
assertFalse(mPreference.isEnabled());
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
index 6abfe69..942db3f 100644
--- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
@@ -116,6 +116,7 @@
when(mPreference.isEnabled()).thenReturn(true);
doCallRealMethod().when(mPreference).init();
+ mPreference.setStream(STREAM);
mPreference.init();
verify(mPreference, never()).updateContentDescription(CONTENT_DESCRIPTION);
@@ -136,6 +137,7 @@
@Test
public void init_changeProgress_overrideStateDescriptionCalled() {
final int progress = 4;
+ when(mPreference.isEnabled()).thenReturn(true);
when(mPreference.formatStateDescription(progress)).thenReturn(CONTENT_DESCRIPTION);
doCallRealMethod().when(mPreference).init();
@@ -157,6 +159,7 @@
when(mAudioManager.getStreamMaxVolume(STREAM)).thenReturn(max);
when(mAudioManager.getStreamMinVolumeInt(STREAM)).thenReturn(min);
when(mAudioManager.getStreamVolume(STREAM)).thenReturn(progress);
+ when(mPreference.isEnabled()).thenReturn(true);
when(mPreference.getMin()).thenReturn(min);
when(mPreference.getMax()).thenReturn(max);
when(mPreference.getContext()).thenReturn(mContext);
@@ -168,6 +171,8 @@
mPreference.setStream(STREAM);
mPreference.init();
+ verify(mSeekBarVolumizerFactory).create(eq(STREAM), eq(null), mSbvc.capture());
+
// On progress change, Round down the percent to match it with what the talkback says.
// (b/285458191)
// when progress is 4, the percent is 0.187. The state description should be set to 18%.
diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
index 2d2fcc8..178aee5 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
@@ -21,17 +21,15 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.graphics.drawable.Drawable;
import android.util.Pair;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
@@ -50,7 +48,8 @@
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
+ Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+ mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java b/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
index 39a5714..c5733bf 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
@@ -28,13 +28,15 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import androidx.preference.PreferenceViewHolder;
+
import com.android.settings.R;
-import com.android.settings.notification.app.ImportancePreference;
import org.junit.Before;
import org.junit.Test;
@@ -42,8 +44,6 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import androidx.preference.PreferenceViewHolder;
-
@RunWith(RobolectricTestRunner.class)
public class ImportancePreferenceTest {
@@ -51,7 +51,8 @@
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
+ Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+ mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
index 516d088..9322317 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
@@ -33,9 +33,13 @@
import android.content.Context;
import android.net.Uri;
+import android.text.TextUtils;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import androidx.lifecycle.LiveData;
import androidx.slice.Slice;
@@ -44,6 +48,7 @@
import com.android.settings.panel.PanelSlicesAdapter.SliceRowViewHolder;
import com.android.settings.testutils.FakeFeatureFactory;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -94,7 +99,6 @@
.get()
.getSupportFragmentManager()
.findFragmentById(R.id.main_content));
-
}
private void addTestLiveData(Uri uri) {
@@ -106,6 +110,61 @@
mData.put(uri, liveData);
}
+ /**
+ * Edge case where fragment context is not available.
+ */
+ @Test
+ public void withPanelFragmentContextNull_createAdapter_noExceptionThrown() {
+ when(mPanelFragment.getContext()).thenReturn(null);
+
+ final PanelSlicesAdapter adapter = spy(new PanelSlicesAdapter(mPanelFragment, mData, 0));
+
+ Assert.assertNotNull(adapter);
+ }
+
+ /**
+ * ViewHolder should load and set the action label correctly.
+ */
+ @Test
+ public void setActionLabel_loadsActionLabel() {
+ addTestLiveData(VOLUME_NOTIFICATION_URI);
+ final PanelSlicesAdapter adapter = new PanelSlicesAdapter(mPanelFragment, mData, 0);
+ final ViewGroup view = new FrameLayout(mContext);
+ final SliceRowViewHolder viewHolder = adapter.onCreateViewHolder(view, VIEW_TYPE_SLIDER);
+
+ // now let's see if setActionLabel can load and set the label correctly.
+ LinearLayout llRow = new LinearLayout(mContext);
+ viewHolder.setActionLabel(llRow);
+
+ boolean isLabelSet = isActionLabelSet(llRow);
+ Assert.assertTrue("Action label was not set correctly.", isLabelSet);
+ }
+
+ /**
+ * @param rowView the view with id row_view
+ * @return whether the accessibility action label is set
+ */
+ private boolean isActionLabelSet(View rowView) {
+ View.AccessibilityDelegate delegate = rowView.getAccessibilityDelegate();
+ if (delegate == null) {
+ return false;
+ }
+ AccessibilityNodeInfo node = new AccessibilityNodeInfo(rowView);
+ delegate.onInitializeAccessibilityNodeInfo(rowView, node);
+
+ boolean foundLabel = false;
+ final String expectedLabel =
+ mContext.getString(R.string.accessibility_action_label_panel_slice);
+ for (AccessibilityNodeInfo.AccessibilityAction action : node.getActionList()) {
+ if (action.equals(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)
+ && TextUtils.equals(action.getLabel(), expectedLabel)) {
+ foundLabel = true;
+ break;
+ }
+ }
+ return foundLabel;
+ }
+
@Test
public void sizeOfAdapter_shouldNotExceedMaxNum() {
for (int i = 0; i < MAX_NUM_OF_SLICES + 2; i++) {
@@ -141,7 +200,7 @@
}
@Test
- public void onCreateViewHolder_viewTypeSlider_verifyActionLabelSet() {
+ public void onBindViewHolder_viewTypeSlider_verifyActionLabelSet() {
addTestLiveData(VOLUME_NOTIFICATION_URI);
final PanelSlicesAdapter adapter =
diff --git a/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
deleted file mode 100644
index 61aa294..0000000
--- a/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 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.android.settings.system;
-
-import static android.os.SystemUpdateManager.KEY_STATUS;
-import static android.os.SystemUpdateManager.KEY_TITLE;
-import static android.os.SystemUpdateManager.STATUS_IDLE;
-import static android.os.SystemUpdateManager.STATUS_UNKNOWN;
-import static android.os.SystemUpdateManager.STATUS_WAITING_DOWNLOAD;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemUpdateManager;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUserManager.class)
-public class SystemUpdatePreferenceControllerTest {
-
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private SystemUpdateManager mSystemUpdateManager;
-
- private Context mContext;
- private ShadowUserManager mShadowUserManager;
- private SystemUpdatePreferenceController mController;
- private Preference mPreference;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mShadowUserManager = ShadowUserManager.getShadow();
-
- ShadowApplication.getInstance().setSystemService(Context.SYSTEM_UPDATE_SERVICE,
- mSystemUpdateManager);
- mController = new SystemUpdatePreferenceController(mContext);
- mPreference = new Preference(RuntimeEnvironment.application);
- mPreference.setKey(mController.getPreferenceKey());
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
- }
-
- @After
- public void cleanUp() {
- mShadowUserManager.setIsAdminUser(false);
- }
-
- @Test
- public void updateNonIndexable_ifAvailable_shouldNotUpdate() {
- final List<String> keys = new ArrayList<>();
- mShadowUserManager.setIsAdminUser(true);
-
- mController.updateNonIndexableKeys(keys);
-
- assertThat(keys).isEmpty();
- }
-
- @Test
- public void updateNonIndexable_ifNotAvailable_shouldUpdate() {
- mShadowUserManager.setIsAdminUser(false);
- final List<String> keys = new ArrayList<>();
-
- mController.updateNonIndexableKeys(keys);
-
- assertThat(keys).hasSize(1);
- }
-
- @Test
- public void displayPrefs_ifVisible_butNotAdminUser_shouldNotDisplay() {
- mShadowUserManager.setIsAdminUser(false);
- mController.displayPreference(mScreen);
-
- assertThat(mPreference.isVisible()).isFalse();
- }
-
- @Test
- @Config(qualifiers = "mcc999")
- public void displayPrefs_ifAdminUser_butNotVisible_shouldNotDisplay() {
- mShadowUserManager.setIsAdminUser(true);
- mController.displayPreference(mScreen);
-
- assertThat(mPreference.isVisible()).isFalse();
- }
-
- @Test
- public void displayPrefs_ifAvailable_shouldDisplay() {
- mShadowUserManager.setIsAdminUser(true);
-
- mController.displayPreference(mScreen);
-
- assertThat(mPreference.isVisible()).isTrue();
- }
-
- @Test
- public void updateState_systemUpdateStatusUnknown_shouldSetToAndroidVersion() {
- final Bundle bundle = new Bundle();
- bundle.putInt(KEY_STATUS, STATUS_UNKNOWN);
- when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getString(R.string.android_version_summary,
- Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY));
- }
-
- @Test
- public void updateState_systemUpdateStatusIdle_shouldSetToAndroidVersion() {
- final String testReleaseName = "ANDROID TEST VERSION";
-
- final Bundle bundle = new Bundle();
- bundle.putInt(KEY_STATUS, STATUS_IDLE);
- bundle.putString(KEY_TITLE, testReleaseName);
- when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getString(R.string.android_version_summary, testReleaseName));
- }
-
- @Test
- public void updateState_systemUpdateInProgress_shouldSetToUpdatePending() {
- final Bundle bundle = new Bundle();
- bundle.putInt(KEY_STATUS, STATUS_WAITING_DOWNLOAD);
- when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getString(R.string.android_version_pending_update_summary));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 1035560..e98ea1b 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -247,6 +247,7 @@
.setEventId("BrightnessAnomaly")
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
.setKey(PowerAnomalyKey.KEY_BRIGHTNESS)
+ .setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name())
.setScore(1.2f)
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
.setMainButtonDestination(DisplaySettings.class.getName())
@@ -264,6 +265,7 @@
.setEventId("ScreenTimeoutAnomaly")
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
.setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
+ .setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name())
.setScore(1.1f)
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
@@ -280,15 +282,12 @@
return PowerAnomalyEvent.newBuilder()
.setEventId("AppAnomaly")
.setType(PowerAnomalyType.TYPE_APPS_ITEM)
- .setKey(PowerAnomalyKey.KEY_APP)
+ .setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL)
+ .setDismissRecordKey("KEY_APP_1")
.setScore(2.0f)
.setWarningItemInfo(WarningItemInfo.newBuilder()
- .setDismissRecordKey("KEY_APP_1")
.setStartTimestamp(1694361600000L) // 2023-09-11 00:00:00
.setEndTimestamp(1694368800000L) // 2023-09-11 02:00:00
- .setTitleString("Chrome used more battery than usual in foreground")
- .setMainButtonString("Check")
- .setCancelButtonString("Got it")
.build())
.build();
}
diff --git a/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java b/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
index 00f2e19..d6d5abf 100644
--- a/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
@@ -174,6 +174,20 @@
assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isNull();
}
+ /**
+ * When background is being updated, we also request the a11y focus on the preference
+ */
+ @Test
+ public void updateBackground_shouldRequestAccessibilityFocus() {
+ View viewItem = mock(View.class);
+ mViewHolder = PreferenceViewHolder.createInstanceForTests(viewItem);
+ ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
+
+ mAdapter.updateBackground(mViewHolder, 10);
+
+ verify(viewItem).requestAccessibilityFocus();
+ }
+
@Test
public void updateBackground_highlight_shouldAnimateBackgroundAndSetHighlightedTag() {
ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10);
diff --git a/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
new file mode 100644
index 0000000..2e2620b
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage
+
+import android.content.Context
+import android.net.NetworkTemplate
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.datausage.lib.BillingCycleRepository
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+class BillingCyclePreferenceTest {
+
+ private val mockBillingCycleRepository = mock<BillingCycleRepository> {
+ on { isModifiable(SUB_ID) } doReturn false
+ }
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
+
+ @Test
+ fun isEnabled_initialState() {
+ val enabled = preference.isEnabled
+
+ assertThat(enabled).isTrue()
+ }
+
+ @Test
+ fun isEnabled_afterSetTemplate_updated() {
+ preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
+
+ val enabled = preference.isEnabled
+
+ assertThat(enabled).isFalse()
+ }
+
+ private companion object {
+ const val SUB_ID = 1
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt
new file mode 100644
index 0000000..af5dc89
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage
+
+import android.content.Context
+import android.content.Intent
+import android.net.NetworkTemplate
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.SettingsActivity
+import com.android.settingslib.AppItem
+import com.android.settingslib.net.NetworkCycleChartData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class DataUsageListAppsControllerTest {
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ doNothing().whenever(mock).startActivity(any())
+ }
+
+ private val controller = DataUsageListAppsController(context, "test_key")
+
+ @Before
+ fun setUp() {
+ controller.init(mock<NetworkTemplate>())
+ val data = NetworkCycleChartData.Builder().apply {
+ setStartTime(START_TIME)
+ setEndTime(END_TIME)
+ }.build()
+ controller.setCycleData(listOf(data))
+ }
+
+ @Test
+ fun startAppDataUsage_shouldAddCyclesInfoToLaunchArguments() {
+ controller.startAppDataUsage(AppItem(), END_TIME)
+
+ val intent = argumentCaptor<Intent> {
+ verify(context).startActivity(capture())
+ }.firstValue
+ val arguments = intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)!!
+ assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(END_TIME)
+ assertThat(
+ arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES, ArrayList::class.java)
+ ).containsExactly(END_TIME, START_TIME).inOrder()
+ }
+
+ private companion object {
+ const val START_TIME = 1521583200000L
+ const val END_TIME = 1521676800000L
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
index 016d6d2..531e6e7 100644
--- a/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
@@ -20,12 +20,13 @@
import android.content.pm.UserInfo
import android.content.res.Resources
import android.net.NetworkPolicyManager
+import android.net.NetworkTemplate
import android.os.UserHandle
import android.os.UserManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
-import com.android.settings.datausage.lib.AppDataUsageRepository.Bucket
+import com.android.settings.datausage.lib.AppDataUsageRepository.Companion.Bucket
import com.android.settingslib.AppItem
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.google.common.truth.Truth.assertThat
@@ -72,15 +73,15 @@
val repository = AppDataUsageRepository(
context = context,
currentUserId = USER_ID,
- carrierId = null,
- getPackageName = { "" },
+ template = Template,
+ getPackageName = { null },
)
val buckets = listOf(
Bucket(uid = APP_ID_1, bytes = 1),
Bucket(uid = APP_ID_2, bytes = 2),
)
- val appPercentList = repository.getAppPercent(buckets)
+ val appPercentList = repository.getAppPercent(null, buckets)
assertThat(appPercentList).hasSize(2)
appPercentList[0].first.apply {
@@ -102,15 +103,15 @@
val repository = AppDataUsageRepository(
context = context,
currentUserId = USER_ID,
- carrierId = HIDING_CARRIER_ID,
- getPackageName = { if (it.key == APP_ID_1) HIDING_PACKAGE_NAME else "" },
+ template = Template,
+ getPackageName = { if (it.key == APP_ID_1) HIDING_PACKAGE_NAME else null },
)
val buckets = listOf(
Bucket(uid = APP_ID_1, bytes = 1),
Bucket(uid = APP_ID_2, bytes = 2),
)
- val appPercentList = repository.getAppPercent(buckets)
+ val appPercentList = repository.getAppPercent(HIDING_CARRIER_ID, buckets)
assertThat(appPercentList).hasSize(1)
appPercentList[0].first.apply {
@@ -127,5 +128,7 @@
const val APP_ID_2 = 110002
const val HIDING_CARRIER_ID = 4
const val HIDING_PACKAGE_NAME = "hiding.package.name"
+
+ val Template: NetworkTemplate = mock<NetworkTemplate>()
}
}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
new file mode 100644
index 0000000..deaaf2d
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 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.android.settings.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.UserManager
+import android.telephony.TelephonyManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class BillingCycleRepositoryTest {
+
+ private val mockNetworkManagementService = mock<INetworkManagementService> {
+ on { isBandwidthControlEnabled } doReturn true
+ }
+
+ private val mockUserManager = mock<UserManager> {
+ on { isAdminUser } doReturn true
+ }
+
+ private val mockTelephonyManager = mock<TelephonyManager> {
+ on { createForSubscriptionId(SUB_ID) } doReturn mock
+ on { isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) } doReturn false
+ }
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { userManager } doReturn mockUserManager
+ on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+ }
+
+ private val repository = BillingCycleRepository(context, mockNetworkManagementService)
+
+ @Test
+ fun isModifiable_bandwidthControlDisabled_returnFalse() {
+ whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+ val modifiable = repository.isModifiable(SUB_ID)
+
+ assertThat(modifiable).isFalse()
+ }
+
+ @Test
+ fun isModifiable_notAdminUser_returnFalse() {
+ whenever(mockUserManager.isAdminUser).thenReturn(false)
+
+ val modifiable = repository.isModifiable(SUB_ID)
+
+ assertThat(modifiable).isFalse()
+ }
+
+ @Test
+ fun isModifiable_dataDisabled_returnFalse() {
+ whenever(
+ mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+ ).thenReturn(false)
+
+ val modifiable = repository.isModifiable(SUB_ID)
+
+ assertThat(modifiable).isFalse()
+ }
+
+ @Test
+ fun isModifiable_meetAllRequirements_returnTrue() {
+ whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+ whenever(mockUserManager.isAdminUser).thenReturn(true)
+ whenever(
+ mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+ ).thenReturn(true)
+
+ val modifiable = repository.isModifiable(SUB_ID)
+
+ assertThat(modifiable).isTrue()
+ }
+
+ @Test
+ fun isBandwidthControlEnabled_bandwidthControlDisabled_returnFalse() {
+ whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+ val enabled = repository.isBandwidthControlEnabled()
+
+ assertThat(enabled).isFalse()
+ }
+
+ @Test
+ fun isBandwidthControlEnabled_bandwidthControlEnabled_returnTrue() {
+ whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+
+ val enabled = repository.isBandwidthControlEnabled()
+
+ assertThat(enabled).isTrue()
+ }
+
+ private companion object {
+ const val SUB_ID = 1
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
new file mode 100644
index 0000000..590fe9e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2023 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.android.settings.network.apn
+
+import android.content.Context
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performScrollToNode
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ApnEditPageProviderTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val apnName = "apn_name"
+ private val mmsc = "mmsc"
+ private val mmsProxy = "mms_proxy"
+ private val mnc = "mnc"
+ private val apnType = "apn_type"
+ private val apnRoaming = "IPv4"
+ private val apnEnable = context.resources.getString(R.string.carrier_enabled)
+ private val apnProtocolOptions = context.resources.getStringArray(R.array.apn_protocol_entries).toList()
+ private val apnData = ApnData(
+ name = apnName,
+ mmsc = mmsc,
+ mmsProxy = mmsProxy,
+ mnc = mnc,
+ apnType = apnType,
+ apnRoaming = apnProtocolOptions.indexOf(apnRoaming),
+ apnEnable = true
+ )
+
+ @Test
+ fun apnEditPageProvider_name() {
+ Truth.assertThat(ApnEditPageProvider.name).isEqualTo("Apn")
+ }
+
+ @Test
+ fun title_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onNodeWithText(context.getString(R.string.apn_edit)).assertIsDisplayed()
+ }
+
+ @Test
+ fun name_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onNodeWithText(apnName, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun mmsc_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(mmsc, true))
+ composeTestRule.onNodeWithText(mmsc, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun mms_proxy_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(mmsProxy, true))
+ composeTestRule.onNodeWithText(mmsProxy, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun mnc_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(mnc, true))
+ composeTestRule.onNodeWithText(mnc, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun apn_type_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(apnType, true))
+ composeTestRule.onNodeWithText(apnType, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun apn_roaming_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(apnRoaming, true))
+ composeTestRule.onNodeWithText(apnRoaming, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun carrier_enabled_displayed() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(apnEnable, true))
+ composeTestRule.onNodeWithText(apnEnable, true).assertIsDisplayed()
+ }
+
+ @Test
+ fun carrier_enabled_isChecked() {
+ composeTestRule.setContent {
+ ApnPage(remember {
+ mutableStateOf(apnData)
+ })
+ }
+ composeTestRule.onRoot().onChild().onChildAt(0)
+ .performScrollToNode(hasText(apnEnable, true))
+ composeTestRule.onNodeWithText(apnEnable, true).assertIsOn()
+ }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
index 265d92d..9a17032 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
@@ -37,7 +37,6 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R
import com.android.settings.applications.appcompat.UserAspectRatioDetails
-import com.android.settings.applications.appcompat.UserAspectRatioManager
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settings.testutils.TestDeviceConfig
@@ -87,6 +86,8 @@
.startMocking()
whenever(context.resources).thenReturn(resources)
whenever(context.packageManager).thenReturn(packageManager)
+ // True is ignored but need this here or getBoolean will complain null object
+ mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, true)
}
@After
@@ -124,8 +125,6 @@
@Test
fun whenCannotDisplayAspectRatioUiAndConfigTrue_notDisplayed() {
- // True is ignored but need this here or getBoolean will complain null object
- mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, true)
setConfig(true)
setContent()
@@ -135,8 +134,6 @@
@Test
fun whenCanDisplayAspectRatioUiAndConfigTrue_Displayed() {
- // True is ignored but need this here or getBoolean will complain null object
- mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, true)
setConfig(true)
whenever(packageManager.queryIntentActivities(any(), anyInt()))
.thenReturn(listOf(RESOLVE_INFO))
@@ -145,7 +142,7 @@
composeTestRule.onNode(
hasTextExactly(
- context.getString(R.string.aspect_ratio_title),
+ context.getString(R.string.aspect_ratio_experimental_title),
context.getString(R.string.user_aspect_ratio_app_default)
),
).assertIsDisplayed().assertIsEnabled()
@@ -153,8 +150,6 @@
@Test
fun onClick_startActivity() {
- // True is ignored but need this here or getBoolean will complain null object
- mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, true)
setConfig(true)
whenever(packageManager.queryIntentActivities(any(), anyInt()))
.thenReturn(listOf(RESOLVE_INFO))
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index b36a74c..f550326 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -59,7 +59,7 @@
@Test
fun injectEntry_title() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
.assertIsDisplayed()
}
@@ -74,7 +74,7 @@
@Test
fun injectEntry_onClick_navigate() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
.performClick()
assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
}
@@ -93,7 +93,7 @@
UserAspectRatioAppList {}
}
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
.assertIsDisplayed()
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreferenceTest.kt
index 0deeaf7..2524308 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreferenceTest.kt
@@ -30,7 +30,6 @@
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
-import androidx.compose.ui.test.printToLog
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
@@ -38,6 +37,7 @@
import com.android.settings.Utils
import com.android.settings.applications.AppStoreUtil
import com.android.settingslib.applications.AppUtils
+import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.model.app.userHandle
import org.junit.After
@@ -45,13 +45,13 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.any
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.verify
import org.mockito.MockitoSession
import org.mockito.Spy
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
-import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
class AppInstallerInfoPreferenceTest {
@@ -136,7 +136,6 @@
setContent(instantApp)
waitUntilDisplayed()
- composeTestRule.onRoot().printToLog("AAA")
composeTestRule.onNodeWithText("More info on installer label")
.assertIsDisplayed()
.assertIsEnabled()
@@ -147,7 +146,6 @@
setContent()
waitUntilDisplayed()
- composeTestRule.onRoot().printToLog("AAA")
composeTestRule.onNodeWithText("App installed from installer label")
.assertIsDisplayed()
.assertIsEnabled()
@@ -158,6 +156,7 @@
setContent()
waitUntilDisplayed()
composeTestRule.onRoot().performClick()
+ composeTestRule.delay()
verify(context).startActivityAsUser(STORE_LINK, APP.userHandle)
}
diff --git a/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt b/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt
new file mode 100644
index 0000000..0ba91df
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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.android.settings.system
+
+import android.content.Context
+import android.os.Bundle
+import android.os.SystemUpdateManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class SystemUpdateManagerExtKtTest {
+
+ private val mockSystemUpdateManager = mock<SystemUpdateManager>()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(SystemUpdateManager::class.java) } doReturn mockSystemUpdateManager
+ }
+
+ @Test
+ fun getSystemUpdateInfo() = runTest {
+ val bundle = Bundle()
+ whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+
+ val info = context.getSystemUpdateInfo()
+
+ assertThat(info).isSameInstanceAs(bundle)
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt
new file mode 100644
index 0000000..17cdf04
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 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.android.settings.system
+
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
+import android.os.SystemClock
+import android.os.SystemUpdateManager
+import android.os.UserManager
+import androidx.lifecycle.testing.TestLifecycleOwner
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class SystemUpdatePreferenceControllerTest {
+ private val mockUserManager = mock<UserManager>()
+ private val mockSystemUpdateManager = mock<SystemUpdateManager>()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { userManager } doReturn mockUserManager
+ on { getSystemService(SystemUpdateManager::class.java) } doReturn mockSystemUpdateManager
+ }
+
+ private val resources = spy(context.resources) {
+ on { getBoolean(R.bool.config_show_system_update_settings) } doReturn true
+ }
+
+ private val preference = Preference(context).apply { key = KEY }
+ private val preferenceScreen = mock<PreferenceScreen> {
+ onGeneric { findPreference(KEY) } doReturn preference
+ }
+ private val controller = SystemUpdatePreferenceController(context, KEY)
+
+ @Before
+ fun setUp() {
+ whenever(context.resources).thenReturn(resources)
+ }
+
+ @Test
+ fun updateNonIndexable_ifAvailable_shouldNotUpdate() {
+ whenever(mockUserManager.isAdminUser).thenReturn(true)
+ val keys = mutableListOf<String>()
+
+ controller.updateNonIndexableKeys(keys)
+
+ assertThat(keys).isEmpty()
+ }
+
+ @Test
+ fun updateNonIndexable_ifNotAvailable_shouldUpdate() {
+ whenever(mockUserManager.isAdminUser).thenReturn(false)
+ val keys = mutableListOf<String>()
+
+ controller.updateNonIndexableKeys(keys)
+
+ assertThat(keys).containsExactly(KEY)
+ }
+
+ @Test
+ fun displayPrefs_ifVisible_butNotAdminUser_shouldNotDisplay() {
+ whenever(mockUserManager.isAdminUser).thenReturn(false)
+
+ controller.displayPreference(preferenceScreen)
+
+ assertThat(preference.isVisible).isFalse()
+ }
+
+ @Test
+ fun displayPrefs_ifAdminUser_butNotVisible_shouldNotDisplay() {
+ whenever(mockUserManager.isAdminUser).thenReturn(true)
+ whenever(resources.getBoolean(R.bool.config_show_system_update_settings)).thenReturn(false)
+
+ controller.displayPreference(preferenceScreen)
+
+ assertThat(preference.isVisible).isFalse()
+ }
+
+ @Test
+ fun displayPrefs_ifAvailable_shouldDisplay() {
+ whenever(mockUserManager.isAdminUser).thenReturn(true)
+
+ controller.displayPreference(preferenceScreen)
+
+ assertThat(preference.isVisible).isTrue()
+ }
+
+ @Test
+ fun updateState_systemUpdateStatusUnknown_shouldSetToAndroidVersion() {
+ val bundle = Bundle().apply {
+ putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_UNKNOWN)
+ }
+ whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+ controller.displayPreference(preferenceScreen)
+
+ controller.onViewCreated(TestLifecycleOwner())
+ SystemClock.sleep(100)
+
+ assertThat(preference.summary).isEqualTo(
+ context.getString(
+ R.string.android_version_summary,
+ Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY,
+ )
+ )
+ }
+
+ @Test
+ fun updateState_systemUpdateStatusIdle_shouldSetToAndroidVersion() {
+ val testReleaseName = "ANDROID TEST VERSION"
+ val bundle = Bundle().apply {
+ putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_IDLE)
+ putString(SystemUpdateManager.KEY_TITLE, testReleaseName)
+ }
+ whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+ controller.displayPreference(preferenceScreen)
+
+ controller.onViewCreated(TestLifecycleOwner())
+ SystemClock.sleep(100)
+
+ assertThat(preference.summary)
+ .isEqualTo(context.getString(R.string.android_version_summary, testReleaseName))
+ }
+
+ @Test
+ fun updateState_systemUpdateInProgress_shouldSetToUpdatePending() {
+ val bundle = Bundle().apply {
+ putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_WAITING_DOWNLOAD)
+ }
+ whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+ controller.displayPreference(preferenceScreen)
+
+ controller.onViewCreated(TestLifecycleOwner())
+ SystemClock.sleep(100)
+
+ assertThat(preference.summary)
+ .isEqualTo(context.getString(R.string.android_version_pending_update_summary))
+ }
+
+ private companion object {
+ const val KEY = "test_key"
+ }
+}
diff --git a/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java b/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java
deleted file mode 100644
index 36beb90..0000000
--- a/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2018 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.android.settings.ui;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.Intent;
-import android.nfc.NfcAdapter;
-import android.nfc.NfcManager;
-import android.os.RemoteException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@Ignore
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class ConnectedDeviceTests {
-
- private static final String SETTINGS_PACKAGE = "com.android.settings";
- private static final int TIMEOUT = 2000;
- private UiDevice mDevice;
-
- @Before
- public void setUp() throws Exception {
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- try {
- mDevice.setOrientationNatural();
- } catch (RemoteException e) {
- throw new RuntimeException("failed to freeze device orientation", e);
- }
- }
-
- @After
- public void tearDown() throws Exception {
- mDevice.pressBack();
- mDevice.pressHome();
- }
-
- // This NFC toggle test is set up this way since there's no way to set
- // the NFC flag to enabled or disabled without touching UI.
- // This way, we get coverage for whether or not the toggle button works.
- @Test
- public void testNFCToggle() throws Exception {
- NfcManager manager = (NfcManager) InstrumentationRegistry.getTargetContext()
- .getSystemService(Context.NFC_SERVICE);
- NfcAdapter nfcAdapter = manager.getDefaultAdapter();
- boolean nfcInitiallyEnabled = nfcAdapter.isEnabled();
- InstrumentationRegistry.getContext().startActivity(new Intent()
- .setClassName(
- SETTINGS_PACKAGE,
- "com.android.settings.Settings$ConnectedDeviceDashboardActivity"));
- UiObject2 nfcSetting = mDevice.wait(Until.findObject(By.text("NFC")), TIMEOUT);
- nfcSetting.click();
- Thread.sleep(TIMEOUT * 2);
- if (nfcInitiallyEnabled) {
- assertFalse("NFC wasn't disabled on toggle", nfcAdapter.isEnabled());
- nfcSetting.click();
- Thread.sleep(TIMEOUT * 2);
- assertTrue("NFC wasn't enabled on toggle", nfcAdapter.isEnabled());
- } else {
- assertTrue("NFC wasn't enabled on toggle", nfcAdapter.isEnabled());
- nfcSetting.click();
- Thread.sleep(TIMEOUT * 2);
- assertFalse("NFC wasn't disabled on toggle", nfcAdapter.isEnabled());
- }
- }
-}
diff --git a/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTest.kt b/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTest.kt
new file mode 100644
index 0000000..413fae7
--- /dev/null
+++ b/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.android.settings.ui
+
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.settings.ui.testutils.SettingsTestUtils.assertHasTexts
+import com.android.settings.ui.testutils.SettingsTestUtils.startMainActivityFromHomeScreen
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class DataUsageSettingsTest {
+ private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+
+ @Before
+ fun setUp() {
+ device.startMainActivityFromHomeScreen(Settings.ACTION_DATA_USAGE_SETTINGS)
+ }
+
+ @Test
+ fun hasTexts() {
+ device.assertHasTexts(ON_SCREEN_TEXTS)
+ }
+
+ private companion object {
+ val ON_SCREEN_TEXTS = listOf(
+ "0 B",
+ "Data Saver",
+ "Wi‑Fi data usage",
+ )
+ }
+}
diff --git a/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java b/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java
deleted file mode 100644
index 3befca3..0000000
--- a/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2018 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.android.settings.ui;
-
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.system.helpers.SettingsHelper;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
-import org.junit.Ignore;
-
-@Ignore
-public class DataUsageSettingsTests extends InstrumentationTestCase {
-
- private static final String SETTINGS_PACKAGE = "com.android.settings";
- private static final int TIMEOUT = 2000;
- private UiDevice mDevice;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mDevice = UiDevice.getInstance(getInstrumentation());
- try {
- mDevice.setOrientationNatural();
- } catch (RemoteException e) {
- throw new RuntimeException("failed to freeze device orientaion", e);
- }
- }
-
- @Override
- protected void tearDown() throws Exception {
- // Need to finish settings activity
- mDevice.pressBack();
- mDevice.pressHome();
- super.tearDown();
- }
-
- @MediumTest
- public void testElementsOnDataUsageScreen() throws Exception {
- launchDataUsageSettings();
- assertNotNull("Data usage element not found",
- mDevice.wait(Until.findObject(By.text("Usage")),
- TIMEOUT));
- assertNotNull("Data usage bar not found",
- mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE,
- "color_bar")), TIMEOUT));
- assertNotNull("WiFi Data usage element not found",
- mDevice.wait(Until.findObject(By.text("Wi-Fi data usage")),
- TIMEOUT));
- assertNotNull("Network restrictions element not found",
- mDevice.wait(Until.findObject(By.text("Network restrictions")),
- TIMEOUT));
- }
-
- public void launchDataUsageSettings() throws Exception {
- SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
- Settings.ACTION_SETTINGS);
- mDevice.wait(Until
- .findObject(By.text("Network & Internet")), TIMEOUT)
- .click();
- Thread.sleep(TIMEOUT * 2);
- assertNotNull("Network & internet screen not loaded", mDevice.wait(
- Until.findObject(By.text("Data usage")), TIMEOUT));
- mDevice.wait(Until
- .findObject(By.text("Data usage")), TIMEOUT)
- .click();
- }
-}
diff --git a/tests/uitests/src/com/android/settings/ui/DevelopmentSettingsTest.kt b/tests/uitests/src/com/android/settings/ui/DevelopmentSettingsTest.kt
index 1afa3ab..1215383 100644
--- a/tests/uitests/src/com/android/settings/ui/DevelopmentSettingsTest.kt
+++ b/tests/uitests/src/com/android/settings/ui/DevelopmentSettingsTest.kt
@@ -16,13 +16,14 @@
package com.android.settings.ui
-import android.os.SystemClock
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import com.android.settings.ui.testutils.SettingsTestUtils.assertHasTexts
+import com.android.settings.ui.testutils.SettingsTestUtils.clickObject
import com.android.settings.ui.testutils.SettingsTestUtils.startMainActivityFromHomeScreen
import org.junit.Before
import org.junit.Test
@@ -35,8 +36,11 @@
@Before
fun setUp() {
- device.executeShellCommand("settings put global development_settings_enabled 1")
- SystemClock.sleep(1000)
+ device.startMainActivityFromHomeScreen(Settings.ACTION_DEVICE_INFO_SETTINGS)
+ device.assertHasTexts(listOf(BUILD_NUMBER))
+ repeat(7) { // Enable development mode
+ device.clickObject(By.text(BUILD_NUMBER))
+ }
device.startMainActivityFromHomeScreen(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
}
@@ -46,6 +50,7 @@
}
private companion object {
+ private const val BUILD_NUMBER = "Build number"
val ON_SCREEN_TEXTS = listOf(
"Use developer options",
"Memory",
diff --git a/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java b/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java
index 5bfc59d..25b4767 100644
--- a/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java
+++ b/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java
@@ -24,6 +24,7 @@
import android.test.suitebuilder.annotation.MediumTest;
import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
@@ -86,8 +87,8 @@
public void testVPNMenuLoad() throws Exception {
SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
Settings.ACTION_WIRELESS_SETTINGS);
- mDevice.wait(Until
- .findObject(By.text("VPN")), TIMEOUT)
+ mDevice.findObject(By.res(SETTINGS_PACKAGE, "main_content"))
+ .scrollUntil(Direction.DOWN, Until.findObject(By.text("VPN")))
.click();
Thread.sleep(TIMEOUT);
UiObject2 usbTethering = mDevice.wait(Until
diff --git a/tests/uitests/src/com/android/settings/ui/NetworkOperatorSettingsTest.kt b/tests/uitests/src/com/android/settings/ui/NetworkOperatorSettingsTest.kt
new file mode 100644
index 0000000..701ba2f
--- /dev/null
+++ b/tests/uitests/src/com/android/settings/ui/NetworkOperatorSettingsTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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.android.settings.ui
+
+import android.provider.Settings
+import android.telephony.SubscriptionManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.settings.ui.testutils.SettingsTestUtils.assertHasTexts
+import com.android.settings.ui.testutils.SettingsTestUtils.startMainActivityFromHomeScreen
+import com.google.common.truth.TruthJUnit.assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NetworkOperatorSettingsTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val device = UiDevice.getInstance(instrumentation)
+
+ @Before
+ fun setUp() {
+ assume().that(
+ instrumentation.context.getSystemService(SubscriptionManager::class.java)!!
+ .availableSubscriptionInfoList
+ ).isNotEmpty()
+ device.startMainActivityFromHomeScreen(Settings.ACTION_NETWORK_OPERATOR_SETTINGS)
+ }
+
+ @Test
+ fun hasTexts() {
+ device.assertHasTexts(ON_SCREEN_TEXTS)
+ }
+
+ private companion object {
+ val ON_SCREEN_TEXTS = listOf(
+ "Use SIM",
+ "0 B",
+ "Calls preference",
+ "SMS preference",
+ "Mobile data",
+ "Roaming",
+ "App data usage",
+ "Data warning & limit",
+ "Preferred network type",
+ "Carrier settings version",
+ "Automatically select network",
+ "Choose network",
+ "Access Point Names",
+ )
+ }
+}
diff --git a/tests/uitests/src/com/android/settings/ui/NfcSettingsTest.kt b/tests/uitests/src/com/android/settings/ui/NfcSettingsTest.kt
new file mode 100644
index 0000000..2fbbfe5
--- /dev/null
+++ b/tests/uitests/src/com/android/settings/ui/NfcSettingsTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 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.android.settings.ui
+
+import android.nfc.NfcAdapter
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.settings.ui.testutils.SettingsTestUtils.assertHasTexts
+import com.android.settings.ui.testutils.SettingsTestUtils.startMainActivityFromHomeScreen
+import com.google.common.truth.TruthJUnit.assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NfcSettingsTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val device = UiDevice.getInstance(instrumentation)
+
+ @Before
+ fun setUp() {
+ assume().that(NfcAdapter.getDefaultAdapter(instrumentation.context)).isNotNull()
+ device.startMainActivityFromHomeScreen(Settings.ACTION_NFC_SETTINGS)
+ }
+
+ @Test
+ fun hasTexts() {
+ device.assertHasTexts(ON_SCREEN_TEXTS)
+ }
+
+ private companion object {
+ val ON_SCREEN_TEXTS = listOf(
+ "Use NFC",
+ "Require device unlock for NFC",
+ "Contactless payments",
+ )
+ }
+}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 0ded397..196b809 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -27,6 +27,7 @@
"platform-test-annotations",
"truth-prebuilt",
"kotlinx_coroutines_test",
+ "flag-junit",
// Don't add SettingsLib libraries here - you can use them directly as they are in the
// instrumented Settings app.
],
diff --git a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java b/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
deleted file mode 100644
index f74768f..0000000
--- a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.android.settings.datausage;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.telephony.TelephonyManager;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class BillingCyclePreferenceTest {
-
- private Context mContext;
- private BillingCyclePreference mPreference;
- private TemplatePreference.NetworkServices mServices;
- @Mock
- private INetworkManagementService mNetManageSerice;
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private UserManager mUserManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(ApplicationProvider.getApplicationContext());
-
- mServices = new TemplatePreference.NetworkServices();
- mServices.mNetworkService = mNetManageSerice;
- mServices.mTelephonyManager = mTelephonyManager;
- mServices.mUserManager = mUserManager;
-
- doReturn(mTelephonyManager).when(mTelephonyManager)
- .createForSubscriptionId(anyInt());
-
- mPreference = spy(new BillingCyclePreference(mContext, null /* attrs */));
- mPreference.setTemplate(null, 0, mServices);
- }
-
- @Test
- public void testPreferenceUpdate_onMobileDataEnabledChange_accessDataEnabledApi() {
- try {
- doReturn(true).when(mNetManageSerice).isBandwidthControlEnabled();
- } catch (RemoteException exception) {}
- doReturn(true).when(mUserManager).isAdminUser();
- mPreference.onMobileDataEnabledChange();
-
- verify(mTelephonyManager)
- .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER);
- }
-}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java
new file mode 100644
index 0000000..707d2b9
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppStateBridgeTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class QuarantinedAppStateBridgeTest {
+ private static final String TEST_PACKAGE = "com.example.test.pkg";
+ private static final int TEST_APP_ID = 1234;
+ private static final int TEST_USER_ID_1 = 0;
+ private static final int TEST_USER_ID_2 = 10;
+
+ @Mock
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void updateExtraInfo_packageQuarantined() throws Exception {
+ setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_1, false);
+ setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_2, true);
+
+ final QuarantinedAppStateBridge bridge =
+ new QuarantinedAppStateBridge(mContext, null, null);
+ final AppEntry entry = mock(AppEntry.class);
+
+ bridge.updateExtraInfo(entry, TEST_PACKAGE, UserHandle.getUid(TEST_USER_ID_2, TEST_APP_ID));
+ assertThat(entry.extraInfo).isEqualTo(true);
+ }
+
+ @Test
+ public void updateExtraInfo_packageNotQuarantined() throws Exception {
+ setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_1, false);
+ setPackageQuarantined(TEST_PACKAGE, TEST_USER_ID_2, false);
+
+ final QuarantinedAppStateBridge bridge =
+ new QuarantinedAppStateBridge(mContext, null, null);
+ final AppEntry entry = mock(AppEntry.class);
+
+ bridge.updateExtraInfo(entry, TEST_PACKAGE, UserHandle.getUid(TEST_USER_ID_2, TEST_APP_ID));
+ assertThat(entry.extraInfo).isEqualTo(false);
+ }
+
+ private void setPackageQuarantined(String packageName, int userId, boolean quarantined)
+ throws Exception {
+ final Context userContext = mock(Context.class);
+ when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
+ .thenReturn(userContext);
+ final PackageManager packageManager = mock(PackageManager.class);
+ when(userContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.isPackageQuarantined(packageName)).thenReturn(quarantined);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java
new file mode 100644
index 0000000..33e4392
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/quarantine/QuarantinedAppsPreferenceControllerTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.android.settings.development.quarantine;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.content.pm.Flags;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class QuarantinedAppsPreferenceControllerTest {
+
+ private static final String PREF_KEY = "quarantined_apps";
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Mock
+ private Context mContext;
+ private QuarantinedAppsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new QuarantinedAppsPreferenceController(mContext, PREF_KEY);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_QUARANTINED_ENABLED)
+ public void testAvailabilityStatus_flagEnabled() {
+ assertEquals(mController.getAvailabilityStatus(), AVAILABLE);
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_QUARANTINED_ENABLED)
+ public void testAvailabilityStatus_flagDisabled() {
+ assertEquals(mController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
index e2bdd17..f807f70 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
@@ -22,8 +22,10 @@
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.EnrollReason
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerEnrollStateViewModel
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flow
/** Fake to be used by other classes to easily fake the FingerprintManager implementation. */
class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
@@ -32,6 +34,7 @@
var enrolledFingerprintsInternal: MutableList<FingerprintViewModel> = mutableListOf()
var challengeToGenerate: Pair<Long, ByteArray> = Pair(-1L, byteArrayOf())
var authenticateAttempt = FingerprintAuthAttemptViewModel.Success(1)
+ val enrollStateViewModel = FingerEnrollStateViewModel.EnrollProgress(1)
var pressToAuthEnabled = true
var sensorProps =
@@ -53,16 +56,25 @@
override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray> {
return challengeToGenerate
}
- override val enrolledFingerprints: Flow<List<FingerprintViewModel>> =
- flowOf(enrolledFingerprintsInternal)
- override val canEnrollFingerprints: Flow<Boolean> =
- flowOf(enrolledFingerprintsInternal.size < enrollableFingerprints)
+ override val enrolledFingerprints: Flow<List<FingerprintViewModel>> = flow {
+ emit(enrolledFingerprintsInternal)
+ }
- override val sensorPropertiesInternal: Flow<FingerprintSensorPropertiesInternal?> =
- flowOf(sensorProps.first())
+ override val canEnrollFingerprints: Flow<Boolean> = flow {
+ emit(enrolledFingerprintsInternal.size < enrollableFingerprints)
+ }
- override val maxEnrollableFingerprints: Flow<Int> = flowOf(enrollableFingerprints)
+ override val sensorPropertiesInternal: Flow<FingerprintSensorPropertiesInternal?> = flow {
+ emit(sensorProps.first())
+ }
+
+ override val maxEnrollableFingerprints: Flow<Int> = flow { emit(enrollableFingerprints) }
+
+ override suspend fun enroll(
+ hardwareAuthToken: ByteArray?,
+ enrollReason: EnrollReason
+ ): Flow<FingerEnrollStateViewModel> = flow { emit(enrollStateViewModel) }
override suspend fun removeFingerprint(fp: FingerprintViewModel): Boolean {
return enrolledFingerprintsInternal.remove(fp)
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
index 70943f0..de2c494 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
@@ -30,6 +30,8 @@
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.EnrollReason.FindSensor
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerEnrollStateViewModel
import com.android.settings.password.ChooseLockSettingsHelper
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelAndJoin
@@ -143,7 +145,7 @@
.thenReturn(byteArray)
val generateChallengeCallback: ArgumentCaptor<FingerprintManager.GenerateChallengeCallback> =
- ArgumentCaptor.forClass(FingerprintManager.GenerateChallengeCallback::class.java)
+ argumentCaptor()
var result: Pair<Long, ByteArray?>? = null
val job = testScope.launch { result = underTest.generateChallenge(1L) }
@@ -165,8 +167,7 @@
val fingerprintViewModelToRemove = FingerprintViewModel("Finger 2", 1, 2L)
val fingerprintToRemove = Fingerprint("Finger 2", 1, 2L)
- val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> =
- ArgumentCaptor.forClass(FingerprintManager.RemovalCallback::class.java)
+ val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> = argumentCaptor()
var result: Boolean? = null
val job =
@@ -189,8 +190,7 @@
val fingerprintViewModelToRemove = FingerprintViewModel("Finger 2", 1, 2L)
val fingerprintToRemove = Fingerprint("Finger 2", 1, 2L)
- val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> =
- ArgumentCaptor.forClass(FingerprintManager.RemovalCallback::class.java)
+ val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> = argumentCaptor()
var result: Boolean? = null
val job =
@@ -229,8 +229,7 @@
var result: FingerprintAuthAttemptViewModel? = null
val job = launch { result = underTest.authenticate() }
- val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> =
- ArgumentCaptor.forClass(FingerprintManager.AuthenticationCallback::class.java)
+ val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> = argumentCaptor()
runCurrent()
@@ -257,8 +256,7 @@
var result: FingerprintAuthAttemptViewModel? = null
val job = launch { result = underTest.authenticate() }
- val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> =
- ArgumentCaptor.forClass(FingerprintManager.AuthenticationCallback::class.java)
+ val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> = argumentCaptor()
runCurrent()
@@ -280,8 +278,82 @@
)
}
+ @Test
+ fun testEnroll_progress() =
+ testScope.runTest {
+ val token = byteArrayOf(5, 3, 2)
+ var result: FingerEnrollStateViewModel? = null
+ val job = launch { underTest.enroll(token, FindSensor).collect { result = it } }
+ val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
+ runCurrent()
+
+ verify(fingerprintManager)
+ .enroll(
+ eq(token),
+ any(CancellationSignal::class.java),
+ anyInt(),
+ capture(enrollCallback),
+ eq(FingerprintManager.ENROLL_FIND_SENSOR)
+ )
+ enrollCallback.value.onEnrollmentProgress(1)
+ runCurrent()
+ job.cancelAndJoin()
+
+ assertThat(result).isEqualTo(FingerEnrollStateViewModel.EnrollProgress(1))
+ }
+
+ @Test
+ fun testEnroll_help() =
+ testScope.runTest {
+ val token = byteArrayOf(5, 3, 2)
+ var result: FingerEnrollStateViewModel? = null
+ val job = launch { underTest.enroll(token, FindSensor).collect { result = it } }
+ val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
+ runCurrent()
+
+ verify(fingerprintManager)
+ .enroll(
+ eq(token),
+ any(CancellationSignal::class.java),
+ anyInt(),
+ capture(enrollCallback),
+ eq(FingerprintManager.ENROLL_FIND_SENSOR)
+ )
+ enrollCallback.value.onEnrollmentHelp(-1, "help")
+ runCurrent()
+ job.cancelAndJoin()
+
+ assertThat(result).isEqualTo(FingerEnrollStateViewModel.EnrollHelp(-1, "help"))
+ }
+
+ @Test
+ fun testEnroll_error() =
+ testScope.runTest {
+ val token = byteArrayOf(5, 3, 2)
+ var result: FingerEnrollStateViewModel? = null
+ val job = launch { underTest.enroll(token, FindSensor).collect { result = it } }
+ val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
+ runCurrent()
+
+ verify(fingerprintManager)
+ .enroll(
+ eq(token),
+ any(CancellationSignal::class.java),
+ anyInt(),
+ capture(enrollCallback),
+ eq(FingerprintManager.ENROLL_FIND_SENSOR)
+ )
+ enrollCallback.value.onEnrollmentError(-2, "error")
+ runCurrent()
+ job.cancelAndJoin()
+
+ assertThat(result).isEqualTo(FingerEnrollStateViewModel.EnrollError(-2, "error"))
+ }
+
private fun <T : Any> safeEq(value: T): T = eq(value) ?: value
private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
+ inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> =
+ ArgumentCaptor.forClass(T::class.java)
}
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
index f063042..587e734 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -18,9 +18,7 @@
import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
import static com.android.settings.network.SubscriptionUtil.SUB_ID;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
@@ -185,7 +183,7 @@
@Ignore
@Test
public void getUniqueDisplayNames_identicalCarriers_fourDigitsUsed() {
- // Both subscriptoins have the same display name.
+ // Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -215,7 +213,7 @@
@Ignore
@Test
public void getUniqueDisplayNames_identicalCarriersAfterTrim_fourDigitsUsed() {
- // Both subscriptoins have the same display name.
+ // Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -244,8 +242,8 @@
@Ignore
@Test
- public void getUniqueDisplayNames_phoneNumberBlocked_subscriptoinIdFallback() {
- // Both subscriptoins have the same display name.
+ public void getUniqueDisplayNames_phoneNumberBlocked_subscriptionIdFallback() {
+ // Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -273,9 +271,9 @@
@Ignore
@Test
- public void getUniqueDisplayNames_phoneNumberIdentical_subscriptoinIdFallback() {
+ public void getUniqueDisplayNames_phoneNumberIdentical_subscriptionIdFallback() {
// TODO have three here from the same carrier
- // Both subscriptoins have the same display name.
+ // Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
@@ -464,8 +462,8 @@
SharedPreferences sp = mock(SharedPreferences.class);
when(mContext.getSharedPreferences(
KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
- when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + "6789");
- when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + "4321");
+ when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
+ when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
final CharSequence nameOfSub1 =
@@ -475,8 +473,41 @@
assertThat(nameOfSub1).isNotNull();
assertThat(nameOfSub2).isNotNull();
- assertEquals(CARRIER_1 + "6789", nameOfSub1.toString());
- assertEquals(CARRIER_1 + "4321", nameOfSub2.toString());
+ assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
+ assertEquals(CARRIER_1 + " 4321", nameOfSub2.toString());
+ }
+
+ @Test
+ public void getUniqueDisplayName_hasRecordAndNameIsChanged_doesNotUseRecordBeTheResult() {
+ final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+ when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+ when(info2.getSubscriptionId()).thenReturn(SUBID_2);
+ when(info1.getDisplayName()).thenReturn(CARRIER_1);
+ when(info2.getDisplayName()).thenReturn(CARRIER_2);
+ when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(
+ Arrays.asList(info1, info2));
+
+ SharedPreferences sp = mock(SharedPreferences.class);
+ SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+ when(mContext.getSharedPreferences(
+ KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
+ when(sp.edit()).thenReturn(editor);
+ when(editor.remove(anyString())).thenReturn(editor);
+
+ when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
+ when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
+
+
+ final CharSequence nameOfSub1 =
+ SubscriptionUtil.getUniqueSubscriptionDisplayName(info1, mContext);
+ final CharSequence nameOfSub2 =
+ SubscriptionUtil.getUniqueSubscriptionDisplayName(info2, mContext);
+
+ assertThat(nameOfSub1).isNotNull();
+ assertThat(nameOfSub2).isNotNull();
+ assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
+ assertEquals(CARRIER_2.toString(), nameOfSub2.toString());
}
@Test
@@ -501,4 +532,60 @@
assertTrue(SubscriptionUtil.isSimHardwareVisible(mContext));
}
+
+ @Test
+ public void isValidCachedDisplayName_matchesRule1_returnTrue() {
+ String originalName = "originalName";
+ String cacheString = "originalName 1234";
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_matchesRule2_returnTrue() {
+ String originalName = "original Name";
+ String cacheString = originalName + " " + 1234;
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_nameIsEmpty1_returnFalse() {
+ String originalName = "original Name";
+ String cacheString = "";
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_nameIsEmpty2_returnFalse() {
+ String originalName = "";
+ String cacheString = "originalName 1234";
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_nameIsDifferent_returnFalse() {
+ String originalName = "original Name";
+ String cacheString = "originalName 1234";
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_noNumber_returnFalse() {
+ String originalName = "original Name";
+ String cacheString = originalName;
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+ }
+
+ @Test
+ public void isValidCachedDisplayName_noSpace_returnFalse() {
+ String originalName = "original Name";
+ String cacheString = originalName;
+
+ assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+ }
}
diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java
index 2dc00e1..ddf5287 100644
--- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceSafetySourceTest.java
@@ -27,10 +27,11 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.os.Flags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceStatus;
-import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -39,6 +40,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -51,15 +53,13 @@
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
/** Required setup before a test. */
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
-
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, true);
}
/** Required setup after a test. */
@@ -83,6 +83,7 @@
@Test
public void onDeviceRebootedEvent_whenSafetyCenterEnabled_setsData() {
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
@@ -90,13 +91,11 @@
any(), eq(SAFETY_SOURCE_ID), any(), eq(EVENT_TYPE_DEVICE_REBOOTED));
}
- // TODO(b/295516544): Modify this test for the new trunk stable flag instead when available.
/** Tests that when the feature is disabled null data is set. */
@Test
public void setSafetySourceData_whenFeatureDisabled_setsNullData() {
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, false);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
@@ -105,15 +104,13 @@
any(), eq(SAFETY_SOURCE_ID), captor.capture(), eq(EVENT_TYPE_DEVICE_REBOOTED));
SafetySourceData safetySourceData = captor.getValue();
assertThat(safetySourceData).isNull();
-
- FeatureFlagUtils
- .setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, true);
}
/** Tests that setSafetySourceData sets the source status enabled. */
@Test
public void setSafetySourceData_setsEnabled() {
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
@@ -129,6 +126,7 @@
@Test
public void setSafetySourceData_setsPsIntent() {
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index 4a6afb1..3538727 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -64,14 +64,11 @@
private Context mApplicationContext;
- @Mock
- private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
- @Mock
- private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils;
+ @Mock private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils;
- @Mock
- private LockPatternUtils mLockPatternUtils;
+ @Mock private LockPatternUtils mLockPatternUtils;
@Before
public void setUp() {
@@ -94,11 +91,11 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
- any(), any(), any(), any());
+ verify(mSafetyCenterManagerWrapper, never())
+ .setSafetySourceData(any(), any(), any(), any());
}
@Test
@@ -106,11 +103,12 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), eq(null), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), eq(null), any());
}
@Test
@@ -118,11 +116,12 @@
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), any(), any());
}
@Test
@@ -130,11 +129,11 @@
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), any(), any(), eq(EVENT_SOURCE_STATE_CHANGED));
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), any(), eq(EVENT_SOURCE_STATE_CHANGED));
}
@Test
@@ -142,26 +141,28 @@
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), any(), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), captor.capture(), any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
assertThat(safetySourceStatus.getTitle().toString())
- .isEqualTo(ResourcesUtils.getResourcesString(
- mApplicationContext,
- "unlock_set_unlock_launch_picker_title"));
- assertThat(safetySourceStatus.getSummary().toString())
- .isEqualTo(SUMMARY);
+ .isEqualTo(
+ ResourcesUtils.getResourcesString(
+ mApplicationContext, "unlock_set_unlock_launch_picker_title"));
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(SUMMARY);
assertThat(safetySourceStatus.getPendingIntent().getIntent()).isNotNull();
assertThat(safetySourceStatus.getPendingIntent().getIntent().getAction())
.isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
assertThat(
- safetySourceStatus.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
+ safetySourceStatus
+ .getPendingIntent()
+ .getIntent()
+ .getStringExtra(EXTRA_DESTINATION))
.isEqualTo(FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
}
@@ -173,12 +174,16 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -194,12 +199,16 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -215,12 +224,16 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -236,12 +249,16 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -257,12 +274,12 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), any(), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), captor.capture(), any());
SafetySourceData safetySourceData = captor.getValue();
assertThat(safetySourceData.getIssues()).isEmpty();
@@ -276,34 +293,41 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
assertThat(safetySourceData.getIssues()).hasSize(1);
SafetySourceIssue issue = safetySourceData.getIssues().get(0);
assertThat(issue.getId()).isEqualTo(LockScreenSafetySource.NO_SCREEN_LOCK_ISSUE_ID);
- assertThat(issue.getTitle().toString()).isEqualTo(
- ResourcesUtils.getResourcesString(mApplicationContext,
- "no_screen_lock_issue_title"));
- assertThat(issue.getSummary().toString()).isEqualTo(
- ResourcesUtils.getResourcesString(mApplicationContext,
- "no_screen_lock_issue_summary"));
- assertThat(issue.getSeverityLevel()).isEqualTo(
- SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION);
- assertThat(issue.getIssueTypeId()).isEqualTo(
- LockScreenSafetySource.NO_SCREEN_LOCK_ISSUE_TYPE_ID);
+ assertThat(issue.getTitle().toString())
+ .isEqualTo(
+ ResourcesUtils.getResourcesString(
+ mApplicationContext, "no_screen_lock_issue_title"));
+ assertThat(issue.getSummary().toString())
+ .isEqualTo(
+ ResourcesUtils.getResourcesString(
+ mApplicationContext, "no_screen_lock_issue_summary"));
+ assertThat(issue.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION);
+ assertThat(issue.getIssueTypeId())
+ .isEqualTo(LockScreenSafetySource.NO_SCREEN_LOCK_ISSUE_TYPE_ID);
assertThat(issue.getIssueCategory()).isEqualTo(SafetySourceIssue.ISSUE_CATEGORY_DEVICE);
assertThat(issue.getActions()).hasSize(1);
SafetySourceIssue.Action action = issue.getActions().get(0);
assertThat(action.getId()).isEqualTo(LockScreenSafetySource.SET_SCREEN_LOCK_ACTION_ID);
- assertThat(action.getLabel().toString()).isEqualTo(
- ResourcesUtils.getResourcesString(mApplicationContext,
- "no_screen_lock_issue_action_label"));
+ assertThat(action.getLabel().toString())
+ .isEqualTo(
+ ResourcesUtils.getResourcesString(
+ mApplicationContext, "no_screen_lock_issue_action_label"));
assertThat(action.getPendingIntent().getIntent().getAction())
.isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
assertThat(action.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
@@ -318,12 +342,12 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), any(), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), captor.capture(), any());
SafetySourceData safetySourceData = captor.getValue();
assertThat(safetySourceData.getIssues()).isEmpty();
@@ -337,12 +361,16 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
assertThat(safetySourceData.getIssues()).isEmpty();
@@ -355,16 +383,28 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
assertThat(safetySourceStatus.isEnabled()).isFalse();
+ assertThat(safetySourceStatus.getPendingIntent()).isNull();
+ assertThat(safetySourceStatus.getIconAction()).isNull();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
+ assertThat(safetySourceStatus.getSummary().toString())
+ .isEqualTo(
+ ResourcesUtils.getResourcesString(
+ mApplicationContext, "disabled_by_policy_title"));
}
@Test
@@ -374,16 +414,25 @@
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
assertThat(safetySourceStatus.isEnabled()).isTrue();
+ assertThat(safetySourceStatus.getPendingIntent()).isNotNull();
+ assertThat(safetySourceStatus.getIconAction()).isNotNull();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(SUMMARY);
}
@Test
@@ -392,20 +441,23 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(true);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
- final ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(
- SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ final ArgumentCaptor<SafetySourceData> captor =
+ ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
final IconAction iconAction = captor.getValue().getStatus().getIconAction();
assertThat(iconAction.getIconType()).isEqualTo(IconAction.ICON_TYPE_GEAR);
assertThat(iconAction.getPendingIntent().getIntent().getAction())
.isEqualTo(FAKE_ACTION_OPEN_SUB_SETTING);
- assertThat(
- iconAction.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
+ assertThat(iconAction.getPendingIntent().getIntent().getStringExtra(EXTRA_DESTINATION))
.isEqualTo(FAKE_SCREEN_LOCK_SETTINGS);
}
@@ -415,12 +467,16 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(false);
- LockScreenSafetySource.setSafetySourceData(mApplicationContext,
- mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
+ LockScreenSafetySource.setSafetySourceData(
+ mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(LockScreenSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
SafetySourceData safetySourceData = captor.getValue();
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
@@ -434,10 +490,12 @@
LockScreenSafetySource.onLockScreenChange(mApplicationContext);
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), any(), any());
- verify(mSafetyCenterManagerWrapper).setSafetySourceData(
- any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(BiometricsSafetySource.SAFETY_SOURCE_ID), any(), any());
}
@Test
@@ -447,8 +505,8 @@
LockScreenSafetySource.onLockScreenChange(mApplicationContext);
- verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
- any(), any(), any(), any());
+ verify(mSafetyCenterManagerWrapper, never())
+ .setSafetySourceData(any(), any(), any(), any());
}
private void whenScreenLockIsEnabled() {
@@ -456,8 +514,8 @@
when(mScreenLockPreferenceDetailsUtils.getSummary(anyInt())).thenReturn(SUMMARY);
Intent launchChooseLockGenericFragment = new Intent(FAKE_ACTION_OPEN_SUB_SETTING);
- launchChooseLockGenericFragment.putExtra(EXTRA_DESTINATION,
- FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
+ launchChooseLockGenericFragment.putExtra(
+ EXTRA_DESTINATION, FAKE_CHOOSE_LOCK_GENERIC_FRAGMENT);
when(mScreenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent(anyInt()))
.thenReturn(launchChooseLockGenericFragment);
diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
index caae44a..85bd0e2 100644
--- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
@@ -30,9 +30,10 @@
import android.content.Context;
import android.content.Intent;
+import android.os.Flags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
-import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -43,6 +44,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -62,6 +64,7 @@
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
@Mock private LockPatternUtils mLockPatternUtils;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Before
public void setUp() {
@@ -241,15 +244,10 @@
}
/** Tests that the PS source sets null data when it's disabled. */
- // TODO(b/295516544): Modify this test for the new trunk stable flag instead when available.
@Test
public void onReceive_onRefresh_withPrivateSpaceFeatureDisabled_setsNullData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- FeatureFlagUtils
- .setEnabled(
- mApplicationContext,
- FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS,
- false);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
Intent intent =
new Intent()
@@ -265,12 +263,6 @@
.setSafetySourceData(any(), any(), captor.capture(), any());
assertThat(captor.getValue()).isEqualTo(null);
-
- FeatureFlagUtils
- .setEnabled(
- mApplicationContext,
- FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS,
- true);
}
@Test