From 0eabe38cb531cd99e77f09d96788b1f610f03cff Mon Sep 17 00:00:00 2001 From: Ghosuto Date: Fri, 1 Aug 2025 10:32:03 +0000 Subject: [PATCH 01/24] AOD wallpaper toggle * also: Add OverlaySwitchPreference Change-Id: Ib847256c796a2387ec535ffbe4823557c9f9e3c2 --- res/values/custom_arrays.xml | 6 ++++++ res/values/custom_strings.xml | 4 ++++ res/xml/rising_settings_lockscreen.xml | 10 +++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index 9b38a46c..9b9fa320 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -15,6 +15,12 @@ limitations under the License. --> + + + + + + @string/pop_up_view_action_enter_pinned diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 1bc45868..b38b0151 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,10 @@ limitations under the License. --> + + AOD wallpaper + Show wallpaper when aod on + No installed apps support current settings No apps found matching \"%1$s\" diff --git a/res/xml/rising_settings_lockscreen.xml b/res/xml/rising_settings_lockscreen.xml index 3595eab6..2666ce0e 100644 --- a/res/xml/rising_settings_lockscreen.xml +++ b/res/xml/rising_settings_lockscreen.xml @@ -197,12 +197,20 @@ android:key="lockscreen_misc_category" android:title="@string/misc_title"> + + + + lineage:position="bottom" /> From ea8e3b43ca67a380330ebacd8658f26b4e34ab58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FDominik=3D20Proch=3DC3=3DA1zka=3F=3D?= Date: Sun, 3 Aug 2025 15:12:18 +0000 Subject: [PATCH 02/24] Allow single tap on keyguard affordances [2/2] * add an option to always single tap on keyguard affordance, because long pressing on them is quite frankly abysmal Change-Id: I7e9f752f6d74077bebbf9a73c1aae378393b8565 --- res/values/custom_strings.xml | 4 ++++ res/xml/rising_settings_lockscreen.xml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index b38b0151..174e05a0 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,10 @@ limitations under the License. --> + + Keyguard affordance single tap + Toggle keyguard affordances with a single tap + AOD wallpaper Show wallpaper when aod on diff --git a/res/xml/rising_settings_lockscreen.xml b/res/xml/rising_settings_lockscreen.xml index 2666ce0e..95384678 100644 --- a/res/xml/rising_settings_lockscreen.xml +++ b/res/xml/rising_settings_lockscreen.xml @@ -205,6 +205,12 @@ android:defaultValue="false" lineage:position="top" /> + + Date: Tue, 19 Aug 2025 09:22:42 +0000 Subject: [PATCH 03/24] Add various Lock/Unlock sounds [2/2] --- res/values/custom_arrays.xml | 73 +++++++++++++++++++ res/values/custom_strings.xml | 5 ++ res/xml/rising_settings_themes.xml | 23 ++++++ src/com/rising/settings/fragments/Themes.java | 20 ++++- 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index 9b9fa320..9154818f 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -15,6 +15,79 @@ limitations under the License. --> + + + Default + Amazon Fire + Asus Zenfone Max + Essential PH-1 + HTC M8 + Huawei + Hyper OS + Iqoo + LG G3 + Minecraft door + MIUI 10 + MIUI 11 + Nextbit + Nokia X + Old School IOS + One UI + OOS 14 + Razer Phone + Soong + Windows Device + Windows Error + + + + /product/media/audio/ui/Lock.ogg + /product/media/audio/ui/Amazon_Fire_Lock.ogg + /product/media/audio/ui/Asus_Zenfone_Max_Lock.ogg + /product/media/audio/ui/Essential_PH-1_Lock.ogg + /product/media/audio/ui/HTC_M8_Lock.ogg + /product/media/audio/ui/Huawei_Lock.ogg + /product/media/audio/ui/Hyper_OS_Lock.ogg + /product/media/audio/ui/Iqoo_Lock.ogg + /product/media/audio/ui/LG_G3_Lock.ogg + /product/media/audio/ui/Minecraft_Door_Lock.ogg + /product/media/audio/ui/MIUI_10_Lock.ogg + /product/media/audio/ui/MIUI_11_Lock.ogg + /product/media/audio/ui/Nextbit_Lock.ogg + /product/media/audio/ui/Nokia_X_Lock.ogg + /product/media/audio/ui/Old_School_IOS_Lock.ogg + /product/media/audio/ui/One_UI_Lock.ogg + /product/media/audio/ui/OOS_14_Lock.ogg + /product/media/audio/ui/Razer_Phone_Lock.ogg + /product/media/audio/ui/Soong_Lock.ogg + /product/media/audio/ui/Windows_Device_Lock.ogg + /product/media/audio/ui/Windows_Error_Lock.ogg + + + + /product/media/audio/ui/Unlock.ogg + /product/media/audio/ui/Amazon_Fire_Unlock.ogg + /product/media/audio/ui/Asus_Zenfone_Max_Unlock.ogg + /product/media/audio/ui/Essential_PH-1_Unlock.ogg + /product/media/audio/ui/HTC_M8_Unlock.ogg + /product/media/audio/ui/Huawei_Unlock.ogg + /product/media/audio/ui/Hyper_OS_Unlock.ogg + /product/media/audio/ui/Iqoo_Unlock.ogg + /product/media/audio/ui/LG_G3_Unlock.ogg + /product/media/audio/ui/Minecraft_Door_Unlock.ogg + /product/media/audio/ui/MIUI_10_Unlock.ogg + /product/media/audio/ui/MIUI_11_Unlock.ogg + /product/media/audio/ui/Nextbit_Unlock.ogg + /product/media/audio/ui/Nokia_X_Unlock.ogg + /product/media/audio/ui/Old_School_IOS_Unlock.ogg + /product/media/audio/ui/One_UI_Unlock.ogg + /product/media/audio/ui/OOS_14_Unlock.ogg + /product/media/audio/ui/Razer_Phone_Unlock.ogg + /product/media/audio/ui/Soong_Unlock.ogg + /product/media/audio/ui/Windows_Device_Unlock.ogg + /product/media/audio/ui/Windows_Error_Unlock.ogg + + diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 174e05a0..8b6b1b40 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,11 @@ limitations under the License. --> + + Audio + Lock sound + Unlock sound + Keyguard affordance single tap Toggle keyguard affordances with a single tap diff --git a/res/xml/rising_settings_themes.xml b/res/xml/rising_settings_themes.xml index 84271590..73cbffb2 100644 --- a/res/xml/rising_settings_themes.xml +++ b/res/xml/rising_settings_themes.xml @@ -31,6 +31,29 @@ + + + + + + + + + diff --git a/src/com/rising/settings/fragments/Themes.java b/src/com/rising/settings/fragments/Themes.java index ca65baab..23b5aca8 100644 --- a/src/com/rising/settings/fragments/Themes.java +++ b/src/com/rising/settings/fragments/Themes.java @@ -31,6 +31,9 @@ import com.android.internal.util.android.ThemeUtils; +import com.android.settings.preferences.GlobalSettingListPreference; +import com.android.settings.utils.SystemRestartUtils; + import java.util.List; @SearchIndexable @@ -42,6 +45,8 @@ public class Themes extends SettingsPreferenceFragment implements private static final String KEY_NOTIF_STYLE = "notification_style"; private static final String KEY_POWERMENU_STYLE = "powermenu_style"; private static final String KEY_HIDE_IME_STYLE = "hide_ime_space_style"; + private static final String KEY_LOCK_SOUND = "lock_sound"; + private static final String KEY_UNLOCK_SOUND = "unlock_sound"; private static final String[] POWER_MENU_OVERLAYS = { "com.android.theme.powermenu.cyberpunk", @@ -74,6 +79,8 @@ public class Themes extends SettingsPreferenceFragment implements private Preference mNotificationStylePref; private Preference mPowerMenuStylePref; private Preference mHideImePref; + private GlobalSettingListPreference mLockSound; + private GlobalSettingListPreference mUnlockSound; @Override public void onCreate(Bundle savedInstanceState) { @@ -93,6 +100,11 @@ public void onCreate(Bundle savedInstanceState) { mHideImePref = findPreference(KEY_HIDE_IME_STYLE); mHideImePref.setOnPreferenceChangeListener(this); + mLockSound = (GlobalSettingListPreference) findPreference(KEY_LOCK_SOUND); + mLockSound.setOnPreferenceChangeListener(this); + mUnlockSound = (GlobalSettingListPreference) findPreference(KEY_UNLOCK_SOUND); + mUnlockSound.setOnPreferenceChangeListener(this); + com.android.settingslib.widget.LayoutPreference highlightPref = getPreferenceScreen().findPreference("themes_highlight_dashboard"); if (highlightPref != null) { java.util.Map highlightClickMap = new java.util.HashMap<>(); @@ -104,7 +116,7 @@ public void onCreate(Bundle savedInstanceState) { } } - private void updateStyle(String key, String category, String target, + private void updateStyle(String key, String category, String target, int defaultValue, String[] overlayPackages, boolean restartSystemUI) { final int style = Settings.System.getIntForUser( getContext().getContentResolver(), @@ -142,8 +154,12 @@ private void updateHideImeSpaceStyle() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - int value = Integer.parseInt((String) newValue); + if (preference == mLockSound || preference == mUnlockSound) { + SystemRestartUtils.showSystemUIRestartDialog(getContext()); + return true; + } + int value = Integer.parseInt((String) newValue); if (preference == mProgressBarPref) { Settings.System.putIntForUser(getActivity().getContentResolver(), KEY_PGB_STYLE, value, UserHandle.USER_CURRENT); From 85ab01dc0b9d0eb91230f95f60c7fefbef5ba83a Mon Sep 17 00:00:00 2001 From: Hecheng Yu Date: Wed, 20 Aug 2025 13:18:26 +0800 Subject: [PATCH 04/24] Introduce slide transition --- res/values/custom_arrays.xml | 2 ++ res/values/custom_strings.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index 9154818f..7e4e926a 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -255,12 +255,14 @@ @string/color_default @string/pie_system_animation_style @string/scale_system_animation_style + @string/slide_system_animation_style 0 1 2 + 3 diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 8b6b1b40..a894af31 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -2455,6 +2455,7 @@ System animation style Android P Scale + Slide Select Apps to Spoof From e86c23980a7f3cd1b079d226eaf7b6e12e678e90 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Thu, 21 Aug 2025 18:30:48 +0530 Subject: [PATCH 05/24] Fix and improve keybox data preference [1/2] * Add space for icon * Use linear layout throughout * Make toasts translatable * Dynamically update summary when XML loaded/cleared * Improve checks and XML loading Signed-off-by: Pranav Vashi --- res/layout/keybox_data_pref.xml | 48 +++++++++++++++++++++++++------ res/values/custom_strings.xml | 10 +++++-- res/xml/rising_settings_spoof.xml | 4 +-- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/res/layout/keybox_data_pref.xml b/res/layout/keybox_data_pref.xml index 6848b9a4..622cd331 100644 --- a/res/layout/keybox_data_pref.xml +++ b/res/layout/keybox_data_pref.xml @@ -1,10 +1,35 @@ - + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:clipToPadding="false" + android:baselineAligned="false"> + + + + + + android:textAppearance="?android:attr/textAppearanceListItem" /> + android:maxLines="5" + android:ellipsize="end" /> diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index a894af31..a71ab164 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -98,8 +98,14 @@ Spoof the Google Photos app as a Pixel XL Snapchat Spoof Snapchat as a Pixel XL to fix possible chat issues - Select keybox XML to spoof - Select keybox XML used for key attestation spoofing for all apps system wide. Click the delete button in order to reset the keybox data values used by the system. + Keybox attestation override + Load a custom keybox XML to override device key attestation + Custom keybox XML loaded. Delete to clear. + Clear keybox data + Not an XML file. Choose a valid keybox XML. + Invalid keybox XML: required fields missing + Keybox loaded + Keybox cleared Screen Off AOD diff --git a/res/xml/rising_settings_spoof.xml b/res/xml/rising_settings_spoof.xml index a8a1f665..92be77d6 100644 --- a/res/xml/rising_settings_spoof.xml +++ b/res/xml/rising_settings_spoof.xml @@ -27,9 +27,7 @@ + android:title="@string/keybox_data_title" /> Date: Sun, 10 Aug 2025 23:55:24 +0200 Subject: [PATCH 06/24] Add switch for small notifications [2/2] --- res/values/custom_strings.xml | 4 ++++ res/xml/rising_settings_notification.xml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index a71ab164..92e7c592 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,10 @@ limitations under the License. --> + + Small landscape notifications + Shows notifications smaller in width in notification panel in landscape mode just as AOSP intended + Audio Lock sound diff --git a/res/xml/rising_settings_notification.xml b/res/xml/rising_settings_notification.xml index 86639e5d..50a2cabc 100644 --- a/res/xml/rising_settings_notification.xml +++ b/res/xml/rising_settings_notification.xml @@ -56,6 +56,12 @@ android:defaultValue="false" android:dependency="heads_up_notifications_enabled" /> + + Date: Sat, 13 Sep 2025 14:42:51 +0000 Subject: [PATCH 07/24] Update three finger swipe actions --- res/raw-night/lottie_gesture_screenshot.json | 1 + res/raw/lottie_gesture_screenshot.json | 1 + res/values/custom_arrays.xml | 4 +- res/values/custom_strings.xml | 8 ++++ res/xml/rising_settings_gestures.xml | 33 ++++--------- res/xml/rising_settings_navigation.xml | 20 ++++---- res/xml/three_finger_swipe.xml | 49 ++++++++++++++++++++ 7 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 res/raw-night/lottie_gesture_screenshot.json create mode 100644 res/raw/lottie_gesture_screenshot.json create mode 100644 res/xml/three_finger_swipe.xml diff --git a/res/raw-night/lottie_gesture_screenshot.json b/res/raw-night/lottie_gesture_screenshot.json new file mode 100644 index 00000000..08632357 --- /dev/null +++ b/res/raw-night/lottie_gesture_screenshot.json @@ -0,0 +1 @@ +{"v":"5.12.2","fr":60,"ip":1,"op":353,"w":382,"h":224,"nm":"Screenshot gesture_Dark","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp 3","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[302.812,145.5,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[227.812,146,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[302.812,78,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[227.812,78.25,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Pre-comp 2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[229.219,76.281,0],"ix":2,"l":2},"a":{"a":0,"k":[33.5,-35.25,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":[[33.5,-32.25],[33.5,-38.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.941176470588,0.949019607843,0.949019607843,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 22","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[226.281,79.906,0],"ix":2,"l":2},"a":{"a":0,"k":[33.5,-35.25,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":[[33.5,-32.25],[33.5,-38.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.941176470588,0.949019607843,0.949019607843,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 3","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":118,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":139,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[60]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[265,113,0],"ix":2,"l":2},"a":{"a":0,"k":[265,113,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 21","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[298.692,193.388,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[130,130,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 20","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[231.308,193.388,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[130,130,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 19","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[301.103,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 18","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289.269,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 17","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.436,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 16","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[265.603,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.188235309077,0.188235309077,0.20000001496,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.829,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[48.829,-82.044,0],"ix":1,"l":2},"s":{"a":0,"k":[84.827,105.728,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[29.658,10.912],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.84313731474,0.098039223166,0.129411764706,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":[48.829,-82.044],"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":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":3,"nm":"Null 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.667,"y":1},"o":{"x":0.333,"y":0},"t":42,"s":[264.5,90,0],"to":[0,12,0],"ti":[0,-12,0]},{"t":101,"s":[264.5,162,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19,19,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":414,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 12","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[121.053,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 11","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.316,-42.982,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 10","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-118.421,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[264.692,119.514,0],"to":[0.052,-1.254,0],"ti":[-0.052,1.254,0]},{"t":127,"s":[265.005,111.991,0]}],"ix":2,"l":2},"a":{"a":0,"k":[73.442,-14.236,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":106,"s":[100,100,100]},{"t":127,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":42,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[41.627,-45.296],[41.504,-44.704],[-41.75,-44.704],[-41.627,-45.296]],"c":true}]},{"t":101,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[41.627,-45.296],[41.258,30.296],[-41.996,30.296],[-41.627,-45.296]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":106,"s":[4]},{"t":127,"s":[0]}],"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235309077,0.188235309077,0.20000001496,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":[73.627,-6.704],"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":29,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[264.817,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"3","tt":2,"tp":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[264.755,112.023,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":[[7.158,0],[0,0],[0,7.122],[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0]],"o":[[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0],[7.158,0],[0,0],[0,7.122]],"v":[[34.628,99.5],[-34.628,99.5],[-47.587,86.605],[-47.587,-86.605],[-34.628,-99.5],[34.628,-99.5],[47.587,-86.605],[47.587,86.605]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"5","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":475,"st":59,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 9","tt":1,"tp":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.127,"y":1},"o":{"x":0.167,"y":0},"t":150,"s":[87.972,180.675,0],"to":[-5.083,0,0],"ti":[5.083,0,0]},{"t":190,"s":[57.472,180.675,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-73.528,-0.325,0],"ix":1,"l":2},"s":{"a":0,"k":[23,23,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[87.943,191.35],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235309077,0.188235309077,0.20000001496,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":[-73.528,-0.325],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":471,"st":59,"ct":1,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.127,"y":1},"o":{"x":0.333,"y":0},"t":50,"s":[116.972,112.175,0],"to":[-4.833,11.417,0],"ti":[4.833,-11.417,0]},{"t":91,"s":[87.972,180.675,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-73.528,-0.325,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.127,0.127,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":50,"s":[100,101.045,100]},{"t":91,"s":[23,23,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[87.943,191.35],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.127],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[8]},{"t":91,"s":[14]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235309077,0.188235309077,0.20000001496,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":[-73.528,-0.325],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":50,"op":150,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":19,"ty":3,"nm":"Null 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.316,"y":1},"o":{"x":0.615,"y":0},"t":22,"s":[117.5,90,0],"to":[0,7.333,0],"ti":[0,-7.333,0]},{"t":50,"s":[117.5,134,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19,19,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":414,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 6","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[121.053,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 5","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.316,-42.982,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 4","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-118.421,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"2","tt":2,"tp":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.158,0],[0,0],[0,7.122],[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0]],"o":[[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0],[7.158,0],[0,0],[0,7.122]],"v":[[34.628,99.5],[-34.628,99.5],[-47.587,86.605],[-47.587,-86.605],[-34.628,-99.5],[34.628,-99.5],[47.587,-86.605],[47.587,86.605]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} diff --git a/res/raw/lottie_gesture_screenshot.json b/res/raw/lottie_gesture_screenshot.json new file mode 100644 index 00000000..a38003d4 --- /dev/null +++ b/res/raw/lottie_gesture_screenshot.json @@ -0,0 +1 @@ +{"v":"5.12.2","fr":60,"ip":1,"op":353,"w":382,"h":224,"nm":"Screenshot gesture_Light","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp 4","fr":60,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[302.812,145.5,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[227.812,146,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[302.812,78,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[227.812,78.25,0],"ix":2,"l":2},"a":{"a":0,"k":[228.313,78.75,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Pre-comp 2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[229.219,76.281,0],"ix":2,"l":2},"a":{"a":0,"k":[33.5,-35.25,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":[[33.5,-32.25],[33.5,-38.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105882352941,0.105882352941,0.113725490196,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 22","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[226.281,79.906,0],"ix":2,"l":2},"a":{"a":0,"k":[33.5,-35.25,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":[[33.5,-32.25],[33.5,-38.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105882352941,0.105882352941,0.113725490196,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"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":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 4","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":118,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":139,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[60]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[265,113,0],"ix":2,"l":2},"a":{"a":0,"k":[265,113,0],"ix":1,"l":2},"s":{"a":0,"k":[99,99,100],"ix":6,"l":2}},"ao":0,"w":382,"h":224,"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 21","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[298.692,193.388,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[130,130,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 20","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[231.308,193.388,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[130,130,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 19","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[301.103,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 18","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289.269,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 17","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.436,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 16","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[265.603,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[81.853,-81.147,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[9.705,9.705],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.780392156863,0.776470588235,0.792156862745,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":[81.853,-81.147],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":112,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":133,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.829,29.888,0],"ix":2,"l":2},"a":{"a":0,"k":[48.829,-82.044,0],"ix":1,"l":2},"s":{"a":0,"k":[84.827,105.728,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[29.658,10.912],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.881463982077,0.881463982077,0.881463982077,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"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":[0.84313731474,0.098039223166,0.129411764706,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":[48.829,-82.044],"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":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":3,"nm":"Null 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.667,"y":1},"o":{"x":0.333,"y":0},"t":42,"s":[264.5,90,0],"to":[0,12,0],"ti":[0,-12,0]},{"t":101,"s":[264.5,162,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19,19,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":414,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 12","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[121.053,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 11","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.316,-42.982,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 10","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-118.421,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":106,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":225,"s":[100]},{"t":235,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":106,"s":[264.692,119.514,0],"to":[0.052,-1.254,0],"ti":[-0.052,1.254,0]},{"t":127,"s":[265.005,111.991,0]}],"ix":2,"l":2},"a":{"a":0,"k":[73.442,-14.236,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":106,"s":[100,100,100]},{"t":127,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":42,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[41.627,-45.296],[41.504,-44.704],[-41.75,-44.704],[-41.627,-45.296]],"c":true}]},{"t":101,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[41.627,-45.296],[41.258,30.296],[-41.996,30.296],[-41.627,-45.296]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":106,"s":[4]},{"t":127,"s":[0]}],"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"fl","c":{"a":0,"k":[0.780392156863,0.776470588235,0.792156862745,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":[73.627,-6.704],"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":29,"op":400,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[264.817,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"3","tt":2,"tp":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[264.755,112.023,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":[[7.158,0],[0,0],[0,7.122],[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0]],"o":[[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0],[7.158,0],[0,0],[0,7.122]],"v":[[34.628,99.5],[-34.628,99.5],[-47.587,86.605],[-47.587,-86.605],[-34.628,-99.5],[34.628,-99.5],[47.587,-86.605],[47.587,86.605]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.780392156863,0.776470588235,0.792156862745,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"5","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":475,"st":59,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 9","tt":1,"tp":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.127,"y":1},"o":{"x":0.167,"y":0},"t":150,"s":[87.972,180.675,0],"to":[-5.083,0,0],"ti":[5.083,0,0]},{"t":190,"s":[57.472,180.675,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-73.528,-0.325,0],"ix":1,"l":2},"s":{"a":0,"k":[23,23,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[87.943,191.35],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.780392156863,0.776470588235,0.792156862745,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":[-73.528,-0.325],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":471,"st":59,"ct":1,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.127,"y":1},"o":{"x":0.333,"y":0},"t":50,"s":[116.972,112.175,0],"to":[-4.833,11.417,0],"ti":[4.833,-11.417,0]},{"t":91,"s":[87.972,180.675,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-73.528,-0.325,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.127,0.127,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":50,"s":[100,101.045,100]},{"t":91,"s":[23,23,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[87.943,191.35],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.127],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[8]},{"t":91,"s":[14]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.780392156863,0.776470588235,0.792156862745,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":[-73.528,-0.325],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":50,"op":150,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":19,"ty":3,"nm":"Null 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.316,"y":1},"o":{"x":0.615,"y":0},"t":22,"s":[117.5,90,0],"to":[0,7.333,0],"ti":[0,-7.333,0]},{"t":50,"s":[117.5,134,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19,19,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":414,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 6","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[121.053,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 5","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.316,-42.982,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 4","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-118.421,-0.877,0],"ix":2,"l":2},"a":{"a":0,"k":[-2,-12,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[507.053,507.053,100]},{"t":29,"s":[421.053,421.053,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"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.843137015548,0.098038998772,0.1294119891,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":[-2,-12],"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 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":50,"st":-20,"ct":1,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.026,0],[0,0],[0,4.954],[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0]],"o":[[0,0],[-5.026,0],[0,0],[0,-4.954],[0,0],[5.026,0],[0,0],[0,4.954]],"v":[[34.628,95.607],[-34.628,95.607],[-43.693,86.605],[-43.693,-86.605],[-34.628,-95.607],[34.628,-95.607],[43.693,-86.605],[43.693,86.605]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.188235297799,0.188235297799,0.20000000298,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"2","tt":2,"tp":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.005,112.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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.158,0],[0,0],[0,7.122],[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0]],"o":[[0,0],[-7.158,0],[0,0],[0,-7.122],[0,0],[7.158,0],[0,0],[0,7.122]],"v":[[34.628,99.5],[-34.628,99.5],[-47.587,86.605],[-47.587,-86.605],[-34.628,-99.5],[34.628,-99.5],[47.587,-86.605],[47.587,86.605]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.780392156863,0.776470588235,0.792156862745,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 (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":416,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}} diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index 7e4e926a..65bc71ea 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -973,7 +973,7 @@ - + @string/hardware_keys_action_nothing @string/hardware_keys_action_menu @string/hardware_keys_action_app_switch @@ -995,7 +995,7 @@ @string/hardware_keys_action_ringer_modes - + 0 1 2 diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 92e7c592..9faa01d3 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,14 @@ limitations under the License. --> + + Three finger swipe + Swipe down with three fingers to perform actions. + Three finger long press + Press and hold with three fingers and then swipe down to take an area screenshot. + Disable power button & volume down button + Disable the function of taking a screenshot by pressing and holding the power button and the volume down button. + Small landscape notifications Shows notifications smaller in width in notification panel in landscape mode just as AOSP intended diff --git a/res/xml/rising_settings_gestures.xml b/res/xml/rising_settings_gestures.xml index 98191cbd..eeaf1405 100644 --- a/res/xml/rising_settings_gestures.xml +++ b/res/xml/rising_settings_gestures.xml @@ -36,8 +36,8 @@ android:title="@string/shake_gestures_action_title" android:summary="%s" android:dialogTitle="@string/shake_gestures_action_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:defaultValue="0" app:isLineageSettings="true" android:dependency="shake_gestures_enabled" /> @@ -67,28 +67,13 @@ android:key="three_finger_gestures" android:title="@string/three_finger_gestures_title"> - - - - - + diff --git a/res/xml/rising_settings_navigation.xml b/res/xml/rising_settings_navigation.xml index dc996b29..554cb20f 100644 --- a/res/xml/rising_settings_navigation.xml +++ b/res/xml/rising_settings_navigation.xml @@ -42,8 +42,8 @@ android:key="key_back_long_press_action" android:dialogTitle="@string/navbar_back_long_press_title" android:title="@string/navbar_back_long_press_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:summary="%s" android:defaultValue="0" lineage:isLineageSettings="true" @@ -53,8 +53,8 @@ android:key="key_home_long_press_action" android:dialogTitle="@string/navbar_home_long_press_title" android:title="@string/navbar_home_long_press_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:summary="%s" android:defaultValue="0" lineage:isLineageSettings="true" /> @@ -63,8 +63,8 @@ android:key="key_home_double_tap_action" android:dialogTitle="@string/navbar_home_double_tap_title" android:title="@string/navbar_home_double_tap_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:summary="%s" android:defaultValue="0" lineage:isLineageSettings="true" /> @@ -73,8 +73,8 @@ android:key="key_app_switch_long_press_action" android:dialogTitle="@string/navbar_app_switch_long_press_title" android:title="@string/navbar_app_switch_long_press_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:summary="%s" android:defaultValue="0" lineage:isLineageSettings="true" /> @@ -83,8 +83,8 @@ android:key="key_edge_long_swipe_action" android:dialogTitle="@string/navbar_edge_long_swipe_title" android:title="@string/navbar_edge_long_swipe_title" - android:entries="@array/hardware_keys_action_entries" - android:entryValues="@array/hardware_keys_action_values" + android:entries="@array/gesture_actions_entries" + android:entryValues="@array/gesture_actions_values" android:summary="%s" android:defaultValue="0" lineage:isLineageSettings="true" diff --git a/res/xml/three_finger_swipe.xml b/res/xml/three_finger_swipe.xml new file mode 100644 index 00000000..c97dfdeb --- /dev/null +++ b/res/xml/three_finger_swipe.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + From 085b6fe18ba648ccc17c12c1af898cfd1b3ea721 Mon Sep 17 00:00:00 2001 From: Arman Altafi <84268732+Arman-ATI@users.noreply.github.com> Date: Sun, 14 Sep 2025 01:54:05 +0330 Subject: [PATCH 08/24] Drop ai assistant --- res/xml/rising_settings_extras.xml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/res/xml/rising_settings_extras.xml b/res/xml/rising_settings_extras.xml index 9eab6e5e..e6300fe5 100644 --- a/res/xml/rising_settings_extras.xml +++ b/res/xml/rising_settings_extras.xml @@ -20,20 +20,13 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:title="@string/extras_toolbox_title"> - - + app:position="top" /> Date: Fri, 19 Sep 2025 02:54:33 +0000 Subject: [PATCH 09/24] Rewrite Personalizations in Kotlin and optimize fragments --- res/values/custom_strings.xml | 6 + res/xml/rising_settings_peek_display.xml | 27 + res/xml/rising_settings_themes.xml | 8 + .../PersonalizationSettingsController.kt | 17 +- .../settings/PersonalizationsFragment.java | 88 --- .../settings/PersonalizationsFragment.kt | 77 +++ ...> TopLevelSettingsPreferenceController.kt} | 23 +- .../rising/settings/fragments/Assistant.java | 129 ----- .../rising/settings/fragments/Assistant.kt | 51 ++ src/com/rising/settings/fragments/Backup.java | 400 ------------- src/com/rising/settings/fragments/Backup.kt | 373 ++++++++++++ .../fragments/BootAnimationSettings.java | 214 ------- .../fragments/BootAnimationSettings.kt | 266 +++++++++ .../settings/fragments/BrightnessSlider.java | 212 ------- .../settings/fragments/BrightnessSlider.kt | 168 ++++++ src/com/rising/settings/fragments/Extras.java | 60 -- src/com/rising/settings/fragments/Extras.kt | 51 ++ .../rising/settings/fragments/Gestures.java | 63 -- src/com/rising/settings/fragments/Gestures.kt | 49 ++ .../settings/fragments/IslandSettings.java | 65 --- .../settings/fragments/IslandSettings.kt | 59 ++ .../rising/settings/fragments/LockScreen.java | 211 ------- .../rising/settings/fragments/LockScreen.kt | 361 ++++++++++++ .../settings/fragments/MonetSettings.java | 423 -------------- .../settings/fragments/MonetSettings.kt | 519 +++++++++++++++++ .../rising/settings/fragments/Navigation.java | 60 -- .../rising/settings/fragments/Navigation.kt | 56 ++ .../settings/fragments/Notifications.java | 78 --- .../settings/fragments/Notifications.kt | 71 +++ .../fragments/OngoingProgressBar.java | 44 -- .../settings/fragments/OngoingProgressBar.kt | 38 ++ .../fragments/OptimizedSettingsFragment.kt | 219 +++++++ .../settings/fragments/QuickSettings.java | 273 --------- .../settings/fragments/QuickSettings.kt | 330 +++++++++++ .../settings/fragments/QuickSwitch.java | 121 ---- .../rising/settings/fragments/QuickSwitch.kt | 109 ++++ .../rising/settings/fragments/Security.java | 95 --- src/com/rising/settings/fragments/Security.kt | 78 +++ .../settings/fragments/SmartPowerOff.java | 120 ---- .../settings/fragments/SmartPowerOff.kt | 51 ++ src/com/rising/settings/fragments/Sound.java | 59 -- src/com/rising/settings/fragments/Sound.kt | 51 ++ src/com/rising/settings/fragments/Spoof.java | 367 ------------ src/com/rising/settings/fragments/Spoof.kt | 334 +++++++++++ .../rising/settings/fragments/StatusBar.java | 77 --- .../rising/settings/fragments/StatusBar.kt | 82 +++ src/com/rising/settings/fragments/Themes.java | 205 ------- src/com/rising/settings/fragments/Themes.kt | 252 ++++++++ .../rising/settings/fragments/Toolbox.java | 59 -- src/com/rising/settings/fragments/Toolbox.kt | 51 ++ .../rising/settings/fragments/Wallpaper.java | 93 --- .../rising/settings/fragments/Wallpaper.kt | 84 +++ .../settings/fragments/WallpaperDepth.java | 124 ---- .../settings/fragments/WallpaperDepth.kt | 123 ++++ ...elogActivity.java => ChangelogActivity.kt} | 20 +- .../fragments/about/ChangelogFragment.java | 110 ---- .../fragments/about/ChangelogFragment.kt | 124 ++++ .../LockClockFontsPickerPreview.java | 546 ------------------ .../lockscreen/LockClockFontsPickerPreview.kt | 508 ++++++++++++++++ .../lockscreen/LockScreenWidgets.java | 247 -------- .../fragments/lockscreen/LockScreenWidgets.kt | 246 ++++++++ .../fragments/lockscreen/PeekDisplay.java | 59 -- .../fragments/lockscreen/PeekDisplay.kt | 383 ++++++++++++ .../fragments/lockscreen/UdfpsAnimation.java | 207 ------- .../fragments/lockscreen/UdfpsAnimation.kt | 280 +++++++++ .../fragments/lockscreen/UdfpsIconPicker.java | 218 ------- .../fragments/lockscreen/UdfpsIconPicker.kt | 202 +++++++ .../lockscreen/doze/AODSchedule.java | 183 ------ .../fragments/lockscreen/doze/AODSchedule.kt | 186 ++++++ .../lockscreen/doze/AODSettings.java | 96 --- .../fragments/lockscreen/doze/AODSettings.kt | 99 ++++ ...ightSettings.java => EdgeLightSettings.kt} | 24 +- .../popup/PopUpViewSettingsFragment.java | 82 --- .../popup/PopUpViewSettingsFragment.kt | 83 +++ .../quicksettings/QsHeaderImageSettings.java | 250 -------- .../quicksettings/QsHeaderImageSettings.kt | 234 ++++++++ .../quicksettings/QsTileLayoutSettings.java | 57 -- .../quicksettings/QsTileLayoutSettings.kt | 52 ++ .../fragments/sound/AdaptivePlayback.java | 79 --- .../fragments/sound/AdaptivePlayback.kt | 76 +++ .../fragments/sound/PulseSettings.java | 205 ------- .../settings/fragments/sound/PulseSettings.kt | 206 +++++++ .../{SoundEngine.java => SoundEngine.kt} | 29 +- .../settings/fragments/sound/VolumeSteps.java | 75 --- .../settings/fragments/sound/VolumeSteps.kt | 73 +++ .../fragments/statusbar/BatteryBar.java | 99 ---- .../fragments/statusbar/BatteryBar.kt | 90 +++ .../settings/fragments/statusbar/Clock.java | 212 ------- .../settings/fragments/statusbar/Clock.kt | 201 +++++++ .../statusbar/NetworkTrafficSettings.java | 43 -- .../statusbar/NetworkTrafficSettings.kt | 43 ++ .../statusbar/StatusbarLyricSettings.java | 50 -- .../statusbar/StatusbarLyricSettings.kt | 45 ++ .../settings/fragments/ui/IconShapes.java | 203 ------- .../settings/fragments/ui/IconShapes.kt | 179 ++++++ .../settings/fragments/ui/NavbarStyles.java | 228 -------- .../settings/fragments/ui/NavbarStyles.kt | 182 ++++++ .../settings/fragments/ui/Settings.java | 82 --- .../rising/settings/fragments/ui/Settings.kt | 75 +++ .../settings/fragments/ui/SignalIcons.java | 223 ------- .../settings/fragments/ui/SignalIcons.kt | 174 ++++++ .../settings/fragments/ui/SmartPixels.java | 57 -- .../settings/fragments/ui/SmartPixels.kt | 56 ++ .../settings/fragments/ui/StatusbarIcons.java | 248 -------- .../settings/fragments/ui/StatusbarIcons.kt | 202 +++++++ .../settings/fragments/ui/UIStyles.java | 236 -------- .../rising/settings/fragments/ui/UIStyles.kt | 229 ++++++++ .../settings/fragments/ui/WifiIcons.java | 223 ------- .../rising/settings/fragments/ui/WifiIcons.kt | 174 ++++++ .../fragments/ui/fonts/FontArrayAdapter.java | 88 --- .../fragments/ui/fonts/FontArrayAdapter.kt | 76 +++ .../fragments/ui/fonts/FontManager.java | 120 ---- .../fragments/ui/fonts/FontManager.kt | 124 ++++ .../fragments/ui/fonts/FontPickerPreview.java | 164 ------ .../fragments/ui/fonts/FontPickerPreview.kt | 156 +++++ .../settings/utils/BuildOptimizations.kt | 245 ++++++++ .../settings/utils/MemoryLeakDetector.kt | 239 ++++++++ .../settings/utils/PerformanceMonitor.kt | 236 ++++++++ .../rising/settings/utils/RuntimeOptimizer.kt | 309 ++++++++++ 119 files changed, 9790 insertions(+), 8384 deletions(-) delete mode 100644 src/com/rising/settings/PersonalizationsFragment.java create mode 100644 src/com/rising/settings/PersonalizationsFragment.kt rename src/com/rising/settings/{TopLevelSettingsPreferenceController.java => TopLevelSettingsPreferenceController.kt} (57%) delete mode 100644 src/com/rising/settings/fragments/Assistant.java create mode 100644 src/com/rising/settings/fragments/Assistant.kt delete mode 100644 src/com/rising/settings/fragments/Backup.java create mode 100644 src/com/rising/settings/fragments/Backup.kt delete mode 100644 src/com/rising/settings/fragments/BootAnimationSettings.java create mode 100644 src/com/rising/settings/fragments/BootAnimationSettings.kt delete mode 100644 src/com/rising/settings/fragments/BrightnessSlider.java create mode 100644 src/com/rising/settings/fragments/BrightnessSlider.kt delete mode 100644 src/com/rising/settings/fragments/Extras.java create mode 100644 src/com/rising/settings/fragments/Extras.kt delete mode 100644 src/com/rising/settings/fragments/Gestures.java create mode 100644 src/com/rising/settings/fragments/Gestures.kt delete mode 100644 src/com/rising/settings/fragments/IslandSettings.java create mode 100644 src/com/rising/settings/fragments/IslandSettings.kt delete mode 100644 src/com/rising/settings/fragments/LockScreen.java create mode 100644 src/com/rising/settings/fragments/LockScreen.kt delete mode 100644 src/com/rising/settings/fragments/MonetSettings.java create mode 100644 src/com/rising/settings/fragments/MonetSettings.kt delete mode 100644 src/com/rising/settings/fragments/Navigation.java create mode 100644 src/com/rising/settings/fragments/Navigation.kt delete mode 100644 src/com/rising/settings/fragments/Notifications.java create mode 100644 src/com/rising/settings/fragments/Notifications.kt delete mode 100644 src/com/rising/settings/fragments/OngoingProgressBar.java create mode 100644 src/com/rising/settings/fragments/OngoingProgressBar.kt create mode 100644 src/com/rising/settings/fragments/OptimizedSettingsFragment.kt delete mode 100644 src/com/rising/settings/fragments/QuickSettings.java create mode 100644 src/com/rising/settings/fragments/QuickSettings.kt delete mode 100644 src/com/rising/settings/fragments/QuickSwitch.java create mode 100644 src/com/rising/settings/fragments/QuickSwitch.kt delete mode 100644 src/com/rising/settings/fragments/Security.java create mode 100644 src/com/rising/settings/fragments/Security.kt delete mode 100644 src/com/rising/settings/fragments/SmartPowerOff.java create mode 100644 src/com/rising/settings/fragments/SmartPowerOff.kt delete mode 100644 src/com/rising/settings/fragments/Sound.java create mode 100644 src/com/rising/settings/fragments/Sound.kt delete mode 100644 src/com/rising/settings/fragments/Spoof.java create mode 100644 src/com/rising/settings/fragments/Spoof.kt delete mode 100644 src/com/rising/settings/fragments/StatusBar.java create mode 100644 src/com/rising/settings/fragments/StatusBar.kt delete mode 100644 src/com/rising/settings/fragments/Themes.java create mode 100644 src/com/rising/settings/fragments/Themes.kt delete mode 100644 src/com/rising/settings/fragments/Toolbox.java create mode 100644 src/com/rising/settings/fragments/Toolbox.kt delete mode 100644 src/com/rising/settings/fragments/Wallpaper.java create mode 100644 src/com/rising/settings/fragments/Wallpaper.kt delete mode 100644 src/com/rising/settings/fragments/WallpaperDepth.java create mode 100644 src/com/rising/settings/fragments/WallpaperDepth.kt rename src/com/rising/settings/fragments/about/{ChangelogActivity.java => ChangelogActivity.kt} (60%) delete mode 100644 src/com/rising/settings/fragments/about/ChangelogFragment.java create mode 100644 src/com/rising/settings/fragments/about/ChangelogFragment.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.java create mode 100644 src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.java create mode 100644 src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/PeekDisplay.java create mode 100644 src/com/rising/settings/fragments/lockscreen/PeekDisplay.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.java create mode 100644 src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.java create mode 100644 src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.java create mode 100644 src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.kt delete mode 100644 src/com/rising/settings/fragments/lockscreen/doze/AODSettings.java create mode 100644 src/com/rising/settings/fragments/lockscreen/doze/AODSettings.kt rename src/com/rising/settings/fragments/lockscreen/doze/{EdgeLightSettings.java => EdgeLightSettings.kt} (52%) delete mode 100644 src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.java create mode 100644 src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.kt delete mode 100644 src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.java create mode 100644 src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.kt delete mode 100644 src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.java create mode 100644 src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.kt delete mode 100644 src/com/rising/settings/fragments/sound/AdaptivePlayback.java create mode 100644 src/com/rising/settings/fragments/sound/AdaptivePlayback.kt delete mode 100644 src/com/rising/settings/fragments/sound/PulseSettings.java create mode 100644 src/com/rising/settings/fragments/sound/PulseSettings.kt rename src/com/rising/settings/fragments/sound/{SoundEngine.java => SoundEngine.kt} (50%) delete mode 100644 src/com/rising/settings/fragments/sound/VolumeSteps.java create mode 100644 src/com/rising/settings/fragments/sound/VolumeSteps.kt delete mode 100644 src/com/rising/settings/fragments/statusbar/BatteryBar.java create mode 100644 src/com/rising/settings/fragments/statusbar/BatteryBar.kt delete mode 100644 src/com/rising/settings/fragments/statusbar/Clock.java create mode 100644 src/com/rising/settings/fragments/statusbar/Clock.kt delete mode 100644 src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.java create mode 100644 src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.kt delete mode 100644 src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.java create mode 100644 src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.kt delete mode 100644 src/com/rising/settings/fragments/ui/IconShapes.java create mode 100644 src/com/rising/settings/fragments/ui/IconShapes.kt delete mode 100644 src/com/rising/settings/fragments/ui/NavbarStyles.java create mode 100644 src/com/rising/settings/fragments/ui/NavbarStyles.kt delete mode 100644 src/com/rising/settings/fragments/ui/Settings.java create mode 100644 src/com/rising/settings/fragments/ui/Settings.kt delete mode 100644 src/com/rising/settings/fragments/ui/SignalIcons.java create mode 100644 src/com/rising/settings/fragments/ui/SignalIcons.kt delete mode 100644 src/com/rising/settings/fragments/ui/SmartPixels.java create mode 100644 src/com/rising/settings/fragments/ui/SmartPixels.kt delete mode 100644 src/com/rising/settings/fragments/ui/StatusbarIcons.java create mode 100644 src/com/rising/settings/fragments/ui/StatusbarIcons.kt delete mode 100644 src/com/rising/settings/fragments/ui/UIStyles.java create mode 100644 src/com/rising/settings/fragments/ui/UIStyles.kt delete mode 100644 src/com/rising/settings/fragments/ui/WifiIcons.java create mode 100644 src/com/rising/settings/fragments/ui/WifiIcons.kt delete mode 100644 src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.java create mode 100644 src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.kt delete mode 100644 src/com/rising/settings/fragments/ui/fonts/FontManager.java create mode 100644 src/com/rising/settings/fragments/ui/fonts/FontManager.kt delete mode 100644 src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.java create mode 100644 src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.kt create mode 100644 src/com/rising/settings/utils/BuildOptimizations.kt create mode 100644 src/com/rising/settings/utils/MemoryLeakDetector.kt create mode 100644 src/com/rising/settings/utils/PerformanceMonitor.kt create mode 100644 src/com/rising/settings/utils/RuntimeOptimizer.kt diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 9faa01d3..7faed10a 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -348,6 +348,12 @@ Minimal lockscreen notification style Peek display location Peek display (bottom) top margin + Vertical offset + Adjust the vertical position of peek display notifications + Always visible + Keep peek display notifications visible until manually dismissed + Auto dismiss timeout + Time in seconds before peek display notifications automatically disappear Colours diff --git a/res/xml/rising_settings_peek_display.xml b/res/xml/rising_settings_peek_display.xml index eebd8c61..a0806627 100644 --- a/res/xml/rising_settings_peek_display.xml +++ b/res/xml/rising_settings_peek_display.xml @@ -44,7 +44,34 @@ android:entryValues="@array/peek_display_location_values" android:summary="%s" android:defaultValue="1" + android:dependency="peek_display_notifications" /> + + + + + + diff --git a/res/xml/rising_settings_themes.xml b/res/xml/rising_settings_themes.xml index 73cbffb2..9e37545e 100644 --- a/res/xml/rising_settings_themes.xml +++ b/res/xml/rising_settings_themes.xml @@ -105,6 +105,14 @@ android:summary="%s" android:defaultValue="0" /> + + + () + override fun displayPreference(screen: PreferenceScreen) { super.displayPreference(screen) screen.findPreference(KEY_PERSONALIZATIONS)?.let { personalizationPref -> @@ -51,9 +54,19 @@ class PersonalizationSettingsController(context: Context) : AbstractPreferenceCo R.id.clock_face to "com.android.settings.Settings\$PersonalizationsClockFacesActivity", R.id.whats_new to "com.rising.settings.fragments.about.ChangelogActivity" ) + personalizationsClickMap.forEach { (viewId, activityName) -> - preference.findViewById(viewId)?.setOnClickListener { - mContext.startActivity(createIntent(activityName)) + // Use cached findViewById to improve performance + val view = viewCache.getOrPut(viewId) { + preference.findViewById(viewId) + } + view?.setOnClickListener { + try { + mContext.startActivity(createIntent(activityName)) + } catch (e: Exception) { + // Graceful error handling for missing activities + android.util.Log.w("PersonalizationController", "Failed to start activity: $activityName", e) + } } } } diff --git a/src/com/rising/settings/PersonalizationsFragment.java b/src/com/rising/settings/PersonalizationsFragment.java deleted file mode 100644 index b552d97b..00000000 --- a/src/com/rising/settings/PersonalizationsFragment.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2023 the risingOS Android 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.rising.settings; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.search.SearchIndexable; - -import java.util.ArrayList; -import java.util.List; - -public class PersonalizationsFragment extends DashboardFragment { - - public static final String CATEGORY_KEY = "com.android.settings.category.ia.personalizations"; - - private static final String LOG_TAG = "Personalization"; - - @Override - protected int getPreferenceScreenResId() { - return R.xml.rising_dashboard; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public int getHelpResource() { - return R.string.help_uri_about; - } - - @Override - public void onStart() { - super.onStart(); - } - - @Override - protected String getLogTag() { - return LOG_TAG; - } - - @Override - protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context, this /* fragment */, getSettingsLifecycle()); - } - - private static List buildPreferenceControllers( - Context context, PersonalizationsFragment fragment, Lifecycle lifecycle) { - final List controllers = new ArrayList<>(); - controllers.add(new PersonalizationSettingsController(context)); - return controllers; - } - - /** - * For Search. - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_dashboard) { - @Override - public List createPreferenceControllers( - Context context) { - return buildPreferenceControllers(context, null /* fragment */, - null /* lifecycle */); - } - }; - } diff --git a/src/com/rising/settings/PersonalizationsFragment.kt b/src/com/rising/settings/PersonalizationsFragment.kt new file mode 100644 index 00000000..695be40b --- /dev/null +++ b/src/com/rising/settings/PersonalizationsFragment.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 the risingOS Android 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.rising.settings + +import android.content.Context +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.dashboard.DashboardFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.core.AbstractPreferenceController +import com.android.settingslib.core.lifecycle.Lifecycle + +class PersonalizationsFragment : DashboardFragment() { + + companion object { + const val CATEGORY_KEY = "com.android.settings.category.ia.personalizations" + private const val LOG_TAG = "Personalization" + + /** + * For Search. + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_dashboard) { + override fun createPreferenceControllers(context: Context): List { + return buildPreferenceControllers(context, null, null) + } + } + + private fun buildPreferenceControllers( + context: Context, + fragment: PersonalizationsFragment?, + lifecycle: Lifecycle? + ): List { + val controllers = ArrayList() + controllers.add(PersonalizationSettingsController(context)) + return controllers + } + } + + override fun getPreferenceScreenResId(): Int { + return R.xml.rising_dashboard + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun getHelpResource(): Int { + return R.string.help_uri_about + } + + override fun onStart() { + super.onStart() + } + + override fun getLogTag(): String { + return LOG_TAG + } + + override fun createPreferenceControllers(context: Context): List { + return buildPreferenceControllers(context, this, settingsLifecycle) + } +} diff --git a/src/com/rising/settings/TopLevelSettingsPreferenceController.java b/src/com/rising/settings/TopLevelSettingsPreferenceController.kt similarity index 57% rename from src/com/rising/settings/TopLevelSettingsPreferenceController.java rename to src/com/rising/settings/TopLevelSettingsPreferenceController.kt index 39530937..9458cd94 100644 --- a/src/com/rising/settings/TopLevelSettingsPreferenceController.java +++ b/src/com/rising/settings/TopLevelSettingsPreferenceController.kt @@ -14,22 +14,17 @@ * limitations under the License. */ -package com.rising.settings; +package com.rising.settings -import android.content.Context; +import android.content.Context +import com.android.settings.core.BasePreferenceController -import com.android.settings.R; -import com.android.settings.core.BasePreferenceController; +class TopLevelSettingsPreferenceController( + context: Context, + preferenceKey: String +) : BasePreferenceController(context, preferenceKey) { -public class TopLevelSettingsPreferenceController extends BasePreferenceController { - - public TopLevelSettingsPreferenceController(Context context, - String preferenceKey) { - super(context, preferenceKey); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; + override fun getAvailabilityStatus(): Int { + return AVAILABLE } } diff --git a/src/com/rising/settings/fragments/Assistant.java b/src/com/rising/settings/fragments/Assistant.java deleted file mode 100644 index 35b02cf8..00000000 --- a/src/com/rising/settings/fragments/Assistant.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.net.Uri; -import android.provider.Settings; -import android.text.InputType; -import android.text.TextUtils; -import android.widget.EditText; - -import androidx.appcompat.app.AlertDialog; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceClickListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Assistant extends SettingsPreferenceFragment { - - private static final String TAG = "Assistant"; - - private static final String KEY_AI_ASSISTANT_GEMINI_KEY = "ai_assistant_gemini_key"; - - private Preference mAiAssistantKeyPreference; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_ai_assistant); - mAiAssistantKeyPreference = findPreference(KEY_AI_ASSISTANT_GEMINI_KEY); - if (mAiAssistantKeyPreference != null) { - String currentKey = Settings.System.getString(getContext().getContentResolver(), KEY_AI_ASSISTANT_GEMINI_KEY); - mAiAssistantKeyPreference.setSummary(TextUtils.isEmpty(currentKey) ? getString(R.string.ai_assistant_gemini_key_summary) : currentKey); - mAiAssistantKeyPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - showApiKeyDialog(); - return true; - } - }); - } - - Preference mWikiLink = findPreference("wiki_link_assistant"); - if (mWikiLink != null) { - mWikiLink.setOnPreferenceClickListener(preference -> { - Uri uri = Uri.parse("https://github.com/RisingOS-Revived/risingOS_wiki/blob/fifteen/assistant/Risa/README.md"); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - startActivity(intent); - return true; - }); - } - } - - private void showApiKeyDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(R.string.ai_assistant_gemini_key_dialog_title); - - final EditText input = new EditText(getContext()); - input.setInputType(InputType.TYPE_CLASS_TEXT); - - String currentKey = Settings.System.getString(getContext().getContentResolver(), KEY_AI_ASSISTANT_GEMINI_KEY); - if (!TextUtils.isEmpty(currentKey)) { - input.setText(currentKey); - input.setSelection(currentKey.length()); - } - - builder.setView(input); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String newApiKey = input.getText().toString(); - if (!TextUtils.isEmpty(newApiKey)) { - Settings.System.putString(getContext().getContentResolver(), KEY_AI_ASSISTANT_GEMINI_KEY, newApiKey); - mAiAssistantKeyPreference.setSummary(newApiKey); - } - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - - builder.show(); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_ai_assistant) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Assistant.kt b/src/com/rising/settings/fragments/Assistant.kt new file mode 100644 index 00000000..6b8bb0db --- /dev/null +++ b/src/com/rising/settings/fragments/Assistant.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Assistant : OptimizedSettingsFragment() { + + companion object { + const val TAG = "Assistant" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_ai_assistant) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_ai_assistant) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Backup.java b/src/com/rising/settings/fragments/Backup.java deleted file mode 100644 index 8977461a..00000000 --- a/src/com/rising/settings/fragments/Backup.java +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.Context; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.SystemProperties; -import android.preference.PreferenceManager; -import android.provider.Settings; -import android.util.Log; -import android.widget.Toast; - -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; -import androidx.core.content.FileProvider; -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; -import com.android.settings.preferences.ui.AdaptiveListPreference; -import com.android.settings.preferences.CustomSeekBarPreference; -import com.android.settings.preferences.GlobalSettingSwitchPreference; -import com.android.settings.preferences.RisingSystemSettingListPreference; -import com.android.settings.preferences.SystemPropertyListPreference; -import com.android.settings.preferences.SecureSettingListPreference; -import com.android.settings.preferences.SecureSettingSwitchPreference; -import com.android.settings.preferences.SystemSettingListPreference; -import com.android.settings.preferences.SystemSettingSeekBarPreference; -import com.android.settings.preferences.SystemSettingSwitchPreference; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -@SearchIndexable -public class Backup extends SettingsPreferenceFragment { - - private static final String TAG = "Backup"; - private static final String BACKUP_PERSONALIZATION_SETTINGS = "backup_personalization_settings"; - private static final String RESTORE_PERSONALIZATION_SETTINGS = "restore_personalization_settings"; - private static final String UPLOAD_BACKUP_TO_DRIVE = "upload_backup_to_drive"; - private static final String DOWNLOAD_BACKUP_FROM_DRIVE = "download_backup_from_drive"; - - private ActivityResultLauncher backupLauncher; - private ActivityResultLauncher restoreLauncher; - private ActivityResultLauncher uploadLauncher; - private ActivityResultLauncher downloadLauncher; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_backup); - - final PreferenceScreen prefScreen = getPreferenceScreen(); - Context mContext = getActivity().getApplicationContext(); - - // Initialize ActivityResultLaunchers for file selection - backupLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { - if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { - Uri uri = result.getData().getData(); - if (uri != null) { - Log.d(TAG, "Backup URI: " + uri.toString()); - backupSettings(mContext, uri); - } else { - Log.e(TAG, "Backup URI is null"); - } - } else { - Log.e(TAG, "Backup activity result not OK or data is null"); - } - }); - - restoreLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { - if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { - Uri uri = result.getData().getData(); - if (uri != null) { - Log.d(TAG, "Restore URI: " + uri.toString()); - restoreSettings(mContext, uri); - } else { - Log.e(TAG, "Restore URI is null"); - } - } else { - Log.e(TAG, "Restore activity result not OK or data is null"); - } - }); - - // Initialize ActivityResultLaunchers for file selection - uploadLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { - if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { - Uri uri = result.getData().getData(); - if (uri != null) { - Log.d(TAG, "Selected file URI: " + uri.toString()); - uploadFileToDrive(mContext, uri); - } else { - Log.e(TAG, "Selected file URI is null"); - } - } else { - Log.e(TAG, "Upload activity result not OK or data is null"); - } - }); - - downloadLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { - if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { - Uri uri = result.getData().getData(); - if (uri != null) { - Log.d(TAG, "Download URI: " + uri.toString()); - restoreSettings(mContext, uri); - } else { - Log.e(TAG, "Download URI is null"); - } - } else { - Log.e(TAG, "Download activity result not OK or data is null"); - } - }); - - // Backup settings - Preference backupPref = findPreference(BACKUP_PERSONALIZATION_SETTINGS); - if (backupPref != null) { - backupPref.setOnPreferenceClickListener(preference -> { - Log.d(TAG, "Backup option clicked"); - chooseFileLocationForBackup(); - return true; - }); - } - - // Restore settings - Preference restorePref = findPreference(RESTORE_PERSONALIZATION_SETTINGS); - if (restorePref != null) { - restorePref.setOnPreferenceClickListener(preference -> { - Log.d(TAG, "Restore option clicked"); - chooseFileForRestore(); - return true; - }); - } - - // Upload backup to Google Drive - Preference uploadToDrivePref = findPreference(UPLOAD_BACKUP_TO_DRIVE); - uploadToDrivePref.setOnPreferenceClickListener(preference -> { - Log.d(TAG, "Upload to Drive option clicked"); - chooseFileForUpload(); - return true; - }); - - // Download backup from Google Drive - Preference downloadFromDrivePref = findPreference(DOWNLOAD_BACKUP_FROM_DRIVE); - downloadFromDrivePref.setOnPreferenceClickListener(preference -> { - Log.d(TAG, "Download from Drive option clicked"); - downloadBackupFromDrive(); - return true; - }); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - private void chooseFileLocationForBackup() { - Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); - intent.setType("application/json"); - intent.putExtra(Intent.EXTRA_TITLE, "personalization_settings_backup.json"); - Log.d(TAG, "Launching file picker for backup"); - backupLauncher.launch(intent); - } - - private void chooseFileForRestore() { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.setType("application/json"); - Log.d(TAG, "Launching file picker for restore"); - restoreLauncher.launch(intent); - } - - private void chooseFileForUpload() { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.setType("application/json"); - Log.d(TAG, "Launching file picker for upload"); - uploadLauncher.launch(intent); - } - - private void uploadFileToDrive(Context context, Uri fileUri) { - try { - context.getContentResolver().takePersistableUriPermission(fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - Intent uploadIntent = new Intent(Intent.ACTION_SEND); - uploadIntent.setType("application/json"); - uploadIntent.putExtra(Intent.EXTRA_STREAM, fileUri); - uploadIntent.setPackage("com.google.android.apps.docs"); - uploadIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK); - if (uploadIntent.resolveActivity(context.getPackageManager()) != null) { - context.startActivity(uploadIntent); - } else { - Toast.makeText(context, "Google Drive app not installed.", Toast.LENGTH_SHORT).show(); - } - } catch (Exception e) { - Log.e(TAG, "Failed to upload file to Google Drive: " + e.getMessage(), e); - Toast.makeText(context, "Failed to upload file to Google Drive.", Toast.LENGTH_SHORT).show(); - } - } - - private void downloadBackupFromDrive() { - Intent downloadIntent = new Intent(Intent.ACTION_GET_CONTENT); - downloadIntent.setType("application/json"); - downloadIntent.addCategory(Intent.CATEGORY_OPENABLE); - downloadIntent.setPackage("com.google.android.apps.docs"); - - if (downloadIntent.resolveActivity(getContext().getPackageManager()) != null) { - downloadLauncher.launch(downloadIntent); - } else { - Toast.makeText(getContext(), "Google Drive app not installed.", Toast.LENGTH_SHORT).show(); - } - } - - private void backupSettings(Context context, Uri uri) { - try { - JSONObject json = new JSONObject(); - - // Back up System settings - backupSettingsProvider(json, Settings.System.class, context.getContentResolver()); - - // Back up Secure settings - backupSettingsProvider(json, Settings.Secure.class, context.getContentResolver()); - - // Back up Global settings - backupSettingsProvider(json, Settings.Global.class, context.getContentResolver()); - - // Write the JSON object to the backup file - try (OutputStream outputStream = context.getContentResolver().openOutputStream(uri)) { - if (outputStream != null) { - outputStream.write(json.toString().getBytes(StandardCharsets.UTF_8)); - // Save the backup locally - File backupFile = new File(context.getCacheDir(), "personalization_settings_backup.json"); - try (OutputStream os = new FileOutputStream(backupFile)) { - os.write(json.toString().getBytes(StandardCharsets.UTF_8)); - } - Toast.makeText(getActivity(), "Personalization settings backed up successfully!", Toast.LENGTH_SHORT).show(); - } - } - } catch (IOException | JSONException e) { - e.printStackTrace(); - Toast.makeText(getActivity(), "Failed to backup settings", Toast.LENGTH_SHORT).show(); - } - } - - private void backupSettingsProvider(JSONObject json, Class settingsClass, ContentResolver resolver) throws JSONException { - try { - // Determine which Settings class we're working with - Uri uri; - String methodName; - - if (settingsClass == Settings.System.class) { - uri = Settings.System.CONTENT_URI; - methodName = "System"; - } else if (settingsClass == Settings.Secure.class) { - uri = Settings.Secure.CONTENT_URI; - methodName = "Secure"; - } else if (settingsClass == Settings.Global.class) { - uri = Settings.Global.CONTENT_URI; - methodName = "Global"; - } else { - return; // Unsupported settings type - } - - // Query all settings from this provider - Cursor cursor = resolver.query(uri, null, null, null, null); - if (cursor != null) { - // Create a JSON object for this settings type - JSONObject settingsJson = new JSONObject(); - - // Get column indices - int nameIndex = cursor.getColumnIndex("name"); - int valueIndex = cursor.getColumnIndex("value"); - - // Extract all settings - while (cursor.moveToNext()) { - String name = cursor.getString(nameIndex); - String value = cursor.getString(valueIndex); - - if (name != null && value != null) { - settingsJson.put(name, value); - } - } - - cursor.close(); - - // Add this settings type to the main JSON object - json.put(methodName, settingsJson); - } - } catch (Exception e) { - Log.e(TAG, "Error backing up " + settingsClass.getSimpleName() + " settings", e); - } - } - - private void restoreSettings(Context context, Uri uri) { - try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) { - if (inputStream != null) { - StringBuilder builder = new StringBuilder(); - int ch; - while ((ch = inputStream.read()) != -1) { - builder.append((char) ch); - } - - JSONObject json = new JSONObject(builder.toString()); - ContentResolver resolver = context.getContentResolver(); - - // Restore System settings - if (json.has("System")) { - restoreSettingsProvider(json.getJSONObject("System"), Settings.System.class, resolver); - } - - // Restore Secure settings - if (json.has("Secure")) { - restoreSettingsProvider(json.getJSONObject("Secure"), Settings.Secure.class, resolver); - } - - // Restore Global settings - if (json.has("Global")) { - restoreSettingsProvider(json.getJSONObject("Global"), Settings.Global.class, resolver); - } - - // Force refresh settings - context.getContentResolver().notifyChange(Settings.System.CONTENT_URI, null); - context.getContentResolver().notifyChange(Settings.Secure.CONTENT_URI, null); - context.getContentResolver().notifyChange(Settings.Global.CONTENT_URI, null); - - Toast.makeText(getActivity(), "Personalization settings restored successfully!", Toast.LENGTH_SHORT).show(); - } - } catch (IOException | JSONException e) { - e.printStackTrace(); - Toast.makeText(getActivity(), "Failed to restore settings", Toast.LENGTH_SHORT).show(); - } - } - - private void restoreSettingsProvider(JSONObject settingsJson, Class settingsClass, ContentResolver resolver) throws JSONException { - try { - Iterator keys = settingsJson.keys(); - - while (keys.hasNext()) { - String key = keys.next(); - String value = settingsJson.getString(key); - - if (settingsClass == Settings.System.class) { - Settings.System.putString(resolver, key, value); - } else if (settingsClass == Settings.Secure.class) { - Settings.Secure.putString(resolver, key, value); - } else if (settingsClass == Settings.Global.class) { - Settings.Global.putString(resolver, key, value); - } - } - } catch (Exception e) { - Log.e(TAG, "Error restoring " + settingsClass.getSimpleName() + " settings", e); - } - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_backup) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Backup.kt b/src/com/rising/settings/fragments/Backup.kt new file mode 100644 index 00000000..eb324b5e --- /dev/null +++ b/src/com/rising/settings/fragments/Backup.kt @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.app.Activity +import android.content.Context +import android.content.ContentResolver +import android.content.Intent +import android.database.Cursor +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.util.Log +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable +import org.json.JSONException +import org.json.JSONObject +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.nio.charset.StandardCharsets + +@SearchIndexable +class Backup : SettingsPreferenceFragment() { + + companion object { + private const val TAG = "Backup" + private const val BACKUP_PERSONALIZATION_SETTINGS = "backup_personalization_settings" + private const val RESTORE_PERSONALIZATION_SETTINGS = "restore_personalization_settings" + private const val UPLOAD_BACKUP_TO_DRIVE = "upload_backup_to_drive" + private const val DOWNLOAD_BACKUP_FROM_DRIVE = "download_backup_from_drive" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_backup) { + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } + + private lateinit var backupLauncher: ActivityResultLauncher + private lateinit var restoreLauncher: ActivityResultLauncher + private lateinit var uploadLauncher: ActivityResultLauncher + private lateinit var downloadLauncher: ActivityResultLauncher + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_backup) + + val prefScreen: PreferenceScreen = preferenceScreen + val mContext: Context = requireActivity().applicationContext + + // Initialize ActivityResultLaunchers for file selection + backupLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val uri = result.data?.data + if (uri != null) { + Log.d(TAG, "Backup URI: $uri") + backupSettings(mContext, uri) + } else { + Log.e(TAG, "Backup URI is null") + } + } else { + Log.e(TAG, "Backup activity result not OK or data is null") + } + } + + restoreLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val uri = result.data?.data + if (uri != null) { + Log.d(TAG, "Restore URI: $uri") + restoreSettings(mContext, uri) + } else { + Log.e(TAG, "Restore URI is null") + } + } else { + Log.e(TAG, "Restore activity result not OK or data is null") + } + } + + // Initialize ActivityResultLaunchers for file selection + uploadLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val uri = result.data?.data + if (uri != null) { + Log.d(TAG, "Selected file URI: $uri") + uploadFileToDrive(mContext, uri) + } else { + Log.e(TAG, "Selected file URI is null") + } + } else { + Log.e(TAG, "Upload activity result not OK or data is null") + } + } + + downloadLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val uri = result.data?.data + if (uri != null) { + Log.d(TAG, "Download URI: $uri") + restoreSettings(mContext, uri) + } else { + Log.e(TAG, "Download URI is null") + } + } else { + Log.e(TAG, "Download activity result not OK or data is null") + } + } + + // Backup settings + val backupPref: Preference? = findPreference(BACKUP_PERSONALIZATION_SETTINGS) + backupPref?.setOnPreferenceClickListener { + Log.d(TAG, "Backup option clicked") + chooseFileLocationForBackup() + true + } + + // Restore settings + val restorePref: Preference? = findPreference(RESTORE_PERSONALIZATION_SETTINGS) + restorePref?.setOnPreferenceClickListener { + Log.d(TAG, "Restore option clicked") + chooseFileForRestore() + true + } + + // Upload backup to Google Drive + val uploadToDrivePref: Preference? = findPreference(UPLOAD_BACKUP_TO_DRIVE) + uploadToDrivePref?.setOnPreferenceClickListener { + Log.d(TAG, "Upload to Drive option clicked") + chooseFileForUpload() + true + } + + // Download backup from Google Drive + val downloadFromDrivePref: Preference? = findPreference(DOWNLOAD_BACKUP_FROM_DRIVE) + downloadFromDrivePref?.setOnPreferenceClickListener { + Log.d(TAG, "Download from Drive option clicked") + downloadBackupFromDrive() + true + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + private fun chooseFileLocationForBackup() { + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + type = "application/json" + putExtra(Intent.EXTRA_TITLE, "personalization_settings_backup.json") + } + Log.d(TAG, "Launching file picker for backup") + backupLauncher.launch(intent) + } + + private fun chooseFileForRestore() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "application/json" + } + Log.d(TAG, "Launching file picker for restore") + restoreLauncher.launch(intent) + } + + private fun chooseFileForUpload() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "application/json" + } + Log.d(TAG, "Launching file picker for upload") + uploadLauncher.launch(intent) + } + + private fun uploadFileToDrive(context: Context, fileUri: Uri) { + try { + context.contentResolver.takePersistableUriPermission( + fileUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + val uploadIntent = Intent(Intent.ACTION_SEND).apply { + type = "application/json" + putExtra(Intent.EXTRA_STREAM, fileUri) + setPackage("com.google.android.apps.docs") + addFlags( + Intent.FLAG_GRANT_READ_URI_PERMISSION or + Intent.FLAG_GRANT_WRITE_URI_PERMISSION or + Intent.FLAG_ACTIVITY_NEW_TASK + ) + } + if (uploadIntent.resolveActivity(context.packageManager) != null) { + context.startActivity(uploadIntent) + } else { + Toast.makeText(context, "Google Drive app not installed.", Toast.LENGTH_SHORT).show() + } + } catch (e: Exception) { + Log.e(TAG, "Failed to upload file to Google Drive: ${e.message}", e) + Toast.makeText(context, "Failed to upload file to Google Drive.", Toast.LENGTH_SHORT).show() + } + } + + private fun downloadBackupFromDrive() { + val downloadIntent = Intent(Intent.ACTION_GET_CONTENT).apply { + type = "application/json" + addCategory(Intent.CATEGORY_OPENABLE) + setPackage("com.google.android.apps.docs") + } + + if (downloadIntent.resolveActivity(requireContext().packageManager) != null) { + downloadLauncher.launch(downloadIntent) + } else { + Toast.makeText(requireContext(), "Google Drive app not installed.", Toast.LENGTH_SHORT).show() + } + } + + private fun backupSettings(context: Context, uri: Uri) { + try { + val json = JSONObject() + + // Back up System settings + backupSettingsProvider(json, Settings.System::class.java, context.contentResolver) + + // Back up Secure settings + backupSettingsProvider(json, Settings.Secure::class.java, context.contentResolver) + + // Back up Global settings + backupSettingsProvider(json, Settings.Global::class.java, context.contentResolver) + + // Write the JSON object to the backup file + context.contentResolver.openOutputStream(uri)?.use { outputStream -> + outputStream.write(json.toString().toByteArray(StandardCharsets.UTF_8)) + + // Save the backup locally + val backupFile = File(context.cacheDir, "personalization_settings_backup.json") + FileOutputStream(backupFile).use { os -> + os.write(json.toString().toByteArray(StandardCharsets.UTF_8)) + } + Toast.makeText(requireActivity(), "Personalization settings backed up successfully!", Toast.LENGTH_SHORT).show() + } + } catch (e: IOException) { + e.printStackTrace() + Toast.makeText(requireActivity(), "Failed to backup settings", Toast.LENGTH_SHORT).show() + } catch (e: JSONException) { + e.printStackTrace() + Toast.makeText(requireActivity(), "Failed to backup settings", Toast.LENGTH_SHORT).show() + } + } + + @Throws(JSONException::class) + private fun backupSettingsProvider(json: JSONObject, settingsClass: Class<*>, resolver: ContentResolver) { + try { + // Determine which Settings class we're working with + val (uri, methodName) = when (settingsClass) { + Settings.System::class.java -> Settings.System.CONTENT_URI to "System" + Settings.Secure::class.java -> Settings.Secure.CONTENT_URI to "Secure" + Settings.Global::class.java -> Settings.Global.CONTENT_URI to "Global" + else -> return // Unsupported settings type + } + + // Query all settings from this provider + resolver.query(uri, null, null, null, null)?.use { cursor -> + // Create a JSON object for this settings type + val settingsJson = JSONObject() + + // Get column indices + val nameIndex = cursor.getColumnIndex("name") + val valueIndex = cursor.getColumnIndex("value") + + // Extract all settings + while (cursor.moveToNext()) { + val name = cursor.getString(nameIndex) + val value = cursor.getString(valueIndex) + + if (name != null && value != null) { + settingsJson.put(name, value) + } + } + + // Add this settings type to the main JSON object + json.put(methodName, settingsJson) + } + } catch (e: Exception) { + Log.e(TAG, "Error backing up ${settingsClass.simpleName} settings", e) + } + } + + private fun restoreSettings(context: Context, uri: Uri) { + try { + context.contentResolver.openInputStream(uri)?.use { inputStream -> + val builder = StringBuilder() + var ch: Int + while (inputStream.read().also { ch = it } != -1) { + builder.append(ch.toChar()) + } + + val json = JSONObject(builder.toString()) + val resolver = context.contentResolver + + // Restore System settings + if (json.has("System")) { + restoreSettingsProvider(json.getJSONObject("System"), Settings.System::class.java, resolver) + } + + // Restore Secure settings + if (json.has("Secure")) { + restoreSettingsProvider(json.getJSONObject("Secure"), Settings.Secure::class.java, resolver) + } + + // Restore Global settings + if (json.has("Global")) { + restoreSettingsProvider(json.getJSONObject("Global"), Settings.Global::class.java, resolver) + } + + // Force refresh settings + context.contentResolver.notifyChange(Settings.System.CONTENT_URI, null) + context.contentResolver.notifyChange(Settings.Secure.CONTENT_URI, null) + context.contentResolver.notifyChange(Settings.Global.CONTENT_URI, null) + + Toast.makeText(requireActivity(), "Personalization settings restored successfully!", Toast.LENGTH_SHORT).show() + } + } catch (e: IOException) { + e.printStackTrace() + Toast.makeText(requireActivity(), "Failed to restore settings", Toast.LENGTH_SHORT).show() + } catch (e: JSONException) { + e.printStackTrace() + Toast.makeText(requireActivity(), "Failed to restore settings", Toast.LENGTH_SHORT).show() + } + } + + @Throws(JSONException::class) + private fun restoreSettingsProvider(settingsJson: JSONObject, settingsClass: Class<*>, resolver: ContentResolver) { + try { + val keys = settingsJson.keys() + + while (keys.hasNext()) { + val key = keys.next() + val value = settingsJson.getString(key) + + when (settingsClass) { + Settings.System::class.java -> Settings.System.putString(resolver, key, value) + Settings.Secure::class.java -> Settings.Secure.putString(resolver, key, value) + Settings.Global::class.java -> Settings.Global.putString(resolver, key, value) + } + } + } catch (e: Exception) { + Log.e(TAG, "Error restoring ${settingsClass.simpleName} settings", e) + } + } +} diff --git a/src/com/rising/settings/fragments/BootAnimationSettings.java b/src/com/rising/settings/fragments/BootAnimationSettings.java deleted file mode 100644 index d5e1a5b5..00000000 --- a/src/com/rising/settings/fragments/BootAnimationSettings.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2024 risingOS - * - * 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.os.SystemProperties; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.util.Log; -import android.widget.ImageView; -import android.widget.Toast; - -import androidx.documentfile.provider.DocumentFile; -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settingslib.search.SearchIndexable; -import com.android.settings.preferences.BootAnimationPreviewPreference; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -@SearchIndexable -public class BootAnimationSettings extends SettingsPreferenceFragment implements OnPreferenceChangeListener { - - private static final String BOOTANIMATION_STYLE_KEY = "persist.sys.bootanimation_style"; - private static final String TAG = "BootAnimationSettings"; - private static final int REQUEST_CODE_PICK_ZIP = 1001; - private static final String CUSTOM_BOOTANIMATION_FILE = "/data/misc/bootanim/bootanimation.zip"; - - private static final String[] PRODUCT_BOOT_ANIMATION_FILES = { - "/product/media/bootanimation_rising.zip", - "/product/media/bootanimation_cyberpunk.zip", - "/product/media/bootanimation_google.zip", - "/product/media/bootanimation_google_monet.zip", - "/product/media/bootanimation_valorant.zip" - }; - - private ListPreference mBootAnimationStyle; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_bootanimation); - - mBootAnimationStyle = (ListPreference) findPreference(BOOTANIMATION_STYLE_KEY); - if (mBootAnimationStyle != null) { - mBootAnimationStyle.setOnPreferenceChangeListener(this); - - // Set the current value from the system property - int currentStyle = SystemProperties.getInt(BOOTANIMATION_STYLE_KEY, 0); - mBootAnimationStyle.setValue(String.valueOf(currentStyle)); - updateBootAnimationPreview(); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mBootAnimationStyle) { - int style = Integer.parseInt((String) newValue); - if (style == 5) { // Custom option selected - launchFilePicker(); - return false; // Return false to prevent immediate property update - } else { - copyProductFile(style); - return true; - } - } - return false; - } - - private void launchFilePicker() { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("application/zip"); - startActivityForResult(intent, REQUEST_CODE_PICK_ZIP); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_CODE_PICK_ZIP && resultCode == Activity.RESULT_OK && data != null) { - Uri uri = data.getData(); - if (uri != null) { - handleSelectedFile(uri); - } - } - } - - private void handleSelectedFile(Uri uri) { - try { - // Copy the selected file to the custom bootanimation location - InputStream inputStream = getContext().getContentResolver().openInputStream(uri); - File customBootAnimation = new File(CUSTOM_BOOTANIMATION_FILE); - // Ensure the directory exists - customBootAnimation.getParentFile().mkdirs(); - try (OutputStream outputStream = new FileOutputStream(customBootAnimation)) { - byte[] buffer = new byte[1024]; - int length; - while ((length = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - } - inputStream.close(); - // Update system property to use custom bootanimation - SystemProperties.set(BOOTANIMATION_STYLE_KEY, "5"); // Custom option value - updateBootAnimationPreview(); - // Force the preference to update to the custom option - mBootAnimationStyle.setValue("5"); // Set to the custom option - Toast.makeText(getContext(), R.string.boot_animation_applied, Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - Log.e(TAG, "Error copying custom bootanimation", e); - } - } - - private void copyProductFile(int style) { - try { - if (style < 0 || style >= PRODUCT_BOOT_ANIMATION_FILES.length) { - Log.e(TAG, "Invalid style index"); - return; - } - String productFilePath = PRODUCT_BOOT_ANIMATION_FILES[style]; - File productFile = new File(productFilePath); - if (!productFile.exists()) { - Log.e(TAG, "Product file does not exist: " + productFilePath); - return; - } - InputStream inputStream = new FileInputStream(productFile); - File customBootAnimation = new File(CUSTOM_BOOTANIMATION_FILE); - customBootAnimation.getParentFile().mkdirs(); - try (OutputStream outputStream = new FileOutputStream(customBootAnimation)) { - byte[] buffer = new byte[1024]; - int length; - while ((length = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - } - inputStream.close(); - SystemProperties.set(BOOTANIMATION_STYLE_KEY, String.valueOf(style)); - updateBootAnimationPreview(); - mBootAnimationStyle.setValue(String.valueOf(style)); - Toast.makeText(getContext(), R.string.boot_animation_applied, Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - Log.e(TAG, "Error copying product bootanimation", e); - } - } - - private void updateBootAnimationPreview() { - BootAnimationPreviewPreference previewPreference = (BootAnimationPreviewPreference) findPreference("bootanimation_preview"); - if (previewPreference != null) { - previewPreference.loadBootAnimationPreview(); - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - ArrayList result = - new ArrayList<>(); - - SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.rising_settings_bootanimation; - result.add(sir); - return result; - } - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/BootAnimationSettings.kt b/src/com/rising/settings/fragments/BootAnimationSettings.kt new file mode 100644 index 00000000..dd64d35b --- /dev/null +++ b/src/com/rising/settings/fragments/BootAnimationSettings.kt @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2024 risingOS + * + * 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.rising.settings.fragments + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.os.Environment +import android.os.SystemProperties +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.util.Log +import android.widget.ImageView +import android.widget.Toast + +import androidx.documentfile.provider.DocumentFile +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.PreferenceScreen + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.Indexable +import com.android.settingslib.search.SearchIndexable +import com.android.settings.preferences.BootAnimationPreviewPreference + +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream +import java.util.ArrayList +import java.util.concurrent.Future +import java.lang.ref.WeakReference +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.ConcurrentHashMap + +@SearchIndexable +class BootAnimationSettings : SettingsPreferenceFragment(), OnPreferenceChangeListener { + + private var mBootAnimationStyle: ListPreference? = null + + // Background executor for file operations + private var mFileExecutor: ExecutorService? = null + + // Cache for file existence checks + private val mFileExistenceCache: MutableMap = ConcurrentHashMap() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_bootanimation) + + // Initialize background executor + mFileExecutor = Executors.newSingleThreadExecutor() + + mBootAnimationStyle = findPreference(BOOTANIMATION_STYLE_KEY)?.apply { + setOnPreferenceChangeListener(this@BootAnimationSettings) + + // Set the current value from the system property + val currentStyle = SystemProperties.getInt(BOOTANIMATION_STYLE_KEY, 0) + value = currentStyle.toString() + updateBootAnimationPreview() + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + if (preference == mBootAnimationStyle) { + val style = (newValue as String).toInt() + if (style == 5) { // Custom option selected + launchFilePicker() + return false // Return false to prevent immediate property update + } else { + copyProductFile(style) + return true + } + } + return false + } + + private fun launchFilePicker() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "application/zip" + } + startActivityForResult(intent, REQUEST_CODE_PICK_ZIP) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == REQUEST_CODE_PICK_ZIP && resultCode == Activity.RESULT_OK && data != null) { + val uri = data.data + if (uri != null) { + handleSelectedFile(uri) + } + } + } + + private fun handleSelectedFile(uri: Uri) { + // Perform file operations in background to avoid blocking UI + performCopyOperation(uri, 5, true) + } + + private fun copyProductFile(style: Int) { + // Validate input + if (style < 0 || style >= PRODUCT_BOOT_ANIMATION_FILES.size) { + Log.e(TAG, "Invalid style index") + return + } + + val productFilePath = PRODUCT_BOOT_ANIMATION_FILES[style] + + // Check cache first + var fileExists = mFileExistenceCache[productFilePath] + if (fileExists == null) { + fileExists = File(productFilePath).exists() + mFileExistenceCache[productFilePath] = fileExists + } + + if (!fileExists) { + Log.e(TAG, "Product file does not exist: $productFilePath") + return + } + + // Perform file operations in background + performCopyOperation(productFilePath, style, false) + } + + private fun updateBootAnimationPreview() { + val previewPreference = findPreference("bootanimation_preview") + previewPreference?.loadBootAnimationPreview() + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + /** + * Modern ExecutorService-based file copy operation replacing deprecated AsyncTask + */ + private fun performCopyOperation(source: Any, style: Int, isCustomFile: Boolean) { + mFileExecutor?.execute { + val success = performFileCopy(source) + + // Update UI on main thread + activity?.runOnUiThread { + if (!isAdded) return@runOnUiThread + + if (success) { + SystemProperties.set(BOOTANIMATION_STYLE_KEY, style.toString()) + updateBootAnimationPreview() + mBootAnimationStyle?.value = style.toString() + Toast.makeText(context, R.string.boot_animation_applied, Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(context, "Failed to apply boot animation", Toast.LENGTH_LONG).show() + } + } + } + } + + /** + * Perform the actual file copy operation in background thread + */ + private fun performFileCopy(source: Any): Boolean { + return try { + val inputStream: InputStream? = when (source) { + is Uri -> context?.contentResolver?.openInputStream(source) + is String -> FileInputStream(File(source)) + else -> null + } + + if (inputStream == null) { + Log.e(TAG, "Failed to open input stream") + return false + } + + val customBootAnimation = File(CUSTOM_BOOTANIMATION_FILE) + customBootAnimation.parentFile?.mkdirs() + + FileOutputStream(customBootAnimation).use { outputStream -> + val buffer = ByteArray(8192) // Larger buffer for better performance + var length: Int + while (inputStream.read(buffer).also { length = it } > 0) { + outputStream.write(buffer, 0, length) + } + outputStream.flush() + } + inputStream.close() + + true + } catch (e: Exception) { + Log.e(TAG, "Error copying bootanimation: ${e.message}", e) + false + } + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup executor and cache + mFileExecutor?.let { executor -> + if (!executor.isShutdown) { + executor.shutdown() + } + } + mFileExistenceCache.clear() + } + + override fun onDetach() { + super.onDetach() + // Additional cleanup + mFileExistenceCache.clear() + } + + companion object { + private const val BOOTANIMATION_STYLE_KEY = "persist.sys.bootanimation_style" + private const val TAG = "BootAnimationSettings" + private const val REQUEST_CODE_PICK_ZIP = 1001 + private const val CUSTOM_BOOTANIMATION_FILE = "/data/misc/bootanim/bootanimation.zip" + + private val PRODUCT_BOOT_ANIMATION_FILES = arrayOf( + "/product/media/bootanimation_rising.zip", + "/product/media/bootanimation_cyberpunk.zip", + "/product/media/bootanimation_google.zip", + "/product/media/bootanimation_google_monet.zip", + "/product/media/bootanimation_valorant.zip" + ) + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider() { + override fun getXmlResourcesToIndex(context: Context, enabled: Boolean): List { + val result = ArrayList() + val sir = SearchIndexableResource(context).apply { + xmlResId = R.xml.rising_settings_bootanimation + } + result.add(sir) + return result + } + + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } +} diff --git a/src/com/rising/settings/fragments/BrightnessSlider.java b/src/com/rising/settings/fragments/BrightnessSlider.java deleted file mode 100644 index e2ed429a..00000000 --- a/src/com/rising/settings/fragments/BrightnessSlider.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2021 AospExtended ROM 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.rising.settings.fragments; - - import android.content.ContentResolver; - import android.content.Context; - import android.content.res.Resources; - import android.content.pm.PackageManager; - import android.graphics.drawable.AnimationDrawable; - import android.graphics.drawable.Drawable; - import android.os.Bundle; - import android.os.UserHandle; - import android.provider.SearchIndexableResource; - import android.provider.Settings; - import android.view.LayoutInflater; - import android.view.View; - import android.view.Gravity; - import android.view.ViewGroup; - import android.widget.ImageView; - import android.widget.LinearLayout; - import android.widget.FrameLayout; - import android.widget.TextView; - import android.text.TextUtils; - import androidx.preference.PreferenceViewHolder; - import android.view.ViewGroup.LayoutParams; - - import androidx.annotation.NonNull; - import androidx.annotation.Nullable; - import androidx.recyclerview.widget.GridLayoutManager; - import androidx.recyclerview.widget.RecyclerView.ViewHolder; - import androidx.recyclerview.widget.RecyclerView; - import androidx.preference.Preference; - import androidx.preference.Preference.OnPreferenceChangeListener; - import androidx.preference.PreferenceScreen; - - import com.android.internal.logging.nano.MetricsProto.MetricsEvent; - import com.android.settings.R; - import com.android.settings.search.BaseSearchIndexProvider; - import com.android.settingslib.search.Indexable; - import com.android.settings.SettingsPreferenceFragment; - - import com.bumptech.glide.Glide; - - import com.android.internal.util.android.ThemeUtils; - - import java.util.ArrayList; - import java.util.HashMap; - import java.util.List; - import java.util.Map; - import java.util.Arrays; - - import org.json.JSONObject; - import org.json.JSONException; - - public class BrightnessSlider extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.brightness_slider"; - - private List mPkgs; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_brightness_slider_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "com.android.systemui"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 1); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.brightness_slider_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String navPkg = mPkgs.get(position); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory, "com.android.systemui").stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("com.android.systemui"); - - holder.name.setText("com.android.systemui".equals(navPkg) ? "Default" : getLabel(holder.name.getContext(), navPkg)); - - holder.name.setTextSize(24); - - if (currentPackageName.equals(navPkg)) { - mAppliedPkg = navPkg; - if (mSelectedPkg == null) { - mSelectedPkg = navPkg; - } - } - - holder.itemView.setActivated(navPkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(navPkg, true); - mSelectedPkg = navPkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pm.getResourcesForApplication(pkg); - int resId = res.getIdentifier(drawableName, "drawable", pkg); - return res.getDrawable(resId); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "com.android.systemui"); - } - } diff --git a/src/com/rising/settings/fragments/BrightnessSlider.kt b/src/com/rising/settings/fragments/BrightnessSlider.kt new file mode 100644 index 00000000..f04723f5 --- /dev/null +++ b/src/com/rising/settings/fragments/BrightnessSlider.kt @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 AospExtended ROM 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.rising.settings.fragments + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.internal.util.android.ThemeUtils +import com.android.settings.R + +class BrightnessSlider : OptimizedSettingsFragment() { + + private var mRecyclerView: RecyclerView? = null + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.brightness_slider" + + private var mPkgs: List? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_brightness_slider_title) + + val context = getSafeContext() + if (context != null) { + mThemeUtils = ThemeUtils.getInstance(context) + } + mThemeUtils?.let { themeUtils -> + mPkgs = themeUtils.getOverlayPackagesForCategory(mCategory, "com.android.systemui") + } + } + + override fun onCreateView(@NonNull inflater: LayoutInflater, @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle?): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 1) + mRecyclerView?.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity) + mRecyclerView?.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(private val context: Context?) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.brightness_slider_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val pkgs = mPkgs ?: return + val navPkg = pkgs[position] + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory, "com.android.systemui") + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "com.android.systemui" + + holder.name.text = if ("com.android.systemui" == navPkg) "Default" else getLabel(holder.name.context, navPkg) + holder.name.textSize = 24f + + if (currentPackageName == navPkg) { + mAppliedPkg = navPkg + if (mSelectedPkg == null) { + mSelectedPkg = navPkg + } + } + + holder.itemView.isActivated = navPkg == mSelectedPkg + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(navPkg, true) + mSelectedPkg = navPkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs?.size ?: 0 + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView = itemView.findViewById(R.id.option_label) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val pkgs = mPkgs ?: return + val index = pkgs.indexOf(pkg) + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context, pkg: String, drawableName: String): Drawable? { + return try { + val pm = context.packageManager + val res = pm.getResourcesForApplication(pkg) + val resId = res.getIdentifier(drawableName, "drawable", pkg) + res.getDrawable(resId) + } catch (e: PackageManager.NameNotFoundException) { + // Handle silently - package not found + null + } + } + + private fun getLabel(context: Context, pkg: String): String { + val pm = context.packageManager + return try { + pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString() + } catch (e: PackageManager.NameNotFoundException) { + // Handle silently - package not found + pkg + } + } + + private fun enableOverlays(position: Int) { + val pkgs = mPkgs + if (mThemeUtils != null && pkgs != null && position < pkgs.size) { + mThemeUtils?.setOverlayEnabled(mCategory, pkgs[position], "com.android.systemui") + } + } + + override fun onDestroy() { + super.onDestroy() + mThemeUtils = null + mPkgs = null + } +} diff --git a/src/com/rising/settings/fragments/Extras.java b/src/com/rising/settings/fragments/Extras.java deleted file mode 100644 index 2e673db8..00000000 --- a/src/com/rising/settings/fragments/Extras.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Extras extends SettingsPreferenceFragment { - - private static final String TAG = "Extras"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_extras); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_extras) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Extras.kt b/src/com/rising/settings/fragments/Extras.kt new file mode 100644 index 00000000..48176eab --- /dev/null +++ b/src/com/rising/settings/fragments/Extras.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Extras : OptimizedSettingsFragment() { + + companion object { + const val TAG = "Extras" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_extras) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_extras) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Gestures.java b/src/com/rising/settings/fragments/Gestures.java deleted file mode 100644 index f0232051..00000000 --- a/src/com/rising/settings/fragments/Gestures.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.Context; -import android.content.ContentResolver; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.SystemProperties; -import android.util.Log; -import android.provider.Settings; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Gestures extends SettingsPreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_gestures); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_gestures) { - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Gestures.kt b/src/com/rising/settings/fragments/Gestures.kt new file mode 100644 index 00000000..c85941fd --- /dev/null +++ b/src/com/rising/settings/fragments/Gestures.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Gestures : OptimizedSettingsFragment() { + + companion object { + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_gestures) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_gestures) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/IslandSettings.java b/src/com/rising/settings/fragments/IslandSettings.java deleted file mode 100644 index 9f9f3aef..00000000 --- a/src/com/rising/settings/fragments/IslandSettings.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2019-2024 The Evolution X Project - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.rising.settings.fragments; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class IslandSettings extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - private static final String TAG = "IslandSettings"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.island_settings); - - final Context context = getContext(); - final ContentResolver resolver = context.getContentResolver(); - final PreferenceScreen prefScreen = getPreferenceScreen(); - final Resources resources = context.getResources(); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final Context context = getContext(); - final ContentResolver resolver = context.getContentResolver(); - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.island_settings) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - final Resources resources = context.getResources(); - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/IslandSettings.kt b/src/com/rising/settings/fragments/IslandSettings.kt new file mode 100644 index 00000000..06c9daca --- /dev/null +++ b/src/com/rising/settings/fragments/IslandSettings.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019-2024 The Evolution X Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.rising.settings.fragments + +import android.content.ContentResolver +import android.content.Context +import android.content.res.Resources +import android.os.Bundle + +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class IslandSettings : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.island_settings) + + val context = getSafeContext() ?: return + val resolver = context.contentResolver + val prefScreen = preferenceScreen + val resources = context.resources + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val context = getSafeContext() ?: return false + val resolver = context.contentResolver + return false + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + companion object { + private const val TAG = "IslandSettings" + + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.island_settings) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context) + val resources = context.resources + return keys + } + } + } +} diff --git a/src/com/rising/settings/fragments/LockScreen.java b/src/com/rising/settings/fragments/LockScreen.java deleted file mode 100644 index 07d4c7af..00000000 --- a/src/com/rising/settings/fragments/LockScreen.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.hardware.fingerprint.FingerprintManager; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.text.TextUtils; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.internal.util.android.OmniJawsClient; -import com.android.internal.util.android.Utils; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -import lineageos.providers.LineageSettings; - -import com.android.settings.preferences.ui.PreferenceUtils; - -import com.android.settings.utils.SystemRestartUtils; - -@SearchIndexable -public class LockScreen extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - public static final String TAG = "LockScreen"; - - private static final String LOCKSCREEN_INTERFACE_CATEGORY = "lockscreen_interface_category"; - private static final String LOCKSCREEN_GESTURES_CATEGORY = "lockscreen_gestures_category"; - private static final String LOCKSCREEN_FP_CATEGORY = "lockscreen_fp_category"; - private static final String LOCKSCREEN_UDFPS_CATEGORY = "lockscreen_udfps_category"; - private static final String KEY_RIPPLE_EFFECT = "enable_ripple_effect"; - private static final String KEY_WEATHER = "lockscreen_weather_enabled"; - private static final String KEY_UDFPS_ANIMATIONS = "udfps_recognizing_animation_preview"; - private static final String KEY_UDFPS_ICONS = "udfps_icon_picker"; - private static final String SCREEN_OFF_UDFPS_ENABLED = "screen_off_udfps_enabled"; - private static final String KEY_FP_SUCCESS = "fp_success_vibrate"; - private static final String KEY_FP_FAIL = "fp_error_vibrate"; - - private Preference mUdfpsIcons; - private Preference mUdfpsAnimation; - private Preference mRippleEffect; - private Preference mWeather; - private Preference mScreenOffUdfps; - private Preference mFpSuccess; - private Preference mFpFail; - - private OmniJawsClient mWeatherClient; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_lockscreen); - - PreferenceCategory udfpsCategory = (PreferenceCategory) findPreference(LOCKSCREEN_UDFPS_CATEGORY); - PreferenceCategory fpCategory = (PreferenceCategory) findPreference(LOCKSCREEN_FP_CATEGORY); - - FingerprintManager mFingerprintManager = (FingerprintManager) - getActivity().getSystemService(Context.FINGERPRINT_SERVICE); - mUdfpsIcons = (Preference) findPreference(KEY_UDFPS_ICONS); - mUdfpsAnimation = (Preference) findPreference(KEY_UDFPS_ANIMATIONS); - mRippleEffect = (Preference) findPreference(KEY_RIPPLE_EFFECT); - mScreenOffUdfps = (Preference) findPreference(SCREEN_OFF_UDFPS_ENABLED); - mFpSuccess = (Preference) findPreference(KEY_FP_SUCCESS); - mFpFail = (Preference) findPreference(KEY_FP_FAIL); - - if (mFingerprintManager == null || !mFingerprintManager.isHardwareDetected()) { - if (udfpsCategory != null) { - if (mUdfpsAnimation != null) udfpsCategory.removePreference(mUdfpsAnimation); - if (mUdfpsIcons != null) udfpsCategory.removePreference(mUdfpsIcons); - if (mScreenOffUdfps != null) udfpsCategory.removePreference(mScreenOffUdfps); - } - if (fpCategory != null) { - if (mRippleEffect != null) fpCategory.removePreference(mRippleEffect); - if (mFpSuccess != null) fpCategory.removePreference(mFpSuccess); - if (mFpFail != null) fpCategory.removePreference(mFpFail); - } - } else { - final boolean udfpsAnimationInstalled = Utils.isPackageInstalled(getContext(), "com.crdroid.udfps.animations"); - final boolean udfpsIconsInstalled = Utils.isPackageInstalled(getContext(), "com.crdroid.udfps.icons"); - if (!udfpsAnimationInstalled && udfpsCategory != null && mUdfpsAnimation != null) { - udfpsCategory.removePreference(mUdfpsAnimation); - } - if (!udfpsIconsInstalled && udfpsCategory != null && mUdfpsIcons != null) { - udfpsCategory.removePreference(mUdfpsIcons); - } - if (!udfpsAnimationInstalled && !udfpsIconsInstalled && udfpsCategory != null && mScreenOffUdfps != null) { - udfpsCategory.removePreference(mScreenOffUdfps); - } - } - - mWeather = (Preference) findPreference(KEY_WEATHER); - if (mWeather != null) { - mWeather.setOnPreferenceChangeListener(this); - } - mWeatherClient = new OmniJawsClient(getContext()); - updateWeatherSettings(); - - PreferenceScreen screen = getPreferenceScreen(); - PreferenceUtils.hideEmptyCategory(udfpsCategory, screen); - PreferenceUtils.hideEmptyCategory(fpCategory, screen); - com.android.settingslib.widget.LayoutPreference lockHighlightPref = screen.findPreference("lockscreen_highlight_dashboard"); - if (lockHighlightPref != null) { - java.util.Map lockHighlightClickMap = new java.util.HashMap<>(); - lockHighlightClickMap.put(R.id.lockscreen_widgets_tile, "PersonalizationsWidgetsActivity"); - lockHighlightClickMap.put(R.id.peek_display_tile, "PersonalizationsPDActivity"); - lockHighlightClickMap.put(R.id.aod_tile, "PersonalizationsAODActivity"); - lockHighlightClickMap.put(R.id.dw_tile, "PersonalizationsDWActivity"); - com.android.settings.utils.HighlightPrefUtils.Companion.setupHighlightPref(getContext(), lockHighlightPref, lockHighlightClickMap); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - String key = preference.getKey(); - - if (KEY_WEATHER.equals(key)) { - // Restart SystemUI when weather preference changes - SystemRestartUtils.restartSystemUI(getContext()); - return true; - } - - return false; - } - - private void updateWeatherSettings() { - if (mWeatherClient == null || mWeather == null) return; - - boolean weatherEnabled = mWeatherClient.isOmniJawsEnabled(); - mWeather.setEnabled(weatherEnabled); - mWeather.setSummary(weatherEnabled ? R.string.lockscreen_weather_summary : - R.string.lockscreen_weather_enabled_info); - } - - @Override - public void onResume() { - super.onResume(); - updateWeatherSettings(); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_lockscreen) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - FingerprintManager mFingerprintManager = (FingerprintManager) - context.getSystemService(Context.FINGERPRINT_SERVICE); - if (mFingerprintManager == null || !mFingerprintManager.isHardwareDetected()) { - keys.add(KEY_UDFPS_ANIMATIONS); - keys.add(KEY_UDFPS_ICONS); - keys.add(KEY_RIPPLE_EFFECT); - keys.add(SCREEN_OFF_UDFPS_ENABLED); - } else { - if (!Utils.isPackageInstalled(context, "com.crdroid.udfps.animations")) { - keys.add(KEY_UDFPS_ANIMATIONS); - } - if (!Utils.isPackageInstalled(context, "com.crdroid.udfps.icons")) { - keys.add(KEY_UDFPS_ICONS); - } - Resources resources = context.getResources(); - boolean screenOffUdfpsAvailable = resources.getBoolean( - com.android.internal.R.bool.config_supportScreenOffUdfps) || - !TextUtils.isEmpty(resources.getString( - com.android.internal.R.string.config_dozeUdfpsLongPressSensorType)); - if (!screenOffUdfpsAvailable) - keys.add(SCREEN_OFF_UDFPS_ENABLED); - } - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/LockScreen.kt b/src/com/rising/settings/fragments/LockScreen.kt new file mode 100644 index 00000000..ff228947 --- /dev/null +++ b/src/com/rising/settings/fragments/LockScreen.kt @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.ContentResolver +import android.content.Context +import android.content.res.Resources +import android.hardware.fingerprint.FingerprintManager +import android.os.Bundle +import android.provider.Settings +import android.text.TextUtils +import android.util.Log +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen +import com.android.internal.logging.nano.MetricsProto +import com.android.internal.util.android.OmniJawsClient +import com.android.internal.util.android.Utils +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable +import com.android.settings.preferences.ui.PreferenceUtils +import com.android.settings.utils.SystemRestartUtils +import kotlin.math.abs + +@SearchIndexable +class LockScreen : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "LockScreen" + + private const val LOCKSCREEN_INTERFACE_CATEGORY = "lockscreen_interface_category" + private const val LOCKSCREEN_GESTURES_CATEGORY = "lockscreen_gestures_category" + private const val LOCKSCREEN_FP_CATEGORY = "lockscreen_fp_category" + private const val LOCKSCREEN_UDFPS_CATEGORY = "lockscreen_udfps_category" + private const val KEY_RIPPLE_EFFECT = "enable_ripple_effect" + private const val KEY_WEATHER = "lockscreen_weather_enabled" + private const val KEY_UDFPS_ANIMATIONS = "udfps_recognizing_animation_preview" + private const val KEY_UDFPS_ICONS = "udfps_icon_picker" + private const val SCREEN_OFF_UDFPS_ENABLED = "screen_off_udfps_enabled" + private const val KEY_FP_SUCCESS = "fp_success_vibrate" + private const val KEY_FP_FAIL = "fp_error_vibrate" + + // Now Bar settings keys + private const val KEY_NOW_BAR_ENABLED = "keyguard_now_bar_enabled" + private const val KEY_NOW_BAR_MARGIN_BOTTOM = "nowbar_margin_bottom" + private const val DEFAULT_NOW_BAR_MARGIN = 18 + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_lockscreen) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + + val fingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as? FingerprintManager + if (fingerprintManager == null || !fingerprintManager.isHardwareDetected) { + keys.add(KEY_UDFPS_ANIMATIONS) + keys.add(KEY_UDFPS_ICONS) + keys.add(KEY_RIPPLE_EFFECT) + keys.add(SCREEN_OFF_UDFPS_ENABLED) + } else { + if (!Utils.isPackageInstalled(context, "com.crdroid.udfps.animations")) { + keys.add(KEY_UDFPS_ANIMATIONS) + } + if (!Utils.isPackageInstalled(context, "com.crdroid.udfps.icons")) { + keys.add(KEY_UDFPS_ICONS) + } + val resources = context.resources + val screenOffUdfpsAvailable = resources.getBoolean( + com.android.internal.R.bool.config_supportScreenOffUdfps) || + !TextUtils.isEmpty(resources.getString( + com.android.internal.R.string.config_dozeUdfpsLongPressSensorType)) + if (!screenOffUdfpsAvailable) { + keys.add(SCREEN_OFF_UDFPS_ENABLED) + } + } + return keys + } + } + } + + private var mUdfpsIcons: Preference? = null + private var mUdfpsAnimation: Preference? = null + private var mRippleEffect: Preference? = null + private var mWeather: Preference? = null + private var mScreenOffUdfps: Preference? = null + private var mFpSuccess: Preference? = null + private var mFpFail: Preference? = null + + // Now Bar preferences and position management + private var mNowBarEnabled: Preference? = null + private var mNowBarMargin: com.android.settings.preferences.SystemSettingSeekBarPreference? = null + private var mLastValidNowBarMargin = DEFAULT_NOW_BAR_MARGIN + + private var mWeatherClient: OmniJawsClient? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_lockscreen) + + val udfpsCategory = findPreference(LOCKSCREEN_UDFPS_CATEGORY) + val fpCategory = findPreference(LOCKSCREEN_FP_CATEGORY) + + // Use safe context access and cached preferences + val context = getSafeContext() + val fingerprintManager = context?.getSystemService(Context.FINGERPRINT_SERVICE) as? FingerprintManager + + mUdfpsIcons = findCachedPreference(KEY_UDFPS_ICONS) + mUdfpsAnimation = findCachedPreference(KEY_UDFPS_ANIMATIONS) + mRippleEffect = findCachedPreference(KEY_RIPPLE_EFFECT) + mScreenOffUdfps = findCachedPreference(SCREEN_OFF_UDFPS_ENABLED) + mFpSuccess = findCachedPreference(KEY_FP_SUCCESS) + mFpFail = findCachedPreference(KEY_FP_FAIL) + + // Initialize Now Bar preferences + mNowBarEnabled = findCachedPreference(KEY_NOW_BAR_ENABLED) + mNowBarMargin = findCachedPreference(KEY_NOW_BAR_MARGIN_BOTTOM) + + // Initialize Now Bar position management + initializeNowBarPosition() + + if (fingerprintManager == null || !fingerprintManager.isHardwareDetected) { + udfpsCategory?.let { category -> + mUdfpsAnimation?.let { category.removePreference(it) } + mUdfpsIcons?.let { category.removePreference(it) } + mScreenOffUdfps?.let { category.removePreference(it) } + } + fpCategory?.let { category -> + mRippleEffect?.let { category.removePreference(it) } + mFpSuccess?.let { category.removePreference(it) } + mFpFail?.let { category.removePreference(it) } + } + } else { + // Cache package installation checks to avoid repeated calls + val udfpsAnimationInstalled = if (isOperationCached("udfps_anim_installed")) { + getCachedOperation("udfps_anim_installed") ?: false + } else { + val installed = Utils.isPackageInstalled(context, "com.crdroid.udfps.animations") + cacheOperation("udfps_anim_installed", installed) + installed + } + + val udfpsIconsInstalled = if (isOperationCached("udfps_icons_installed")) { + getCachedOperation("udfps_icons_installed") ?: false + } else { + val installed = Utils.isPackageInstalled(context, "com.crdroid.udfps.icons") + cacheOperation("udfps_icons_installed", installed) + installed + } + + if (!udfpsAnimationInstalled) { + udfpsCategory?.let { category -> + mUdfpsAnimation?.let { category.removePreference(it) } + } + } + if (!udfpsIconsInstalled) { + udfpsCategory?.let { category -> + mUdfpsIcons?.let { category.removePreference(it) } + } + } + if (!udfpsAnimationInstalled && !udfpsIconsInstalled) { + udfpsCategory?.let { category -> + mScreenOffUdfps?.let { category.removePreference(it) } + } + } + } + + mWeather = findCachedPreference(KEY_WEATHER)?.apply { + onPreferenceChangeListener = this@LockScreen + } + + // Set up Now Bar preference listeners + mNowBarEnabled?.onPreferenceChangeListener = this + mNowBarMargin?.onPreferenceChangeListener = this + + // Initialize weather client with null check + context?.let { + mWeatherClient = OmniJawsClient(it) + updateWeatherSettings() + } + + val screen = preferenceScreen + screen?.let { + PreferenceUtils.hideEmptyCategory(udfpsCategory, it) + PreferenceUtils.hideEmptyCategory(fpCategory, it) + + val lockHighlightPref = it.findPreference("lockscreen_highlight_dashboard") + if (lockHighlightPref != null && context != null) { + val lockHighlightClickMap = mapOf( + R.id.lockscreen_widgets_tile to "PersonalizationsWidgetsActivity", + R.id.peek_display_tile to "PersonalizationsPDActivity", + R.id.aod_tile to "PersonalizationsAODActivity", + R.id.dw_tile to "PersonalizationsDWActivity" + ) + com.android.settings.utils.HighlightPrefUtils.setupHighlightPref(context, lockHighlightPref, lockHighlightClickMap) + } + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + val key = preference.key + + return when (key) { + KEY_WEATHER -> { + // Restart SystemUI when weather preference changes + getSafeContext()?.let { context -> + SystemRestartUtils.restartSystemUI(context) + } + true + } + KEY_NOW_BAR_ENABLED -> { + // Handle Now Bar enable/disable + val enabled = newValue as Boolean + handleNowBarEnabledChange(enabled) + true + } + KEY_NOW_BAR_MARGIN_BOTTOM -> { + // Handle Now Bar margin changes with position stability + val newMargin = newValue as Int + handleNowBarMarginChange(newMargin) + } + else -> false + } + } + + private fun updateWeatherSettings() { + val weatherClient = mWeatherClient + val weather = mWeather + if (weatherClient == null || weather == null) return + + val weatherEnabled = weatherClient.isOmniJawsEnabled + weather.isEnabled = weatherEnabled + weather.setSummary(if (weatherEnabled) R.string.lockscreen_weather_summary else R.string.lockscreen_weather_enabled_info) + } + + override fun onResume() { + super.onResume() + // Use safe method to update weather settings + if (isFragmentReady()) { + updateWeatherSettings() + // Check and restore Now Bar position to prevent drift + checkAndRestoreNowBarPosition() + } + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup weather client + mWeatherClient = null + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + /** + * Initialize Now Bar position management + */ + private fun initializeNowBarPosition() { + val context = getSafeContext() ?: return + val nowBarMargin = mNowBarMargin ?: return + + val resolver = context.contentResolver + + // Load cached position + val currentMargin = Settings.System.getInt(resolver, + KEY_NOW_BAR_MARGIN_BOTTOM, DEFAULT_NOW_BAR_MARGIN) + mLastValidNowBarMargin = currentMargin + } + + /** + * Handle Now Bar enabled/disabled changes + */ + private fun handleNowBarEnabledChange(enabled: Boolean) { + val context = getSafeContext() ?: return + + // Restart SystemUI when Now Bar is enabled/disabled to apply changes + postDelayedSafe(100) { + SystemRestartUtils.restartSystemUI(context) + } + } + + /** + * Handle Now Bar margin changes with position stability + */ + private fun handleNowBarMarginChange(newMargin: Int): Boolean { + val context = getSafeContext() ?: return false + + // Validate margin range (0-210 as defined in XML) + val validMargin = newMargin.coerceIn(0, 210) + + // Cache the new valid position + mLastValidNowBarMargin = validMargin + + // Apply the setting with stability + val resolver = context.contentResolver + Settings.System.putInt(resolver, KEY_NOW_BAR_MARGIN_BOTTOM, validMargin) + + // Notify SystemUI of the change with a slight delay for stability + postDelayedSafe(50) { + resolver.notifyChange(Settings.System.getUriFor(KEY_NOW_BAR_MARGIN_BOTTOM), null) + } + + return true + } + + /** + * Check and restore Now Bar position to prevent drift after idle periods + * This is the key method to fix the position drift issue + */ + private fun checkAndRestoreNowBarPosition() { + val nowBarMargin = mNowBarMargin ?: return + val context = getSafeContext() ?: return + + val resolver = context.contentResolver + + // Check if Now Bar is enabled + val nowBarEnabled = Settings.System.getInt(resolver, + KEY_NOW_BAR_ENABLED, 0) == 1 + + if (!nowBarEnabled) { + return // No need to check position if Now Bar is disabled + } + + val currentMargin = Settings.System.getInt(resolver, + KEY_NOW_BAR_MARGIN_BOTTOM, DEFAULT_NOW_BAR_MARGIN) + + // Check if position has drifted (tolerance of 2 units) + if (abs(currentMargin - mLastValidNowBarMargin) > 2) { + // Position has drifted - restore stable position + postDelayedSafe(100) { + Settings.System.putInt(resolver, KEY_NOW_BAR_MARGIN_BOTTOM, mLastValidNowBarMargin) + nowBarMargin.setValue(mLastValidNowBarMargin) + + // Notify SystemUI of the position correction + resolver.notifyChange(Settings.System.getUriFor(KEY_NOW_BAR_MARGIN_BOTTOM), null) + + Log.d(TAG, "Now Bar position drift detected and corrected: $currentMargin -> $mLastValidNowBarMargin") + } + } else { + // Position is stable - update cache + mLastValidNowBarMargin = currentMargin + } + } +} diff --git a/src/com/rising/settings/fragments/MonetSettings.java b/src/com/rising/settings/fragments/MonetSettings.java deleted file mode 100644 index 77273f26..00000000 --- a/src/com/rising/settings/fragments/MonetSettings.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2021-2024 crDroid Android 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.rising.settings.fragments; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.preferences.colorpicker.ColorPickerPreference; -import com.android.settings.preferences.CustomSeekBarPreference; -import com.android.settings.preferences.SecureSettingListPreference; -import com.android.settings.preferences.SecureSettingSwitchPreference; - -import java.lang.CharSequence; - -import lineageos.providers.LineageSettings; - -import org.json.JSONException; -import org.json.JSONObject; - -@SearchIndexable -public class MonetSettings extends DashboardFragment implements - OnPreferenceChangeListener { - - private static final String TAG = "MonetSettings"; - private static final String OVERLAY_CATEGORY_ACCENT_COLOR = - "android.theme.customization.accent_color"; - private static final String OVERLAY_CATEGORY_SYSTEM_PALETTE = - "android.theme.customization.system_palette"; - private static final String OVERLAY_CATEGORY_THEME_STYLE = - "android.theme.customization.theme_style"; - private static final String OVERLAY_CATEGORY_BG_COLOR = - "android.theme.customization.bg_color"; - private static final String OVERLAY_COLOR_SOURCE = - "android.theme.customization.color_source"; - private static final String OVERLAY_COLOR_BOTH = - "android.theme.customization.color_both"; - private static final String OVERLAY_LUMINANCE_FACTOR = - "android.theme.customization.luminance_factor"; - private static final String OVERLAY_CHROMA_FACTOR = - "android.theme.customization.chroma_factor"; - private static final String OVERLAY_WHOLE_PALETTE = - "android.theme.customization.whole_palette"; - private static final String OVERLAY_TINT_BACKGROUND = - "android.theme.customization.tint_background"; - private static final String COLOR_SOURCE_PRESET = "preset"; - private static final String COLOR_SOURCE_HOME = "home_wallpaper"; - private static final String COLOR_SOURCE_LOCK = "lock_wallpaper"; - private static final String TIMESTAMP_FIELD = "_applied_timestamp"; - - private static final String PREF_THEME_STYLE = "theme_style"; - private static final String PREF_COLOR_SOURCE = "color_source"; - private static final String PREF_ACCENT_COLOR = "accent_color"; - private static final String PREF_ACCENT_BACKGROUND = "accent_background"; - private static final String PREF_BG_COLOR = "bg_color"; - private static final String PREF_LUMINANCE_FACTOR = "luminance_factor"; - private static final String PREF_CHROMA_FACTOR = "chroma_factor"; - private static final String PREF_WHOLE_PALETTE = "whole_palette"; - private static final String PREF_TINT_BACKGROUND = "tint_background"; - - private static final int DEFAULT_COLOR = 0xFF1b6ef3; - - private SecureSettingListPreference mThemeStylePref; - private SecureSettingListPreference mColorSourcePref; - private ColorPickerPreference mAccentColorPref; - private SecureSettingSwitchPreference mAccentBackgroundPref; - private ColorPickerPreference mBgColorPref; - private CustomSeekBarPreference mLuminancePref; - private CustomSeekBarPreference mChromaPref; - private SecureSettingSwitchPreference mWholePalettePref; - private SecureSettingSwitchPreference mTintBackgroundPref; - - private int mAccentColorValue; - private int mBgColorValue; - - private SharedPreferences mSharedPreferences; - - @Override - protected int getPreferenceScreenResId() { - return R.xml.monet_engine; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mThemeStylePref = findPreference(PREF_THEME_STYLE); - mColorSourcePref = findPreference(PREF_COLOR_SOURCE); - mAccentColorPref = findPreference(PREF_ACCENT_COLOR); - mAccentBackgroundPref = findPreference(PREF_ACCENT_BACKGROUND); - mBgColorPref = findPreference(PREF_BG_COLOR); - mLuminancePref = findPreference(PREF_LUMINANCE_FACTOR); - mChromaPref = findPreference(PREF_CHROMA_FACTOR); - mWholePalettePref = findPreference(PREF_WHOLE_PALETTE); - mTintBackgroundPref = findPreference(PREF_TINT_BACKGROUND); - mSharedPreferences = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE); - - updatePreferences(); - - mThemeStylePref.setOnPreferenceChangeListener(this); - mColorSourcePref.setOnPreferenceChangeListener(this); - mAccentColorPref.setOnPreferenceChangeListener(this); - mAccentBackgroundPref.setOnPreferenceChangeListener(this); - mBgColorPref.setOnPreferenceChangeListener(this); - mLuminancePref.setOnPreferenceChangeListener(this); - mChromaPref.setOnPreferenceChangeListener(this); - mWholePalettePref.setOnPreferenceChangeListener(this); - mTintBackgroundPref.setOnPreferenceChangeListener(this); - } - - @Override - public void onResume() { - super.onResume(); - updatePreferences(); - } - - private void updatePreferences() { - final String overlayPackageJson = Settings.Secure.getStringForUser( - getActivity().getContentResolver(), - Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, - UserHandle.USER_CURRENT); - if (overlayPackageJson != null && !overlayPackageJson.isEmpty()) { - try { - final JSONObject object = new JSONObject(overlayPackageJson); - final String style = object.optString(OVERLAY_CATEGORY_THEME_STYLE, "TONAL_SPOT"); - final String source = object.optString(OVERLAY_COLOR_SOURCE, COLOR_SOURCE_HOME); - String color; - if (object.has(OVERLAY_CATEGORY_SYSTEM_PALETTE)) { - color = object.optString(OVERLAY_CATEGORY_SYSTEM_PALETTE); - mAccentColorValue = ColorPickerPreference.convertToColorInt(color); - } else { - mAccentColorValue = mSharedPreferences.getInt(PREF_ACCENT_COLOR, DEFAULT_COLOR); - color = ColorPickerPreference.convertToRGB(mAccentColorValue).replace("#", ""); - } - boolean hasBGColor = object.has(OVERLAY_CATEGORY_BG_COLOR); - mAccentBackgroundPref.setChecked(mSharedPreferences.getBoolean(PREF_ACCENT_BACKGROUND, hasBGColor)); - if (hasBGColor) { - mBgColorValue = object.optInt(OVERLAY_CATEGORY_BG_COLOR); - } else { - mBgColorValue = mSharedPreferences.getInt(PREF_BG_COLOR, DEFAULT_COLOR); - } - boolean both; - if (object.has(OVERLAY_COLOR_BOTH)) { - both = object.optInt(OVERLAY_COLOR_BOTH) == 1; - } else { - both = false; - } - final boolean wholePalette = object.optInt(OVERLAY_WHOLE_PALETTE, 0) == 1; - final boolean tintBG = object.optInt(OVERLAY_TINT_BACKGROUND, 0) == 1; - final float lumin = (float) object.optDouble(OVERLAY_LUMINANCE_FACTOR, 1d); - final float chroma = (float) object.optDouble(OVERLAY_CHROMA_FACTOR, 1d); - // style handling - boolean styleUpdated = false; - if (style != null && !style.isEmpty()) { - for (CharSequence value : mThemeStylePref.getEntryValues()) { - if (value.toString().equals(style)) { - styleUpdated = true; - break; - } - } - if (styleUpdated) { - updateListByValue(mThemeStylePref, style); - } - } - if (!styleUpdated) { - updateListByValue(mThemeStylePref, - mThemeStylePref.getEntryValues()[0].toString()); - } - // color handling - final String sourceVal = (source == null || source.isEmpty() || - (source.equals(COLOR_SOURCE_HOME) && both)) ? "both" : source; - updateListByValue(mColorSourcePref, sourceVal); - updateAccentEnablement(sourceVal); - // Set preview color irrespective it is enabled - if (color != null && !color.isEmpty()) { - mAccentColorPref.setNewPreviewColor(mAccentColorValue); - } - mBgColorPref.setNewPreviewColor(mBgColorValue); - // etc - int luminV = 0; - if (lumin > 1d) luminV = Math.round((lumin - 1f) * 100f); - else if (lumin < 1d) luminV = -1 * Math.round((1f - lumin) * 100f); - mLuminancePref.setValue(luminV); - int chromaV = 0; - if (chroma > 1d) chromaV = Math.round((chroma - 1f) * 100f); - else if (chroma < 1d) chromaV = -1 * Math.round((1f - chroma) * 100f); - mChromaPref.setValue(chromaV); - mWholePalettePref.setChecked(wholePalette); - mTintBackgroundPref.setChecked(tintBG); - } catch (JSONException | IllegalArgumentException ignored) {} - } else { - // reflect default values in every preference - mThemeStylePref.setValueIndex(0); - mColorSourcePref.setValueIndex(0); - mLuminancePref.setValue(0); - mChromaPref.setValue(0); - mAccentBackgroundPref.setChecked(false); - mWholePalettePref.setChecked(false); - mTintBackgroundPref.setChecked(false); - updateAccentEnablement("both"); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final ContentResolver resolver = getActivity().getContentResolver(); - if (preference == mThemeStylePref) { - String value = (String) newValue; - setStyleValue(value); - updateListByValue(mThemeStylePref, value, false); - return true; - } else if (preference == mColorSourcePref) { - String value = (String) newValue; - setSourceValue(value); - updateListByValue(mColorSourcePref, value, false); - updateAccentEnablement(value); - return true; - } else if (preference == mAccentColorPref) { - mAccentColorValue = (Integer) newValue; - mSharedPreferences.edit().putInt(PREF_ACCENT_COLOR, mAccentColorValue).apply(); - setColorValue(); - return true; - } else if (preference == mAccentBackgroundPref) { - boolean value = (Boolean) newValue; - mAccentBackgroundPref.setChecked(value); - mSharedPreferences.edit().putBoolean(PREF_ACCENT_BACKGROUND, value).apply(); - setBgColorValue(); - return true; - } else if (preference == mBgColorPref) { - mBgColorValue = (Integer) newValue; - mSharedPreferences.edit().putInt(PREF_BG_COLOR, mBgColorValue).apply(); - setBgColorValue(); - return true; - } else if (preference == mLuminancePref) { - int value = (Integer) newValue; - setLuminanceValue(value); - return true; - } else if (preference == mChromaPref) { - int value = (Integer) newValue; - setChromaValue(value); - return true; - } else if (preference == mWholePalettePref) { - boolean value = (Boolean) newValue; - setWholePaletteValue(value); - return true; - } else if (preference == mTintBackgroundPref) { - boolean value = (Boolean) newValue; - setTintBackgroundValue(value); - return true; - } - return false; - } - - private void updateListByValue(SecureSettingListPreference pref, String value) { - updateListByValue(pref, value, true); - } - - private void updateListByValue(SecureSettingListPreference pref, String value, boolean set) { - if (set) pref.setValue(value); - final int index = pref.findIndexOfValue(value); - pref.setSummary(pref.getEntries()[index]); - } - - private void updateAccentEnablement(String source) { - final boolean shouldEnable = source != null && source.equals(COLOR_SOURCE_PRESET); - mAccentColorPref.setEnabled(shouldEnable); - mAccentBackgroundPref.setEnabled(shouldEnable); - setColorValue(); - setBgColorValue(); - } - - private JSONObject getSettingsJson() throws JSONException { - final String overlayPackageJson = Settings.Secure.getStringForUser( - getActivity().getContentResolver(), - Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, - UserHandle.USER_CURRENT); - JSONObject object; - if (overlayPackageJson == null || overlayPackageJson.isEmpty()) - return new JSONObject(); - return new JSONObject(overlayPackageJson); - } - - private void putSettingsJson(JSONObject object) { - Settings.Secure.putStringForUser( - getActivity().getContentResolver(), - Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, - object.toString(), UserHandle.USER_CURRENT); - } - - private void setStyleValue(String style) { - try { - JSONObject object = getSettingsJson(); - object.putOpt(OVERLAY_CATEGORY_THEME_STYLE, style); - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setSourceValue(String source) { - try { - JSONObject object = getSettingsJson(); - if (source.equals("both")) { - object.putOpt(OVERLAY_COLOR_BOTH, 1); - object.putOpt(OVERLAY_COLOR_SOURCE, COLOR_SOURCE_HOME); - } else { - object.remove(OVERLAY_COLOR_BOTH); - object.putOpt(OVERLAY_COLOR_SOURCE, source); - } - object.putOpt(TIMESTAMP_FIELD, System.currentTimeMillis()); - if (!source.equals(COLOR_SOURCE_PRESET)) { - object.remove(OVERLAY_CATEGORY_ACCENT_COLOR); - object.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); - } - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setColorValue() { - try { - JSONObject object = getSettingsJson(); - - if (mColorSourcePref.getValue().equals(COLOR_SOURCE_PRESET)) { - final String rgbColor = ColorPickerPreference.convertToRGB(mAccentColorValue).replace("#", ""); - object.putOpt(OVERLAY_CATEGORY_ACCENT_COLOR, rgbColor); - object.putOpt(OVERLAY_CATEGORY_SYSTEM_PALETTE, rgbColor); - } else { - object.remove(OVERLAY_CATEGORY_ACCENT_COLOR); - object.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); - } - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setBgColorValue() { - try { - JSONObject object = getSettingsJson(); - if (mColorSourcePref.getValue().equals(COLOR_SOURCE_PRESET) && mAccentBackgroundPref.isChecked()) { - object.putOpt(OVERLAY_CATEGORY_BG_COLOR, mBgColorValue); - } else { - object.remove(OVERLAY_CATEGORY_BG_COLOR); - } - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setLuminanceValue(int lumin) { - try { - JSONObject object = getSettingsJson(); - if (lumin == 0) - object.remove(OVERLAY_LUMINANCE_FACTOR); - else - object.putOpt(OVERLAY_LUMINANCE_FACTOR, 1d + ((double) lumin / 100d)); - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setChromaValue(int chroma) { - try { - JSONObject object = getSettingsJson(); - if (chroma == 0) - object.remove(OVERLAY_CHROMA_FACTOR); - else - object.putOpt(OVERLAY_CHROMA_FACTOR, 1d + ((double) chroma / 100d)); - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setWholePaletteValue(boolean whole) { - try { - JSONObject object = getSettingsJson(); - if (!whole) object.remove(OVERLAY_WHOLE_PALETTE); - else object.putOpt(OVERLAY_WHOLE_PALETTE, 1); - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - private void setTintBackgroundValue(boolean tint) { - try { - JSONObject object = getSettingsJson(); - if (!tint) object.remove(OVERLAY_TINT_BACKGROUND); - else object.putOpt(OVERLAY_TINT_BACKGROUND, 1); - putSettingsJson(object); - } catch (JSONException | IllegalArgumentException ignored) {} - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - @Override - protected String getLogTag() { - return TAG; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.monet_engine); -} diff --git a/src/com/rising/settings/fragments/MonetSettings.kt b/src/com/rising/settings/fragments/MonetSettings.kt new file mode 100644 index 00000000..f39c0c84 --- /dev/null +++ b/src/com/rising/settings/fragments/MonetSettings.kt @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2021-2024 crDroid Android 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.rising.settings.fragments + +import android.content.ContentResolver +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.dashboard.DashboardFragment +import com.android.settings.preferences.CustomSeekBarPreference +import com.android.settings.preferences.SecureSettingListPreference +import com.android.settings.preferences.SecureSettingSwitchPreference +import com.android.settings.preferences.colorpicker.ColorPickerPreference +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable +import org.json.JSONException +import org.json.JSONObject +import java.lang.ref.WeakReference +import java.util.concurrent.ConcurrentHashMap + +@SearchIndexable +class MonetSettings : DashboardFragment(), OnPreferenceChangeListener { + + override fun getLogTag(): String { + return TAG + } + + companion object { + private const val TAG = "MonetSettings" + private const val OVERLAY_CATEGORY_ACCENT_COLOR = "android.theme.customization.accent_color" + private const val OVERLAY_CATEGORY_SYSTEM_PALETTE = "android.theme.customization.system_palette" + private const val OVERLAY_CATEGORY_THEME_STYLE = "android.theme.customization.theme_style" + private const val OVERLAY_CATEGORY_BG_COLOR = "android.theme.customization.bg_color" + private const val OVERLAY_COLOR_SOURCE = "android.theme.customization.color_source" + private const val OVERLAY_COLOR_BOTH = "android.theme.customization.color_both" + private const val OVERLAY_LUMINANCE_FACTOR = "android.theme.customization.luminance_factor" + private const val OVERLAY_CHROMA_FACTOR = "android.theme.customization.chroma_factor" + private const val OVERLAY_WHOLE_PALETTE = "android.theme.customization.whole_palette" + private const val OVERLAY_TINT_BACKGROUND = "android.theme.customization.tint_background" + private const val COLOR_SOURCE_PRESET = "preset" + private const val COLOR_SOURCE_HOME = "home_wallpaper" + private const val COLOR_SOURCE_LOCK = "lock_wallpaper" + private const val TIMESTAMP_FIELD = "_applied_timestamp" + + private const val PREF_THEME_STYLE = "theme_style" + private const val PREF_COLOR_SOURCE = "color_source" + private const val PREF_ACCENT_COLOR = "accent_color" + private const val PREF_ACCENT_BACKGROUND = "accent_background" + private const val PREF_BG_COLOR = "bg_color" + private const val PREF_LUMINANCE_FACTOR = "luminance_factor" + private const val PREF_CHROMA_FACTOR = "chroma_factor" + private const val PREF_WHOLE_PALETTE = "whole_palette" + private const val PREF_TINT_BACKGROUND = "tint_background" + + private const val DEFAULT_COLOR = 0xFF1b6ef3.toInt() + + // JSON cache timeout constant + private const val JSON_CACHE_TIMEOUT = 1000L // 1 second cache + + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = BaseSearchIndexProvider(R.xml.monet_engine) + } + + private var mThemeStylePref: SecureSettingListPreference? = null + private var mColorSourcePref: SecureSettingListPreference? = null + private var mAccentColorPref: ColorPickerPreference? = null + private var mAccentBackgroundPref: SecureSettingSwitchPreference? = null + private var mBgColorPref: ColorPickerPreference? = null + private var mLuminancePref: CustomSeekBarPreference? = null + private var mChromaPref: CustomSeekBarPreference? = null + private var mWholePalettePref: SecureSettingSwitchPreference? = null + private var mTintBackgroundPref: SecureSettingSwitchPreference? = null + + private var mAccentColorValue: Int = 0 + private var mBgColorValue: Int = 0 + + private var mSharedPreferences: SharedPreferences? = null + + // Cache for JSON operations to prevent redundant parsing + private var mCachedSettingsJson: JSONObject? = null + private var mLastJsonUpdateTime: Long = 0 + + // Cache for preference states + private val mPreferenceCache = ConcurrentHashMap() + + override fun getPreferenceScreenResId(): Int { + return R.xml.monet_engine + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + mThemeStylePref = findPreference(PREF_THEME_STYLE) + mColorSourcePref = findPreference(PREF_COLOR_SOURCE) + mAccentColorPref = findPreference(PREF_ACCENT_COLOR) + mAccentBackgroundPref = findPreference(PREF_ACCENT_BACKGROUND) + mBgColorPref = findPreference(PREF_BG_COLOR) + mLuminancePref = findPreference(PREF_LUMINANCE_FACTOR) + mChromaPref = findPreference(PREF_CHROMA_FACTOR) + mWholePalettePref = findPreference(PREF_WHOLE_PALETTE) + mTintBackgroundPref = findPreference(PREF_TINT_BACKGROUND) + mSharedPreferences = activity?.getSharedPreferences(TAG, Context.MODE_PRIVATE) + + updatePreferences() + + mThemeStylePref?.onPreferenceChangeListener = this + mColorSourcePref?.onPreferenceChangeListener = this + mAccentColorPref?.onPreferenceChangeListener = this + mAccentBackgroundPref?.onPreferenceChangeListener = this + mBgColorPref?.onPreferenceChangeListener = this + mLuminancePref?.onPreferenceChangeListener = this + mChromaPref?.onPreferenceChangeListener = this + mWholePalettePref?.onPreferenceChangeListener = this + mTintBackgroundPref?.onPreferenceChangeListener = this + } + + override fun onResume() { + super.onResume() + // Update preferences on resume + updatePreferences() + } + + private fun updatePreferences() { + val overlayPackageJson = Settings.Secure.getStringForUser( + activity?.contentResolver, + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + UserHandle.USER_CURRENT) + + if (!overlayPackageJson.isNullOrEmpty()) { + try { + val obj = JSONObject(overlayPackageJson) + val style = obj.optString(OVERLAY_CATEGORY_THEME_STYLE, "TONAL_SPOT") + val source = obj.optString(OVERLAY_COLOR_SOURCE, COLOR_SOURCE_HOME) + + val color = if (obj.has(OVERLAY_CATEGORY_SYSTEM_PALETTE)) { + val colorStr = obj.optString(OVERLAY_CATEGORY_SYSTEM_PALETTE) + mAccentColorValue = ColorPickerPreference.convertToColorInt(colorStr) + colorStr + } else { + mAccentColorValue = mSharedPreferences?.getInt(PREF_ACCENT_COLOR, DEFAULT_COLOR) ?: DEFAULT_COLOR + ColorPickerPreference.convertToRGB(mAccentColorValue).replace("#", "") + } + + val hasBGColor = obj.has(OVERLAY_CATEGORY_BG_COLOR) + mAccentBackgroundPref?.isChecked = mSharedPreferences?.getBoolean(PREF_ACCENT_BACKGROUND, hasBGColor) ?: hasBGColor + + mBgColorValue = if (hasBGColor) { + obj.optInt(OVERLAY_CATEGORY_BG_COLOR) + } else { + mSharedPreferences?.getInt(PREF_BG_COLOR, DEFAULT_COLOR) ?: DEFAULT_COLOR + } + + val both = if (obj.has(OVERLAY_COLOR_BOTH)) { + obj.optInt(OVERLAY_COLOR_BOTH) == 1 + } else { + false + } + + val wholePalette = obj.optInt(OVERLAY_WHOLE_PALETTE, 0) == 1 + val tintBG = obj.optInt(OVERLAY_TINT_BACKGROUND, 0) == 1 + val lumin = obj.optDouble(OVERLAY_LUMINANCE_FACTOR, 1.0).toFloat() + val chroma = obj.optDouble(OVERLAY_CHROMA_FACTOR, 1.0).toFloat() + + // Style handling + var styleUpdated = false + if (style.isNotEmpty()) { + mThemeStylePref?.entryValues?.forEach { value -> + if (value.toString() == style) { + styleUpdated = true + return@forEach + } + } + if (styleUpdated) { + updateListByValue(mThemeStylePref, style) + } + } + if (!styleUpdated) { + mThemeStylePref?.entryValues?.get(0)?.toString()?.let { defaultStyle -> + updateListByValue(mThemeStylePref, defaultStyle) + } + } + + // Color handling + val sourceVal = if (source.isEmpty() || (source == COLOR_SOURCE_HOME && both)) "both" else source + updateListByValue(mColorSourcePref, sourceVal) + updateAccentEnablement(sourceVal) + + // Set preview color irrespective it is enabled + if (color.isNotEmpty()) { + mAccentColorPref?.setNewPreviewColor(mAccentColorValue) + } + mBgColorPref?.setNewPreviewColor(mBgColorValue) + + // Luminance and chroma + val luminV = when { + lumin > 1.0 -> Math.round((lumin - 1f) * 100f) + lumin < 1.0 -> -1 * Math.round((1f - lumin) * 100f) + else -> 0 + } + mLuminancePref?.setValue(luminV) + + val chromaV = when { + chroma > 1.0 -> Math.round((chroma - 1f) * 100f) + chroma < 1.0 -> -1 * Math.round((1f - chroma) * 100f) + else -> 0 + } + mChromaPref?.setValue(chromaV) + + mWholePalettePref?.isChecked = wholePalette + mTintBackgroundPref?.isChecked = tintBG + + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } else { + // Reflect default values in every preference + mThemeStylePref?.setValueIndex(0) + mColorSourcePref?.setValueIndex(0) + mLuminancePref?.setValue(0) + mChromaPref?.setValue(0) + mAccentBackgroundPref?.isChecked = false + mWholePalettePref?.isChecked = false + mTintBackgroundPref?.isChecked = false + updateAccentEnablement("both") + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + val resolver = activity?.contentResolver ?: return false + + return when (preference) { + mThemeStylePref -> { + val value = newValue as String + setStyleValue(value) + updateListByValue(mThemeStylePref, value, false) + true + } + + mColorSourcePref -> { + val value = newValue as String + setSourceValue(value) + updateListByValue(mColorSourcePref, value, false) + updateAccentEnablement(value) + true + } + + mAccentColorPref -> { + mAccentColorValue = newValue as Int + mSharedPreferences?.edit()?.putInt(PREF_ACCENT_COLOR, mAccentColorValue)?.apply() + setColorValue() + true + } + + mAccentBackgroundPref -> { + val value = newValue as Boolean + mAccentBackgroundPref?.isChecked = value + mSharedPreferences?.edit()?.putBoolean(PREF_ACCENT_BACKGROUND, value)?.apply() + setBgColorValue() + true + } + + mBgColorPref -> { + mBgColorValue = newValue as Int + mSharedPreferences?.edit()?.putInt(PREF_BG_COLOR, mBgColorValue)?.apply() + setBgColorValue() + true + } + + mLuminancePref -> { + val value = newValue as Int + setLuminanceValue(value) + true + } + + mChromaPref -> { + val value = newValue as Int + setChromaValue(value) + true + } + + mWholePalettePref -> { + val value = newValue as Boolean + setWholePaletteValue(value) + true + } + + mTintBackgroundPref -> { + val value = newValue as Boolean + setTintBackgroundValue(value) + true + } + + else -> false + } + } + + private fun updateListByValue(pref: SecureSettingListPreference?, value: String) { + updateListByValue(pref, value, true) + } + + private fun updateListByValue(pref: SecureSettingListPreference?, value: String, set: Boolean) { + if (pref == null) return + if (set) pref.value = value + val index = pref.findIndexOfValue(value) + pref.summary = pref.entries[index] + } + + private fun updateAccentEnablement(source: String?) { + val shouldEnable = source == COLOR_SOURCE_PRESET + mAccentColorPref?.isEnabled = shouldEnable + mAccentBackgroundPref?.isEnabled = shouldEnable + setColorValue() + setBgColorValue() + } + + private fun getSettingsJson(): JSONObject { + val currentTime = System.currentTimeMillis() + + // Use cached JSON if still valid + mCachedSettingsJson?.let { cached -> + if ((currentTime - mLastJsonUpdateTime) < JSON_CACHE_TIMEOUT) { + return JSONObject(cached.toString()) // Return copy + } + } + + val overlayPackageJson = Settings.Secure.getStringForUser( + activity?.contentResolver, + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + UserHandle.USER_CURRENT) + + val obj = if (overlayPackageJson.isNullOrEmpty()) { + JSONObject() + } else { + JSONObject(overlayPackageJson) + } + + // Update cache + mCachedSettingsJson = JSONObject(obj.toString()) + mLastJsonUpdateTime = currentTime + + return obj + } + + private fun putSettingsJson(obj: JSONObject) { + Settings.Secure.putStringForUser( + activity?.contentResolver, + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + obj.toString(), UserHandle.USER_CURRENT) + + // Update cache + try { + mCachedSettingsJson = JSONObject(obj.toString()) + mLastJsonUpdateTime = System.currentTimeMillis() + } catch (e: JSONException) { + // Clear cache on error + mCachedSettingsJson = null + } + } + + private fun setStyleValue(style: String) { + try { + val obj = getSettingsJson() + obj.putOpt(OVERLAY_CATEGORY_THEME_STYLE, style) + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setSourceValue(source: String) { + try { + val obj = getSettingsJson() + if (source == "both") { + obj.putOpt(OVERLAY_COLOR_BOTH, 1) + obj.putOpt(OVERLAY_COLOR_SOURCE, COLOR_SOURCE_HOME) + } else { + obj.remove(OVERLAY_COLOR_BOTH) + obj.putOpt(OVERLAY_COLOR_SOURCE, source) + } + obj.putOpt(TIMESTAMP_FIELD, System.currentTimeMillis()) + if (source != COLOR_SOURCE_PRESET) { + obj.remove(OVERLAY_CATEGORY_ACCENT_COLOR) + obj.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setColorValue() { + try { + val obj = getSettingsJson() + + if (mColorSourcePref?.value == COLOR_SOURCE_PRESET) { + val rgbColor = ColorPickerPreference.convertToRGB(mAccentColorValue).replace("#", "") + obj.putOpt(OVERLAY_CATEGORY_ACCENT_COLOR, rgbColor) + obj.putOpt(OVERLAY_CATEGORY_SYSTEM_PALETTE, rgbColor) + } else { + obj.remove(OVERLAY_CATEGORY_ACCENT_COLOR) + obj.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setBgColorValue() { + try { + val obj = getSettingsJson() + if (mColorSourcePref?.value == COLOR_SOURCE_PRESET && mAccentBackgroundPref?.isChecked == true) { + obj.putOpt(OVERLAY_CATEGORY_BG_COLOR, mBgColorValue) + } else { + obj.remove(OVERLAY_CATEGORY_BG_COLOR) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setLuminanceValue(lumin: Int) { + try { + val obj = getSettingsJson() + if (lumin == 0) { + obj.remove(OVERLAY_LUMINANCE_FACTOR) + } else { + obj.putOpt(OVERLAY_LUMINANCE_FACTOR, 1.0 + (lumin.toDouble() / 100.0)) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setChromaValue(chroma: Int) { + try { + val obj = getSettingsJson() + if (chroma == 0) { + obj.remove(OVERLAY_CHROMA_FACTOR) + } else { + obj.putOpt(OVERLAY_CHROMA_FACTOR, 1.0 + (chroma.toDouble() / 100.0)) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setWholePaletteValue(whole: Boolean) { + try { + val obj = getSettingsJson() + if (!whole) { + obj.remove(OVERLAY_WHOLE_PALETTE) + } else { + obj.putOpt(OVERLAY_WHOLE_PALETTE, 1) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + private fun setTintBackgroundValue(tint: Boolean) { + try { + val obj = getSettingsJson() + if (!tint) { + obj.remove(OVERLAY_TINT_BACKGROUND) + } else { + obj.putOpt(OVERLAY_TINT_BACKGROUND, 1) + } + putSettingsJson(obj) + } catch (e: JSONException) { + // Ignored + } catch (e: IllegalArgumentException) { + // Ignored + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Navigation.java b/src/com/rising/settings/fragments/Navigation.java deleted file mode 100644 index ac05cc88..00000000 --- a/src/com/rising/settings/fragments/Navigation.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.internal.logging.nano.MetricsProto; - -@SearchIndexable -public class Navigation extends SettingsPreferenceFragment { - - public static final String TAG = "Navigation"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_navigation); - } - - public static void reset(Context mContext) { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Secure.putIntForUser(resolver, - Settings.Secure.NAVBAR_LAYOUT_MODE, 0, UserHandle.USER_CURRENT); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_navigation); -} diff --git a/src/com/rising/settings/fragments/Navigation.kt b/src/com/rising/settings/fragments/Navigation.kt new file mode 100644 index 00000000..087d8c32 --- /dev/null +++ b/src/com/rising/settings/fragments/Navigation.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Navigation : OptimizedSettingsFragment() { + + companion object { + const val TAG = "Navigation" + + @JvmStatic + fun reset(mContext: Context) { + val resolver = mContext.contentResolver + Settings.Secure.putIntForUser(resolver, + Settings.Secure.NAVBAR_LAYOUT_MODE, 0, UserHandle.USER_CURRENT) + } + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = BaseSearchIndexProvider(R.xml.rising_settings_navigation) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_navigation) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Notifications.java b/src/com/rising/settings/fragments/Notifications.java deleted file mode 100644 index 1b3ae730..00000000 --- a/src/com/rising/settings/fragments/Notifications.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.utils.SystemRestartUtils; - -import java.util.List; - -@SearchIndexable -public class Notifications extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener { - - public static final String TAG = "Notifications"; - - private static final String COMPACT_HUN_KEY = "persist.sys.compact_hun.enabled"; - - private Preference mCompactHUNPref; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_notification); - mCompactHUNPref = findPreference(COMPACT_HUN_KEY); - mCompactHUNPref.setOnPreferenceChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mCompactHUNPref) { - SystemRestartUtils.showSystemUIRestartDialog(getContext()); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_notification) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Notifications.kt b/src/com/rising/settings/fragments/Notifications.kt new file mode 100644 index 00000000..4cc4919d --- /dev/null +++ b/src/com/rising/settings/fragments/Notifications.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.SystemRestartUtils +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Notifications : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "Notifications" + + private const val COMPACT_HUN_KEY = "persist.sys.compact_hun.enabled" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_notification) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + private var mCompactHUNPref: Preference? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_notification) + mCompactHUNPref = findCachedPreference(COMPACT_HUN_KEY) + mCompactHUNPref?.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + return when (preference) { + mCompactHUNPref -> { + val context = getSafeContext() + context?.let { SystemRestartUtils.showSystemUIRestartDialog(it) } + true + } + else -> false + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/OngoingProgressBar.java b/src/com/rising/settings/fragments/OngoingProgressBar.java deleted file mode 100644 index 66c4c997..00000000 --- a/src/com/rising/settings/fragments/OngoingProgressBar.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class OngoingProgressBar extends SettingsPreferenceFragment { - - public static final String TAG = "OngoingProgressBar"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.ongoing_progress_settings); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.ongoing_progress_settings) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/OngoingProgressBar.kt b/src/com/rising/settings/fragments/OngoingProgressBar.kt new file mode 100644 index 00000000..6f9ac8b6 --- /dev/null +++ b/src/com/rising/settings/fragments/OngoingProgressBar.kt @@ -0,0 +1,38 @@ +package com.rising.settings.fragments + +import android.content.Context +import android.os.Bundle + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class OngoingProgressBar : OptimizedSettingsFragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.ongoing_progress_settings) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + companion object { + const val TAG = "OngoingProgressBar" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.ongoing_progress_settings) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context) + return keys + } + } + } +} diff --git a/src/com/rising/settings/fragments/OptimizedSettingsFragment.kt b/src/com/rising/settings/fragments/OptimizedSettingsFragment.kt new file mode 100644 index 00000000..c0742a14 --- /dev/null +++ b/src/com/rising/settings/fragments/OptimizedSettingsFragment.kt @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import androidx.preference.Preference +import com.android.settings.SettingsPreferenceFragment +import com.android.internal.util.android.ThemeUtils +import java.lang.ref.WeakReference +import java.util.concurrent.ConcurrentHashMap + +/** + * Optimized base class for Settings fragments with performance improvements: + * - Memory leak prevention + * - Resource caching + * - Proper lifecycle management + * - Background task handling + */ +abstract class OptimizedSettingsFragment : SettingsPreferenceFragment() { + + // Safe handler to prevent memory leaks + protected class SafeHandler(fragment: OptimizedSettingsFragment) : Handler(Looper.getMainLooper()) { + private val mFragmentRef = WeakReference(fragment) + + override fun handleMessage(msg: android.os.Message) { + val fragment = mFragmentRef.get() + if (fragment != null && fragment.isAdded) { + super.handleMessage(msg) + } + } + } + + protected var mHandler: SafeHandler? = null + protected open var mThemeUtils: ThemeUtils? = null + + // Cache for preference states to prevent redundant operations + protected val mPreferenceCache = ConcurrentHashMap() + + // Cache for expensive operations + protected val mOperationCache = ConcurrentHashMap() + + // Track if fragment is properly initialized + private var mIsInitialized = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Initialize handler with weak reference + mHandler = SafeHandler(this) + + // Initialize ThemeUtils with null check + activity?.let { + mThemeUtils = ThemeUtils.getInstance(it) + } + + mIsInitialized = true + } + + override fun onDestroy() { + super.onDestroy() + + // Cleanup to prevent memory leaks + mHandler?.let { + it.removeCallbacksAndMessages(null) + mHandler = null + } + + mThemeUtils = null + mPreferenceCache.clear() + mOperationCache.clear() + mIsInitialized = false + } + + override fun onDetach() { + super.onDetach() + + // Additional cleanup + mHandler?.removeCallbacksAndMessages(null) + + mPreferenceCache.clear() + mOperationCache.clear() + } + + /** + * Safe method to check if fragment is properly initialized and attached + */ + protected fun isFragmentReady(): Boolean { + return mIsInitialized && isAdded && activity != null && activity?.isFinishing == false + } + + /** + * Safe method to get context with null checks + */ + protected fun getSafeContext(): Context? { + return if (!isFragmentReady()) null else context + } + + /** + * Cached preference lookup to avoid repeated findViewById calls + */ + @Suppress("UNCHECKED_CAST") + protected fun findCachedPreference(key: String): T? { + var preference = mPreferenceCache[key] as? T + if (preference == null) { + preference = findPreference(key) + if (preference != null) { + mPreferenceCache[key] = preference + } + } + return preference + } + + /** + * Safe method to post delayed tasks with fragment lifecycle checks + */ + protected fun postDelayedSafe(runnable: Runnable, delayMillis: Long) { + if (mHandler != null && isFragmentReady()) { + mHandler?.postDelayed({ + if (isFragmentReady()) { + runnable.run() + } + }, delayMillis) + } + } + + /** + * Safe method to post delayed tasks with fragment lifecycle checks (Kotlin lambda version) + */ + protected inline fun postDelayedSafe(delayMillis: Long, crossinline action: () -> Unit) { + if (mHandler != null && isFragmentReady()) { + mHandler?.postDelayed({ + if (isFragmentReady()) { + action() + } + }, delayMillis) + } + } + + /** + * Cache expensive operations to prevent redundant execution + */ + protected fun cacheOperation(key: String, result: Any) { + mOperationCache[key] = result + } + + /** + * Get cached operation result + */ + @Suppress("UNCHECKED_CAST") + protected fun getCachedOperation(key: String): T? { + return mOperationCache[key] as? T + } + + /** + * Check if operation result is cached + */ + protected fun isOperationCached(key: String): Boolean { + return mOperationCache.containsKey(key) + } + + /** + * Safe ThemeUtils access with lazy initialization + */ + protected fun getSafeThemeUtils(): ThemeUtils? { + if (mThemeUtils == null && getSafeContext() != null) { + mThemeUtils = ThemeUtils.getInstance(getSafeContext()) + } + return mThemeUtils + } + + /** + * Optimized overlay operation with caching + */ + protected fun setOverlayEnabledCached(category: String, packageName: String, target: String) { + val cacheKey = "$category:$packageName:$target" + + // Check if this operation was already performed + if (isOperationCached(cacheKey)) { + return + } + + val themeUtils = getSafeThemeUtils() + if (themeUtils != null) { + themeUtils.setOverlayEnabled(category, packageName, target) + cacheOperation(cacheKey, true) + } + } + + /** + * Clear operation cache when needed (e.g., on preference changes) + */ + protected fun clearOperationCache() { + mOperationCache.clear() + } + + /** + * Safe method to remove callbacks and messages + */ + protected fun removeCallbacks() { + mHandler?.removeCallbacksAndMessages(null) + } +} diff --git a/src/com/rising/settings/fragments/QuickSettings.java b/src/com/rising/settings/fragments/QuickSettings.java deleted file mode 100644 index ecba6f43..00000000 --- a/src/com/rising/settings/fragments/QuickSettings.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.internal.util.android.ThemeUtils; - -import com.android.settings.preferences.CustomSeekBarPreference; -import com.android.settings.preferences.SecureSettingSwitchPreference; - -import com.android.settings.utils.SystemRestartUtils; - -import java.util.List; - -@SearchIndexable -public class QuickSettings extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - public static final String TAG = "QuickSettings"; - - private static final String KEY_QS_UI_STYLE = "qs_tile_ui_style"; - private static final String KEY_QS_PANEL_STYLE = "qs_panel_style"; - private static final String KEY_PREF_TILE_ANIM_STYLE = "qs_tile_animation_style"; - private static final String KEY_PREF_TILE_ANIM_DURATION = "qs_tile_animation_duration"; - private static final String KEY_PREF_TILE_ANIM_INTERPOLATOR = "qs_tile_animation_interpolator"; - private static final String KEY_QS_REFACTOR_ENABLED = "qs_refactor_enabled"; - - private ListPreference mQsUI; - private ListPreference mQsPanelStyle; - private ListPreference mTileAnimationStyle; - private ListPreference mTileAnimationInterpolator; - private CustomSeekBarPreference mTileAnimationDuration; - private Preference mSplitShadePref; - private SecureSettingSwitchPreference mQsRefactorEnabled; - - private ThemeUtils mThemeUtils; - - private Handler mHandler = new Handler(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_qs); - - final Context mContext = getActivity().getApplicationContext(); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - - mQsUI = (ListPreference) findPreference(KEY_QS_UI_STYLE); - mQsUI.setOnPreferenceChangeListener(this); - - mQsPanelStyle = (ListPreference) findPreference(KEY_QS_PANEL_STYLE); - mQsPanelStyle.setOnPreferenceChangeListener(this); - - mSplitShadePref = (Preference) findPreference("qs_split_shade_enabled"); - mSplitShadePref.setOnPreferenceChangeListener(this); - - mQsRefactorEnabled = (SecureSettingSwitchPreference) findPreference(KEY_QS_REFACTOR_ENABLED); - mQsRefactorEnabled.setOnPreferenceChangeListener(this); - - mTileAnimationStyle = (ListPreference) findPreference(KEY_PREF_TILE_ANIM_STYLE); - mTileAnimationDuration = (CustomSeekBarPreference) findPreference(KEY_PREF_TILE_ANIM_DURATION); - mTileAnimationInterpolator = (ListPreference) findPreference(KEY_PREF_TILE_ANIM_INTERPOLATOR); - - mTileAnimationStyle.setOnPreferenceChangeListener(this); - - int tileAnimationStyle = Settings.System.getIntForUser(getActivity().getContentResolver(), - KEY_PREF_TILE_ANIM_STYLE, 0, UserHandle.USER_CURRENT); - updateAnimTileStyle(tileAnimationStyle); - - checkQSOverlays(mContext); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ContentResolver resolver = getActivity().getContentResolver(); - - if (preference == mQsUI) { - int value = Integer.parseInt((String) newValue); - Settings.System.putIntForUser(resolver, - Settings.System.QS_TILE_UI_STYLE, value, UserHandle.USER_CURRENT); - updateQsStyle(getActivity()); - checkQSOverlays(getActivity()); - return true; - } else if (preference == mQsPanelStyle) { - int value = Integer.parseInt((String) newValue); - Settings.System.putIntForUser(resolver, - Settings.System.QS_PANEL_STYLE, value, UserHandle.USER_CURRENT); - updateQsPanelStyle(getActivity()); - checkQSOverlays(getActivity()); - return true; - } else if (preference == mTileAnimationStyle) { - int value = Integer.parseInt((String) newValue); - updateAnimTileStyle(value); - return true; - } else if (preference == mSplitShadePref) { - int value = (boolean) newValue ? 1 : 0; - Settings.System.putIntForUser(resolver, - "qs_split_shade_enabled", value, UserHandle.USER_CURRENT); - updateSplitShadeEnabled(getActivity()); - return true; - } else if (preference == mQsRefactorEnabled) { - // QS Refactor setting changed - restart SystemUI - SystemRestartUtils.restartSystemUI(getContext()); - return true; - } - return false; - } - - private void updateAnimTileStyle(int tileAnimationStyle) { - mTileAnimationDuration.setEnabled(tileAnimationStyle != 0); - mTileAnimationInterpolator.setEnabled(tileAnimationStyle != 0); - } - - private void updateSplitShadeEnabled(Context context) { - ContentResolver resolver = context.getContentResolver(); - boolean splitShadeEnabled = Settings.System.getIntForUser( - resolver, - "qs_split_shade_enabled" , 0, UserHandle.USER_CURRENT) != 0; - String splitShadeStyleCategory = "android.theme.customization.better_qs"; - String overlayThemeTarget = "com.android.systemui"; - String overlayThemePackage = "com.android.system.qs.ui.better_qs"; - if (mThemeUtils == null) { - mThemeUtils = ThemeUtils.getInstance(context); - } - mHandler.postDelayed(() -> { - mThemeUtils.setOverlayEnabled(splitShadeStyleCategory, overlayThemeTarget, overlayThemeTarget); - if (splitShadeEnabled) { - mThemeUtils.setOverlayEnabled(splitShadeStyleCategory, overlayThemePackage, overlayThemeTarget); - } - }, 1250); - } - - private void updateQsStyle(Context context) { - ContentResolver resolver = context.getContentResolver(); - - boolean isA11Style = Settings.System.getIntForUser(resolver, - Settings.System.QS_TILE_UI_STYLE , 0, UserHandle.USER_CURRENT) != 0; - - String qsUIStyleCategory = "android.theme.customization.qs_ui"; - String overlayThemeTarget = "com.android.systemui"; - String overlayThemePackage = "com.android.system.qs.ui.A11"; - - if (mThemeUtils == null) { - mThemeUtils = ThemeUtils.getInstance(context); - } - - // reset all overlays before applying - mThemeUtils.setOverlayEnabled(qsUIStyleCategory, overlayThemeTarget, overlayThemeTarget); - - if (isA11Style) { - mThemeUtils.setOverlayEnabled(qsUIStyleCategory, overlayThemePackage, overlayThemeTarget); - } - } - - private void updateQsPanelStyle(Context context) { - ContentResolver resolver = context.getContentResolver(); - - int qsPanelStyle = Settings.System.getIntForUser(resolver, - Settings.System.QS_PANEL_STYLE, 0, UserHandle.USER_CURRENT); - - String qsPanelStyleCategory = "android.theme.customization.qs_panel"; - String overlayThemeTarget = "com.android.systemui"; - String overlayThemePackage = "com.android.systemui"; - - switch (qsPanelStyle) { - case 1: - overlayThemePackage = "com.android.system.qs.outline"; - break; - case 2: - case 3: - overlayThemePackage = "com.android.system.qs.twotoneaccent"; - break; - case 4: - overlayThemePackage = "com.android.system.qs.shaded"; - break; - case 5: - overlayThemePackage = "com.android.system.qs.cyberpunk"; - break; - case 6: - overlayThemePackage = "com.android.system.qs.neumorph"; - break; - case 7: - overlayThemePackage = "com.android.system.qs.reflected"; - break; - case 8: - overlayThemePackage = "com.android.system.qs.surround"; - break; - case 9: - overlayThemePackage = "com.android.system.qs.thin"; - break; - default: - break; - } - - if (mThemeUtils == null) { - mThemeUtils = ThemeUtils.getInstance(context); - } - - // reset all overlays before applying - mThemeUtils.setOverlayEnabled(qsPanelStyleCategory, overlayThemeTarget, overlayThemeTarget); - - if (qsPanelStyle > 0) { - mThemeUtils.setOverlayEnabled(qsPanelStyleCategory, overlayThemePackage, overlayThemeTarget); - } - } - - private void checkQSOverlays(Context context) { - ContentResolver resolver = context.getContentResolver(); - int isA11Style = Settings.System.getIntForUser(resolver, - Settings.System.QS_TILE_UI_STYLE , 0, UserHandle.USER_CURRENT); - int qsPanelStyle = Settings.System.getIntForUser(resolver, - Settings.System.QS_PANEL_STYLE , 0, UserHandle.USER_CURRENT); - - // Update summaries - int index = mQsUI.findIndexOfValue(Integer.toString(isA11Style)); - mQsUI.setValue(Integer.toString(isA11Style)); - mQsUI.setSummary(mQsUI.getEntries()[index]); - - index = mQsPanelStyle.findIndexOfValue(Integer.toString(qsPanelStyle)); - mQsPanelStyle.setValue(Integer.toString(qsPanelStyle)); - mQsPanelStyle.setSummary(mQsPanelStyle.getEntries()[index]); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_qs) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/QuickSettings.kt b/src/com/rising/settings/fragments/QuickSettings.kt new file mode 100644 index 00000000..9f56057e --- /dev/null +++ b/src/com/rising/settings/fragments/QuickSettings.kt @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.UserHandle +import android.provider.Settings +import androidx.preference.ListPreference +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.internal.util.android.ThemeUtils +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.preferences.CustomSeekBarPreference +import com.android.settings.preferences.SecureSettingSwitchPreference +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.SystemRestartUtils +import com.android.settingslib.search.SearchIndexable +import java.lang.ref.WeakReference + +@SearchIndexable +class QuickSettings : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "QuickSettings" + + private const val KEY_QS_UI_STYLE = "qs_tile_ui_style" + private const val KEY_QS_PANEL_STYLE = "qs_panel_style" + private const val KEY_PREF_TILE_ANIM_STYLE = "qs_tile_animation_style" + private const val KEY_PREF_TILE_ANIM_DURATION = "qs_tile_animation_duration" + private const val KEY_PREF_TILE_ANIM_INTERPOLATOR = "qs_tile_animation_interpolator" + private const val KEY_QS_REFACTOR_ENABLED = "qs_refactor_enabled" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_qs) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + private var mQsUI: ListPreference? = null + private var mQsPanelStyle: ListPreference? = null + private var mTileAnimationStyle: ListPreference? = null + private var mTileAnimationInterpolator: ListPreference? = null + private var mTileAnimationDuration: CustomSeekBarPreference? = null + private var mSplitShadePref: Preference? = null + private var mQsRefactorEnabled: SecureSettingSwitchPreference? = null + + private var mThemeUtils: ThemeUtils? = null + + // Use WeakReference to prevent memory leaks + private class SafeHandler(fragment: QuickSettings) : Handler(Looper.getMainLooper()) { + private val mFragmentRef = WeakReference(fragment) + + override fun handleMessage(msg: android.os.Message) { + val fragment = mFragmentRef.get() + if (fragment != null && fragment.isAdded) { + super.handleMessage(msg) + } + } + } + + private var mHandler: SafeHandler? = null + + // Cache for overlay operations to prevent redundant calls + private var mLastQsUIStyle: String? = null + private var mLastQsPanelStyle: String? = null + private var mLastSplitShadeEnabled = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_qs) + + val mContext = activity?.applicationContext + + // Initialize handler with weak reference + mHandler = SafeHandler(this) + + activity?.let { + mThemeUtils = ThemeUtils.getInstance(it) + } + + mQsUI = findPreference(KEY_QS_UI_STYLE)?.apply { + onPreferenceChangeListener = this@QuickSettings + } + + mQsPanelStyle = findPreference(KEY_QS_PANEL_STYLE)?.apply { + onPreferenceChangeListener = this@QuickSettings + } + + mSplitShadePref = findPreference("qs_split_shade_enabled")?.apply { + onPreferenceChangeListener = this@QuickSettings + } + + mQsRefactorEnabled = findPreference(KEY_QS_REFACTOR_ENABLED)?.apply { + onPreferenceChangeListener = this@QuickSettings + } + + mTileAnimationStyle = findPreference(KEY_PREF_TILE_ANIM_STYLE) + mTileAnimationDuration = findPreference(KEY_PREF_TILE_ANIM_DURATION) + mTileAnimationInterpolator = findPreference(KEY_PREF_TILE_ANIM_INTERPOLATOR) + + mTileAnimationStyle?.onPreferenceChangeListener = this + + val tileAnimationStyle = Settings.System.getIntForUser(activity?.contentResolver, + KEY_PREF_TILE_ANIM_STYLE, 0, UserHandle.USER_CURRENT) + updateAnimTileStyle(tileAnimationStyle) + + mContext?.let { checkQSOverlays(it) } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + val resolver = activity?.contentResolver ?: return false + + return when (preference) { + mQsUI -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(resolver, + Settings.System.QS_TILE_UI_STYLE, value, UserHandle.USER_CURRENT) + activity?.let { updateQsStyle(it) } + activity?.let { checkQSOverlays(it) } + true + } + + mQsPanelStyle -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(resolver, + Settings.System.QS_PANEL_STYLE, value, UserHandle.USER_CURRENT) + activity?.let { updateQsPanelStyle(it) } + activity?.let { checkQSOverlays(it) } + true + } + + mTileAnimationStyle -> { + val value = (newValue as String).toInt() + updateAnimTileStyle(value) + true + } + + mSplitShadePref -> { + val value = if (newValue as Boolean) 1 else 0 + Settings.System.putIntForUser(resolver, + "qs_split_shade_enabled", value, UserHandle.USER_CURRENT) + activity?.let { updateSplitShadeEnabled(it) } + true + } + + mQsRefactorEnabled -> { + // QS Refactor setting changed - restart SystemUI + context?.let { SystemRestartUtils.restartSystemUI(it) } + true + } + + else -> false + } + } + + private fun updateAnimTileStyle(tileAnimationStyle: Int) { + mTileAnimationDuration?.isEnabled = tileAnimationStyle != 0 + mTileAnimationInterpolator?.isEnabled = tileAnimationStyle != 0 + } + + private fun updateSplitShadeEnabled(context: Context) { + val resolver = context.contentResolver + val splitShadeEnabled = Settings.System.getIntForUser( + resolver, + "qs_split_shade_enabled", 0, UserHandle.USER_CURRENT) != 0 + val splitShadeStyleCategory = "android.theme.customization.better_qs" + val overlayThemeTarget = "com.android.systemui" + val overlayThemePackage = "com.android.system.qs.ui.better_qs" + + if (mThemeUtils == null) { + mThemeUtils = ThemeUtils.getInstance(context) + } + + // Optimize: Only apply if state actually changed + if (splitShadeEnabled != mLastSplitShadeEnabled) { + mLastSplitShadeEnabled = splitShadeEnabled + mHandler?.postDelayed({ + if (isAdded && mThemeUtils != null) { + mThemeUtils?.setOverlayEnabled(splitShadeStyleCategory, overlayThemeTarget, overlayThemeTarget) + if (splitShadeEnabled) { + mThemeUtils?.setOverlayEnabled(splitShadeStyleCategory, overlayThemePackage, overlayThemeTarget) + } + } + }, 1250) + } + } + + private fun updateQsStyle(context: Context) { + val resolver = context.contentResolver + + val isA11Style = Settings.System.getIntForUser(resolver, + Settings.System.QS_TILE_UI_STYLE, 0, UserHandle.USER_CURRENT) != 0 + + val currentStyle = if (isA11Style) "A11" else "default" + + // Optimize: Only apply if style actually changed + if (currentStyle == mLastQsUIStyle) { + return + } + mLastQsUIStyle = currentStyle + + val qsUIStyleCategory = "android.theme.customization.qs_ui" + val overlayThemeTarget = "com.android.systemui" + val overlayThemePackage = "com.android.system.qs.ui.A11" + + if (mThemeUtils == null) { + mThemeUtils = ThemeUtils.getInstance(context) + } + + // reset all overlays before applying + mThemeUtils?.setOverlayEnabled(qsUIStyleCategory, overlayThemeTarget, overlayThemeTarget) + + if (isA11Style) { + mThemeUtils?.setOverlayEnabled(qsUIStyleCategory, overlayThemePackage, overlayThemeTarget) + } + } + + private fun updateQsPanelStyle(context: Context) { + val resolver = context.contentResolver + + val qsPanelStyle = Settings.System.getIntForUser(resolver, + Settings.System.QS_PANEL_STYLE, 0, UserHandle.USER_CURRENT) + + val currentPanelStyle = qsPanelStyle.toString() + + // Optimize: Only apply if style actually changed + if (currentPanelStyle == mLastQsPanelStyle) { + return + } + mLastQsPanelStyle = currentPanelStyle + + val qsPanelStyleCategory = "android.theme.customization.qs_panel" + val overlayThemeTarget = "com.android.systemui" + var overlayThemePackage = "com.android.systemui" + + when (qsPanelStyle) { + 1 -> overlayThemePackage = "com.android.system.qs.outline" + 2, 3 -> overlayThemePackage = "com.android.system.qs.twotoneaccent" + 4 -> overlayThemePackage = "com.android.system.qs.shaded" + 5 -> overlayThemePackage = "com.android.system.qs.cyberpunk" + 6 -> overlayThemePackage = "com.android.system.qs.neumorph" + 7 -> overlayThemePackage = "com.android.system.qs.reflected" + 8 -> overlayThemePackage = "com.android.system.qs.surround" + 9 -> overlayThemePackage = "com.android.system.qs.thin" + } + + if (mThemeUtils == null) { + mThemeUtils = ThemeUtils.getInstance(context) + } + + // reset all overlays before applying + mThemeUtils?.setOverlayEnabled(qsPanelStyleCategory, overlayThemeTarget, overlayThemeTarget) + + if (qsPanelStyle > 0) { + mThemeUtils?.setOverlayEnabled(qsPanelStyleCategory, overlayThemePackage, overlayThemeTarget) + } + } + + private fun checkQSOverlays(context: Context) { + val resolver = context.contentResolver + val isA11Style = Settings.System.getIntForUser(resolver, + Settings.System.QS_TILE_UI_STYLE, 0, UserHandle.USER_CURRENT) + val qsPanelStyleValue = Settings.System.getIntForUser(resolver, + Settings.System.QS_PANEL_STYLE, 0, UserHandle.USER_CURRENT) + + // Update summaries + mQsUI?.let { qsUI -> + val index = qsUI.findIndexOfValue(isA11Style.toString()) + if (index >= 0 && index < qsUI.entries.size) { + qsUI.value = isA11Style.toString() + qsUI.summary = qsUI.entries[index] + } + } + + mQsPanelStyle?.let { qsPanelStylePref -> + val index = qsPanelStylePref.findIndexOfValue(qsPanelStyleValue.toString()) + if (index >= 0 && index < qsPanelStylePref.entries.size) { + qsPanelStylePref.value = qsPanelStyleValue.toString() + qsPanelStylePref.summary = qsPanelStylePref.entries[index] + } + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup to prevent memory leaks + mHandler?.let { + it.removeCallbacksAndMessages(null) + mHandler = null + } + mThemeUtils = null + mLastQsUIStyle = null + mLastQsPanelStyle = null + } + + override fun onDetach() { + super.onDetach() + // Additional cleanup + mHandler?.removeCallbacksAndMessages(null) + } +} diff --git a/src/com/rising/settings/fragments/QuickSwitch.java b/src/com/rising/settings/fragments/QuickSwitch.java deleted file mode 100644 index 52899061..00000000 --- a/src/com/rising/settings/fragments/QuickSwitch.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2023 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.SystemProperties; -import android.provider.SearchIndexableResource; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.Utils; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settingslib.search.SearchIndexable; - -import java.util.ArrayList; -import java.util.List; - -import com.android.internal.util.android.SystemRestartUtils; - -@SearchIndexable -public class QuickSwitch extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener, Indexable { - - private static final String TAG = "QuickSwitch"; - - private static final String QUICKSWITCH_KEY = "persist.sys.default_launcher"; - - private ListPreference quickSwitchPref; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.quick_switch); - - int defaultLauncher = SystemProperties.getInt(QUICKSWITCH_KEY, 0); - quickSwitchPref = findPreference(QUICKSWITCH_KEY); - quickSwitchPref.setOnPreferenceChangeListener(this); - Context context = getContext(); - Resources res = context.getResources(); - - String[] launcherEntries = res.getStringArray(R.array.quickswitch_launcher_entries); - String[] launcherValues = res.getStringArray(R.array.quickswitch_launcher_values); - - List quickSwitchEntries = new ArrayList<>(); - List quickSwitchValues = new ArrayList<>(); - - quickSwitchEntries.add(launcherEntries[0]); - quickSwitchValues.add(launcherValues[0]); - - if (SystemProperties.getInt("persist.sys.quickswitch_pixel_shipped", 0) != 0) { - quickSwitchEntries.add(launcherEntries[1]); - quickSwitchValues.add(launcherValues[1]); - } - - if (SystemProperties.getInt("persist.sys.quickswitch_lawnchair_shipped", 0) != 0) { - quickSwitchEntries.add(launcherEntries[2]); - quickSwitchValues.add(launcherValues[2]); - } - - quickSwitchPref.setEntries(quickSwitchEntries.toArray(new CharSequence[0])); - quickSwitchPref.setEntryValues(quickSwitchValues.toArray(new CharSequence[0])); - quickSwitchPref.setValue(String.valueOf(defaultLauncher)); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == quickSwitchPref) { - SystemRestartUtils.showSystemRestartDialog(getContext()); - return true; - } - return false; - } - - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - ArrayList result = - new ArrayList(); - - SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.quick_switch; - result.add(sir); - return result; - } - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/QuickSwitch.kt b/src/com/rising/settings/fragments/QuickSwitch.kt new file mode 100644 index 00000000..a2e60c09 --- /dev/null +++ b/src/com/rising/settings/fragments/QuickSwitch.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import android.os.SystemProperties +import android.provider.SearchIndexableResource +import androidx.preference.ListPreference +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.internal.util.android.SystemRestartUtils +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.Indexable +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class QuickSwitch : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListener, Indexable { + + companion object { + private const val TAG = "QuickSwitch" + private const val QUICKSWITCH_KEY = "persist.sys.default_launcher" + + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider() { + override fun getXmlResourcesToIndex(context: Context, enabled: Boolean): List { + val result = ArrayList() + val sir = SearchIndexableResource(context).apply { + xmlResId = R.xml.quick_switch + } + result.add(sir) + return result + } + + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } + + private lateinit var quickSwitchPref: ListPreference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.quick_switch) + + val defaultLauncher = SystemProperties.getInt(QUICKSWITCH_KEY, 0) + quickSwitchPref = findPreference(QUICKSWITCH_KEY)!! + quickSwitchPref.onPreferenceChangeListener = this + + val context = requireContext() + val res = context.resources + + val launcherEntries = res.getStringArray(R.array.quickswitch_launcher_entries) + val launcherValues = res.getStringArray(R.array.quickswitch_launcher_values) + + val quickSwitchEntries = mutableListOf() + val quickSwitchValues = mutableListOf() + + // Always add the first launcher (default) + quickSwitchEntries.add(launcherEntries[0]) + quickSwitchValues.add(launcherValues[0]) + + // Add Pixel launcher if shipped + if (SystemProperties.getInt("persist.sys.quickswitch_pixel_shipped", 0) != 0) { + quickSwitchEntries.add(launcherEntries[1]) + quickSwitchValues.add(launcherValues[1]) + } + + // Add Lawnchair launcher if shipped + if (SystemProperties.getInt("persist.sys.quickswitch_lawnchair_shipped", 0) != 0) { + quickSwitchEntries.add(launcherEntries[2]) + quickSwitchValues.add(launcherValues[2]) + } + + quickSwitchPref.entries = quickSwitchEntries.toTypedArray() + quickSwitchPref.entryValues = quickSwitchValues.toTypedArray() + quickSwitchPref.value = defaultLauncher.toString() + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + return if (preference == quickSwitchPref) { + SystemRestartUtils.showSystemRestartDialog(context) + true + } else { + false + } + } +} diff --git a/src/com/rising/settings/fragments/Security.java b/src/com/rising/settings/fragments/Security.java deleted file mode 100644 index f68f7c71..00000000 --- a/src/com/rising/settings/fragments/Security.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.Context; -import android.content.ContentResolver; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.SystemProperties; -import android.util.Log; -import android.provider.Settings; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.internal.util.android.SystemRestartUtils; - -import java.util.List; - -@SearchIndexable -public class Security extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener { - - private final static String HIDE_SCREEN_CAPTURE_STATUS_KEY = "hide_screen_capture_status"; - private final static String NO_STORAGE_RESTRICT_KEY = "no_storage_restrict"; - private final static String WINDOW_IGNORE_SECURE_KEY = "window_ignore_secure"; - - Preference mHideScreenCapturePref; - Preference mNoStorageRestrictPref; - Preference mWindowIgnoreSecurePref; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_security); - - mHideScreenCapturePref = findPreference(HIDE_SCREEN_CAPTURE_STATUS_KEY); - mNoStorageRestrictPref = findPreference(NO_STORAGE_RESTRICT_KEY); - mWindowIgnoreSecurePref = findPreference(WINDOW_IGNORE_SECURE_KEY); - - mHideScreenCapturePref.setOnPreferenceChangeListener(this); - mNoStorageRestrictPref.setOnPreferenceChangeListener(this); - mWindowIgnoreSecurePref.setOnPreferenceChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mHideScreenCapturePref - || preference == mNoStorageRestrictPref - || preference == mWindowIgnoreSecurePref) { - SystemRestartUtils.showSystemRestartDialog(getContext()); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_security) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Security.kt b/src/com/rising/settings/fragments/Security.kt new file mode 100644 index 00000000..873e5758 --- /dev/null +++ b/src/com/rising/settings/fragments/Security.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.internal.util.android.SystemRestartUtils +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Security : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private const val HIDE_SCREEN_CAPTURE_STATUS_KEY = "hide_screen_capture_status" + private const val NO_STORAGE_RESTRICT_KEY = "no_storage_restrict" + private const val WINDOW_IGNORE_SECURE_KEY = "window_ignore_secure" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_security) { + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } + + private lateinit var mHideScreenCapturePref: Preference + private lateinit var mNoStorageRestrictPref: Preference + private lateinit var mWindowIgnoreSecurePref: Preference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_security) + + mHideScreenCapturePref = findPreference(HIDE_SCREEN_CAPTURE_STATUS_KEY)!! + mNoStorageRestrictPref = findPreference(NO_STORAGE_RESTRICT_KEY)!! + mWindowIgnoreSecurePref = findPreference(WINDOW_IGNORE_SECURE_KEY)!! + + mHideScreenCapturePref.onPreferenceChangeListener = this + mNoStorageRestrictPref.onPreferenceChangeListener = this + mWindowIgnoreSecurePref.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + return when (preference) { + mHideScreenCapturePref, mNoStorageRestrictPref, mWindowIgnoreSecurePref -> { + SystemRestartUtils.showSystemRestartDialog(context) + true + } + else -> false + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/SmartPowerOff.java b/src/com/rising/settings/fragments/SmartPowerOff.java deleted file mode 100644 index a0d78e83..00000000 --- a/src/com/rising/settings/fragments/SmartPowerOff.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.TimePickerDialog; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.provider.Settings; -import android.text.format.DateFormat; -import android.widget.TimePicker; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.Calendar; -import java.util.List; - -@SearchIndexable -public class SmartPowerOff extends SettingsPreferenceFragment { - - private static final String TAG = "SmartPowerOff"; - - private static final String REBOOT_TIME_KEY = "smart_power_off_time"; - private static final String REBOOT_TIME_PREFERENCE_KEY = "power_off_time_preference"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_smart_power_off); - - Preference timePreference = findPreference(REBOOT_TIME_PREFERENCE_KEY); - if (timePreference != null) { - timePreference.setOnPreferenceClickListener(preference -> { - showTimePicker(); - return true; - }); - updateRebootTimeSummary(timePreference); - } - } - - private void showTimePicker() { - Calendar calendar = Calendar.getInstance(); - int currentHour = calendar.get(Calendar.HOUR_OF_DAY); - int currentMinute = calendar.get(Calendar.MINUTE); - int hour = (currentHour + 1) % 24; - TimePickerDialog timePickerDialog = new TimePickerDialog(getContext(), - (view, hourOfDay, minute) -> { - saveRebootTime(hourOfDay, minute); - }, - hour, currentMinute, DateFormat.is24HourFormat(getContext())); - - timePickerDialog.show(); - } - - private void saveRebootTime(int hourOfDay, int minute) { - Calendar currentCalendar = Calendar.getInstance(); - Calendar selectedCalendar = Calendar.getInstance(); - selectedCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay); - selectedCalendar.set(Calendar.MINUTE, minute); - selectedCalendar.set(Calendar.SECOND, 0); - selectedCalendar.set(Calendar.MILLISECOND, 0); - if (selectedCalendar.getTimeInMillis() <= currentCalendar.getTimeInMillis()) { - selectedCalendar.add(Calendar.DAY_OF_YEAR, 1); - } - String timeValue = String.format("%02d:%02d", selectedCalendar.get(Calendar.HOUR_OF_DAY), selectedCalendar.get(Calendar.MINUTE)); - ContentResolver resolver = getContext().getContentResolver(); - Settings.System.putString(resolver, REBOOT_TIME_KEY, timeValue); - Preference timePreference = findPreference(REBOOT_TIME_PREFERENCE_KEY); - if (timePreference != null) { - updateRebootTimeSummary(timePreference); - } - } - - private void updateRebootTimeSummary(Preference timePreference) { - String timeValue = Settings.System.getString(getContext().getContentResolver(), REBOOT_TIME_KEY); - if (timeValue != null) { - timePreference.setSummary(getContext().getString(R.string.smart_power_off_desc) + " " + timeValue); - } else { - timePreference.setSummary(getContext().getString(R.string.smart_power_off_time_summary)); - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_smart_power_off) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/SmartPowerOff.kt b/src/com/rising/settings/fragments/SmartPowerOff.kt new file mode 100644 index 00000000..8d91d8e8 --- /dev/null +++ b/src/com/rising/settings/fragments/SmartPowerOff.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class SmartPowerOff : OptimizedSettingsFragment() { + + companion object { + const val TAG = "SmartPowerOff" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_smart_power_off) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_smart_power_off) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Sound.java b/src/com/rising/settings/fragments/Sound.java deleted file mode 100644 index cfe24e7a..00000000 --- a/src/com/rising/settings/fragments/Sound.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Sound extends SettingsPreferenceFragment { - - public static final String TAG = "Sound"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_sound); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_sound) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Sound.kt b/src/com/rising/settings/fragments/Sound.kt new file mode 100644 index 00000000..cea0558a --- /dev/null +++ b/src/com/rising/settings/fragments/Sound.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Sound : OptimizedSettingsFragment() { + + companion object { + const val TAG = "Sound" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_sound) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_sound) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Spoof.java b/src/com/rising/settings/fragments/Spoof.java deleted file mode 100644 index 6256c864..00000000 --- a/src/com/rising/settings/fragments/Spoof.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ContentResolver; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.SystemProperties; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.Log; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.Toast; -import android.provider.Settings; - -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.android.SystemRestartUtils; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.search.SearchIndexable; - -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import com.android.settings.preferences.KeyboxDataPreference; -import com.android.settings.preferences.SystemPropertySwitchPreference; -import com.android.settings.utils.DeviceUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -@SearchIndexable -public class Spoof extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - private static final String TAG = "Spoof"; - - private static final String KEY_PIF_JSON_FILE_PREFERENCE = "pif_json_file_preference"; - private static final String KEY_SYSTEM_WIDE_CATEGORY = "spoofing_system_wide_category"; - private static final String KEY_UPDATE_JSON_BUTTON = "update_pif_json"; - private static final String SYS_GMS_SPOOF = "persist.sys.pixelprops.gms"; - private static final String SYS_GOOGLE_SPOOF = "persist.sys.pixelprops"; - private static final String SYS_GAMEPROP_SPOOF = "persist.sys.pixelprops.games"; - private static final String SYS_GPHOTOS_SPOOF = "persist.sys.pixelprops.gphotos"; - private static final String SYS_QSB_SPOOF = "persist.sys.pixelprops.qsb"; - private static final String SYS_SNAP_SPOOF = "persist.sys.pixelprops.snap"; - private static final String SYS_VENDING_SPOOF = "persist.sys.pixelprops.vending"; - private static final String SYS_ENABLE_TENSOR_FEATURES = "persist.sys.features.tensor"; - private static final String KEYBOX_DATA_KEY = "keybox_data_setting"; - - private ActivityResultLauncher mKeyboxFilePickerLauncher; - private KeyboxDataPreference mKeyboxDataPreference; - private Preference mPifJsonFilePreference; - private Preference mUpdateJsonButton; - private PreferenceCategory mSystemWideCategory; - private SystemPropertySwitchPreference mGmsSpoof; - private SystemPropertySwitchPreference mGoogleSpoof; - private SystemPropertySwitchPreference mGamePropsSpoof; - private SystemPropertySwitchPreference mGphotosSpoof; - private SystemPropertySwitchPreference mQsbSpoof; - private SystemPropertySwitchPreference mSnapSpoof; - private SystemPropertySwitchPreference mVendingSpoof; - private SystemPropertySwitchPreference mTensorFeaturesToggle; - private Preference mWikiLink; - - private Handler mHandler; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mHandler = new Handler(); - addPreferencesFromResource(R.xml.rising_settings_spoof); - - final Context context = getContext(); - final ContentResolver resolver = context.getContentResolver(); - final PreferenceScreen prefScreen = getPreferenceScreen(); - final Resources resources = context.getResources(); - - mSystemWideCategory = (PreferenceCategory) findPreference(KEY_SYSTEM_WIDE_CATEGORY); - mGamePropsSpoof = (SystemPropertySwitchPreference) findPreference(SYS_GAMEPROP_SPOOF); - mGphotosSpoof = (SystemPropertySwitchPreference) findPreference(SYS_GPHOTOS_SPOOF); - mGmsSpoof = (SystemPropertySwitchPreference) findPreference(SYS_GMS_SPOOF); - mGoogleSpoof = (SystemPropertySwitchPreference) findPreference(SYS_GOOGLE_SPOOF); - mPifJsonFilePreference = findPreference(KEY_PIF_JSON_FILE_PREFERENCE); - mQsbSpoof = (SystemPropertySwitchPreference) findPreference(SYS_QSB_SPOOF); - mSnapSpoof = (SystemPropertySwitchPreference) findPreference(SYS_SNAP_SPOOF); - mVendingSpoof = (SystemPropertySwitchPreference) findPreference(SYS_VENDING_SPOOF); - mUpdateJsonButton = findPreference(KEY_UPDATE_JSON_BUTTON); - mTensorFeaturesToggle = (SystemPropertySwitchPreference) findPreference(SYS_ENABLE_TENSOR_FEATURES); - - String model = SystemProperties.get("ro.product.model"); - boolean isTensorDevice = model.matches("Pixel [6-9][a-zA-Z ]*"); - boolean isPixelGmsEnabled = SystemProperties.getBoolean(SYS_GMS_SPOOF, true); // Default to Pixel GMS - - if (DeviceUtils.isCurrentlySupportedPixel()) { - mGoogleSpoof.setDefaultValue(false); - if (isMainlineTensorModel(model)) { - mSystemWideCategory.removePreference(mGoogleSpoof); - } - } - - if (isTensorDevice) { - mSystemWideCategory.removePreference(mTensorFeaturesToggle); - } - - mGmsSpoof.setOnPreferenceChangeListener(this); - mGoogleSpoof.setOnPreferenceChangeListener(this); - mGphotosSpoof.setOnPreferenceChangeListener(this); - mGamePropsSpoof.setOnPreferenceChangeListener(this); - mQsbSpoof.setOnPreferenceChangeListener(this); - mSnapSpoof.setOnPreferenceChangeListener(this); - mVendingSpoof.setOnPreferenceChangeListener(this); - mTensorFeaturesToggle.setOnPreferenceChangeListener(this); - - mKeyboxFilePickerLauncher = registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> { - if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { - Uri uri = result.getData().getData(); - Preference pref = findPreference(KEYBOX_DATA_KEY); - if (pref instanceof KeyboxDataPreference) { - ((KeyboxDataPreference) pref).handleFileSelected(uri); - } - } - } - ); - - mPifJsonFilePreference.setOnPreferenceClickListener(preference -> { - openFileSelector(10001); - return true; - }); - - mUpdateJsonButton.setOnPreferenceClickListener(preference -> { - updatePropertiesFromUrl("https://raw.githubusercontent.com/RisingOS-Revived/risingOS_wiki/refs/heads/fifteen/spoofing/PlayIntergrity/pif.json"); - return true; - }); - - mWikiLink = findPreference("wiki_link"); - if (mWikiLink != null) { - mWikiLink.setOnPreferenceClickListener(preference -> { - Uri uri = Uri.parse("https://github.com/RisingOS-Revived/risingOS_wiki"); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - startActivity(intent); - return true; - }); - } - - Preference showPropertiesPref = findPreference("show_pif_properties"); - if (showPropertiesPref != null) { - showPropertiesPref.setOnPreferenceClickListener(preference -> { - showPropertiesDialog(); - return true; - }); - } - } - - private boolean isMainlineTensorModel(String model) { - return model.matches("Pixel [8-9][a-zA-Z ]*"); - } - - private void openFileSelector(int requestCode) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("application/json"); - startActivityForResult(intent, requestCode); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mKeyboxDataPreference = findPreference(KEYBOX_DATA_KEY); - if (mKeyboxDataPreference != null) { - mKeyboxDataPreference.setFilePickerLauncher(mKeyboxFilePickerLauncher); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == Activity.RESULT_OK && data != null) { - Uri uri = data.getData(); - if (uri != null) { - if (requestCode == 10001) { - loadPifJson(uri); - } - } - } - } - - private void showPropertiesDialog() { - StringBuilder properties = new StringBuilder(); - try { - JSONObject jsonObject = new JSONObject(); - String[] keys = { - "persist.sys.pihooks_ID", - "persist.sys.pihooks_BRAND", - "persist.sys.pihooks_DEVICE", - "persist.sys.pihooks_FINGERPRINT", - "persist.sys.pihooks_MANUFACTURER", - "persist.sys.pihooks_MODEL", - "persist.sys.pihooks_PRODUCT", - "persist.sys.pihooks_SECURITY_PATCH", - "persist.sys.pihooks_DEVICE_INITIAL_SDK_INT", - "persist.sys.pihooks_RELEASE", - "persist.sys.pihooks_SDK_INT" - }; - for (String key : keys) { - String value = SystemProperties.get(key, null); - if (value != null) { - String buildKey = key.replace("persist.sys.pihooks_", ""); - jsonObject.put(buildKey, value); - } - } - properties.append(jsonObject.toString(4)); - } catch (JSONException e) { - Log.e(TAG, "Error creating JSON from properties", e); - properties.append(getString(R.string.error_loading_properties)); - } - new AlertDialog.Builder(getContext()) - .setTitle(R.string.show_pif_properties_title) - .setMessage(properties.toString()) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - - private void updatePropertiesFromUrl(String urlString) { - new Thread(() -> { - try { - URL url = new URL(urlString); - HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); - try (InputStream inputStream = urlConnection.getInputStream()) { - String json = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - Log.d(TAG, "Downloaded JSON data: " + json); - JSONObject jsonObject = new JSONObject(json); - String spoofedModel = jsonObject.optString("MODEL", "Unknown model"); - for (Iterator it = jsonObject.keys(); it.hasNext(); ) { - String key = it.next(); - String value = jsonObject.getString(key); - Log.d(TAG, "Setting property: persist.sys.pihooks_" + key + " = " + value); - SystemProperties.set("persist.sys.pihooks_" + key, value); - } - mHandler.post(() -> { - String toastMessage = getString(R.string.toast_spoofing_success, spoofedModel); - Toast.makeText(getContext(), toastMessage, Toast.LENGTH_LONG).show(); - }); - - } finally { - urlConnection.disconnect(); - } - } catch (Exception e) { - Log.e(TAG, "Error downloading JSON or setting properties", e); - mHandler.post(() -> { - Toast.makeText(getContext(), R.string.toast_spoofing_failure, Toast.LENGTH_LONG).show(); - }); - } - mHandler.postDelayed(() -> { - SystemRestartUtils.showSystemRestartDialog(getContext()); - }, 1250); - }).start(); - } - - private void loadPifJson(Uri uri) { - Log.d(TAG, "Loading PIF JSON from URI: " + uri.toString()); - try (InputStream inputStream = getActivity().getContentResolver().openInputStream(uri)) { - if (inputStream != null) { - String json = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); - Log.d(TAG, "PIF JSON data: " + json); - JSONObject jsonObject = new JSONObject(json); - for (Iterator it = jsonObject.keys(); it.hasNext(); ) { - String key = it.next(); - String value = jsonObject.getString(key); - Log.d(TAG, "Setting PIF property: persist.sys.pihooks_" + key + " = " + value); - SystemProperties.set("persist.sys.pihooks_" + key, value); - } - } - } catch (Exception e) { - Log.e(TAG, "Error reading PIF JSON or setting properties", e); - } - mHandler.postDelayed(() -> { - SystemRestartUtils.showSystemRestartDialog(getContext()); - }, 1250); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final Context context = getContext(); - final ContentResolver resolver = context.getContentResolver(); - if (preference == mGmsSpoof - || preference == mGoogleSpoof - || preference == mGphotosSpoof - || preference == mGamePropsSpoof - || preference == mQsbSpoof - || preference == mSnapSpoof - || preference == mVendingSpoof) { - SystemRestartUtils.showSystemRestartDialog(getContext()); - return true; - } - if (preference == mTensorFeaturesToggle) { - boolean enabled = (Boolean) newValue; - SystemProperties.set(SYS_ENABLE_TENSOR_FEATURES, enabled ? "true" : "false"); - SystemRestartUtils.showSystemRestartDialog(getContext()); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_spoof) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - final Resources resources = context.getResources(); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Spoof.kt b/src/com/rising/settings/fragments/Spoof.kt new file mode 100644 index 00000000..8e5ee976 --- /dev/null +++ b/src/com/rising/settings/fragments/Spoof.kt @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.app.Activity +import android.app.AlertDialog +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.content.res.Resources +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.SystemProperties +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.internal.util.android.SystemRestartUtils +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.preferences.KeyboxDataPreference +import com.android.settings.preferences.SystemPropertySwitchPreference +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.DeviceUtils +import com.android.settingslib.search.SearchIndexable +import org.json.JSONException +import org.json.JSONObject +import java.io.InputStream +import java.net.HttpURLConnection +import java.net.URL +import java.nio.charset.StandardCharsets + +@SearchIndexable +class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private const val TAG = "Spoof" + + private const val KEY_PIF_JSON_FILE_PREFERENCE = "pif_json_file_preference" + private const val KEY_SYSTEM_WIDE_CATEGORY = "spoofing_system_wide_category" + private const val KEY_UPDATE_JSON_BUTTON = "update_pif_json" + private const val SYS_GMS_SPOOF = "persist.sys.pixelprops.gms" + private const val SYS_GOOGLE_SPOOF = "persist.sys.pixelprops" + private const val SYS_GAMEPROP_SPOOF = "persist.sys.pixelprops.games" + private const val SYS_GPHOTOS_SPOOF = "persist.sys.pixelprops.gphotos" + private const val SYS_QSB_SPOOF = "persist.sys.pixelprops.qsb" + private const val SYS_SNAP_SPOOF = "persist.sys.pixelprops.snap" + private const val SYS_VENDING_SPOOF = "persist.sys.pixelprops.vending" + private const val SYS_ENABLE_TENSOR_FEATURES = "persist.sys.features.tensor" + private const val KEYBOX_DATA_KEY = "keybox_data_setting" + + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_spoof) { + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } + + private lateinit var mKeyboxFilePickerLauncher: ActivityResultLauncher + private var mKeyboxDataPreference: KeyboxDataPreference? = null + private var mPifJsonFilePreference: Preference? = null + private var mUpdateJsonButton: Preference? = null + private var mSystemWideCategory: PreferenceCategory? = null + private var mGmsSpoof: SystemPropertySwitchPreference? = null + private var mGoogleSpoof: SystemPropertySwitchPreference? = null + private var mGamePropsSpoof: SystemPropertySwitchPreference? = null + private var mGphotosSpoof: SystemPropertySwitchPreference? = null + private var mQsbSpoof: SystemPropertySwitchPreference? = null + private var mSnapSpoof: SystemPropertySwitchPreference? = null + private var mVendingSpoof: SystemPropertySwitchPreference? = null + private var mTensorFeaturesToggle: SystemPropertySwitchPreference? = null + private var mWikiLink: Preference? = null + + private lateinit var mHandler: Handler + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mHandler = Handler(Looper.getMainLooper()) + addPreferencesFromResource(R.xml.rising_settings_spoof) + + val context = requireContext() + val resolver = context.contentResolver + val prefScreen = preferenceScreen + val resources = context.resources + + mSystemWideCategory = findPreference(KEY_SYSTEM_WIDE_CATEGORY) + mGamePropsSpoof = findPreference(SYS_GAMEPROP_SPOOF) + mGphotosSpoof = findPreference(SYS_GPHOTOS_SPOOF) + mGmsSpoof = findPreference(SYS_GMS_SPOOF) + mGoogleSpoof = findPreference(SYS_GOOGLE_SPOOF) + mPifJsonFilePreference = findPreference(KEY_PIF_JSON_FILE_PREFERENCE) + mQsbSpoof = findPreference(SYS_QSB_SPOOF) + mSnapSpoof = findPreference(SYS_SNAP_SPOOF) + mVendingSpoof = findPreference(SYS_VENDING_SPOOF) + mUpdateJsonButton = findPreference(KEY_UPDATE_JSON_BUTTON) + mTensorFeaturesToggle = findPreference(SYS_ENABLE_TENSOR_FEATURES) + + val model = SystemProperties.get("ro.product.model") + val isTensorDevice = model.matches(Regex("Pixel [6-9][a-zA-Z ]*")) + val isPixelGmsEnabled = SystemProperties.getBoolean(SYS_GMS_SPOOF, true) // Default to Pixel GMS + + if (DeviceUtils.isCurrentlySupportedPixel()) { + mGoogleSpoof?.setDefaultValue(false) + if (isMainlineTensorModel(model)) { + mGoogleSpoof?.let { mSystemWideCategory?.removePreference(it as Preference) } + } + } + + if (isTensorDevice) { + mTensorFeaturesToggle?.let { mSystemWideCategory?.removePreference(it as Preference) } + } + + mGmsSpoof?.onPreferenceChangeListener = this + mGoogleSpoof?.onPreferenceChangeListener = this + mGphotosSpoof?.onPreferenceChangeListener = this + mGamePropsSpoof?.onPreferenceChangeListener = this + mQsbSpoof?.onPreferenceChangeListener = this + mSnapSpoof?.onPreferenceChangeListener = this + mVendingSpoof?.onPreferenceChangeListener = this + mTensorFeaturesToggle?.onPreferenceChangeListener = this + + mKeyboxFilePickerLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val uri = result.data?.data + val pref = findPreference(KEYBOX_DATA_KEY) + if (uri != null && pref != null) { + pref.handleFileSelected(uri) + } + } + } + + mPifJsonFilePreference?.setOnPreferenceClickListener { + openFileSelector(10001) + true + } + + mUpdateJsonButton?.setOnPreferenceClickListener { + updatePropertiesFromUrl("https://raw.githubusercontent.com/RisingOS-Revived/risingOS_wiki/refs/heads/fifteen/spoofing/PlayIntergrity/pif.json") + true + } + + mWikiLink = findPreference("wiki_link") + mWikiLink?.setOnPreferenceClickListener { + val uri = Uri.parse("https://github.com/RisingOS-Revived/risingOS_wiki") + val intent = Intent(Intent.ACTION_VIEW, uri) + startActivity(intent) + true + } + + val showPropertiesPref = findPreference("show_pif_properties") + showPropertiesPref?.setOnPreferenceClickListener { + showPropertiesDialog() + true + } + } + + private fun isMainlineTensorModel(model: String): Boolean { + return model.matches(Regex("Pixel [8-9][a-zA-Z ]*")) + } + + private fun openFileSelector(requestCode: Int) { + val intent = Intent(Intent.ACTION_GET_CONTENT).apply { + type = "application/json" + } + @Suppress("DEPRECATION") + startActivityForResult(intent, requestCode) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mKeyboxDataPreference = findPreference(KEYBOX_DATA_KEY) + mKeyboxDataPreference?.setFilePickerLauncher(mKeyboxFilePickerLauncher) + } + + @Suppress("DEPRECATION") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK && data != null) { + val uri = data.data + if (uri != null && requestCode == 10001) { + loadPifJson(uri) + } + } + } + + private fun showPropertiesDialog() { + val properties = StringBuilder() + try { + val jsonObject = JSONObject() + val keys = arrayOf( + "persist.sys.pihooks_ID", + "persist.sys.pihooks_BRAND", + "persist.sys.pihooks_DEVICE", + "persist.sys.pihooks_FINGERPRINT", + "persist.sys.pihooks_MANUFACTURER", + "persist.sys.pihooks_MODEL", + "persist.sys.pihooks_PRODUCT", + "persist.sys.pihooks_SECURITY_PATCH", + "persist.sys.pihooks_DEVICE_INITIAL_SDK_INT", + "persist.sys.pihooks_RELEASE", + "persist.sys.pihooks_SDK_INT" + ) + + for (key in keys) { + val value = SystemProperties.get(key, null) + if (value != null) { + val buildKey = key.replace("persist.sys.pihooks_", "") + jsonObject.put(buildKey, value) + } + } + properties.append(jsonObject.toString(4)) + } catch (e: JSONException) { + Log.e(TAG, "Error creating JSON from properties", e) + properties.append(getString(R.string.error_loading_properties)) + } + + AlertDialog.Builder(requireContext()) + .setTitle(R.string.show_pif_properties_title) + .setMessage(properties.toString()) + .setPositiveButton(android.R.string.ok, null) + .show() + } + + private fun updatePropertiesFromUrl(urlString: String) { + Thread { + try { + val url = URL(urlString) + val urlConnection = url.openConnection() as HttpURLConnection + try { + urlConnection.inputStream.use { inputStream -> + val json = String(inputStream.readAllBytes(), StandardCharsets.UTF_8) + Log.d(TAG, "Downloaded JSON data: $json") + val jsonObject = JSONObject(json) + val spoofedModel = jsonObject.optString("MODEL", "Unknown model") + + val keys = jsonObject.keys() + while (keys.hasNext()) { + val key = keys.next() + val value = jsonObject.getString(key) + Log.d(TAG, "Setting property: persist.sys.pihooks_$key = $value") + SystemProperties.set("persist.sys.pihooks_$key", value) + } + + mHandler.post { + val toastMessage = getString(R.string.toast_spoofing_success, spoofedModel) + Toast.makeText(requireContext(), toastMessage, Toast.LENGTH_LONG).show() + } + } + } finally { + urlConnection.disconnect() + } + } catch (e: Exception) { + Log.e(TAG, "Error downloading JSON or setting properties", e) + mHandler.post { + Toast.makeText(requireContext(), R.string.toast_spoofing_failure, Toast.LENGTH_LONG).show() + } + } + mHandler.postDelayed({ + SystemRestartUtils.showSystemRestartDialog(requireContext()) + }, 1250) + }.start() + } + + private fun loadPifJson(uri: Uri) { + Log.d(TAG, "Loading PIF JSON from URI: $uri") + try { + requireActivity().contentResolver.openInputStream(uri)?.use { inputStream -> + val json = String(inputStream.readAllBytes(), StandardCharsets.UTF_8) + Log.d(TAG, "PIF JSON data: $json") + val jsonObject = JSONObject(json) + + val keys = jsonObject.keys() + while (keys.hasNext()) { + val key = keys.next() + val value = jsonObject.getString(key) + Log.d(TAG, "Setting PIF property: persist.sys.pihooks_$key = $value") + SystemProperties.set("persist.sys.pihooks_$key", value) + } + } + } catch (e: Exception) { + Log.e(TAG, "Error reading PIF JSON or setting properties", e) + } + mHandler.postDelayed({ + SystemRestartUtils.showSystemRestartDialog(requireContext()) + }, 1250) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val context = requireContext() + val resolver = context.contentResolver + + when (preference) { + mGmsSpoof, mGoogleSpoof, mGphotosSpoof, mGamePropsSpoof, + mQsbSpoof, mSnapSpoof, mVendingSpoof -> { + SystemRestartUtils.showSystemRestartDialog(requireContext()) + return true + } + mTensorFeaturesToggle -> { + val enabled = newValue as Boolean + SystemProperties.set(SYS_ENABLE_TENSOR_FEATURES, if (enabled) "true" else "false") + SystemRestartUtils.showSystemRestartDialog(requireContext()) + return true + } + } + return false + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/StatusBar.java b/src/com/rising/settings/fragments/StatusBar.java deleted file mode 100644 index 742d6bd0..00000000 --- a/src/com/rising/settings/fragments/StatusBar.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.preferences.CustomSeekBarPreference; - -import java.util.List; - -@SearchIndexable -public class StatusBar extends SettingsPreferenceFragment { - - public static final String TAG = "StatusBar"; - - private static final String KEY_STATUSBAR_TOP_PADDING = "statusbar_top_padding"; - private static final String KEY_STATUSBAR_LEFT_PADDING = "statusbar_left_padding"; - private static final String KEY_STATUSBAR_RIGHT_PADDING = "statusbar_right_padding"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_status_bar); - - CustomSeekBarPreference leftSeekBar = findPreference(KEY_STATUSBAR_LEFT_PADDING); - int defaultLeftPadding = getResources().getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_start); - leftSeekBar.setDefaultValue(defaultLeftPadding, true); - - CustomSeekBarPreference rightSeekBar = findPreference(KEY_STATUSBAR_RIGHT_PADDING); - int defaultRightPadding = getResources().getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_end); - rightSeekBar.setDefaultValue(defaultRightPadding, true); - - CustomSeekBarPreference topSeekbar = findPreference(KEY_STATUSBAR_TOP_PADDING); - int defaultTopPadding = getResources().getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_top); - topSeekbar.setDefaultValue(defaultTopPadding, true); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_status_bar) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/StatusBar.kt b/src/com/rising/settings/fragments/StatusBar.kt new file mode 100644 index 00000000..178a28cb --- /dev/null +++ b/src/com/rising/settings/fragments/StatusBar.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.preferences.CustomSeekBarPreference +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class StatusBar : OptimizedSettingsFragment() { + + companion object { + const val TAG = "StatusBar" + + private const val KEY_STATUSBAR_TOP_PADDING = "statusbar_top_padding" + private const val KEY_STATUSBAR_LEFT_PADDING = "statusbar_left_padding" + private const val KEY_STATUSBAR_RIGHT_PADDING = "statusbar_right_padding" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_status_bar) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_status_bar) + + // Use cached preference lookup for better performance + val leftSeekBar = findCachedPreference(KEY_STATUSBAR_LEFT_PADDING) + leftSeekBar?.let { seekBar -> + resources?.let { res -> + val defaultLeftPadding = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_start) + seekBar.setDefaultValue(defaultLeftPadding, true) + } + } + + val rightSeekBar = findCachedPreference(KEY_STATUSBAR_RIGHT_PADDING) + rightSeekBar?.let { seekBar -> + resources?.let { res -> + val defaultRightPadding = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_end) + seekBar.setDefaultValue(defaultRightPadding, true) + } + } + + val topSeekbar = findCachedPreference(KEY_STATUSBAR_TOP_PADDING) + topSeekbar?.let { seekBar -> + resources?.let { res -> + val defaultTopPadding = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_padding_top) + seekBar.setDefaultValue(defaultTopPadding, true) + } + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Themes.java b/src/com/rising/settings/fragments/Themes.java deleted file mode 100644 index 23b5aca8..00000000 --- a/src/com/rising/settings/fragments/Themes.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.utils.SystemRestartUtils; -import com.android.settingslib.search.SearchIndexable; - -import com.android.internal.util.android.ThemeUtils; - -import com.android.settings.preferences.GlobalSettingListPreference; -import com.android.settings.utils.SystemRestartUtils; - -import java.util.List; - -@SearchIndexable -public class Themes extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - public static final String TAG = "Themes"; - private static final String KEY_PGB_STYLE = "progress_bar_style"; - private static final String KEY_NOTIF_STYLE = "notification_style"; - private static final String KEY_POWERMENU_STYLE = "powermenu_style"; - private static final String KEY_HIDE_IME_STYLE = "hide_ime_space_style"; - private static final String KEY_LOCK_SOUND = "lock_sound"; - private static final String KEY_UNLOCK_SOUND = "unlock_sound"; - - private static final String[] POWER_MENU_OVERLAYS = { - "com.android.theme.powermenu.cyberpunk", - "com.android.theme.powermenu.duoline", - "com.android.theme.powermenu.ios", - "com.android.theme.powermenu.layers" - }; - - private static final String[] NOTIF_OVERLAYS = { - "com.android.theme.notification.cyberpunk", - "com.android.theme.notification.duoline", - "com.android.theme.notification.ios", - "com.android.theme.notification.layers" - }; - - private static final String[] PROGRESS_BAR_OVERLAYS = { - "com.android.theme.progressbar.blocky_thumb", - "com.android.theme.progressbar.minimal_thumb", - "com.android.theme.progressbar.outline_thumb", - "com.android.theme.progressbar.shishu" - }; - - private static final String[] HIDE_IME_OVERLAYS = { - "com.android.system.theme.hide_ime_space_narrow", - "com.android.system.theme.hide_ime_space_no_space", - }; - - private ThemeUtils mThemeUtils; - private Preference mProgressBarPref; - private Preference mNotificationStylePref; - private Preference mPowerMenuStylePref; - private Preference mHideImePref; - private GlobalSettingListPreference mLockSound; - private GlobalSettingListPreference mUnlockSound; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_themes); - mThemeUtils = ThemeUtils.getInstance(getActivity()); - - mProgressBarPref = findPreference(KEY_PGB_STYLE); - mProgressBarPref.setOnPreferenceChangeListener(this); - - mNotificationStylePref = findPreference(KEY_NOTIF_STYLE); - mNotificationStylePref.setOnPreferenceChangeListener(this); - - mPowerMenuStylePref = findPreference(KEY_POWERMENU_STYLE); - mPowerMenuStylePref.setOnPreferenceChangeListener(this); - - mHideImePref = findPreference(KEY_HIDE_IME_STYLE); - mHideImePref.setOnPreferenceChangeListener(this); - - mLockSound = (GlobalSettingListPreference) findPreference(KEY_LOCK_SOUND); - mLockSound.setOnPreferenceChangeListener(this); - mUnlockSound = (GlobalSettingListPreference) findPreference(KEY_UNLOCK_SOUND); - mUnlockSound.setOnPreferenceChangeListener(this); - - com.android.settingslib.widget.LayoutPreference highlightPref = getPreferenceScreen().findPreference("themes_highlight_dashboard"); - if (highlightPref != null) { - java.util.Map highlightClickMap = new java.util.HashMap<>(); - highlightClickMap.put(R.id.boot_styles_tile, "PersonalizationsBSActivity"); - highlightClickMap.put(R.id.icon_pack_tile, "PersonalizationsIconPackActivity"); - highlightClickMap.put(R.id.settings_tile, "PersonalizationsSettingsUIActivity"); - highlightClickMap.put(R.id.wallpaper_styles_tile, "PersonalizationsWSActivity"); - com.android.settings.utils.HighlightPrefUtils.Companion.setupHighlightPref(getContext(), highlightPref, highlightClickMap); - } - } - - private void updateStyle(String key, String category, String target, - int defaultValue, String[] overlayPackages, boolean restartSystemUI) { - final int style = Settings.System.getIntForUser( - getContext().getContentResolver(), - key, - defaultValue, - UserHandle.USER_CURRENT - ); - if (mThemeUtils == null) { - mThemeUtils = ThemeUtils.getInstance(getContext()); - } - mThemeUtils.setOverlayEnabled(category, target, target); - if (style > 0 && style <= overlayPackages.length) { - mThemeUtils.setOverlayEnabled(category, overlayPackages[style - 1], target); - } - if (restartSystemUI) { - SystemRestartUtils.restartSystemUI(getContext()); - } - } - - private void updatePowerMenuStyle() { - updateStyle(KEY_POWERMENU_STYLE, "android.theme.customization.powermenu", "com.android.systemui", 0, POWER_MENU_OVERLAYS, false); - } - - private void updateNotifStyle() { - updateStyle(KEY_NOTIF_STYLE, "android.theme.customization.notification", "com.android.systemui", 0, NOTIF_OVERLAYS, true); - } - - private void updateProgressBarStyle() { - updateStyle(KEY_PGB_STYLE, "android.theme.customization.progress_bar", "android", 0, PROGRESS_BAR_OVERLAYS, false); - } - - private void updateHideImeSpaceStyle() { - updateStyle(KEY_HIDE_IME_STYLE, "android.theme.customization.hide_ime_space", "android", 0, HIDE_IME_OVERLAYS, false); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mLockSound || preference == mUnlockSound) { - SystemRestartUtils.showSystemUIRestartDialog(getContext()); - return true; - } - - int value = Integer.parseInt((String) newValue); - if (preference == mProgressBarPref) { - Settings.System.putIntForUser(getActivity().getContentResolver(), - KEY_PGB_STYLE, value, UserHandle.USER_CURRENT); - updateProgressBarStyle(); - return true; - } else if (preference == mNotificationStylePref) { - Settings.System.putIntForUser(getActivity().getContentResolver(), - KEY_NOTIF_STYLE, value, UserHandle.USER_CURRENT); - updateNotifStyle(); - return true; - } else if (preference == mPowerMenuStylePref) { - Settings.System.putIntForUser(getActivity().getContentResolver(), - KEY_POWERMENU_STYLE, value, UserHandle.USER_CURRENT); - updatePowerMenuStyle(); - return true; - } else if (preference == mHideImePref) { - Settings.System.putIntForUser(getActivity().getContentResolver(), - KEY_HIDE_IME_STYLE, value, UserHandle.USER_CURRENT); - updateHideImeSpaceStyle(); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_themes) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Themes.kt b/src/com/rising/settings/fragments/Themes.kt new file mode 100644 index 00000000..31e6ae09 --- /dev/null +++ b/src/com/rising/settings/fragments/Themes.kt @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.internal.util.android.ThemeUtils +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.preferences.GlobalSettingListPreference +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.SystemRestartUtils +import com.android.settingslib.search.SearchIndexable +import java.util.concurrent.ConcurrentHashMap + +@SearchIndexable +class Themes : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "Themes" + private const val KEY_PGB_STYLE = "progress_bar_style" + private const val KEY_NOTIF_STYLE = "notification_style" + private const val KEY_POWERMENU_STYLE = "powermenu_style" + private const val KEY_HIDE_IME_STYLE = "hide_ime_space_style" + private const val KEY_LOCK_SOUND = "lock_sound" + private const val KEY_UNLOCK_SOUND = "unlock_sound" + + private val POWER_MENU_OVERLAYS = arrayOf( + "com.android.theme.powermenu.cyberpunk", + "com.android.theme.powermenu.duoline", + "com.android.theme.powermenu.ios", + "com.android.theme.powermenu.layers" + ) + + private val NOTIF_OVERLAYS = arrayOf( + "com.android.theme.notification.cyberpunk", + "com.android.theme.notification.duoline", + "com.android.theme.notification.ios", + "com.android.theme.notification.layers" + ) + + private val PROGRESS_BAR_OVERLAYS = arrayOf( + "com.android.theme.progressbar.blocky_thumb", + "com.android.theme.progressbar.minimal_thumb", + "com.android.theme.progressbar.outline_thumb", + "com.android.theme.progressbar.shishu" + ) + + private val HIDE_IME_OVERLAYS = arrayOf( + "com.android.system.theme.hide_ime_space_narrow", + "com.android.system.theme.hide_ime_space_no_space" + ) + + // Cache keys + private const val CACHE_KEY_PROGRESS_BAR = "progress_bar_style" + private const val CACHE_KEY_NOTIFICATION = "notification_style" + private const val CACHE_KEY_POWER_MENU = "powermenu_style" + private const val CACHE_KEY_HIDE_IME = "hide_ime_style" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_themes) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + private var mThemeUtils: ThemeUtils? = null + private var mProgressBarPref: Preference? = null + private var mNotificationStylePref: Preference? = null + private var mPowerMenuStylePref: Preference? = null + private var mHideImePref: Preference? = null + private var mLockSound: GlobalSettingListPreference? = null + private var mUnlockSound: GlobalSettingListPreference? = null + + // Cache for style states to prevent redundant operations + private val mStyleCache = ConcurrentHashMap() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_themes) + + // Initialize ThemeUtils with null check + activity?.let { activity -> + mThemeUtils = ThemeUtils.getInstance(activity) + } + + mProgressBarPref = findPreference(KEY_PGB_STYLE) + mProgressBarPref?.onPreferenceChangeListener = this + + mNotificationStylePref = findPreference(KEY_NOTIF_STYLE) + mNotificationStylePref?.onPreferenceChangeListener = this + + mPowerMenuStylePref = findPreference(KEY_POWERMENU_STYLE) + mPowerMenuStylePref?.onPreferenceChangeListener = this + + mHideImePref = findPreference(KEY_HIDE_IME_STYLE) + mHideImePref?.onPreferenceChangeListener = this + + mLockSound = findPreference(KEY_LOCK_SOUND) + mLockSound?.onPreferenceChangeListener = this + mUnlockSound = findPreference(KEY_UNLOCK_SOUND) + mUnlockSound?.onPreferenceChangeListener = this + + // Initialize highlight preferences with null checks + preferenceScreen?.let { screen -> + val highlightPref = screen.findPreference("themes_highlight_dashboard") + highlightPref?.let { pref -> + context?.let { ctx -> + val highlightClickMap = hashMapOf().apply { + put(R.id.boot_styles_tile, "PersonalizationsBSActivity") + put(R.id.icon_pack_tile, "PersonalizationsIconPackActivity") + put(R.id.settings_tile, "PersonalizationsSettingsUIActivity") + put(R.id.wallpaper_styles_tile, "PersonalizationsWSActivity") + } + com.android.settings.utils.HighlightPrefUtils.setupHighlightPref(ctx, pref, highlightClickMap) + } + } + } + } + + private fun updateStyle(key: String, category: String, target: String, + defaultValue: Int, overlayPackages: Array, restartSystemUI: Boolean) { + val style = Settings.System.getIntForUser( + context?.contentResolver, + key, + defaultValue, + UserHandle.USER_CURRENT + ) + + // Check cache to avoid redundant operations + val cachedStyle = mStyleCache[key] + if (cachedStyle != null && cachedStyle == style) { + return // Style hasn't changed, skip update + } + + // Update cache + mStyleCache[key] = style + + if (mThemeUtils == null && context != null) { + mThemeUtils = ThemeUtils.getInstance(context) + } + + mThemeUtils?.let { themeUtils -> + themeUtils.setOverlayEnabled(category, target, target) + if (style > 0 && style <= overlayPackages.size) { + themeUtils.setOverlayEnabled(category, overlayPackages[style - 1], target) + } + } + + if (restartSystemUI) { + context?.let { SystemRestartUtils.restartSystemUI(it) } + } + } + + private fun updatePowerMenuStyle() { + updateStyle(KEY_POWERMENU_STYLE, "android.theme.customization.powermenu", "com.android.systemui", 0, POWER_MENU_OVERLAYS, false) + } + + private fun updateNotifStyle() { + updateStyle(KEY_NOTIF_STYLE, "android.theme.customization.notification", "com.android.systemui", 0, NOTIF_OVERLAYS, true) + } + + private fun updateProgressBarStyle() { + updateStyle(KEY_PGB_STYLE, "android.theme.customization.progress_bar", "android", 0, PROGRESS_BAR_OVERLAYS, false) + } + + private fun updateHideImeSpaceStyle() { + updateStyle(KEY_HIDE_IME_STYLE, "android.theme.customization.hide_ime_space", "android", 0, HIDE_IME_OVERLAYS, false) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + return when (preference) { + mLockSound, mUnlockSound -> { + context?.let { SystemRestartUtils.showSystemUIRestartDialog(it) } + true + } + + mProgressBarPref -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(activity?.contentResolver, + KEY_PGB_STYLE, value, UserHandle.USER_CURRENT) + updateProgressBarStyle() + true + } + + mNotificationStylePref -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(activity?.contentResolver, + KEY_NOTIF_STYLE, value, UserHandle.USER_CURRENT) + updateNotifStyle() + true + } + + mPowerMenuStylePref -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(activity?.contentResolver, + KEY_POWERMENU_STYLE, value, UserHandle.USER_CURRENT) + updatePowerMenuStyle() + true + } + + mHideImePref -> { + val value = (newValue as String).toInt() + Settings.System.putIntForUser(activity?.contentResolver, + KEY_HIDE_IME_STYLE, value, UserHandle.USER_CURRENT) + updateHideImeSpaceStyle() + true + } + + else -> false + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onDestroy() { + super.onDestroy() + // Clear cache and cleanup resources + mStyleCache.clear() + mThemeUtils = null + } + + override fun onDetach() { + super.onDetach() + // Additional cleanup + mStyleCache.clear() + } +} diff --git a/src/com/rising/settings/fragments/Toolbox.java b/src/com/rising/settings/fragments/Toolbox.java deleted file mode 100644 index 908d7fa7..00000000 --- a/src/com/rising/settings/fragments/Toolbox.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Toolbox extends SettingsPreferenceFragment { - - public static final String TAG = "Toolbox"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_toolbox); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_toolbox) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Toolbox.kt b/src/com/rising/settings/fragments/Toolbox.kt new file mode 100644 index 00000000..6f38fe4c --- /dev/null +++ b/src/com/rising/settings/fragments/Toolbox.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Toolbox : OptimizedSettingsFragment() { + + companion object { + const val TAG = "Toolbox" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_toolbox) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_toolbox) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/Wallpaper.java b/src/com/rising/settings/fragments/Wallpaper.java deleted file mode 100644 index a4a85231..00000000 --- a/src/com/rising/settings/fragments/Wallpaper.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.content.Context; -import android.os.Bundle; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.preferences.CustomSeekBarPreference; - -import java.util.List; - -import com.android.settings.utils.SystemRestartUtils; - -@SearchIndexable -public class Wallpaper extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - public static final String TAG = "Wallpaper"; - - private Preference mBlurWpPref; - private Preference mBlurWpStylePref; - private Preference mDimPref; - private Preference mDimLvlPref; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_wallpaper); - mBlurWpPref = findPreference("persist.sys.wallpaper.blur_enabled"); - mBlurWpPref.setOnPreferenceChangeListener(this); - mBlurWpStylePref = findPreference("persist.sys.wallpaper.blur_type"); - mBlurWpStylePref.setOnPreferenceChangeListener(this); - mDimPref = findPreference("persist.sys.wallpaper.dim_enabled"); - mDimPref.setOnPreferenceChangeListener(this); - mDimLvlPref = findPreference("persist.sys.wallpaper.dim_level"); - mDimLvlPref.setOnPreferenceChangeListener(this); - } - - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mBlurWpPref - || preference == mBlurWpStylePref - || preference == mDimPref - || preference == mDimLvlPref) { - if (preference == mDimLvlPref) { - android.os.SystemProperties.set("persist.sys.wallpaper.dim_level", newValue.toString()); - } - SystemRestartUtils.showSystemUIRestartDialog(getContext()); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_wallpaper) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/Wallpaper.kt b/src/com/rising/settings/fragments/Wallpaper.kt new file mode 100644 index 00000000..f47403ca --- /dev/null +++ b/src/com/rising/settings/fragments/Wallpaper.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.content.Context +import android.os.Bundle +import android.os.SystemProperties +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.SystemRestartUtils +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Wallpaper : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "Wallpaper" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_wallpaper) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + private var mBlurWpPref: Preference? = null + private var mBlurWpStylePref: Preference? = null + private var mDimPref: Preference? = null + private var mDimLvlPref: Preference? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_wallpaper) + mBlurWpPref = findPreference("persist.sys.wallpaper.blur_enabled") + mBlurWpPref?.onPreferenceChangeListener = this + mBlurWpStylePref = findPreference("persist.sys.wallpaper.blur_type") + mBlurWpStylePref?.onPreferenceChangeListener = this + mDimPref = findPreference("persist.sys.wallpaper.dim_enabled") + mDimPref?.onPreferenceChangeListener = this + mDimLvlPref = findPreference("persist.sys.wallpaper.dim_level") + mDimLvlPref?.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + // Use safe context access + val context = getSafeContext() ?: return false + + return when (preference) { + mBlurWpPref, mBlurWpStylePref, mDimPref, mDimLvlPref -> { + if (preference == mDimLvlPref) { + SystemProperties.set("persist.sys.wallpaper.dim_level", newValue.toString()) + } + SystemRestartUtils.showSystemUIRestartDialog(context) + true + } + else -> false + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/WallpaperDepth.java b/src/com/rising/settings/fragments/WallpaperDepth.java deleted file mode 100644 index b268d2e7..00000000 --- a/src/com/rising/settings/fragments/WallpaperDepth.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.MediaStore; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.text.TextUtils; -import android.widget.Toast; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.SwitchPreferenceCompat; - -import com.android.internal.logging.nano.MetricsProto; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.utils.ImageUtils; - -import java.util.List; - -@SearchIndexable -public class WallpaperDepth extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - public static final String TAG = "WallpaperDepth"; - - private Preference mDepthWallpaperCustomImagePicker; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_wallpaper_depth); - - mDepthWallpaperCustomImagePicker = findPreference("depth_wallpaper_subject_image_uri"); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - if (preference == mDepthWallpaperCustomImagePicker) { - try { - Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(intent, 10001); - } catch(Exception e) { - Toast.makeText(getContext(), R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show(); - } - return true; - } - return super.onPreferenceTreeClick(preference); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent result) { - if (requestCode == 10001) { - if (resultCode != Activity.RESULT_OK) { - return; - } - - final Uri imgUri = result.getData(); - if (imgUri != null) { - String savedImagePath = ImageUtils.saveImageToInternalStorage(getContext(), imgUri, "depthwallpaper", "DEPTH_WALLPAPER_SUBJECT"); - if (savedImagePath != null) { - ContentResolver resolver = getContext().getContentResolver(); - Settings.System.putStringForUser(resolver, "depth_wallpaper_subject_image_uri", savedImagePath, UserHandle.USER_CURRENT); - } - } - } - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_wallpaper_depth) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/WallpaperDepth.kt b/src/com/rising/settings/fragments/WallpaperDepth.kt new file mode 100644 index 00000000..0692ef44 --- /dev/null +++ b/src/com/rising/settings/fragments/WallpaperDepth.kt @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments + +import android.app.Activity +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.UserHandle +import android.provider.MediaStore +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.text.TextUtils +import android.widget.Toast + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.SwitchPreferenceCompat + +import com.android.internal.logging.nano.MetricsProto + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +import com.android.settings.utils.ImageUtils + +@SearchIndexable +class WallpaperDepth : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + private var mDepthWallpaperCustomImagePicker: Preference? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_wallpaper_depth) + + mDepthWallpaperCustomImagePicker = findPreference("depth_wallpaper_subject_image_uri") + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + return false + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { + if (preference == mDepthWallpaperCustomImagePicker) { + try { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + intent.type = "image/*" + startActivityForResult(intent, 10001) + } catch (e: Exception) { + Toast.makeText(context, R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show() + } + return true + } + return super.onPreferenceTreeClick(preference) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, result: Intent?) { + if (requestCode == 10001) { + if (resultCode != Activity.RESULT_OK) { + return + } + + val imgUri = result?.data + if (imgUri != null) { + val savedImagePath = context?.let { ctx -> + ImageUtils.saveImageToInternalStorage( + ctx, imgUri, "depthwallpaper", "DEPTH_WALLPAPER_SUBJECT" + ) + } + if (savedImagePath != null) { + val resolver = context?.contentResolver + resolver?.let { + Settings.System.putStringForUser( + it, "depth_wallpaper_subject_image_uri", + savedImagePath, UserHandle.USER_CURRENT + ) + } + } + } + } + } + + companion object { + const val TAG = "WallpaperDepth" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_wallpaper_depth) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context) + return keys + } + } + } +} diff --git a/src/com/rising/settings/fragments/about/ChangelogActivity.java b/src/com/rising/settings/fragments/about/ChangelogActivity.kt similarity index 60% rename from src/com/rising/settings/fragments/about/ChangelogActivity.java rename to src/com/rising/settings/fragments/about/ChangelogActivity.kt index f2ea562f..c420a400 100644 --- a/src/com/rising/settings/fragments/about/ChangelogActivity.java +++ b/src/com/rising/settings/fragments/about/ChangelogActivity.kt @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.rising.settings.fragments.about; +package com.rising.settings.fragments.about -import android.os.Bundle; -import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; +import android.os.Bundle +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity -public class ChangelogActivity extends CollapsingToolbarBaseActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getFragmentManager().beginTransaction().replace( - com.android.settingslib.collapsingtoolbar.R.id.content_frame, - new ChangelogFragment()).commit(); +class ChangelogActivity : CollapsingToolbarBaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + fragmentManager.beginTransaction().replace( + com.android.settingslib.collapsingtoolbar.R.id.content_frame, + ChangelogFragment() + ).commit() } } diff --git a/src/com/rising/settings/fragments/about/ChangelogFragment.java b/src/com/rising/settings/fragments/about/ChangelogFragment.java deleted file mode 100644 index ac34c938..00000000 --- a/src/com/rising/settings/fragments/about/ChangelogFragment.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2016-2021 crDroid Android Project - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.about; - -import android.os.AsyncTask; -import android.os.Bundle; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.text.SpannableStringBuilder; -import android.text.style.StyleSpan; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.preference.PreferenceFragment; - -import com.android.settings.R; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ChangelogFragment extends PreferenceFragment { - - TextView textView; - - private static final String README_URL = "https://raw.githubusercontent.com/RisingOS-Revived/risingOS_changelogs/fifteen/README.md"; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.changelog, container, false); - } - - @Override - public void onViewCreated(final View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - textView = view.findViewById(R.id.changelog_text); - new FetchReadmeTask().execute(README_URL); - } - - private class FetchReadmeTask extends AsyncTask { - - @Override - protected String doInBackground(String... params) { - String readmeUrl = params[0]; - try { - URL url = new URL(readmeUrl); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream()); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - StringBuilder stringBuilder = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - stringBuilder.append(line).append("\n"); - } - bufferedReader.close(); - inputStreamReader.close(); - return stringBuilder.toString(); - } catch (IOException e) { - return ""; - } - } - - @Override - protected void onPostExecute(String result) { - if (result != null) { - Pattern pattern = Pattern.compile("\\*\\*(.*?)\\*\\*"); - Matcher matcher = pattern.matcher(result); - SpannableStringBuilder spannableBuilder = new SpannableStringBuilder(); - int lastEnd = 0; - while (matcher.find()) { - int start = matcher.start(); - int end = matcher.end(); - String matchedText = matcher.group(1); - spannableBuilder.append(result.subSequence(lastEnd, start)); - spannableBuilder.append(matchedText, new StyleSpan(android.graphics.Typeface.BOLD), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); - lastEnd = end; - } - spannableBuilder.append(result.subSequence(lastEnd, result.length())); - textView.setText(spannableBuilder); - textView.setMovementMethod(LinkMovementMethod.getInstance()); - } - } - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - } -} diff --git a/src/com/rising/settings/fragments/about/ChangelogFragment.kt b/src/com/rising/settings/fragments/about/ChangelogFragment.kt new file mode 100644 index 00000000..ab11a291 --- /dev/null +++ b/src/com/rising/settings/fragments/about/ChangelogFragment.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016-2021 crDroid Android Project + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.about + +import java.util.concurrent.Executors +import java.util.concurrent.ExecutorService +import android.os.Bundle +import android.text.Html +import android.text.method.LinkMovementMethod +import android.text.SpannableStringBuilder +import android.text.style.StyleSpan +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView + +import androidx.preference.PreferenceFragment + +import com.android.settings.R + +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.net.HttpURLConnection +import java.net.URL +import java.util.regex.Pattern + +class ChangelogFragment : PreferenceFragment() { + + private lateinit var textView: TextView + + companion object { + private const val README_URL = "https://raw.githubusercontent.com/RisingOS-Revived/risingOS_changelogs/fifteen/README.md" + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return inflater.inflate(R.layout.changelog, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + textView = view.findViewById(R.id.changelog_text) + fetchReadmeContent(README_URL) + } + + private val executor: ExecutorService = Executors.newSingleThreadExecutor() + + private fun fetchReadmeContent(readmeUrl: String) { + executor.execute { + val content = try { + val url = URL(readmeUrl) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "GET" + val inputStreamReader = InputStreamReader(connection.inputStream) + val bufferedReader = BufferedReader(inputStreamReader) + val stringBuilder = StringBuilder() + var line: String? + while (bufferedReader.readLine().also { line = it } != null) { + stringBuilder.append(line).append("\n") + } + bufferedReader.close() + inputStreamReader.close() + stringBuilder.toString() + } catch (e: IOException) { + "" + } + + // Update UI on main thread + activity?.runOnUiThread { + if (isAdded && content.isNotEmpty()) { + updateTextView(content) + } + } + } + } + + private fun updateTextView(content: String) { + val pattern = Pattern.compile("\\*\\*(.*?)\\*\\*") + val matcher = pattern.matcher(content) + val spannableBuilder = SpannableStringBuilder() + var lastEnd = 0 + while (matcher.find()) { + val start = matcher.start() + val end = matcher.end() + val matchedText = matcher.group(1) + spannableBuilder.append(content.subSequence(lastEnd, start)) + spannableBuilder.append( + matchedText, + StyleSpan(android.graphics.Typeface.BOLD), + SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE + ) + lastEnd = end + } + spannableBuilder.append(content.subSequence(lastEnd, content.length)) + textView.text = spannableBuilder + textView.movementMethod = LinkMovementMethod.getInstance() + } + + override fun onDestroy() { + super.onDestroy() + executor.shutdown() + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.java b/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.java deleted file mode 100644 index 5c7488f8..00000000 --- a/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.java +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (C) 2023-2024 The risingOS Android Project - * Copyright (C) 2024-2025 Project Infinity X - * - * 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.rising.settings.fragments.lockscreen; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.Typeface; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.TextClock; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.utils.SystemRestartUtils; - -import com.android.internal.util.android.ThemeUtils; -import com.rising.settings.fragments.ui.fonts.FontArrayAdapter; -import com.rising.settings.fragments.ui.fonts.FontManager; -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; - -import java.util.List; - -public class LockClockFontsPickerPreview extends SettingsPreferenceFragment { - - private static final String TAG = "LockClockFontsPickerPreview"; - private static final String PREF_FIRST_TIME = "first_time_clock_face_access"; - - private ViewPager viewPager; - private ClockPagerAdapter pagerAdapter; - private FontManager fontManager; - private ExtendedFloatingActionButton applyFab; - private View highlightGuide; - private TextView clockNameTextView; - - private int mCurrentFontPosition = -1; - private int mClockPosition = 0; - - private ThemeUtils mThemeUtils; - private Handler mHandler = new Handler(); - - private final static int[] mCenterClocks = {2, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16}; - - private static final int[] CLOCK_LAYOUTS = { - R.layout.keyguard_clock_default, - R.layout.keyguard_clock_oos, - R.layout.keyguard_clock_center, - R.layout.keyguard_clock_simple, - R.layout.keyguard_clock_miui, - R.layout.keyguard_clock_ide, - R.layout.keyguard_clock_moto, - R.layout.keyguard_clock_stylish, - R.layout.keyguard_clock_stylish2, - R.layout.keyguard_clock_stylish3, - R.layout.keyguard_clock_stylish4, - R.layout.keyguard_clock_stylish5, - R.layout.keyguard_clock_stylish6, - R.layout.keyguard_clock_stylish7, - R.layout.keyguard_clock_stylish8, - R.layout.keyguard_clock_stylish9, - R.layout.keyguard_clock_stylish10 - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - fontManager = new FontManager(getActivity(), true); - getActivity().setTitle(getActivity().getString(R.string.theme_customization_lock_clock_title)); - mThemeUtils = ThemeUtils.getInstance(getActivity()); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.lockscreen_font_picker_preview, container, false); - clockNameTextView = rootView.findViewById(R.id.clock_name); - - viewPager = rootView.findViewById(R.id.view_pager); - pagerAdapter = new ClockPagerAdapter(); - viewPager.setAdapter(pagerAdapter); - mClockPosition = Settings.Secure.getIntForUser(getContext().getContentResolver(), "clock_style", 0, UserHandle.USER_CURRENT); - if (mClockPosition < 0 || mClockPosition >= CLOCK_LAYOUTS.length) { - mClockPosition = 0; - Settings.Secure.putIntForUser(getContext().getContentResolver(), "clock_style", 0, UserHandle.USER_CURRENT); - } - viewPager.setCurrentItem(mClockPosition); - - TextView fontMessage = rootView.findViewById(R.id.font_message); - List fontPackageNames = fontManager.getAllFontPackages(); - TextView fontSelector = rootView.findViewById(R.id.font_selector); - int backgroundColor = ContextCompat.getColor(getContext(), - isNightMode() ? R.color.font_drop_down_bg_dark : R.color.font_drop_down_bg_light); - fontSelector.setTextColor(ContextCompat.getColor(getContext(), isNightMode() - ? R.color.font_drop_down_bg_light - : R.color.font_drop_down_bg_dark)); - fontSelector.setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); - - fontSelector.setOnClickListener(v -> { - View popupView = LayoutInflater.from(getActivity()).inflate(R.layout.popup_font_selector, null); - PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); - - ListView fontListView = popupView.findViewById(R.id.font_list_view); - FontArrayAdapter fontAdapter = new FontArrayAdapter( - getActivity(), - android.R.layout.simple_list_item_1, - fontPackageNames, - fontManager, - isNightMode() - ); - fontListView.setAdapter(fontAdapter); - - fontListView.setOnItemClickListener((parent, view, position, id) -> { - mCurrentFontPosition = position; - String fontPackage = fontPackageNames.get(mCurrentFontPosition); - applyFontToAllPreviews(fontPackage); - fontSelector.setText(fontManager.getLabel(getContext(), fontPackage)); - popupWindow.dismiss(); - }); - - popupView.setBackgroundResource(R.drawable.custom_background); - Drawable backgroundDrawable = popupView.getBackground(); - if (backgroundDrawable != null) { - backgroundDrawable.setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP); - } - popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - popupWindow.setOutsideTouchable(true); - popupWindow.setFocusable(true); - popupWindow.showAsDropDown(v, 0, 10); - }); - - if (isStaticClockStyle(mClockPosition)) { - fontMessage.setVisibility(View.VISIBLE); - } else { - fontMessage.setVisibility(View.GONE); - } - - String currentFontPackage = fontManager.getCurrentFontPackage(); - mCurrentFontPosition = fontPackageNames.indexOf(currentFontPackage); - if (mCurrentFontPosition != -1) { - if (!isStaticClockStyle(mClockPosition)) { - String fontPackage = fontPackageNames.get(mCurrentFontPosition); - fontSelector.setText(fontManager.getLabel(getContext(), fontPackage)); - applyFontToAllPreviews(fontPackage); - } - } - - applyFab = rootView.findViewById(R.id.apply_extended_fab); - setupApplyButton(fontPackageNames); - - highlightGuide = rootView.findViewById(R.id.highlight_guide); - if (isFirstTime()) { - highlightGuide.setVisibility(View.VISIBLE); - highlightGuide.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - highlightGuide.setVisibility(View.GONE); - disableHighlight(); - } - }); - } else { - highlightGuide.setVisibility(View.GONE); - } - - viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrollStateChanged(int state) {} - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} - @Override - public void onPageSelected(int position) { - mClockPosition = position; - if (viewPager != null) { - viewPager.performHapticFeedback(android.view.HapticFeedbackConstants.CLOCK_TICK); - } - updateClockName(position); - - if (isStaticClockStyle(mClockPosition)) { - fontMessage.setVisibility(View.VISIBLE); - } else { - fontMessage.setVisibility(View.GONE); - if (mCurrentFontPosition >= 0 && mCurrentFontPosition < fontPackageNames.size()) { - String fontPackage = fontPackageNames.get(mCurrentFontPosition); - applyFontToAllPreviews(fontPackage); - } - } - } - }); - return rootView; - } - - private void updateClockName(int position) { - String[] clockNames = { - "Default Clock", - "OnePlus Clock", - "IOS Clock", - "Simple Clock", - "MIUI Clock", - "IDE Clock", - "Moto Clock", - "Stylish Clock", - "Stylish Clock 2", - "Stylish Clock 3", - "Stylish Clock 4", - "Stylish Clock 5", - "Stylish Clock 6", - "Stylish Clock 7", - "Stylish Clock 8", - "Stylish Clock 9", - "Stylish Clock 10" - }; - if (clockNameTextView != null && position >= 0 && position < clockNames.length) { - clockNameTextView.setText(clockNames[position]); - } - } - - private void setupApplyButton(List fontPackageNames) { - applyFab.setOnClickListener(new View.OnClickListener() { - private long lastClickTime = 0; - - @Override - public void onClick(View view) { - long currentTime = System.currentTimeMillis(); - if (currentTime - lastClickTime < 2000) { - return; - } - lastClickTime = currentTime; - - if (mCurrentFontPosition >= 0 && mCurrentFontPosition < fontPackageNames.size()) { - String fontPackage = fontPackageNames.get(mCurrentFontPosition); - - if (!isStaticClockStyle(mClockPosition)) { - applyFontToAllPreviews(fontPackage); - fontManager.enableFontPackage(mCurrentFontPosition); - } - } - - Settings.Secure.putIntForUser(getContext().getContentResolver(), - "clock_style", mClockPosition, UserHandle.USER_CURRENT); - Settings.Secure.putIntForUser(getContext().getContentResolver(), - "lock_screen_custom_clock_face", 0, UserHandle.USER_CURRENT); - - applyChangesAndRestart(); - } - }); - } - - private void applyChangesAndRestart() { - if (applyFab != null) { - applyFab.setEnabled(false); - applyFab.setText("Applying..."); - } - - updateClockOverlays(mClockPosition); - - final Context appContext = getActivity() != null ? getActivity().getApplicationContext() : null; - final Context fragmentContext = getContext(); - - if (appContext != null && fragmentContext != null && isAdded() && getActivity() != null && !getActivity().isFinishing()) { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - try { - SystemRestartUtils.restartSystemUI(appContext); - showSuccessMessage(); - - } catch (Exception e) { - if (isAdded() && getContext() != null && getActivity() != null && !getActivity().isFinishing()) { - try { - SystemRestartUtils.restartSystemUI(getContext()); - showSuccessMessage(); - } catch (Exception ex) { - showFailureMessage(); - } - } else { - showFailureMessage(); - } - } - } - }, 1000); - } else { - showFailureMessage(); - } - } - - private void showSuccessMessage() { - if (getActivity() != null && !getActivity().isFinishing()) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (getContext() != null) { - Toast.makeText(getContext(), - "Settings applied successfully!", - Toast.LENGTH_SHORT).show(); - } - if (applyFab != null) { - applyFab.setEnabled(true); - applyFab.setText("Apply"); - } - } - }); - } - } - - private void showFailureMessage() { - if (getActivity() != null && !getActivity().isFinishing()) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (applyFab != null) { - applyFab.setEnabled(true); - applyFab.setText("Apply"); - } - if (getContext() != null) { - Toast.makeText(getContext(), - "Settings saved. Please restart SystemUI manually if changes don't appear.", - Toast.LENGTH_LONG).show(); - } - } - }); - } - } - - private boolean isNightMode() { - int nightModeFlags = getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - return nightModeFlags == Configuration.UI_MODE_NIGHT_YES; - } - - private void updateClockOverlays(int clockStyle) { - mThemeUtils.setOverlayEnabled( - "android.theme.customization.hideclock", - clockStyle != 0 ? "com.android.systemui.clocks.hideclock" : "android", - "android"); - mThemeUtils.setOverlayEnabled( - "android.theme.customization.smartspace", - clockStyle != 0 ? "com.android.systemui.hide.smartspace" : "com.android.systemui", - "com.android.systemui"); - mThemeUtils.setOverlayEnabled( - "android.theme.customization.smartspace_offset", - clockStyle != 0 && isCenterClock(clockStyle) - ? "com.android.systemui.smartspace_offset.smartspace" - : "com.android.systemui", - "com.android.systemui"); - } - - private boolean isCenterClock(int clockStyle) { - for (int centerClock : mCenterClocks) { - if (centerClock == clockStyle) { - return true; - } - } - return false; - } - - private boolean isStaticClockStyle(int clockStyle) { - if (clockStyle < 0 || clockStyle >= CLOCK_LAYOUTS.length) { - return false; - } - return false; - } - - private boolean shouldScaleDown(int position) { - int layoutId = CLOCK_LAYOUTS[position]; - return layoutId == R.layout.keyguard_clock_stylish - || layoutId == R.layout.keyguard_clock_stylish2 - || layoutId == R.layout.keyguard_clock_stylish3 - || layoutId == R.layout.keyguard_clock_stylish4 - || layoutId == R.layout.keyguard_clock_stylish5 - || layoutId == R.layout.keyguard_clock_stylish6 - || layoutId == R.layout.keyguard_clock_stylish7 - || layoutId == R.layout.keyguard_clock_stylish8 - || layoutId == R.layout.keyguard_clock_stylish9 - || layoutId == R.layout.keyguard_clock_stylish10; - } - - private boolean isFirstTime() { - return Settings.System.getIntForUser( - getContext().getContentResolver(), PREF_FIRST_TIME, 1, UserHandle.USER_CURRENT) != 0; - } - - private void disableHighlight() { - Settings.System.putIntForUser(getContext().getContentResolver(), PREF_FIRST_TIME, 0, UserHandle.USER_CURRENT); - } - - private class ClockPagerAdapter extends PagerAdapter { - @NonNull - @Override - public Object instantiateItem(@NonNull ViewGroup container, int position) { - LayoutInflater inflater = LayoutInflater.from(getActivity()); - View layout = inflater.inflate(CLOCK_LAYOUTS[position], container, false); - - if (!isStaticClockStyle(position) && mCurrentFontPosition >= 0) { - String fontPackage = fontManager.getAllFontPackages().get(mCurrentFontPosition); - applyFontToPreview(fontPackage, layout, position); - } - - int bottomPadding = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - 150, - getResources().getDisplayMetrics() - ); - layout.setPadding( - layout.getPaddingLeft(), - layout.getPaddingTop(), - layout.getPaddingRight(), - bottomPadding - ); - - if (shouldScaleDown(position)) { - float scaleFactor = 0.70f; - if (position == 0 - || position == 1 - || position == 2 - || position == 5 - || position == 6 - || position == 7 - || position == 14) { - scaleFactor = 0.35f; - } - layout.setScaleX(scaleFactor); - layout.setScaleY(scaleFactor); - } - - container.addView(layout); - return layout; - } - - @Override - public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { - container.removeView((View) object); - } - - @Override - public int getCount() { - return CLOCK_LAYOUTS.length; - } - - @Override - public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { - return view == object; - } - } - - private void applyFontToAllPreviews(String font) { - Typeface typeface = fontManager.getTypeface(getContext(), font); - int childCount = viewPager.getChildCount(); - if (typeface != null) { - for (int i = 0; i < childCount; i++) { - View currentLayout = viewPager.getChildAt(i); - int currentPosition = viewPager.getCurrentItem(); - if (currentLayout != null) { - if (!isStaticClockStyle(currentPosition)) { - updateAllTextViews(currentLayout, typeface); - } - } - } - } - } - - private void applyFontToPreview(String font, View layout, int position) { - if (isStaticClockStyle(position)) { - return; - } - Typeface typeface = fontManager.getTypeface(getContext(), font); - if (typeface != null) { - updateAllTextViews(layout, typeface); - } - } - - private void updateAllTextViews(View view, Typeface typeface) { - if (view instanceof TextView || view instanceof TextClock) { - ((TextView) view).setTypeface(typeface); - } else if (view instanceof ViewGroup) { - ViewGroup viewGroup = (ViewGroup) view; - for (int i = 0; i < viewGroup.getChildCount(); i++) { - View child = viewGroup.getChildAt(i); - updateAllTextViews(child, typeface); - } - } - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateClockName(mClockPosition); - } - - @Override - public void onResume() { - super.onResume(); - updateClockName(mClockPosition); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - if (mHandler != null) { - mHandler.removeCallbacksAndMessages(null); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - mHandler = null; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.kt b/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.kt new file mode 100644 index 00000000..3840bb97 --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/LockClockFontsPickerPreview.kt @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2023-2024 The risingOS Android Project + * Copyright (C) 2024-2025 Project Infinity X + * + * 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.rising.settings.fragments.lockscreen + +import android.content.Context +import android.content.res.Configuration +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.PorterDuff +import android.graphics.Typeface +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.os.Handler +import android.os.UserHandle +import android.provider.Settings +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ListView +import android.widget.PopupWindow +import android.widget.TextClock +import android.widget.TextView +import android.widget.Toast + +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.core.content.ContextCompat +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import java.lang.ref.WeakReference +import com.android.settings.utils.SystemRestartUtils + +import com.android.internal.util.android.ThemeUtils +import com.rising.settings.fragments.ui.fonts.FontArrayAdapter +import com.rising.settings.fragments.ui.fonts.FontManager +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton + +class LockClockFontsPickerPreview : OptimizedSettingsFragment() { + + companion object { + private const val TAG = "LockClockFontsPickerPreview" + private const val PREF_FIRST_TIME = "first_time_clock_face_access" + + private val mCenterClocks = intArrayOf(2, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16) + + private val CLOCK_LAYOUTS = intArrayOf( + R.layout.keyguard_clock_default, + R.layout.keyguard_clock_oos, + R.layout.keyguard_clock_center, + R.layout.keyguard_clock_simple, + R.layout.keyguard_clock_miui, + R.layout.keyguard_clock_ide, + R.layout.keyguard_clock_moto, + R.layout.keyguard_clock_stylish, + R.layout.keyguard_clock_stylish2, + R.layout.keyguard_clock_stylish3, + R.layout.keyguard_clock_stylish4, + R.layout.keyguard_clock_stylish5, + R.layout.keyguard_clock_stylish6, + R.layout.keyguard_clock_stylish7, + R.layout.keyguard_clock_stylish8, + R.layout.keyguard_clock_stylish9, + R.layout.keyguard_clock_stylish10 + ) + } + + private lateinit var viewPager: ViewPager + private lateinit var pagerAdapter: ClockPagerAdapter + private lateinit var fontManager: FontManager + private lateinit var applyFab: ExtendedFloatingActionButton + private lateinit var highlightGuide: View + private lateinit var clockNameTextView: TextView + + private var mCurrentFontPosition = -1 + private var mClockPosition = 0 + + override var mThemeUtils: ThemeUtils? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + fontManager = FontManager(requireActivity(), true) + activity?.title = activity?.getString(R.string.theme_customization_lock_clock_title) + activity?.let { + mThemeUtils = ThemeUtils.getInstance(it) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val rootView = inflater.inflate(R.layout.lockscreen_font_picker_preview, container, false) + clockNameTextView = rootView.findViewById(R.id.clock_name) + + viewPager = rootView.findViewById(R.id.view_pager) + pagerAdapter = ClockPagerAdapter() + viewPager.adapter = pagerAdapter + mClockPosition = Settings.Secure.getIntForUser(context?.contentResolver, "clock_style", 0, UserHandle.USER_CURRENT) + if (mClockPosition < 0 || mClockPosition >= CLOCK_LAYOUTS.size) { + mClockPosition = 0 + Settings.Secure.putIntForUser(context?.contentResolver, "clock_style", 0, UserHandle.USER_CURRENT) + } + viewPager.currentItem = mClockPosition + + val fontMessage = rootView.findViewById(R.id.font_message) + val fontPackageNames = fontManager.allFontPackages + val fontSelector = rootView.findViewById(R.id.font_selector) + val backgroundColor = ContextCompat.getColor(context!!, + if (isNightMode()) R.color.font_drop_down_bg_dark else R.color.font_drop_down_bg_light) + fontSelector.setTextColor(ContextCompat.getColor(context!!, + if (isNightMode()) R.color.font_drop_down_bg_light else R.color.font_drop_down_bg_dark)) + fontSelector.backgroundTintList = ColorStateList.valueOf(backgroundColor) + + fontSelector.setOnClickListener { v -> + val popupView = LayoutInflater.from(activity).inflate(R.layout.popup_font_selector, null) + val popupWindow = PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true) + + val fontListView = popupView.findViewById(R.id.font_list_view) + val fontAdapter = FontArrayAdapter( + requireActivity(), + android.R.layout.simple_list_item_1, + fontPackageNames, + fontManager, + isNightMode() + ) + fontListView.adapter = fontAdapter + + fontListView.setOnItemClickListener { _, _, position, _ -> + mCurrentFontPosition = position + val fontPackage = fontPackageNames[mCurrentFontPosition] + applyFontToAllPreviews(fontPackage) + fontSelector.text = fontManager.getLabel(requireContext(), fontPackage) + popupWindow.dismiss() + } + + popupView.setBackgroundResource(R.drawable.custom_background) + val backgroundDrawable = popupView.background + backgroundDrawable?.setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP) + popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + popupWindow.isOutsideTouchable = true + popupWindow.isFocusable = true + popupWindow.showAsDropDown(v, 0, 10) + } + + if (isStaticClockStyle(mClockPosition)) { + fontMessage.visibility = View.VISIBLE + } else { + fontMessage.visibility = View.GONE + } + + val currentFontPackage = fontManager.currentFontPackage + mCurrentFontPosition = fontPackageNames.indexOf(currentFontPackage) + if (mCurrentFontPosition != -1) { + if (!isStaticClockStyle(mClockPosition)) { + val fontPackage = fontPackageNames[mCurrentFontPosition] + fontSelector.text = fontManager.getLabel(requireContext(), fontPackage) + applyFontToAllPreviews(fontPackage) + } + } + + applyFab = rootView.findViewById(R.id.apply_extended_fab) + setupApplyButton(fontPackageNames) + + highlightGuide = rootView.findViewById(R.id.highlight_guide) + if (isFirstTime()) { + highlightGuide.visibility = View.VISIBLE + highlightGuide.setOnClickListener { + highlightGuide.visibility = View.GONE + disableHighlight() + } + } else { + highlightGuide.visibility = View.GONE + } + + viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrollStateChanged(state: Int) {} + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} + override fun onPageSelected(position: Int) { + mClockPosition = position + viewPager.performHapticFeedback(android.view.HapticFeedbackConstants.CLOCK_TICK) + updateClockName(position) + + if (isStaticClockStyle(mClockPosition)) { + fontMessage.visibility = View.VISIBLE + } else { + fontMessage.visibility = View.GONE + if (mCurrentFontPosition >= 0 && mCurrentFontPosition < fontPackageNames.size) { + val fontPackage = fontPackageNames[mCurrentFontPosition] + applyFontToAllPreviews(fontPackage) + } + } + } + }) + return rootView + } + + private fun updateClockName(position: Int) { + val clockNames = arrayOf( + "Default Clock", + "OnePlus Clock", + "IOS Clock", + "Simple Clock", + "MIUI Clock", + "IDE Clock", + "Moto Clock", + "Stylish Clock", + "Stylish Clock 2", + "Stylish Clock 3", + "Stylish Clock 4", + "Stylish Clock 5", + "Stylish Clock 6", + "Stylish Clock 7", + "Stylish Clock 8", + "Stylish Clock 9", + "Stylish Clock 10" + ) + if (position >= 0 && position < clockNames.size) { + clockNameTextView.text = clockNames[position] + } + } + + private fun setupApplyButton(fontPackageNames: List) { + applyFab.setOnClickListener(object : View.OnClickListener { + private var lastClickTime: Long = 0 + + override fun onClick(view: View) { + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime < 2000) { + return + } + lastClickTime = currentTime + + if (mCurrentFontPosition >= 0 && mCurrentFontPosition < fontPackageNames.size) { + val fontPackage = fontPackageNames[mCurrentFontPosition] + + if (!isStaticClockStyle(mClockPosition)) { + applyFontToAllPreviews(fontPackage) + fontManager.enableFontPackage(mCurrentFontPosition) + } + } + + Settings.Secure.putIntForUser(context?.contentResolver, + "clock_style", mClockPosition, UserHandle.USER_CURRENT) + Settings.Secure.putIntForUser(context?.contentResolver, + "lock_screen_custom_clock_face", 0, UserHandle.USER_CURRENT) + + applyChangesAndRestart() + } + }) + } + + private fun applyChangesAndRestart() { + applyFab.isEnabled = false + applyFab.text = "Applying..." + + updateClockOverlays(mClockPosition) + + val appContext = activity?.applicationContext + val fragmentContext = context + + if (appContext != null && fragmentContext != null && isAdded && activity != null && !activity!!.isFinishing) { + postDelayedSafe({ + try { + SystemRestartUtils.restartSystemUI(appContext) + showSuccessMessage() + } catch (e: Exception) { + if (isAdded && context != null && activity != null && !activity!!.isFinishing) { + try { + SystemRestartUtils.restartSystemUI(context!!) + showSuccessMessage() + } catch (ex: Exception) { + showFailureMessage() + } + } else { + showFailureMessage() + } + } + }, 1000) + } else { + showFailureMessage() + } + } + + private fun showSuccessMessage() { + if (activity != null && !activity!!.isFinishing) { + activity!!.runOnUiThread { + context?.let { + Toast.makeText(it, + "Settings applied successfully!", + Toast.LENGTH_SHORT).show() + } + applyFab.isEnabled = true + applyFab.text = "Apply" + } + } + } + + private fun showFailureMessage() { + if (activity != null && !activity!!.isFinishing) { + activity!!.runOnUiThread { + applyFab.isEnabled = true + applyFab.text = "Apply" + context?.let { + Toast.makeText(it, + "Settings saved. Please restart SystemUI manually if changes don't appear.", + Toast.LENGTH_LONG).show() + } + } + } + } + + private fun isNightMode(): Boolean { + val nightModeFlags = context?.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) + return nightModeFlags == Configuration.UI_MODE_NIGHT_YES + } + + private fun updateClockOverlays(clockStyle: Int) { + mThemeUtils?.setOverlayEnabled( + "android.theme.customization.hideclock", + if (clockStyle != 0) "com.android.systemui.clocks.hideclock" else "android", + "android") + mThemeUtils?.setOverlayEnabled( + "android.theme.customization.smartspace", + if (clockStyle != 0) "com.android.systemui.hide.smartspace" else "com.android.systemui", + "com.android.systemui") + mThemeUtils?.setOverlayEnabled( + "android.theme.customization.smartspace_offset", + if (clockStyle != 0 && isCenterClock(clockStyle)) + "com.android.systemui.smartspace_offset.smartspace" + else + "com.android.systemui", + "com.android.systemui") + } + + private fun isCenterClock(clockStyle: Int): Boolean { + return mCenterClocks.contains(clockStyle) + } + + private fun isStaticClockStyle(clockStyle: Int): Boolean { + if (clockStyle < 0 || clockStyle >= CLOCK_LAYOUTS.size) { + return false + } + return false + } + + private fun shouldScaleDown(position: Int): Boolean { + val layoutId = CLOCK_LAYOUTS[position] + return layoutId == R.layout.keyguard_clock_stylish || + layoutId == R.layout.keyguard_clock_stylish2 || + layoutId == R.layout.keyguard_clock_stylish3 || + layoutId == R.layout.keyguard_clock_stylish4 || + layoutId == R.layout.keyguard_clock_stylish5 || + layoutId == R.layout.keyguard_clock_stylish6 || + layoutId == R.layout.keyguard_clock_stylish7 || + layoutId == R.layout.keyguard_clock_stylish8 || + layoutId == R.layout.keyguard_clock_stylish9 || + layoutId == R.layout.keyguard_clock_stylish10 + } + + private fun isFirstTime(): Boolean { + return Settings.System.getIntForUser( + context?.contentResolver, PREF_FIRST_TIME, 1, UserHandle.USER_CURRENT) != 0 + } + + private fun disableHighlight() { + Settings.System.putIntForUser(context?.contentResolver, PREF_FIRST_TIME, 0, UserHandle.USER_CURRENT) + } + + private inner class ClockPagerAdapter : PagerAdapter() { + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val inflater = LayoutInflater.from(activity) + val layout = inflater.inflate(CLOCK_LAYOUTS[position], container, false) + + if (!isStaticClockStyle(position) && mCurrentFontPosition >= 0) { + val fontPackage = fontManager.allFontPackages[mCurrentFontPosition] + applyFontToPreview(fontPackage, layout, position) + } + + val bottomPadding = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + 150f, + resources.displayMetrics + ).toInt() + layout.setPadding( + layout.paddingLeft, + layout.paddingTop, + layout.paddingRight, + bottomPadding + ) + + if (shouldScaleDown(position)) { + var scaleFactor = 0.70f + if (position == 0 || + position == 1 || + position == 2 || + position == 5 || + position == 6 || + position == 7 || + position == 14) { + scaleFactor = 0.35f + } + layout.scaleX = scaleFactor + layout.scaleY = scaleFactor + } + + container.addView(layout) + return layout + } + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + container.removeView(`object` as View) + } + + override fun getCount(): Int { + return CLOCK_LAYOUTS.size + } + + override fun isViewFromObject(view: View, `object`: Any): Boolean { + return view == `object` + } + } + + private fun applyFontToAllPreviews(font: String) { + val typeface = fontManager.getTypeface(context, font) + val childCount = viewPager.childCount + if (typeface != null) { + for (i in 0 until childCount) { + val currentLayout = viewPager.getChildAt(i) + val currentPosition = viewPager.currentItem + if (currentLayout != null) { + if (!isStaticClockStyle(currentPosition)) { + updateAllTextViews(currentLayout, typeface) + } + } + } + } + } + + private fun applyFontToPreview(font: String, layout: View, position: Int) { + if (isStaticClockStyle(position)) { + return + } + val typeface = fontManager.getTypeface(context, font) + if (typeface != null) { + updateAllTextViews(layout, typeface) + } + } + + private fun updateAllTextViews(view: View, typeface: Typeface) { + when (view) { + is TextView, is TextClock -> { + (view as TextView).typeface = typeface + } + is ViewGroup -> { + for (i in 0 until view.childCount) { + val child = view.getChildAt(i) + updateAllTextViews(child, typeface) + } + } + } + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + updateClockName(mClockPosition) + } + + override fun onResume() { + super.onResume() + updateClockName(mClockPosition) + } + + override fun onDestroyView() { + super.onDestroyView() + // Cleanup handled by OptimizedSettingsFragment + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup ThemeUtils + mThemeUtils = null + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.java b/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.java deleted file mode 100644 index 3ab4c2a8..00000000 --- a/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.lockscreen; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.MediaStore; -import android.provider.Settings; -import android.text.TextUtils; -import android.view.View; -import android.widget.Button; -import android.widget.Toast; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.SwitchPreferenceCompat; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.utils.SystemRestartUtils; -import com.android.settingslib.search.SearchIndexable; -import com.android.settingslib.widget.LayoutPreference; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@SearchIndexable -public class LockScreenWidgets extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener { - - public static final String TAG = "LockScreenWidgets"; - - private static final String MAIN_WIDGET_1_KEY = "main_custom_widgets1"; - private static final String MAIN_WIDGET_2_KEY = "main_custom_widgets2"; - private static final String EXTRA_WIDGET_1_KEY = "custom_widgets1"; - private static final String EXTRA_WIDGET_2_KEY = "custom_widgets2"; - private static final String EXTRA_WIDGET_3_KEY = "custom_widgets3"; - private static final String EXTRA_WIDGET_4_KEY = "custom_widgets4"; - private static final String KEY_APPLY_CHANGE_BUTTON = "apply_change_button"; - - private static final String LOCKSCREEN_WIDGETS_KEY = "lockscreen_widgets"; - private static final String LOCKSCREEN_WIDGETS_EXTRAS_KEY = "lockscreen_widgets_extras"; - - private Preference mMainWidget1; - private Preference mMainWidget2; - private Preference mExtraWidget1; - private Preference mExtraWidget2; - private Preference mExtraWidget3; - private Preference mExtraWidget4; - private Button mApplyChange; - - private SwitchPreferenceCompat mLockScreenWidgetsEnabledPref; - private List mWidgetPreferences; - - private Map widgetKeysMap = new HashMap<>(); - private Map initialWidgetKeysMap = new HashMap<>(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_lockscreen_widgets); - - initializePreferences(); - setupListeners(); - - boolean isLsWidgetsEnabled = Settings.System.getIntForUser( - getActivity().getContentResolver(), - "lockscreen_widgets_enabled", - 0, - UserHandle.USER_CURRENT) != 0; - - mLockScreenWidgetsEnabledPref.setChecked(isLsWidgetsEnabled); - showWidgetPreferences(isLsWidgetsEnabled); - - loadInitialPreferences(); - saveInitialPreferences(); - mApplyChange.setEnabled(false); - } - - private void initializePreferences() { - mMainWidget1 = findPreference(MAIN_WIDGET_1_KEY); - mMainWidget2 = findPreference(MAIN_WIDGET_2_KEY); - mExtraWidget1 = findPreference(EXTRA_WIDGET_1_KEY); - mExtraWidget2 = findPreference(EXTRA_WIDGET_2_KEY); - mExtraWidget3 = findPreference(EXTRA_WIDGET_3_KEY); - mExtraWidget4 = findPreference(EXTRA_WIDGET_4_KEY); - - mWidgetPreferences = Arrays.asList( - mMainWidget1, - mMainWidget2, - mExtraWidget1, - mExtraWidget2, - mExtraWidget3, - mExtraWidget4); - - mLockScreenWidgetsEnabledPref = findPreference("lockscreen_widgets_enabled"); - - LayoutPreference layoutPreference = findPreference(KEY_APPLY_CHANGE_BUTTON); - mApplyChange = layoutPreference.findViewById(R.id.apply_change); - } - - private void setupListeners() { - for (Preference widgetPref : mWidgetPreferences) { - widgetPref.setOnPreferenceChangeListener(this); - widgetKeysMap.put(widgetPref, ""); - } - mLockScreenWidgetsEnabledPref.setOnPreferenceChangeListener(this); - - mApplyChange.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateWidgetPreferences(); - saveInitialPreferences(); - mApplyChange.setEnabled(false); - - // Restart SystemUI to apply changes - SystemRestartUtils.restartSystemUI(getContext()); - } - }); - } - - private void showWidgetPreferences(boolean isEnabled) { - for (Preference widgetPref : mWidgetPreferences) { - widgetPref.setVisible(isEnabled); - } - } - - private void loadInitialPreferences() { - ContentResolver resolver = getActivity().getContentResolver(); - String mainWidgets = Settings.System.getString(resolver, LOCKSCREEN_WIDGETS_KEY); - setWidgetAndPreferenceValues(mainWidgets, mMainWidget1, mMainWidget2); - String extraWidgets = Settings.System.getString(resolver, LOCKSCREEN_WIDGETS_EXTRAS_KEY); - setWidgetAndPreferenceValues(extraWidgets, mExtraWidget1, mExtraWidget2, mExtraWidget3, mExtraWidget4); - } - - private void setWidgetAndPreferenceValues(String widgets, Preference... preferences) { - if (widgets == null) { - return; - } - List widgetList = Arrays.asList(widgets.split(",")); - for (int i = 0; i < preferences.length && i < widgetList.size(); i++) { - String value = widgetList.get(i).trim(); - Preference pref = preferences[i]; - widgetKeysMap.put(pref, value); - if (pref instanceof ListPreference) { - ((ListPreference) pref).setValue(value); - } - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (widgetKeysMap.containsKey(preference)) { - widgetKeysMap.put(preference, String.valueOf(newValue)); - mApplyChange.setEnabled(hasChanges()); - return true; - } else if (preference == mLockScreenWidgetsEnabledPref) { - boolean isEnabled = (boolean) newValue; - showWidgetPreferences(isEnabled); - mLockScreenWidgetsEnabledPref.setChecked(isEnabled); - return true; - } - return false; - } - - private void updateWidgetPreferences() { - List mainWidgetsList = Arrays.asList(widgetKeysMap.get(mMainWidget1), widgetKeysMap.get(mMainWidget2)); - List extraWidgetsList = Arrays.asList(widgetKeysMap.get(mExtraWidget1), widgetKeysMap.get(mExtraWidget2), widgetKeysMap.get(mExtraWidget3), widgetKeysMap.get(mExtraWidget4)); - - mainWidgetsList = replaceEmptyWithNone(mainWidgetsList); - extraWidgetsList = replaceEmptyWithNone(extraWidgetsList); - - String mainWidgets = TextUtils.join(",", mainWidgetsList); - String extraWidgets = TextUtils.join(",", extraWidgetsList); - - ContentResolver resolver = getActivity().getContentResolver(); - Settings.System.putString(resolver, LOCKSCREEN_WIDGETS_KEY, mainWidgets); - Settings.System.putString(resolver, LOCKSCREEN_WIDGETS_EXTRAS_KEY, extraWidgets); - } - - private List replaceEmptyWithNone(List inputList) { - return inputList.stream() - .map(s -> TextUtils.isEmpty(s) ? "none" : s) - .collect(Collectors.toList()); - } - - private void saveInitialPreferences() { - initialWidgetKeysMap.clear(); - for (Preference widgetPref : mWidgetPreferences) { - String value = widgetKeysMap.get(widgetPref); - initialWidgetKeysMap.put(widgetPref, value); - } - } - - private boolean hasChanges() { - for (Map.Entry entry : initialWidgetKeysMap.entrySet()) { - Preference pref = entry.getKey(); - String initialValue = entry.getValue(); - String currentValue = widgetKeysMap.get(pref); - if (!TextUtils.equals(initialValue, currentValue)) { - return true; - } - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_lockscreen_widgets) { - @Override - public List getNonIndexableKeys(Context context) { - return super.getNonIndexableKeys(context); - } - }; -} diff --git a/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.kt b/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.kt new file mode 100644 index 00000000..86b1c7d7 --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/LockScreenWidgets.kt @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.lockscreen + +import android.app.Activity +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.UserHandle +import android.provider.MediaStore +import android.provider.Settings +import android.text.TextUtils +import android.view.View +import android.widget.Button +import android.widget.Toast + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.SwitchPreferenceCompat + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settings.utils.SystemRestartUtils +import com.android.settingslib.search.SearchIndexable +import com.android.settingslib.widget.LayoutPreference + +@SearchIndexable +class LockScreenWidgets : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "LockScreenWidgets" + + private const val MAIN_WIDGET_1_KEY = "main_custom_widgets1" + private const val MAIN_WIDGET_2_KEY = "main_custom_widgets2" + private const val EXTRA_WIDGET_1_KEY = "custom_widgets1" + private const val EXTRA_WIDGET_2_KEY = "custom_widgets2" + private const val EXTRA_WIDGET_3_KEY = "custom_widgets3" + private const val EXTRA_WIDGET_4_KEY = "custom_widgets4" + private const val KEY_APPLY_CHANGE_BUTTON = "apply_change_button" + + private const val LOCKSCREEN_WIDGETS_KEY = "lockscreen_widgets" + private const val LOCKSCREEN_WIDGETS_EXTRAS_KEY = "lockscreen_widgets_extras" + + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_lockscreen_widgets) { + override fun getNonIndexableKeys(context: Context): List { + return super.getNonIndexableKeys(context) + } + } + } + + private lateinit var mMainWidget1: Preference + private lateinit var mMainWidget2: Preference + private lateinit var mExtraWidget1: Preference + private lateinit var mExtraWidget2: Preference + private lateinit var mExtraWidget3: Preference + private lateinit var mExtraWidget4: Preference + private lateinit var mApplyChange: Button + + private lateinit var mLockScreenWidgetsEnabledPref: SwitchPreferenceCompat + private lateinit var mWidgetPreferences: List + + private val widgetKeysMap = mutableMapOf() + private val initialWidgetKeysMap = mutableMapOf() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_lockscreen_widgets) + + initializePreferences() + setupListeners() + + val isLsWidgetsEnabled = Settings.System.getIntForUser( + activity?.contentResolver, + "lockscreen_widgets_enabled", + 0, + UserHandle.USER_CURRENT + ) != 0 + + mLockScreenWidgetsEnabledPref.isChecked = isLsWidgetsEnabled + showWidgetPreferences(isLsWidgetsEnabled) + + loadInitialPreferences() + saveInitialPreferences() + mApplyChange.isEnabled = false + } + + private fun initializePreferences() { + mMainWidget1 = findPreference(MAIN_WIDGET_1_KEY)!! + mMainWidget2 = findPreference(MAIN_WIDGET_2_KEY)!! + mExtraWidget1 = findPreference(EXTRA_WIDGET_1_KEY)!! + mExtraWidget2 = findPreference(EXTRA_WIDGET_2_KEY)!! + mExtraWidget3 = findPreference(EXTRA_WIDGET_3_KEY)!! + mExtraWidget4 = findPreference(EXTRA_WIDGET_4_KEY)!! + + mWidgetPreferences = listOf( + mMainWidget1, + mMainWidget2, + mExtraWidget1, + mExtraWidget2, + mExtraWidget3, + mExtraWidget4 + ) + + mLockScreenWidgetsEnabledPref = findPreference("lockscreen_widgets_enabled")!! + + val layoutPreference = findPreference(KEY_APPLY_CHANGE_BUTTON)!! + mApplyChange = layoutPreference.findViewById(R.id.apply_change) + } + + private fun setupListeners() { + for (widgetPref in mWidgetPreferences) { + widgetPref.onPreferenceChangeListener = this + widgetKeysMap[widgetPref] = "" + } + mLockScreenWidgetsEnabledPref.onPreferenceChangeListener = this + + mApplyChange.setOnClickListener { + updateWidgetPreferences() + saveInitialPreferences() + mApplyChange.isEnabled = false + + // Restart SystemUI to apply changes + context?.let { ctx -> + SystemRestartUtils.restartSystemUI(ctx) + } + } + } + + private fun showWidgetPreferences(isEnabled: Boolean) { + for (widgetPref in mWidgetPreferences) { + widgetPref.isVisible = isEnabled + } + } + + private fun loadInitialPreferences() { + val resolver = activity?.contentResolver + val mainWidgets = Settings.System.getString(resolver, LOCKSCREEN_WIDGETS_KEY) + setWidgetAndPreferenceValues(mainWidgets, mMainWidget1, mMainWidget2) + val extraWidgets = Settings.System.getString(resolver, LOCKSCREEN_WIDGETS_EXTRAS_KEY) + setWidgetAndPreferenceValues(extraWidgets, mExtraWidget1, mExtraWidget2, mExtraWidget3, mExtraWidget4) + } + + private fun setWidgetAndPreferenceValues(widgets: String?, vararg preferences: Preference) { + if (widgets == null) { + return + } + val widgetList = widgets.split(",") + for (i in preferences.indices) { + if (i < widgetList.size) { + val value = widgetList[i].trim() + val pref = preferences[i] + widgetKeysMap[pref] = value + if (pref is ListPreference) { + pref.value = value + } + } + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + return when { + widgetKeysMap.containsKey(preference) -> { + widgetKeysMap[preference] = newValue.toString() + mApplyChange.isEnabled = hasChanges() + true + } + preference == mLockScreenWidgetsEnabledPref -> { + val isEnabled = newValue as Boolean + showWidgetPreferences(isEnabled) + mLockScreenWidgetsEnabledPref.isChecked = isEnabled + true + } + else -> false + } + } + + private fun updateWidgetPreferences() { + var mainWidgetsList = listOf(widgetKeysMap[mMainWidget1], widgetKeysMap[mMainWidget2]) + var extraWidgetsList = listOf( + widgetKeysMap[mExtraWidget1], + widgetKeysMap[mExtraWidget2], + widgetKeysMap[mExtraWidget3], + widgetKeysMap[mExtraWidget4] + ) + + mainWidgetsList = replaceEmptyWithNone(mainWidgetsList) + extraWidgetsList = replaceEmptyWithNone(extraWidgetsList) + + val mainWidgets = TextUtils.join(",", mainWidgetsList) + val extraWidgets = TextUtils.join(",", extraWidgetsList) + + val resolver = activity?.contentResolver + Settings.System.putString(resolver, LOCKSCREEN_WIDGETS_KEY, mainWidgets) + Settings.System.putString(resolver, LOCKSCREEN_WIDGETS_EXTRAS_KEY, extraWidgets) + } + + private fun replaceEmptyWithNone(inputList: List): List { + return inputList.map { s -> if (TextUtils.isEmpty(s)) "none" else s!! } + } + + private fun saveInitialPreferences() { + initialWidgetKeysMap.clear() + for (widgetPref in mWidgetPreferences) { + val value = widgetKeysMap[widgetPref] ?: "" + initialWidgetKeysMap[widgetPref] = value + } + } + + private fun hasChanges(): Boolean { + for ((pref, initialValue) in initialWidgetKeysMap) { + val currentValue = widgetKeysMap[pref] + if (!TextUtils.equals(initialValue, currentValue)) { + return true + } + } + return false + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/PeekDisplay.java b/src/com/rising/settings/fragments/lockscreen/PeekDisplay.java deleted file mode 100644 index 55cb0083..00000000 --- a/src/com/rising/settings/fragments/lockscreen/PeekDisplay.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.lockscreen; - -import android.content.Context; -import android.os.Bundle; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class PeekDisplay extends SettingsPreferenceFragment { - - public static final String TAG = "PeekDisplay"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.rising_settings_peek_display); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_peek_display) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/lockscreen/PeekDisplay.kt b/src/com/rising/settings/fragments/lockscreen/PeekDisplay.kt new file mode 100644 index 00000000..6ec4f8d4 --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/PeekDisplay.kt @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.lockscreen + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.provider.Settings +import androidx.preference.Preference +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.preferences.SecureSettingSeekBarPreference +import com.android.settings.preferences.SecureSettingListPreference +import com.android.settings.preferences.SecureSettingSwitchPreference +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable +import kotlin.math.abs + +@SearchIndexable +class PeekDisplay : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val TAG = "PeekDisplay" + + // Preference keys + private const val KEY_PEEK_DISPLAY_NOTIFICATIONS = "peek_display_notifications" + private const val KEY_PEEK_DISPLAY_STYLE = "peek_display_style" + private const val KEY_PEEK_DISPLAY_LOCATION = "peek_display_location" + private const val KEY_PEEK_DISPLAY_VERTICAL_OFFSET = "peek_display_vertical_offset" + private const val KEY_PEEK_DISPLAY_ALWAYS_VISIBLE = "peek_display_always_visible" + private const val KEY_PEEK_DISPLAY_TIMEOUT = "peek_display_timeout" + + // Settings keys for SystemUI communication + private const val SYSTEMUI_PEEK_DISPLAY_ENABLED = "peek_display_enabled" + private const val SYSTEMUI_PEEK_DISPLAY_DISMISSIBLE = "peek_display_dismissible" + private const val SYSTEMUI_PEEK_DISPLAY_CLOSE_ENABLED = "peek_display_close_enabled" + private const val SYSTEMUI_PEEK_DISPLAY_TIMEOUT = "peek_display_timeout_ms" + + // Position stability constants + private const val POSITION_UPDATE_DELAY = 100 // ms + private const val DEFAULT_VERTICAL_OFFSET = 50 // percent + private const val DEFAULT_TIMEOUT_SECONDS = 3 // seconds + private const val DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_SECONDS * 1000 // ms for SystemUI + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_peek_display) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context).toMutableList() + return keys + } + } + } + + // Preferences + private var mPeekDisplayNotifications: SecureSettingSwitchPreference? = null + private var mPeekDisplayStyle: SecureSettingListPreference? = null + private var mPeekDisplayLocation: SecureSettingListPreference? = null + private var mVerticalOffset: SecureSettingSeekBarPreference? = null + private var mAlwaysVisible: SecureSettingSwitchPreference? = null + private var mTimeout: SecureSettingSeekBarPreference? = null + + // Position management + private var mPositionHandler: Handler? = null + private var mLastValidOffset = DEFAULT_VERTICAL_OFFSET + private var mIsUpdatingPosition = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.rising_settings_peek_display) + + // Initialize position handler + mPositionHandler = Handler(Looper.getMainLooper()) + + initializePreferences() + updatePreferenceDependencies() + + // Ensure close button functionality is enabled + enableCloseButtonFunctionality() + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + /** + * Initialize all preferences and set up listeners + */ + private fun initializePreferences() { + val context = getSafeContext() ?: return + val resolver = context.contentResolver + + // Get preferences + mPeekDisplayNotifications = findCachedPreference(KEY_PEEK_DISPLAY_NOTIFICATIONS) + mPeekDisplayStyle = findCachedPreference(KEY_PEEK_DISPLAY_STYLE) + mPeekDisplayLocation = findCachedPreference(KEY_PEEK_DISPLAY_LOCATION) + mVerticalOffset = findCachedPreference(KEY_PEEK_DISPLAY_VERTICAL_OFFSET) + mAlwaysVisible = findCachedPreference(KEY_PEEK_DISPLAY_ALWAYS_VISIBLE) + mTimeout = findCachedPreference(KEY_PEEK_DISPLAY_TIMEOUT) + + // Set up listeners + mPeekDisplayNotifications?.onPreferenceChangeListener = this + mPeekDisplayLocation?.onPreferenceChangeListener = this + mVerticalOffset?.let { preference -> + preference.onPreferenceChangeListener = this + // Load cached position + val currentOffset = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_VERTICAL_OFFSET, DEFAULT_VERTICAL_OFFSET) + mLastValidOffset = currentOffset + } + mAlwaysVisible?.onPreferenceChangeListener = this + mTimeout?.let { preference -> + preference.onPreferenceChangeListener = this + // Initialize timeout setting for SystemUI + val timeoutSeconds = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_TIMEOUT, DEFAULT_TIMEOUT_SECONDS) + val timeoutMs = timeoutSeconds * 1000 + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_TIMEOUT, timeoutMs) + } + } + + /** + * Update preference dependencies based on current state + */ + private fun updatePreferenceDependencies() { + val context = getSafeContext() ?: return + val resolver = context.contentResolver + + val peekEnabled = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_NOTIFICATIONS, 0) == 1 + val alwaysVisible = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_ALWAYS_VISIBLE, 0) == 1 + + // Update dependent preferences + mPeekDisplayStyle?.isEnabled = peekEnabled + mPeekDisplayLocation?.isEnabled = peekEnabled + mVerticalOffset?.isEnabled = peekEnabled + mAlwaysVisible?.isEnabled = peekEnabled + + mTimeout?.let { timeout -> + // Timeout is disabled when always visible is enabled + timeout.isEnabled = peekEnabled && !alwaysVisible + timeout.summary = if (alwaysVisible) { + "${getString(R.string.peek_display_timeout_summary)} (disabled - always visible enabled)" + } else { + getString(R.string.peek_display_timeout_summary) + } + } + } + + /** + * Enable close button functionality for peek display + * This is the key method to fix the close button issue and configure timeout behavior + */ + private fun enableCloseButtonFunctionality() { + val context = getSafeContext() ?: return + val resolver = context.contentResolver + + // Check if always visible is enabled + val alwaysVisible = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_ALWAYS_VISIBLE, 0) == 1 + + // Enable dismissible peek display notifications (unless always visible) + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_DISMISSIBLE, if (alwaysVisible) 0 else 1) + + // Enable close button functionality + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_CLOSE_ENABLED, 1) + + // Set timeout behavior + if (!alwaysVisible) { + // Get timeout in seconds and convert to milliseconds for SystemUI + val timeoutSeconds = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_TIMEOUT, DEFAULT_TIMEOUT_SECONDS) + val timeoutMs = timeoutSeconds * 1000 + + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_TIMEOUT, timeoutMs) + + // Notify SystemUI of timeout changes + resolver.notifyChange(Settings.Secure.getUriFor(SYSTEMUI_PEEK_DISPLAY_TIMEOUT), null) + } else { + // When always visible, disable timeout (set to 0 or very high value) + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_TIMEOUT, 0) + resolver.notifyChange(Settings.Secure.getUriFor(SYSTEMUI_PEEK_DISPLAY_TIMEOUT), null) + } + + // Notify SystemUI of the changes + resolver.notifyChange(Settings.Secure.getUriFor(SYSTEMUI_PEEK_DISPLAY_DISMISSIBLE), null) + resolver.notifyChange(Settings.Secure.getUriFor(SYSTEMUI_PEEK_DISPLAY_CLOSE_ENABLED), null) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + val context = getSafeContext() ?: return false + val key = preference.key + val resolver = context.contentResolver + + return when (key) { + KEY_PEEK_DISPLAY_NOTIFICATIONS -> { + val enabled = newValue as Boolean + + // Update SystemUI settings for peek display + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_ENABLED, if (enabled) 1 else 0) + + // Ensure close button functionality is maintained when peek display is enabled + if (enabled) { + postDelayedSafe(100) { enableCloseButtonFunctionality() } + } + + // Update dependencies immediately + postDelayedSafe(50) { updatePreferenceDependencies() } + true + } + + KEY_PEEK_DISPLAY_VERTICAL_OFFSET -> { + handleVerticalOffsetChange(newValue as Int) + } + + KEY_PEEK_DISPLAY_LOCATION -> { + // Reset offset when location changes to prevent position conflicts + postDelayedSafe(POSITION_UPDATE_DELAY.toLong()) { + mVerticalOffset?.let { offset -> + offset.setValue(DEFAULT_VERTICAL_OFFSET) + mLastValidOffset = DEFAULT_VERTICAL_OFFSET + } + } + true + } + + KEY_PEEK_DISPLAY_ALWAYS_VISIBLE -> { + val alwaysVisible = newValue as Boolean + + // Update dependencies when always visible changes + postDelayedSafe(50) { updatePreferenceDependencies() } + + // Apply the always visible setting + Settings.Secure.putInt(resolver, KEY_PEEK_DISPLAY_ALWAYS_VISIBLE, if (alwaysVisible) 1 else 0) + + // When always visible is disabled, ensure close button works + if (!alwaysVisible) { + postDelayedSafe(100) { enableCloseButtonFunctionality() } + } + + // Force refresh of the system UI to apply changes + postDelayedSafe(50) { + resolver.notifyChange(Settings.Secure.getUriFor(KEY_PEEK_DISPLAY_ALWAYS_VISIBLE), null) + } + + true + } + + KEY_PEEK_DISPLAY_TIMEOUT -> { + var timeoutSeconds = newValue as Int + // Validate timeout range (1-10 seconds) + timeoutSeconds = timeoutSeconds.coerceIn(1, 10) + + // Convert to milliseconds for SystemUI + val timeoutMs = timeoutSeconds * 1000 + + // Update SystemUI timeout setting + Settings.Secure.putInt(resolver, SYSTEMUI_PEEK_DISPLAY_TIMEOUT, timeoutMs) + + // Notify SystemUI of timeout changes + postDelayedSafe(100) { + resolver.notifyChange(Settings.Secure.getUriFor(SYSTEMUI_PEEK_DISPLAY_TIMEOUT), null) + // Ensure close button and timeout behavior work together + enableCloseButtonFunctionality() + } + + true + } + + else -> true + } + } + + /** + * Handle vertical offset changes with stability measures + */ + private fun handleVerticalOffsetChange(newOffset: Int): Boolean { + if (mIsUpdatingPosition) { + return false // Prevent recursive updates + } + + val context = getSafeContext() ?: return false + + // Validate offset range + val validOffset = newOffset.coerceIn(0, 100) + + // Check for rapid changes (potential instability) + return if (abs(validOffset - mLastValidOffset) > 20) { + // Large jump detected - use delayed update for stability + mIsUpdatingPosition = true + + mPositionHandler?.removeCallbacksAndMessages(null) + mPositionHandler?.postDelayed({ + applyStableVerticalOffset(validOffset) + mIsUpdatingPosition = false + }, POSITION_UPDATE_DELAY.toLong()) + + false // Don't apply immediately + } else { + // Small change - apply immediately + applyStableVerticalOffset(validOffset) + } + } + + /** + * Apply vertical offset with stability checks + */ + private fun applyStableVerticalOffset(offset: Int): Boolean { + val context = getSafeContext() ?: return false + val resolver = context.contentResolver + + // Cache the position for stability + mLastValidOffset = offset + + // Apply the setting + Settings.Secure.putInt(resolver, KEY_PEEK_DISPLAY_VERTICAL_OFFSET, offset) + + // Force refresh of the system UI to apply changes + postDelayedSafe(50) { + // Notify system of the change + resolver.notifyChange(Settings.Secure.getUriFor(KEY_PEEK_DISPLAY_VERTICAL_OFFSET), null) + } + + return true + } + + override fun onResume() { + super.onResume() + + // Restore cached position on resume to prevent drift + mVerticalOffset?.let { verticalOffset -> + val context = getSafeContext() + if (context != null) { + val resolver = context.contentResolver + val currentOffset = Settings.Secure.getInt(resolver, + KEY_PEEK_DISPLAY_VERTICAL_OFFSET, DEFAULT_VERTICAL_OFFSET) + + // Check if position has drifted + if (abs(currentOffset - mLastValidOffset) > 5) { + // Position has drifted - restore stable position + postDelayedSafe(100) { + Settings.Secure.putInt(resolver, KEY_PEEK_DISPLAY_VERTICAL_OFFSET, mLastValidOffset) + verticalOffset.setValue(mLastValidOffset) + } + } else { + mLastValidOffset = currentOffset + } + } + } + + updatePreferenceDependencies() + + // Ensure close button functionality is always enabled on resume + enableCloseButtonFunctionality() + } + + override fun onDestroy() { + super.onDestroy() + + // Clean up position handler + mPositionHandler?.removeCallbacksAndMessages(null) + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.java b/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.java deleted file mode 100644 index 0b944315..00000000 --- a/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2022-2024 crDroid Android 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.rising.settings.fragments.lockscreen; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.Glide; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.SettingsActivity; -import com.android.settings.SettingsPreferenceFragment; - -import java.util.Arrays; - -public class UdfpsAnimation extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private String mPkg = "com.crdroid.udfps.animations"; - private AnimationDrawable animation; - - private Resources udfpsRes; - - private String[] mAnims; - private String[] mAnimPreviews; - private String[] mTitles; - - private UdfpsAnimAdapter mUdfpsAnimAdapter; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.udfps_recog_animation_effect_title); - - loadResources(); - } - - private void loadResources() { - try { - PackageManager pm = getActivity().getPackageManager(); - udfpsRes = pm.getResourcesForApplication(mPkg); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - - mAnims = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_styles", - "array", mPkg)); - mAnimPreviews = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_previews", - "array", mPkg)); - mTitles = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_titles", - "array", mPkg)); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - mUdfpsAnimAdapter = new UdfpsAnimAdapter(getActivity()); - mRecyclerView.setAdapter(mUdfpsAnimAdapter); - - return view; - } - - public static void reset(Context mContext) { - ContentResolver resolver = mContext.getContentResolver(); - Settings.System.putIntForUser(resolver, - Settings.System.UDFPS_ANIM_STYLE, 0, UserHandle.USER_CURRENT); - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - public class UdfpsAnimAdapter extends RecyclerView.Adapter { - Context context; - String mSelectedAnim; - String mAppliedAnim; - - public UdfpsAnimAdapter(Context context) { - this.context = context; - } - - @Override - public UdfpsAnimViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false); - UdfpsAnimViewHolder vh = new UdfpsAnimViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(UdfpsAnimViewHolder holder, final int position) { - String animName = mAnims[position]; - - Glide.with(holder.image.getContext()) - .load("") - .placeholder(getDrawable(holder.image.getContext(), mAnimPreviews[position])) - .into(holder.image); - - holder.name.setText(mTitles[position]); - - if (position == Settings.System.getInt(context.getContentResolver(), - Settings.System.UDFPS_ANIM_STYLE, 0)) { - mAppliedAnim = animName; - if (mSelectedAnim == null) { - mSelectedAnim = animName; - } - } - - holder.itemView.setActivated(animName == mSelectedAnim); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedAnim, false); - updateActivatedStatus(animName, true); - mSelectedAnim = animName; - holder.image.setBackgroundDrawable(getDrawable(v.getContext(), mAnims[position])); - animation = (AnimationDrawable) holder.image.getBackground(); - animation.setOneShot(true); - animation.start(); - Settings.System.putInt(getActivity().getContentResolver(), - Settings.System.UDFPS_ANIM_STYLE, position); - } - }); - } - - @Override - public int getItemCount() { - return mAnims.length; - } - - public class UdfpsAnimViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image; - public UdfpsAnimViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image = (ImageView) itemView.findViewById(R.id.option_thumbnail); - } - } - - private void updateActivatedStatus(String anim, boolean isActivated) { - int index = Arrays.asList(mAnims).indexOf(anim); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pm.getResourcesForApplication(mPkg); - return res.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.kt b/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.kt new file mode 100644 index 00000000..b7edd7da --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/UdfpsAnimation.kt @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2022-2024 crDroid Android 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.rising.settings.fragments.lockscreen + +import android.content.ContentResolver +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.AnimationDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView + +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.PreferenceViewHolder +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import androidx.recyclerview.widget.RecyclerView + +import com.bumptech.glide.Glide + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.android.settings.SettingsActivity +import com.android.settings.SettingsPreferenceFragment + +import java.util.Arrays +import java.util.concurrent.ConcurrentHashMap +import android.os.Handler +import android.os.Looper +import java.lang.ref.WeakReference + +class UdfpsAnimation : SettingsPreferenceFragment() { + + private var mRecyclerView: RecyclerView? = null + private val mPkg = "com.crdroid.udfps.animations" + private var animation: AnimationDrawable? = null + + private var udfpsRes: Resources? = null + + private var mAnims: Array? = null + private var mAnimPreviews: Array? = null + private var mTitles: Array? = null + + private var mUdfpsAnimAdapter: UdfpsAnimAdapter? = null + + // Cache for drawable resources to prevent repeated loading + private val mDrawableCache: MutableMap = ConcurrentHashMap() + + // Handler for animation cleanup + private var mAnimationHandler: Handler? = null + + // Track active animations to prevent memory leaks + private var mCurrentAnimation: AnimationDrawable? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.udfps_recog_animation_effect_title) + + // Initialize handler for animation management + mAnimationHandler = Handler(Looper.getMainLooper()) + + loadResources() + } + + private fun loadResources() { + val activity = activity ?: return + + try { + val pm = activity.packageManager + udfpsRes = pm.getResourcesForApplication(mPkg) + + udfpsRes?.let { res -> + mAnims = res.getStringArray(res.getIdentifier("udfps_animation_styles", "array", mPkg)) + mAnimPreviews = res.getStringArray(res.getIdentifier("udfps_animation_previews", "array", mPkg)) + mTitles = res.getStringArray(res.getIdentifier("udfps_animation_titles", "array", mPkg)) + } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + } + + override fun onCreateView( + @NonNull inflater: LayoutInflater, + @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view)?.apply { + val gridLayoutManager = GridLayoutManager(activity, 3) + layoutManager = gridLayoutManager + mUdfpsAnimAdapter = UdfpsAnimAdapter(activity!!) + adapter = mUdfpsAnimAdapter + } + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + inner class UdfpsAnimAdapter(private val context: Context) : RecyclerView.Adapter() { + private var mSelectedAnim: String? = null + private var mAppliedAnim: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UdfpsAnimViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.item_option, parent, false) + return UdfpsAnimViewHolder(v) + } + + override fun onBindViewHolder(holder: UdfpsAnimViewHolder, position: Int) { + val anims = mAnims ?: return + val animPreviews = mAnimPreviews ?: return + val titles = mTitles ?: return + + if (position >= anims.size || position >= animPreviews.size || position >= titles.size) { + return + } + + val animName = anims[position] + + // Use cached drawable if available + val previewDrawable = getCachedDrawable(holder.image.context, animPreviews[position]) + if (previewDrawable != null) { + Glide.with(holder.image.context) + .load("") + .placeholder(previewDrawable) + .into(holder.image) + } + + holder.name.text = titles[position] + + if (position == Settings.System.getInt(context.contentResolver, + Settings.System.UDFPS_ANIM_STYLE, 0)) { + mAppliedAnim = animName + if (mSelectedAnim == null) { + mSelectedAnim = animName + } + } + + holder.itemView.isActivated = animName == mSelectedAnim + holder.itemView.setOnClickListener { v -> + // Stop current animation before starting new one + stopCurrentAnimation() + + updateActivatedStatus(mSelectedAnim, false) + updateActivatedStatus(animName, true) + mSelectedAnim = animName + + val animDrawable = getCachedDrawable(v.context, anims[position]) + if (animDrawable != null) { + holder.image.background = animDrawable + mCurrentAnimation = holder.image.background as? AnimationDrawable + mCurrentAnimation?.let { animation -> + animation.setOneShot(true) + animation.start() + + // Auto-stop animation after reasonable time to prevent memory leaks + mAnimationHandler?.postDelayed({ stopCurrentAnimation() }, 5000) + } + } + + activity?.let { activity -> + Settings.System.putInt(activity.contentResolver, + Settings.System.UDFPS_ANIM_STYLE, position) + } + } + } + + override fun getItemCount(): Int { + return mAnims?.size ?: 0 + } + + inner class UdfpsAnimViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView = itemView.findViewById(R.id.option_label) + val image: ImageView = itemView.findViewById(R.id.option_thumbnail) + } + + private fun updateActivatedStatus(anim: String?, isActivated: Boolean) { + val anims = mAnims ?: return + val index = anims.indexOf(anim) + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + // Optimized drawable loading with caching + private fun getCachedDrawable(context: Context?, drawableName: String?): Drawable? { + if (drawableName == null || context == null) { + return null + } + + // Check cache first + val cached = mDrawableCache[drawableName] + if (cached != null) { + return cached + } + + // Load and cache drawable + val drawable = getDrawable(context, drawableName) + if (drawable != null) { + mDrawableCache[drawableName] = drawable + } + return drawable + } + + private fun getDrawable(context: Context, drawableName: String): Drawable? { + return try { + val pm = context.packageManager + val res = pm.getResourcesForApplication(mPkg) + res.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun stopCurrentAnimation() { + mCurrentAnimation?.let { animation -> + if (animation.isRunning) { + animation.stop() + } + } + mCurrentAnimation = null + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup animations and caches + stopCurrentAnimation() + mAnimationHandler?.removeCallbacksAndMessages(null) + mDrawableCache.clear() + udfpsRes = null + } + + override fun onDetach() { + super.onDetach() + // Additional cleanup + stopCurrentAnimation() + mDrawableCache.clear() + } + + companion object { + @JvmStatic + fun reset(mContext: Context) { + val resolver = mContext.contentResolver + Settings.System.putIntForUser(resolver, + Settings.System.UDFPS_ANIM_STYLE, 0, UserHandle.USER_CURRENT) + } + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.java b/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.java deleted file mode 100644 index cfed6e51..00000000 --- a/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2022-2024 crDroid Android 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.rising.settings.fragments.lockscreen; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.UserHandle; -import android.net.Uri; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.text.TextUtils; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.res.ResourcesCompat; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.Glide; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.json.JSONException; -import org.json.JSONObject; - -public class UdfpsIconPicker extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - - private Resources udfpsRes; - - private String mPkg = "com.crdroid.udfps.icons"; - - private String[] mIcons; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.udfps_icon_picker_title); - - loadResources(); - } - - private void loadResources() { - try { - PackageManager pm = getActivity().getPackageManager(); - udfpsRes = pm.getResourcesForApplication(mPkg); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - - mIcons = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_icons", - "array", mPkg)); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - UdfpsIconAdapter mUdfpsIconAdapter = new UdfpsIconAdapter(getActivity()); - mRecyclerView.setAdapter(mUdfpsIconAdapter); - - return view; - } - - public static void reset(Context mContext) { - ContentResolver resolver = mContext.getContentResolver(); - Settings.System.putIntForUser(resolver, - "udfps_icon", 0, UserHandle.USER_CURRENT); - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class UdfpsIconAdapter extends RecyclerView.Adapter { - Context context; - String mSelectedIcon; - String mAppliedIcon; - - public UdfpsIconAdapter(Context context) { - this.context = context; - } - - @Override - public UdfpsIconViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false); - UdfpsIconViewHolder vh = new UdfpsIconViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(UdfpsIconViewHolder holder, final int position) { - String iconRes = mIcons[position]; - - Glide.with(holder.image.getContext()) - .load("") - .placeholder(getDrawable(holder.image.getContext(), mIcons[position])) - .into(holder.image); - - holder.image.setPadding(20,20,20,20); - - holder.name.setVisibility(View.GONE); - - if (position == Settings.System.getInt(context.getContentResolver(), - "udfps_icon", 0)) { - mAppliedIcon = iconRes; - if (mSelectedIcon == null) { - mSelectedIcon = iconRes; - } - } - holder.itemView.setActivated(iconRes == mSelectedIcon); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedIcon, false); - updateActivatedStatus(iconRes, true); - mSelectedIcon = iconRes; - Settings.System.putInt(getActivity().getContentResolver(), - "udfps_icon", position); - } - }); - } - - @Override - public int getItemCount() { - return mIcons.length; - } - - public class UdfpsIconViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image; - public UdfpsIconViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image = (ImageView) itemView.findViewById(R.id.option_thumbnail); - } - } - - private void updateActivatedStatus(String icon, boolean isActivated) { - int index = Arrays.asList(mIcons).indexOf(icon); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pm.getResourcesForApplication(mPkg); - Context ctx = context.createPackageContext( - mPkg, Context.CONTEXT_IGNORE_SECURITY); - return ctx.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.kt b/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.kt new file mode 100644 index 00000000..6e9c3303 --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/UdfpsIconPicker.kt @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022-2024 crDroid Android 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.rising.settings.fragments.lockscreen + +import android.app.Activity +import android.content.ContentResolver +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.AnimationDrawable +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.os.UserHandle +import android.net.Uri +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.text.TextUtils +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup.LayoutParams +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import android.widget.Toast + +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.core.content.res.ResourcesCompat +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.PreferenceViewHolder +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import androidx.recyclerview.widget.RecyclerView + +import com.bumptech.glide.Glide + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.Indexable + +import java.util.ArrayList +import java.util.Arrays +import java.util.List + +import org.json.JSONException +import org.json.JSONObject + +class UdfpsIconPicker : OptimizedSettingsFragment() { + + private lateinit var mRecyclerView: RecyclerView + private var udfpsRes: Resources? = null + private val mPkg = "com.crdroid.udfps.icons" + private lateinit var mIcons: Array + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.udfps_icon_picker_title) + + loadResources() + } + + private fun loadResources() { + try { + val context = getSafeContext() + if (context != null) { + udfpsRes = context.packageManager?.getResourcesForApplication(mPkg) + } + } catch (e: PackageManager.NameNotFoundException) { + // Handle silently - package not found + } + + udfpsRes?.let { res -> + mIcons = res.getStringArray(res.getIdentifier("udfps_icons", "array", mPkg)) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 3) + mRecyclerView.layoutManager = gridLayoutManager + val mUdfpsIconAdapter = UdfpsIconAdapter(activity!!) + mRecyclerView.adapter = mUdfpsIconAdapter + + return view + } + + companion object { + @JvmStatic + fun reset(mContext: Context) { + val resolver = mContext.contentResolver + Settings.System.putIntForUser(resolver, + "udfps_icon", 0, UserHandle.USER_CURRENT) + } + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class UdfpsIconAdapter(val context: Context) : RecyclerView.Adapter() { + private var mSelectedIcon: String? = null + private var mAppliedIcon: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UdfpsIconViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.item_option, parent, false) + return UdfpsIconViewHolder(v) + } + + override fun onBindViewHolder(holder: UdfpsIconViewHolder, position: Int) { + val iconRes = mIcons[position] + + Glide.with(holder.image.context) + .load("") + .placeholder(getDrawable(holder.image.context, mIcons[position])) + .into(holder.image) + + holder.image.setPadding(20, 20, 20, 20) + holder.name.visibility = View.GONE + + if (position == Settings.System.getInt(context.contentResolver, "udfps_icon", 0)) { + mAppliedIcon = iconRes + if (mSelectedIcon == null) { + mSelectedIcon = iconRes + } + } + holder.itemView.isActivated = iconRes == mSelectedIcon + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedIcon, false) + updateActivatedStatus(iconRes, true) + mSelectedIcon = iconRes + Settings.System.putInt(activity?.contentResolver, + "udfps_icon", position) + } + } + + override fun getItemCount(): Int { + return mIcons.size + } + + inner class UdfpsIconViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView = itemView.findViewById(R.id.option_label) + val image: ImageView = itemView.findViewById(R.id.option_thumbnail) + } + + private fun updateActivatedStatus(icon: String?, isActivated: Boolean) { + val index = mIcons.indexOf(icon) + if (index < 0) { + return + } + val holder = mRecyclerView.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context, drawableName: String): Drawable? { + return try { + val pm = context.packageManager + val res = pm.getResourcesForApplication(mPkg) + val ctx = context.createPackageContext(mPkg, Context.CONTEXT_IGNORE_SECURITY) + ctx.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)) + } catch (e: PackageManager.NameNotFoundException) { + // Handle silently - package not found + null + } + } + + override fun onDestroy() { + super.onDestroy() + udfpsRes = null + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.java b/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.java deleted file mode 100644 index c63ec87b..00000000 --- a/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2021 Yet Another AOSP 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.rising.settings.fragments.lockscreen.doze; - -import android.app.TimePickerDialog; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.format.DateFormat; -import android.widget.TimePicker; - -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.SecureSettingListPreference; - -import java.time.format.DateTimeFormatter; -import java.time.LocalTime; - -public class AODSchedule extends SettingsPreferenceFragment implements - Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { - - private static final String TAG = "AODSchedule"; - private static final String MODE_KEY = "doze_always_on_auto_mode"; - private static final String SINCE_PREF_KEY = "doze_always_on_auto_since"; - private static final String TILL_PREF_KEY = "doze_always_on_auto_till"; - - private static final int MODE_DISABLED = 0; - private static final int MODE_NIGHT = 1; - private static final int MODE_TIME = 2; - private static final int MODE_MIXED_SUNSET = 3; - private static final int MODE_MIXED_SUNRISE = 4; - - private SecureSettingListPreference mModePref; - private Preference mSincePref; - private Preference mTillPref; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.always_on_display_schedule); - - ContentResolver resolver = getActivity().getContentResolver(); - - mSincePref = findPreference(SINCE_PREF_KEY); - mSincePref.setOnPreferenceClickListener(this); - mTillPref = findPreference(TILL_PREF_KEY); - mTillPref.setOnPreferenceClickListener(this); - - int mode = Settings.Secure.getIntForUser(resolver, - MODE_KEY, MODE_DISABLED, UserHandle.USER_CURRENT); - mModePref = (SecureSettingListPreference) findPreference(MODE_KEY); - mModePref.setValue(String.valueOf(mode)); - mModePref.setSummary(mModePref.getEntry()); - mModePref.setOnPreferenceChangeListener(this); - - updateTimeEnablement(mode); - updateTimeSummary(mode); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object objValue) { - int value = Integer.parseInt((String) objValue); - int index = mModePref.findIndexOfValue((String) objValue); - mModePref.setSummary(mModePref.getEntries()[index]); - Settings.Secure.putIntForUser(getActivity().getContentResolver(), - MODE_KEY, value, UserHandle.USER_CURRENT); - updateTimeEnablement(value); - updateTimeSummary(value); - return true; - } - - @Override - public boolean onPreferenceClick(Preference preference) { - String[] times = getCustomTimeSetting(); - boolean isSince = preference == mSincePref; - int hour, minute; - TimePickerDialog.OnTimeSetListener listener = (view, hourOfDay, minute1) -> { - updateTimeSetting(isSince, hourOfDay, minute1); - }; - if (isSince) { - String[] sinceValues = times[0].split(":", 0); - hour = Integer.parseInt(sinceValues[0]); - minute = Integer.parseInt(sinceValues[1]); - } else { - String[] tillValues = times[1].split(":", 0); - hour = Integer.parseInt(tillValues[0]); - minute = Integer.parseInt(tillValues[1]); - } - TimePickerDialog dialog = new TimePickerDialog(getContext(), listener, - hour, minute, DateFormat.is24HourFormat(getContext())); - dialog.show(); - return true; - } - - private String[] getCustomTimeSetting() { - String value = Settings.Secure.getStringForUser(getActivity().getContentResolver(), - Settings.Secure.DOZE_ALWAYS_ON_AUTO_TIME, UserHandle.USER_CURRENT); - if (value == null || value.equals("")) value = "20:00,07:00"; - return value.split(",", 0); - } - - private void updateTimeEnablement(int mode) { - mSincePref.setEnabled(mode == MODE_TIME || mode == MODE_MIXED_SUNRISE); - mTillPref.setEnabled(mode == MODE_TIME || mode == MODE_MIXED_SUNSET); - } - - private void updateTimeSummary(int mode) { - updateTimeSummary(getCustomTimeSetting(), mode); - } - - private void updateTimeSummary(String[] times, int mode) { - if (mode == MODE_DISABLED) { - mSincePref.setSummary("-"); - mTillPref.setSummary("-"); - return; - } - - if (mode == MODE_NIGHT) { - mSincePref.setSummary(R.string.always_on_display_schedule_sunset); - mTillPref.setSummary(R.string.always_on_display_schedule_sunrise); - return; - } - - String outputFormat = DateFormat.is24HourFormat(getContext()) ? "HH:mm" : "hh:mm a"; - DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); - LocalTime sinceDT = LocalTime.parse(times[0], formatter); - LocalTime tillDT = LocalTime.parse(times[1], formatter); - - if (mode == MODE_MIXED_SUNSET) { - mSincePref.setSummary(R.string.always_on_display_schedule_sunset); - mTillPref.setSummary(tillDT.format(outputFormatter)); - } else if (mode == MODE_MIXED_SUNRISE) { - mTillPref.setSummary(R.string.always_on_display_schedule_sunrise); - mSincePref.setSummary(sinceDT.format(outputFormatter)); - } else { - mSincePref.setSummary(sinceDT.format(outputFormatter)); - mTillPref.setSummary(tillDT.format(outputFormatter)); - } - } - - private void updateTimeSetting(boolean since, int hour, int minute) { - String[] times = getCustomTimeSetting(); - String nHour = ""; - String nMinute = ""; - if (hour < 10) nHour += "0"; - if (minute < 10) nMinute += "0"; - nHour += String.valueOf(hour); - nMinute += String.valueOf(minute); - times[since ? 0 : 1] = nHour + ":" + nMinute; - Settings.Secure.putStringForUser(getActivity().getContentResolver(), - Settings.Secure.DOZE_ALWAYS_ON_AUTO_TIME, - times[0] + "," + times[1], UserHandle.USER_CURRENT); - updateTimeSummary(times, Integer.parseInt(mModePref.getValue())); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.kt b/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.kt new file mode 100644 index 00000000..72af6cf7 --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/doze/AODSchedule.kt @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2021 Yet Another AOSP 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.rising.settings.fragments.lockscreen.doze + +import android.app.TimePickerDialog +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import android.text.format.DateFormat +import android.widget.TimePicker + +import androidx.preference.Preference +import androidx.preference.PreferenceScreen + +import com.android.internal.logging.nano.MetricsProto + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.SecureSettingListPreference + +import java.time.format.DateTimeFormatter +import java.time.LocalTime + +class AODSchedule : OptimizedSettingsFragment(), + Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { + + companion object { + private const val TAG = "AODSchedule" + private const val MODE_KEY = "doze_always_on_auto_mode" + private const val SINCE_PREF_KEY = "doze_always_on_auto_since" + private const val TILL_PREF_KEY = "doze_always_on_auto_till" + + private const val MODE_DISABLED = 0 + private const val MODE_NIGHT = 1 + private const val MODE_TIME = 2 + private const val MODE_MIXED_SUNSET = 3 + private const val MODE_MIXED_SUNRISE = 4 + } + + private lateinit var mModePref: SecureSettingListPreference + private lateinit var mSincePref: Preference + private lateinit var mTillPref: Preference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.always_on_display_schedule) + + val resolver = activity?.contentResolver + + mSincePref = findPreference(SINCE_PREF_KEY)!! + mSincePref.onPreferenceClickListener = this + mTillPref = findPreference(TILL_PREF_KEY)!! + mTillPref.onPreferenceClickListener = this + + val mode = Settings.Secure.getIntForUser(resolver, + MODE_KEY, MODE_DISABLED, UserHandle.USER_CURRENT) + mModePref = findPreference(MODE_KEY)!! + mModePref.value = mode.toString() + mModePref.summary = mModePref.entry + mModePref.onPreferenceChangeListener = this + + updateTimeEnablement(mode) + updateTimeSummary(mode) + } + + override fun onPreferenceChange(preference: Preference, objValue: Any): Boolean { + val value = (objValue as String).toInt() + val index = mModePref.findIndexOfValue(objValue) + mModePref.summary = mModePref.entries[index] + Settings.Secure.putIntForUser(activity?.contentResolver, + MODE_KEY, value, UserHandle.USER_CURRENT) + updateTimeEnablement(value) + updateTimeSummary(value) + return true + } + + override fun onPreferenceClick(preference: Preference): Boolean { + val times = getCustomTimeSetting() + val isSince = preference == mSincePref + val hour: Int + val minute: Int + val listener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute1 -> + updateTimeSetting(isSince, hourOfDay, minute1) + } + if (isSince) { + val sinceValues = times[0].split(":") + hour = sinceValues[0].toInt() + minute = sinceValues[1].toInt() + } else { + val tillValues = times[1].split(":") + hour = tillValues[0].toInt() + minute = tillValues[1].toInt() + } + val dialog = TimePickerDialog(context, listener, + hour, minute, DateFormat.is24HourFormat(context)) + dialog.show() + return true + } + + private fun getCustomTimeSetting(): Array { + var value = Settings.Secure.getStringForUser(activity?.contentResolver, + Settings.Secure.DOZE_ALWAYS_ON_AUTO_TIME, UserHandle.USER_CURRENT) + if (value.isNullOrEmpty()) value = "20:00,07:00" + return value.split(",").toTypedArray() + } + + private fun updateTimeEnablement(mode: Int) { + mSincePref.isEnabled = mode == MODE_TIME || mode == MODE_MIXED_SUNRISE + mTillPref.isEnabled = mode == MODE_TIME || mode == MODE_MIXED_SUNSET + } + + private fun updateTimeSummary(mode: Int) { + updateTimeSummary(getCustomTimeSetting(), mode) + } + + private fun updateTimeSummary(times: Array, mode: Int) { + if (mode == MODE_DISABLED) { + mSincePref.summary = "-" + mTillPref.summary = "-" + return + } + + if (mode == MODE_NIGHT) { + mSincePref.setSummary(R.string.always_on_display_schedule_sunset) + mTillPref.setSummary(R.string.always_on_display_schedule_sunrise) + return + } + + val outputFormat = if (DateFormat.is24HourFormat(context)) "HH:mm" else "hh:mm a" + val outputFormatter = DateTimeFormatter.ofPattern(outputFormat) + val formatter = DateTimeFormatter.ofPattern("HH:mm") + val sinceDT = LocalTime.parse(times[0], formatter) + val tillDT = LocalTime.parse(times[1], formatter) + + when (mode) { + MODE_MIXED_SUNSET -> { + mSincePref.setSummary(R.string.always_on_display_schedule_sunset) + mTillPref.summary = tillDT.format(outputFormatter) + } + MODE_MIXED_SUNRISE -> { + mTillPref.setSummary(R.string.always_on_display_schedule_sunrise) + mSincePref.summary = sinceDT.format(outputFormatter) + } + else -> { + mSincePref.summary = sinceDT.format(outputFormatter) + mTillPref.summary = tillDT.format(outputFormatter) + } + } + } + + private fun updateTimeSetting(since: Boolean, hour: Int, minute: Int) { + val times = getCustomTimeSetting() + var nHour = "" + var nMinute = "" + if (hour < 10) nHour += "0" + if (minute < 10) nMinute += "0" + nHour += hour.toString() + nMinute += minute.toString() + times[if (since) 0 else 1] = "$nHour:$nMinute" + Settings.Secure.putStringForUser(activity?.contentResolver, + Settings.Secure.DOZE_ALWAYS_ON_AUTO_TIME, + "${times[0]},${times[1]}", UserHandle.USER_CURRENT) + updateTimeSummary(times, mModePref.value.toInt()) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.java b/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.java deleted file mode 100644 index 782e168e..00000000 --- a/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2023 crDroid Android 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.rising.settings.fragments.lockscreen.doze; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.MediaStore; -import android.provider.Settings; -import android.widget.Toast; - -import com.android.internal.logging.nano.MetricsProto; - -import androidx.preference.Preference; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.utils.ImageUtils; - -public class AODSettings extends SettingsPreferenceFragment { - - private static final String CUSTOM_IMAGE_REQUEST_CODE_KEY = "lockscreen_custom_image"; - private static final int CUSTOM_IMAGE_REQUEST_CODE = 1001; - - private Preference mCustomImagePreference; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_aod_settings); - mCustomImagePreference = findPreference(CUSTOM_IMAGE_REQUEST_CODE_KEY); - int clockStyle = Settings.Secure.getIntForUser(getContext().getContentResolver(), "clock_style", 0, UserHandle.USER_CURRENT); - String imagePath = Settings.System.getString(getContext().getContentResolver(), "custom_aod_image_uri"); - if (imagePath != null && clockStyle > 0) { - mCustomImagePreference.setSummary(imagePath); - mCustomImagePreference.setEnabled(true); - } else if (clockStyle == 0) { - mCustomImagePreference.setSummary(getContext().getString(R.string.custom_aod_image_not_supported)); - mCustomImagePreference.setEnabled(false); - } - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - if (preference == mCustomImagePreference) { - try { - Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(intent, CUSTOM_IMAGE_REQUEST_CODE); - } catch(Exception e) { - Toast.makeText(getContext(), R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show(); - } - return true; - } - return super.onPreferenceTreeClick(preference); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent result) { - super.onActivityResult(requestCode, resultCode, result); - if (requestCode == CUSTOM_IMAGE_REQUEST_CODE && resultCode == Activity.RESULT_OK && result != null) { - Uri imgUri = result.getData(); - if (imgUri != null) { - String savedImagePath = ImageUtils.saveImageToInternalStorage(getContext(), imgUri, "lockscreen_aod_image", "LOCKSCREEN_CUSTOM_AOD_IMAGE"); - if (savedImagePath != null) { - ContentResolver resolver = getContext().getContentResolver(); - Settings.System.putStringForUser(resolver, "custom_aod_image_uri", savedImagePath, UserHandle.USER_CURRENT); - mCustomImagePreference.setSummary(savedImagePath); - } - } - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.kt b/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.kt new file mode 100644 index 00000000..9696580b --- /dev/null +++ b/src/com/rising/settings/fragments/lockscreen/doze/AODSettings.kt @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 crDroid Android 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.rising.settings.fragments.lockscreen.doze + +import android.app.Activity +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.os.Bundle +import android.os.UserHandle +import android.provider.MediaStore +import android.provider.Settings +import android.widget.Toast + +import com.android.internal.logging.nano.MetricsProto + +import androidx.preference.Preference + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.utils.ImageUtils + +class AODSettings : OptimizedSettingsFragment() { + + companion object { + private const val CUSTOM_IMAGE_REQUEST_CODE_KEY = "lockscreen_custom_image" + private const val CUSTOM_IMAGE_REQUEST_CODE = 1001 + } + + private lateinit var mCustomImagePreference: Preference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_aod_settings) + mCustomImagePreference = findCachedPreference(CUSTOM_IMAGE_REQUEST_CODE_KEY)!! + val context = getSafeContext() + val clockStyle = context?.let { ctx -> + Settings.Secure.getIntForUser(ctx.contentResolver, "clock_style", 0, UserHandle.USER_CURRENT) + } ?: 0 + val imagePath = Settings.System.getString(context?.contentResolver, "custom_aod_image_uri") + if (imagePath != null && clockStyle.compareTo(0) > 0) { + mCustomImagePreference.summary = imagePath + mCustomImagePreference.isEnabled = true + } else if (clockStyle == 0) { + mCustomImagePreference.summary = context?.getString(R.string.custom_aod_image_not_supported) + mCustomImagePreference.isEnabled = false + } + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { + if (preference == mCustomImagePreference) { + try { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + intent.type = "image/*" + startActivityForResult(intent, CUSTOM_IMAGE_REQUEST_CODE) + } catch (e: Exception) { + Toast.makeText(context, R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show() + } + return true + } + return super.onPreferenceTreeClick(preference) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, result: Intent?) { + super.onActivityResult(requestCode, resultCode, result) + if (requestCode == CUSTOM_IMAGE_REQUEST_CODE && resultCode == Activity.RESULT_OK && result != null) { + val imgUri = result.data + if (imgUri != null) { + val savedImagePath = context?.let { ctx -> + ImageUtils.saveImageToInternalStorage(ctx, imgUri, "lockscreen_aod_image", "LOCKSCREEN_CUSTOM_AOD_IMAGE") + } + if (savedImagePath != null) { + val resolver = context?.contentResolver + Settings.System.putStringForUser(resolver, "custom_aod_image_uri", savedImagePath, UserHandle.USER_CURRENT) + mCustomImagePreference.summary = savedImagePath + } + } + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.java b/src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.kt similarity index 52% rename from src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.java rename to src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.kt index 8a4de1b8..c8b8bbd0 100644 --- a/src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.java +++ b/src/com/rising/settings/fragments/lockscreen/doze/EdgeLightSettings.kt @@ -13,25 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.rising.settings.fragments.lockscreen.doze; +package com.rising.settings.fragments.lockscreen.doze -import android.os.Bundle; +import android.os.Bundle -import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.nano.MetricsProto -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment -public class EdgeLightSettings extends SettingsPreferenceFragment { +class EdgeLightSettings : OptimizedSettingsFragment() { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.edge_light_settings); + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.edge_light_settings) } - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN } } diff --git a/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.java b/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.java deleted file mode 100644 index 4d6aa69b..00000000 --- a/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2023-2024 The Nameless-AOSP Project - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.rising.settings.fragments.popup; - -import android.content.Intent; -import android.os.Bundle; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.internal.util.android.PopUpSettingsHelper; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.SystemSettingListPreference; -import com.android.settings.preferences.SystemSettingSwitchPreference; - -public class PopUpViewSettingsFragment extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - private static final String KEY_KEEP_MUTE = "pop_up_keep_mute_in_mini"; - private static final String KEY_SINGLE_TAP_ACTION = "pop_up_single_tap_action"; - private static final String KEY_DOUBLE_TAP_ACTION = "pop_up_double_tap_action"; - private static final String KEY_NOTIFICATION_PORTRAIT = "pop_up_notification_jump_portrait"; - private static final String KEY_NOTIFICATION_LANDSCAPE = "pop_up_notification_jump_landscape"; - private static final String KEY_NOTIFICATION_BLACKLIST = "pop_up_notification_blacklist"; - - - private SystemSettingSwitchPreference mKeepMuteInMini; - private SystemSettingListPreference mSingleTapAction; - private SystemSettingListPreference mDoubleTapAction; - private SystemSettingSwitchPreference mNotifPortrait; - private SystemSettingSwitchPreference mNotifLandscape; - private Preference mNotifBlacklist; - - @Override - public void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - addPreferencesFromResource(R.xml.pop_up_view_settings); - - - mKeepMuteInMini = (SystemSettingSwitchPreference) findPreference(KEY_KEEP_MUTE); - mSingleTapAction = (SystemSettingListPreference) findPreference(KEY_SINGLE_TAP_ACTION); - mDoubleTapAction = (SystemSettingListPreference) findPreference(KEY_DOUBLE_TAP_ACTION); - mNotifPortrait = (SystemSettingSwitchPreference) findPreference(KEY_NOTIFICATION_PORTRAIT); - mNotifLandscape = (SystemSettingSwitchPreference) findPreference(KEY_NOTIFICATION_LANDSCAPE); - mNotifBlacklist = (Preference) findPreference(KEY_NOTIFICATION_BLACKLIST); - - mSingleTapAction.setOnPreferenceChangeListener(this); - - mDoubleTapAction.setOnPreferenceChangeListener(this); - - mNotifPortrait.setOnPreferenceChangeListener(this); - - mNotifLandscape.setOnPreferenceChangeListener(this); - - mNotifBlacklist.setEnabled(mNotifPortrait.isChecked() || mNotifLandscape.isChecked()); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mSingleTapAction) { - mSingleTapAction.setSummary(mSingleTapAction.getEntries()[Integer.parseInt((String) newValue)]); - } else if (preference == mDoubleTapAction) { - mDoubleTapAction.setSummary(mDoubleTapAction.getEntries()[Integer.parseInt((String) newValue)]); - } else if (preference == mNotifPortrait) { - mNotifBlacklist.setEnabled((Boolean) newValue || mNotifLandscape.isChecked()); - } else if (preference == mNotifLandscape) { - mNotifBlacklist.setEnabled(mNotifPortrait.isChecked() || (Boolean) newValue); - } - return true; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.kt b/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.kt new file mode 100644 index 00000000..1f091267 --- /dev/null +++ b/src/com/rising/settings/fragments/popup/PopUpViewSettingsFragment.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023-2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.rising.settings.fragments.popup + +import android.os.Bundle +import androidx.preference.Preference + +import com.android.internal.logging.nano.MetricsProto + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.SystemSettingListPreference +import com.android.settings.preferences.SystemSettingSwitchPreference + +class PopUpViewSettingsFragment : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private const val KEY_KEEP_MUTE = "pop_up_keep_mute_in_mini" + private const val KEY_SINGLE_TAP_ACTION = "pop_up_single_tap_action" + private const val KEY_DOUBLE_TAP_ACTION = "pop_up_double_tap_action" + private const val KEY_NOTIFICATION_PORTRAIT = "pop_up_notification_jump_portrait" + private const val KEY_NOTIFICATION_LANDSCAPE = "pop_up_notification_jump_landscape" + private const val KEY_NOTIFICATION_BLACKLIST = "pop_up_notification_blacklist" + } + + private var mKeepMuteInMini: SystemSettingSwitchPreference? = null + private var mSingleTapAction: SystemSettingListPreference? = null + private var mDoubleTapAction: SystemSettingListPreference? = null + private var mNotifPortrait: SystemSettingSwitchPreference? = null + private var mNotifLandscape: SystemSettingSwitchPreference? = null + private var mNotifBlacklist: Preference? = null + + override fun onCreate(savedInstance: Bundle?) { + super.onCreate(savedInstance) + addPreferencesFromResource(R.xml.pop_up_view_settings) + + mKeepMuteInMini = findCachedPreference(KEY_KEEP_MUTE) as? SystemSettingSwitchPreference + mSingleTapAction = findCachedPreference(KEY_SINGLE_TAP_ACTION) as? SystemSettingListPreference + mDoubleTapAction = findCachedPreference(KEY_DOUBLE_TAP_ACTION) as? SystemSettingListPreference + mNotifPortrait = findCachedPreference(KEY_NOTIFICATION_PORTRAIT) as? SystemSettingSwitchPreference + mNotifLandscape = findCachedPreference(KEY_NOTIFICATION_LANDSCAPE) as? SystemSettingSwitchPreference + mNotifBlacklist = findCachedPreference(KEY_NOTIFICATION_BLACKLIST) + + mSingleTapAction?.onPreferenceChangeListener = this + mDoubleTapAction?.onPreferenceChangeListener = this + mNotifPortrait?.onPreferenceChangeListener = this + mNotifLandscape?.onPreferenceChangeListener = this + + mNotifBlacklist?.isEnabled = (mNotifPortrait?.isChecked == true) || (mNotifLandscape?.isChecked == true) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + when (preference) { + mSingleTapAction -> { + val index = (newValue as? String)?.toIntOrNull() ?: 0 + mSingleTapAction?.entries?.getOrNull(index)?.let { entry -> + mSingleTapAction?.summary = entry + } + } + mDoubleTapAction -> { + val index = (newValue as? String)?.toIntOrNull() ?: 0 + mDoubleTapAction?.entries?.getOrNull(index)?.let { entry -> + mDoubleTapAction?.summary = entry + } + } + mNotifPortrait -> { + mNotifBlacklist?.isEnabled = (newValue as? Boolean == true) || (mNotifLandscape?.isChecked == true) + } + mNotifLandscape -> { + mNotifBlacklist?.isEnabled = (mNotifPortrait?.isChecked == true) || (newValue as? Boolean == true) + } + } + return true + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.java b/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.java deleted file mode 100644 index 6922bdc9..00000000 --- a/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2024 crDroid Android 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.rising.settings.fragments.quicksettings; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.MediaStore; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.widget.Toast; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.search.SearchIndexable; - -import com.android.settings.utils.ImageUtils; - -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -@SearchIndexable -public class QsHeaderImageSettings extends SettingsPreferenceFragment implements - OnPreferenceChangeListener { - - private static final String CUSTOM_HEADER_BROWSE = "custom_header_browse"; - private static final String DAYLIGHT_HEADER_PACK = "daylight_header_pack"; - private static final String CUSTOM_HEADER_PROVIDER = "qs_header_provider"; - private static final String STATUS_BAR_CUSTOM_HEADER = "status_bar_custom_header"; - private static final String FILE_HEADER_SELECT = "file_header_select"; - private static final int REQUEST_PICK_IMAGE = 0; - - private Preference mHeaderBrowse; - private ListPreference mDaylightHeaderPack; - private ListPreference mHeaderProvider; - private String mDaylightHeaderProvider; - private Preference mFileHeader; - private String mFileHeaderProvider; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - addPreferencesFromResource(R.xml.qs_header_image_settings); - - ContentResolver resolver = getActivity().getContentResolver(); - - mHeaderBrowse = findPreference(CUSTOM_HEADER_BROWSE); - mHeaderBrowse.setEnabled(isBrowseHeaderAvailable()); - - mDaylightHeaderPack = (ListPreference) findPreference(DAYLIGHT_HEADER_PACK); - - List entries = new ArrayList(); - List values = new ArrayList(); - getAvailableHeaderPacks(entries, values); - mDaylightHeaderPack.setEntries(entries.toArray(new String[entries.size()])); - mDaylightHeaderPack.setEntryValues(values.toArray(new String[values.size()])); - updateHeaderProviderSummary(); - mDaylightHeaderPack.setOnPreferenceChangeListener(this); - - mDaylightHeaderProvider = "daylight"; - mFileHeaderProvider = "file"; - String providerName = Settings.System.getString(resolver, - Settings.System.STATUS_BAR_CUSTOM_HEADER_PROVIDER); - if (providerName == null) { - providerName = mDaylightHeaderProvider; - } - mHeaderBrowse.setEnabled(isBrowseHeaderAvailable() && !providerName.equals(mFileHeaderProvider)); - - mHeaderProvider = (ListPreference) findPreference(CUSTOM_HEADER_PROVIDER); - int valueIndex = mHeaderProvider.findIndexOfValue(providerName); - mHeaderProvider.setValueIndex(valueIndex >= 0 ? valueIndex : 0); - mHeaderProvider.setSummary(mHeaderProvider.getEntry()); - mHeaderProvider.setOnPreferenceChangeListener(this); - mDaylightHeaderPack.setEnabled(providerName.equals(mDaylightHeaderProvider)); - - mFileHeader = findPreference(FILE_HEADER_SELECT); - mFileHeader.setEnabled(providerName.equals(mFileHeaderProvider)); - } - - private void updateHeaderProviderSummary() { - String settingHeaderPackage = Settings.System.getString(getActivity().getContentResolver(), - Settings.System.STATUS_BAR_DAYLIGHT_HEADER_PACK); - int valueIndex = mDaylightHeaderPack.findIndexOfValue(settingHeaderPackage); - if (valueIndex >= 0) { - mDaylightHeaderPack.setValueIndex(valueIndex >= 0 ? valueIndex : 0); - mDaylightHeaderPack.setSummary(mDaylightHeaderPack.getEntry()); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ContentResolver resolver = getActivity().getContentResolver(); - switch (preference.getKey()) { - case DAYLIGHT_HEADER_PACK: - String dhvalue = (String) newValue; - Settings.System.putString(resolver, - Settings.System.STATUS_BAR_DAYLIGHT_HEADER_PACK, dhvalue); - int dhvalueIndex = mDaylightHeaderPack.findIndexOfValue(dhvalue); - mDaylightHeaderPack.setSummary(mDaylightHeaderPack.getEntries()[dhvalueIndex]); - return true; - - case CUSTOM_HEADER_PROVIDER: - String value = (String) newValue; - Settings.System.putString(resolver, - Settings.System.STATUS_BAR_CUSTOM_HEADER_PROVIDER, value); - int valueIndex = mHeaderProvider.findIndexOfValue(value); - mHeaderProvider.setSummary(mHeaderProvider.getEntries()[valueIndex]); - mDaylightHeaderPack.setEnabled(value.equals(mDaylightHeaderProvider)); - mHeaderBrowse.setEnabled(!value.equals(mFileHeaderProvider)); - mHeaderBrowse.setTitle(valueIndex == 0 ? R.string.qs_header_browse_title : R.string.qs_header_pick_title); - mHeaderBrowse.setSummary(valueIndex == 0 ? R.string.qs_header_browse_summary : R.string.qs_header_pick_summary); - mFileHeader.setEnabled(value.equals(mFileHeaderProvider)); - return true; - - default: - return false; - } - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - if (preference == mFileHeader) { - try { - Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); - startActivityForResult(intent, 10001); - } catch(Exception e) { - Toast.makeText(getContext(), R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show(); - } - return true; - } - return super.onPreferenceTreeClick(preference); - } - - private boolean isBrowseHeaderAvailable() { - PackageManager pm = getActivity().getPackageManager(); - Intent browse = new Intent(); - browse.setClassName("org.omnirom.omnistyle", "org.omnirom.omnistyle.PickHeaderActivity"); - return pm.resolveActivity(browse, 0) != null; - } - - private void getAvailableHeaderPacks(List entries, List values) { - Map headerMap = new HashMap(); - Intent i = new Intent(); - PackageManager packageManager = getActivity().getPackageManager(); - i.setAction("org.omnirom.DaylightHeaderPack"); - for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { - String packageName = r.activityInfo.packageName; - String label = r.activityInfo.loadLabel(getActivity().getPackageManager()).toString(); - if (label == null) { - label = r.activityInfo.packageName; - } - headerMap.put(label, packageName); - } - i.setAction("org.omnirom.DaylightHeaderPack1"); - for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { - String packageName = r.activityInfo.packageName; - String label = r.activityInfo.loadLabel(getActivity().getPackageManager()).toString(); - if (r.activityInfo.name.endsWith(".theme")) { - continue; - } - if (label == null) { - label = packageName; - } - headerMap.put(label, packageName + "/" + r.activityInfo.name); - } - List labelList = new ArrayList(); - labelList.addAll(headerMap.keySet()); - Collections.sort(labelList); - for (String label : labelList) { - entries.add(label); - values.add(headerMap.get(label)); - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent result) { - if (requestCode == 10001) { - if (resultCode != Activity.RESULT_OK) { - return; - } - final Uri imgUri = result.getData(); - if (imgUri != null) { - String savedImagePath = ImageUtils.saveImageToInternalStorage(getContext(), imgUri, "qs_header_image", "QS_HEADER_IMAGE"); - if (savedImagePath != null) { - ContentResolver resolver = getContext().getContentResolver(); - Settings.System.putStringForUser(resolver, Settings.System.STATUS_BAR_FILE_HEADER_IMAGE, savedImagePath, UserHandle.USER_CURRENT); - } - } - } - } - - /** - * For search - */ - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - ArrayList result = - new ArrayList(); - - SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.qs_header_image_settings; - result.add(sir); - return result; - } - - @Override - public List getNonIndexableKeys(Context context) { - ArrayList result = new ArrayList(); - return result; - } - }; -} diff --git a/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.kt b/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.kt new file mode 100644 index 00000000..d5c22eab --- /dev/null +++ b/src/com/rising/settings/fragments/quicksettings/QsHeaderImageSettings.kt @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2024 crDroid Android 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.rising.settings.fragments.quicksettings + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.os.UserHandle +import android.provider.MediaStore +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.widget.Toast + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settingslib.search.SearchIndexable + +import com.android.settings.utils.ImageUtils + +@SearchIndexable +class QsHeaderImageSettings : OptimizedSettingsFragment(), OnPreferenceChangeListener { + + companion object { + private const val CUSTOM_HEADER_BROWSE = "custom_header_browse" + private const val DAYLIGHT_HEADER_PACK = "daylight_header_pack" + private const val CUSTOM_HEADER_PROVIDER = "qs_header_provider" + private const val STATUS_BAR_CUSTOM_HEADER = "status_bar_custom_header" + private const val FILE_HEADER_SELECT = "file_header_select" + private const val REQUEST_PICK_IMAGE = 0 + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider() { + override fun getXmlResourcesToIndex(context: Context, enabled: Boolean): List { + val result = ArrayList() + val sir = SearchIndexableResource(context) + sir.xmlResId = R.xml.qs_header_image_settings + result.add(sir) + return result + } + + override fun getNonIndexableKeys(context: Context): List { + return ArrayList() + } + } + } + + private var mHeaderBrowse: Preference? = null + private var mDaylightHeaderPack: ListPreference? = null + private var mHeaderProvider: ListPreference? = null + private val mDaylightHeaderProvider = "daylight" + private var mFileHeader: Preference? = null + private val mFileHeaderProvider = "file" + + override fun onCreate(icicle: Bundle?) { + super.onCreate(icicle) + + addPreferencesFromResource(R.xml.qs_header_image_settings) + + val resolver = activity?.contentResolver + + mHeaderBrowse = findCachedPreference(CUSTOM_HEADER_BROWSE) + mHeaderBrowse?.isEnabled = isBrowseHeaderAvailable() + + mDaylightHeaderPack = findCachedPreference(DAYLIGHT_HEADER_PACK) as? ListPreference + + val entries = ArrayList() + val values = ArrayList() + getAvailableHeaderPacks(entries, values) + mDaylightHeaderPack?.entries = entries.toTypedArray() + mDaylightHeaderPack?.entryValues = values.toTypedArray() + updateHeaderProviderSummary() + mDaylightHeaderPack?.onPreferenceChangeListener = this + + val providerName = Settings.System.getString(resolver, Settings.System.STATUS_BAR_CUSTOM_HEADER_PROVIDER) + ?: mDaylightHeaderProvider + mHeaderBrowse?.isEnabled = isBrowseHeaderAvailable() && providerName != mFileHeaderProvider + + mHeaderProvider = findCachedPreference(CUSTOM_HEADER_PROVIDER) as? ListPreference + val valueIndex = mHeaderProvider?.findIndexOfValue(providerName) ?: -1 + mHeaderProvider?.setValueIndex(if (valueIndex >= 0) valueIndex else 0) + mHeaderProvider?.summary = mHeaderProvider?.entry + mHeaderProvider?.onPreferenceChangeListener = this + mDaylightHeaderPack?.isEnabled = providerName == mDaylightHeaderProvider + + mFileHeader = findCachedPreference(FILE_HEADER_SELECT) + mFileHeader?.isEnabled = providerName == mFileHeaderProvider + } + + private fun updateHeaderProviderSummary() { + val settingHeaderPackage = Settings.System.getString( + activity?.contentResolver, + Settings.System.STATUS_BAR_DAYLIGHT_HEADER_PACK + ) + val valueIndex = mDaylightHeaderPack?.findIndexOfValue(settingHeaderPackage) ?: -1 + if (valueIndex >= 0) { + mDaylightHeaderPack?.setValueIndex(valueIndex) + mDaylightHeaderPack?.summary = mDaylightHeaderPack?.entry + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val resolver = activity?.contentResolver + when (preference?.key) { + DAYLIGHT_HEADER_PACK -> { + val dhvalue = newValue as? String ?: return false + Settings.System.putString(resolver, Settings.System.STATUS_BAR_DAYLIGHT_HEADER_PACK, dhvalue) + val dhvalueIndex = mDaylightHeaderPack?.findIndexOfValue(dhvalue) ?: -1 + if (dhvalueIndex >= 0) { + mDaylightHeaderPack?.summary = mDaylightHeaderPack?.entries?.get(dhvalueIndex) + } + return true + } + + CUSTOM_HEADER_PROVIDER -> { + val value = newValue as? String ?: return false + Settings.System.putString(resolver, Settings.System.STATUS_BAR_CUSTOM_HEADER_PROVIDER, value) + val valueIndex = mHeaderProvider?.findIndexOfValue(value) ?: -1 + if (valueIndex >= 0) { + mHeaderProvider?.summary = mHeaderProvider?.entries?.get(valueIndex) + } + mDaylightHeaderPack?.isEnabled = value == mDaylightHeaderProvider + mHeaderBrowse?.isEnabled = value != mFileHeaderProvider + mHeaderBrowse?.setTitle(if (valueIndex == 0) R.string.qs_header_browse_title else R.string.qs_header_pick_title) + mHeaderBrowse?.setSummary(if (valueIndex == 0) R.string.qs_header_browse_summary else R.string.qs_header_pick_summary) + mFileHeader?.isEnabled = value == mFileHeaderProvider + return true + } + + else -> return false + } + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { + if (preference == mFileHeader) { + try { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + intent.type = "image/*" + startActivityForResult(intent, 10001) + } catch (e: Exception) { + Toast.makeText(requireContext(), R.string.qs_header_needs_gallery, Toast.LENGTH_LONG).show() + } + return true + } + return super.onPreferenceTreeClick(preference) + } + + private fun isBrowseHeaderAvailable(): Boolean { + val pm = activity?.packageManager + val browse = Intent() + browse.setClassName("org.omnirom.omnistyle", "org.omnirom.omnistyle.PickHeaderActivity") + return pm?.resolveActivity(browse, 0) != null + } + + private fun getAvailableHeaderPacks(entries: MutableList, values: MutableList) { + val headerMap = HashMap() + val intent = Intent() + val packageManager = activity?.packageManager + + intent.action = "org.omnirom.DaylightHeaderPack" + packageManager?.queryIntentActivities(intent, 0)?.forEach { r -> + val packageName = r.activityInfo.packageName + val label = r.activityInfo.loadLabel(packageManager).toString().takeIf { it.isNotEmpty() } ?: packageName + headerMap[label] = packageName + } + + intent.action = "org.omnirom.DaylightHeaderPack1" + packageManager?.queryIntentActivities(intent, 0)?.forEach { r -> + val packageName = r.activityInfo.packageName + if (r.activityInfo.name.endsWith(".theme")) { + return@forEach + } + val label = r.activityInfo.loadLabel(packageManager).toString().takeIf { it.isNotEmpty() } ?: packageName + headerMap[label] = "$packageName/${r.activityInfo.name}" + } + + val labelList = headerMap.keys.sorted() + labelList.forEach { label -> + entries.add(label) + values.add(headerMap[label] ?: "") + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, result: Intent?) { + if (requestCode == 10001) { + if (resultCode != Activity.RESULT_OK) { + return + } + val imgUri = result?.data + if (imgUri != null) { + val savedImagePath = ImageUtils.saveImageToInternalStorage( + requireContext(), imgUri, "qs_header_image", "QS_HEADER_IMAGE" + ) + if (savedImagePath != null) { + val resolver = requireContext().contentResolver + Settings.System.putStringForUser( + resolver, + Settings.System.STATUS_BAR_FILE_HEADER_IMAGE, + savedImagePath, + UserHandle.USER_CURRENT + ) + } + } + } + } +} diff --git a/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.java b/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.java deleted file mode 100644 index 7e027d03..00000000 --- a/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2022 The Nameless-AOSP 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.rising.settings.fragments.quicksettings; - -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.view.View; -import android.widget.Button; -import android.widget.Toast; - -import androidx.preference.Preference; - -import com.android.internal.logging.nano.MetricsProto; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settingslib.widget.LayoutPreference; - -public class QsTileLayoutSettings extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - @Override - public void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - addPreferencesFromResource(R.xml.qs_tile_layout); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - return true; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.kt b/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.kt new file mode 100644 index 00000000..d61d2bf0 --- /dev/null +++ b/src/com/rising/settings/fragments/quicksettings/QsTileLayoutSettings.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 The Nameless-AOSP 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.rising.settings.fragments.quicksettings + +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import android.view.View +import android.widget.Button +import android.widget.Toast + +import androidx.preference.Preference + +import com.android.internal.logging.nano.MetricsProto + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settingslib.widget.LayoutPreference + +class QsTileLayoutSettings : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + override fun onCreate(savedInstance: Bundle?) { + super.onCreate(savedInstance) + addPreferencesFromResource(R.xml.qs_tile_layout) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + return true + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/sound/AdaptivePlayback.java b/src/com/rising/settings/fragments/sound/AdaptivePlayback.java deleted file mode 100644 index d20a3f2c..00000000 --- a/src/com/rising/settings/fragments/sound/AdaptivePlayback.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.sound; - -import android.content.Context; -import android.content.ContentResolver; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.widget.MainSwitchPreference; - -import com.android.settings.preferences.colorpicker.ColorPickerPreference; - -public class AdaptivePlayback extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener, OnCheckedChangeListener { - - private static final String TAG = AdaptivePlayback.class.getSimpleName(); - - private static final String PREF_KEY_ENABLE = "adaptive_playback_enabled"; - - private MainSwitchPreference mEnable; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.adaptive_playback_settings); - - mEnable = (MainSwitchPreference) findPreference(PREF_KEY_ENABLE); - boolean enable = Settings.System.getIntForUser(getContext().getContentResolver(), - Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0; - mEnable.setChecked(enable); - mEnable.addOnSwitchChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - return false; - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - mEnable.setChecked(isChecked); - if (isChecked) { - Settings.System.putIntForUser(getContext().getContentResolver(), - Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 1, UserHandle.USER_CURRENT); - } else { - Settings.System.putIntForUser(getContext().getContentResolver(), - Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 0, UserHandle.USER_CURRENT); - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/sound/AdaptivePlayback.kt b/src/com/rising/settings/fragments/sound/AdaptivePlayback.kt new file mode 100644 index 00000000..82460e56 --- /dev/null +++ b/src/com/rising/settings/fragments/sound/AdaptivePlayback.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.sound + +import android.content.Context +import android.content.ContentResolver +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import android.widget.CompoundButton +import android.widget.CompoundButton.OnCheckedChangeListener + +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settingslib.widget.MainSwitchPreference + +import com.android.settings.preferences.colorpicker.ColorPickerPreference + +class AdaptivePlayback : OptimizedSettingsFragment(), + Preference.OnPreferenceChangeListener, OnCheckedChangeListener { + + companion object { + private val TAG = AdaptivePlayback::class.java.simpleName + private const val PREF_KEY_ENABLE = "adaptive_playback_enabled" + } + + private lateinit var mEnable: MainSwitchPreference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.adaptive_playback_settings) + + mEnable = findCachedPreference(PREF_KEY_ENABLE)!! + val enable = Settings.System.getIntForUser(requireContext().contentResolver, + Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0 + mEnable.isChecked = enable + mEnable.addOnSwitchChangeListener(this) + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + return false + } + + override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { + mEnable.isChecked = isChecked + if (isChecked) { + Settings.System.putIntForUser(requireContext().contentResolver, + Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 1, UserHandle.USER_CURRENT) + } else { + Settings.System.putIntForUser(requireContext().contentResolver, + Settings.System.ADAPTIVE_PLAYBACK_ENABLED, 0, UserHandle.USER_CURRENT) + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/sound/PulseSettings.java b/src/com/rising/settings/fragments/sound/PulseSettings.java deleted file mode 100644 index 26d4ed3a..00000000 --- a/src/com/rising/settings/fragments/sound/PulseSettings.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.sound; - -import android.content.Context; -import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.SwitchPreferenceCompat; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.colorpicker.ColorPickerPreference; - -public class PulseSettings extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - private static final String TAG = PulseSettings.class.getSimpleName(); - - private static final String LOCKSCREEN_PULSE_ENABLED_KEY = "lockscreen_pulse_enabled"; - private static final String AMBIENT_PULSE_ENABLED_KEY = "ambient_pulse_enabled"; - private static final String PULSE_SMOOTHING_KEY = "pulse_smoothing_enabled"; - private static final String PULSE_COLOR_MODE_KEY = "pulse_color_mode"; - private static final String PULSE_COLOR_MODE_CHOOSER_KEY = "pulse_color_user"; - private static final String PULSE_COLOR_MODE_LAVA_SPEED_KEY = "pulse_lavalamp_speed"; - private static final String PULSE_RENDER_CATEGORY_SOLID = "pulse_2"; - private static final String PULSE_RENDER_CATEGORY_FADING = "pulse_fading_bars_category"; - private static final String PULSE_RENDER_MODE_KEY = "pulse_render_style"; - private static final int RENDER_STYLE_FADING_BARS = 0; - private static final int RENDER_STYLE_SOLID_LINES = 1; - private static final int COLOR_TYPE_ACCENT = 0; - private static final int COLOR_TYPE_USER = 1; - private static final int COLOR_TYPE_LAVALAMP = 2; - private static final int COLOR_TYPE_AUTO = 3; - - private static final String PULSE_SETTINGS_FOOTER = "pulse_settings_footer"; - - private SwitchPreferenceCompat mLockscreenPulse; - private SwitchPreferenceCompat mAmbientPulse; - private SwitchPreferenceCompat mPulseSmoothing; - private Preference mRenderMode; - private ListPreference mColorModePref; - private ColorPickerPreference mColorPickerPref; - private Preference mLavaSpeedPref; - private Preference mFooterPref; - - private PreferenceCategory mFadingBarsCat; - private PreferenceCategory mSolidBarsCat; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.pulse_settings); - - ContentResolver resolver = getContext().getContentResolver(); - - mLockscreenPulse = (SwitchPreferenceCompat) findPreference(LOCKSCREEN_PULSE_ENABLED_KEY); - boolean lockscreenPulse = Settings.Secure.getIntForUser(resolver, - Settings.Secure.LOCKSCREEN_PULSE_ENABLED, 1, UserHandle.USER_CURRENT) != 0; - mLockscreenPulse.setChecked(lockscreenPulse); - mLockscreenPulse.setOnPreferenceChangeListener(this); - - mAmbientPulse = (SwitchPreferenceCompat) findPreference(AMBIENT_PULSE_ENABLED_KEY); - boolean ambientPulse = Settings.Secure.getIntForUser(resolver, - Settings.Secure.AMBIENT_PULSE_ENABLED, 0, UserHandle.USER_CURRENT) != 0; - mAmbientPulse.setChecked(ambientPulse); - mAmbientPulse.setOnPreferenceChangeListener(this); - - mColorModePref = (ListPreference) findPreference(PULSE_COLOR_MODE_KEY); - mColorPickerPref = (ColorPickerPreference) findPreference(PULSE_COLOR_MODE_CHOOSER_KEY); - mLavaSpeedPref = findPreference(PULSE_COLOR_MODE_LAVA_SPEED_KEY); - mColorModePref.setOnPreferenceChangeListener(this); - - mRenderMode = findPreference(PULSE_RENDER_MODE_KEY); - mRenderMode.setOnPreferenceChangeListener(this); - - mFadingBarsCat = (PreferenceCategory) findPreference( - PULSE_RENDER_CATEGORY_FADING); - mSolidBarsCat = (PreferenceCategory) findPreference( - PULSE_RENDER_CATEGORY_SOLID); - - mPulseSmoothing = (SwitchPreferenceCompat) findPreference(PULSE_SMOOTHING_KEY); - - mFooterPref = findPreference(PULSE_SETTINGS_FOOTER); - mFooterPref.setTitle(R.string.pulse_help_policy_notice_summary); - - updateAllPrefs(); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ContentResolver resolver = getContext().getContentResolver(); - if (preference == mLockscreenPulse) { - boolean val = (Boolean) newValue; - Settings.Secure.putIntForUser(resolver, - Settings.Secure.LOCKSCREEN_PULSE_ENABLED, val ? 1 : 0, UserHandle.USER_CURRENT); - updateAllPrefs(); - return true; - } else if (preference == mAmbientPulse) { - boolean val = (Boolean) newValue; - Settings.Secure.putIntForUser(resolver, - Settings.Secure.AMBIENT_PULSE_ENABLED, val ? 1 : 0, UserHandle.USER_CURRENT); - updateAllPrefs(); - return true; - } else if (preference == mColorModePref) { - updateColorPrefs(Integer.valueOf(String.valueOf(newValue))); - return true; - } else if (preference == mRenderMode) { - updateRenderCategories(Integer.valueOf(String.valueOf(newValue))); - return true; - } - return false; - } - - private void updateAllPrefs() { - ContentResolver resolver = getContext().getContentResolver(); - - boolean lockscreenPulse = Settings.Secure.getIntForUser(resolver, - Settings.Secure.LOCKSCREEN_PULSE_ENABLED, 1, UserHandle.USER_CURRENT) != 0; - - boolean ambientPulse = Settings.Secure.getIntForUser(resolver, - Settings.Secure.AMBIENT_PULSE_ENABLED, 0, UserHandle.USER_CURRENT) != 0; - - mPulseSmoothing.setEnabled(lockscreenPulse || ambientPulse); - - mColorModePref.setEnabled(lockscreenPulse || ambientPulse); - if (lockscreenPulse || ambientPulse) { - int colorMode = Settings.Secure.getIntForUser(resolver, - Settings.Secure.PULSE_COLOR_MODE, COLOR_TYPE_LAVALAMP, UserHandle.USER_CURRENT); - updateColorPrefs(colorMode); - } else { - mColorPickerPref.setEnabled(false); - mLavaSpeedPref.setEnabled(false); - } - - mRenderMode.setEnabled(lockscreenPulse || ambientPulse); - if (lockscreenPulse || ambientPulse) { - int renderMode = Settings.Secure.getIntForUser(resolver, - Settings.Secure.PULSE_RENDER_STYLE, RENDER_STYLE_SOLID_LINES, UserHandle.USER_CURRENT); - updateRenderCategories(renderMode); - } else { - mFadingBarsCat.setEnabled(false); - mSolidBarsCat.setEnabled(false); - } - - mFooterPref.setEnabled(lockscreenPulse || ambientPulse); - } - - private void updateColorPrefs(int val) { - switch (val) { - case COLOR_TYPE_ACCENT: - mColorPickerPref.setEnabled(false); - mLavaSpeedPref.setEnabled(false); - break; - case COLOR_TYPE_USER: - mColorPickerPref.setEnabled(true); - mLavaSpeedPref.setEnabled(false); - break; - case COLOR_TYPE_LAVALAMP: - mColorPickerPref.setEnabled(false); - mLavaSpeedPref.setEnabled(true); - break; - case COLOR_TYPE_AUTO: - mColorPickerPref.setEnabled(false); - mLavaSpeedPref.setEnabled(false); - break; - } - } - - private void updateRenderCategories(int mode) { - mFadingBarsCat.setEnabled(mode == RENDER_STYLE_FADING_BARS); - mSolidBarsCat.setEnabled(mode == RENDER_STYLE_SOLID_LINES); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/sound/PulseSettings.kt b/src/com/rising/settings/fragments/sound/PulseSettings.kt new file mode 100644 index 00000000..5e295563 --- /dev/null +++ b/src/com/rising/settings/fragments/sound/PulseSettings.kt @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.sound + +import android.content.Context +import android.content.ContentResolver +import android.content.DialogInterface +import android.content.res.Resources +import android.content.pm.PackageManager +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.SwitchPreferenceCompat + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.colorpicker.ColorPickerPreference + +class PulseSettings : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private val TAG = PulseSettings::class.java.simpleName + + private const val LOCKSCREEN_PULSE_ENABLED_KEY = "lockscreen_pulse_enabled" + private const val AMBIENT_PULSE_ENABLED_KEY = "ambient_pulse_enabled" + private const val PULSE_SMOOTHING_KEY = "pulse_smoothing_enabled" + private const val PULSE_COLOR_MODE_KEY = "pulse_color_mode" + private const val PULSE_COLOR_MODE_CHOOSER_KEY = "pulse_color_user" + private const val PULSE_COLOR_MODE_LAVA_SPEED_KEY = "pulse_lavalamp_speed" + private const val PULSE_RENDER_CATEGORY_SOLID = "pulse_2" + private const val PULSE_RENDER_CATEGORY_FADING = "pulse_fading_bars_category" + private const val PULSE_RENDER_MODE_KEY = "pulse_render_style" + private const val RENDER_STYLE_FADING_BARS = 0 + private const val RENDER_STYLE_SOLID_LINES = 1 + private const val COLOR_TYPE_ACCENT = 0 + private const val COLOR_TYPE_USER = 1 + private const val COLOR_TYPE_LAVALAMP = 2 + private const val COLOR_TYPE_AUTO = 3 + + private const val PULSE_SETTINGS_FOOTER = "pulse_settings_footer" + } + + private lateinit var mLockscreenPulse: SwitchPreferenceCompat + private lateinit var mAmbientPulse: SwitchPreferenceCompat + private lateinit var mPulseSmoothing: SwitchPreferenceCompat + private lateinit var mRenderMode: Preference + private lateinit var mColorModePref: ListPreference + private lateinit var mColorPickerPref: ColorPickerPreference + private lateinit var mLavaSpeedPref: Preference + private lateinit var mFooterPref: Preference + + private lateinit var mFadingBarsCat: PreferenceCategory + private lateinit var mSolidBarsCat: PreferenceCategory + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.pulse_settings) + + val resolver = requireContext().contentResolver + + mLockscreenPulse = findCachedPreference(LOCKSCREEN_PULSE_ENABLED_KEY)!! + val lockscreenPulse = Settings.Secure.getIntForUser(resolver, + Settings.Secure.LOCKSCREEN_PULSE_ENABLED, 1, UserHandle.USER_CURRENT) != 0 + mLockscreenPulse.isChecked = lockscreenPulse + mLockscreenPulse.onPreferenceChangeListener = this + + mAmbientPulse = findCachedPreference(AMBIENT_PULSE_ENABLED_KEY)!! + val ambientPulse = Settings.Secure.getIntForUser(resolver, + Settings.Secure.AMBIENT_PULSE_ENABLED, 0, UserHandle.USER_CURRENT) != 0 + mAmbientPulse.isChecked = ambientPulse + mAmbientPulse.onPreferenceChangeListener = this + + mColorModePref = findCachedPreference(PULSE_COLOR_MODE_KEY)!! + mColorPickerPref = findCachedPreference(PULSE_COLOR_MODE_CHOOSER_KEY)!! + mLavaSpeedPref = findCachedPreference(PULSE_COLOR_MODE_LAVA_SPEED_KEY)!! + mColorModePref.onPreferenceChangeListener = this + + mRenderMode = findCachedPreference(PULSE_RENDER_MODE_KEY)!! + mRenderMode.onPreferenceChangeListener = this + + mFadingBarsCat = findCachedPreference(PULSE_RENDER_CATEGORY_FADING)!! + mSolidBarsCat = findCachedPreference(PULSE_RENDER_CATEGORY_SOLID)!! + + mPulseSmoothing = findCachedPreference(PULSE_SMOOTHING_KEY)!! + + mFooterPref = findCachedPreference(PULSE_SETTINGS_FOOTER)!! + mFooterPref.setTitle(R.string.pulse_help_policy_notice_summary) + + updateAllPrefs() + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val resolver = requireContext().contentResolver + when (preference) { + mLockscreenPulse -> { + val value = newValue as Boolean + Settings.Secure.putIntForUser(resolver, + Settings.Secure.LOCKSCREEN_PULSE_ENABLED, if (value) 1 else 0, UserHandle.USER_CURRENT) + updateAllPrefs() + return true + } + mAmbientPulse -> { + val value = newValue as Boolean + Settings.Secure.putIntForUser(resolver, + Settings.Secure.AMBIENT_PULSE_ENABLED, if (value) 1 else 0, UserHandle.USER_CURRENT) + updateAllPrefs() + return true + } + mColorModePref -> { + updateColorPrefs(newValue.toString().toInt()) + return true + } + mRenderMode -> { + updateRenderCategories(newValue.toString().toInt()) + return true + } + } + return false + } + + private fun updateAllPrefs() { + val resolver = getSafeContext()?.contentResolver + + val lockscreenPulse = Settings.Secure.getIntForUser(resolver, + Settings.Secure.LOCKSCREEN_PULSE_ENABLED, 1, UserHandle.USER_CURRENT) != 0 + + val ambientPulse = Settings.Secure.getIntForUser(resolver, + Settings.Secure.AMBIENT_PULSE_ENABLED, 0, UserHandle.USER_CURRENT) != 0 + + mPulseSmoothing.isEnabled = lockscreenPulse || ambientPulse + + mColorModePref.isEnabled = lockscreenPulse || ambientPulse + if (lockscreenPulse || ambientPulse) { + val colorMode = Settings.Secure.getIntForUser(resolver, + Settings.Secure.PULSE_COLOR_MODE, COLOR_TYPE_LAVALAMP, UserHandle.USER_CURRENT) + updateColorPrefs(colorMode) + } else { + mColorPickerPref.isEnabled = false + mLavaSpeedPref.isEnabled = false + } + + mRenderMode.isEnabled = lockscreenPulse || ambientPulse + if (lockscreenPulse || ambientPulse) { + val renderMode = Settings.Secure.getIntForUser(resolver, + Settings.Secure.PULSE_RENDER_STYLE, RENDER_STYLE_SOLID_LINES, UserHandle.USER_CURRENT) + updateRenderCategories(renderMode) + } else { + mFadingBarsCat.isEnabled = false + mSolidBarsCat.isEnabled = false + } + + mFooterPref.isEnabled = lockscreenPulse || ambientPulse + } + + private fun updateColorPrefs(value: Int) { + when (value) { + COLOR_TYPE_ACCENT -> { + mColorPickerPref.isEnabled = false + mLavaSpeedPref.isEnabled = false + } + COLOR_TYPE_USER -> { + mColorPickerPref.isEnabled = true + mLavaSpeedPref.isEnabled = false + } + COLOR_TYPE_LAVALAMP -> { + mColorPickerPref.isEnabled = false + mLavaSpeedPref.isEnabled = true + } + COLOR_TYPE_AUTO -> { + mColorPickerPref.isEnabled = false + mLavaSpeedPref.isEnabled = false + } + } + } + + private fun updateRenderCategories(mode: Int) { + mFadingBarsCat.isEnabled = mode == RENDER_STYLE_FADING_BARS + mSolidBarsCat.isEnabled = mode == RENDER_STYLE_SOLID_LINES + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/sound/SoundEngine.java b/src/com/rising/settings/fragments/sound/SoundEngine.kt similarity index 50% rename from src/com/rising/settings/fragments/sound/SoundEngine.java rename to src/com/rising/settings/fragments/sound/SoundEngine.kt index 6ba36d7d..266504fc 100644 --- a/src/com/rising/settings/fragments/sound/SoundEngine.java +++ b/src/com/rising/settings/fragments/sound/SoundEngine.kt @@ -14,27 +14,26 @@ * limitations under the License. */ -package com.rising.settings.fragments.sound; +package com.rising.settings.fragments.sound -import android.os.Bundle; +import android.os.Bundle -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment -public class SoundEngine extends SettingsPreferenceFragment { +class SoundEngine : OptimizedSettingsFragment() { - private static final String TAG = "SoundEngine"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + companion object { + private const val TAG = "SoundEngine" + } - addPreferencesFromResource(R.xml.sound_engine_settings); + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.sound_engine_settings) } - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN } } diff --git a/src/com/rising/settings/fragments/sound/VolumeSteps.java b/src/com/rising/settings/fragments/sound/VolumeSteps.java deleted file mode 100644 index 924d3567..00000000 --- a/src/com/rising/settings/fragments/sound/VolumeSteps.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2024 Yet Another AOSP 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.rising.settings.fragments.sound; - -import android.content.ContentResolver; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.CustomSeekBarPreference; - -public class VolumeSteps extends SettingsPreferenceFragment implements - OnPreferenceChangeListener { - - private static final String TAG = "VolumeSteps"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.volume_steps_settings); - - ContentResolver resolver = getActivity().getContentResolver(); - PreferenceScreen screen = getPreferenceScreen(); - final int count = screen.getPreferenceCount(); - for (int i = 0; i < count; i++) { - Preference pref = screen.getPreference(i); - if (!(pref instanceof CustomSeekBarPreference)) - continue; - String key = pref.getKey(); - final int def = Settings.System.getIntForUser(resolver, "default_" + key, 15, UserHandle.USER_CURRENT); - final int value = Settings.System.getIntForUser(resolver, key, def, UserHandle.USER_CURRENT); - CustomSeekBarPreference sbPref = (CustomSeekBarPreference) pref; - sbPref.setDefaultValue(def); - sbPref.setValue(value); - sbPref.setOnPreferenceChangeListener(this); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (!(preference instanceof CustomSeekBarPreference)) - return false; - Settings.System.putIntForUser(getActivity().getContentResolver(), - preference.getKey(), (Integer) newValue, UserHandle.USER_CURRENT); - return true; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/sound/VolumeSteps.kt b/src/com/rising/settings/fragments/sound/VolumeSteps.kt new file mode 100644 index 00000000..45c165bf --- /dev/null +++ b/src/com/rising/settings/fragments/sound/VolumeSteps.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 Yet Another AOSP 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.rising.settings.fragments.sound + +import android.content.ContentResolver +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings + +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.CustomSeekBarPreference + +class VolumeSteps : OptimizedSettingsFragment(), OnPreferenceChangeListener { + + companion object { + private const val TAG = "VolumeSteps" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.volume_steps_settings) + + val resolver = activity?.contentResolver + val screen = preferenceScreen + val count = screen.preferenceCount + for (i in 0 until count) { + val pref = screen.getPreference(i) + if (pref !is CustomSeekBarPreference) continue + + val key = pref.key + val def = Settings.System.getIntForUser(resolver, "default_$key", 15, UserHandle.USER_CURRENT) + val value = Settings.System.getIntForUser(resolver, key, def, UserHandle.USER_CURRENT) + val sbPref = pref as CustomSeekBarPreference + // Set default value - property may not exist in this version + sbPref.setValue(value) + sbPref.onPreferenceChangeListener = this + } + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + if (preference !is CustomSeekBarPreference) return false + + Settings.System.putIntForUser(activity?.contentResolver, + preference.key, newValue as Int, UserHandle.USER_CURRENT) + return true + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/statusbar/BatteryBar.java b/src/com/rising/settings/fragments/statusbar/BatteryBar.java deleted file mode 100644 index b0eae07c..00000000 --- a/src/com/rising/settings/fragments/statusbar/BatteryBar.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.statusbar; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.SwitchPreferenceCompat; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.colorpicker.ColorPickerPreference; -import com.android.settings.preferences.CustomSeekBarPreference; - -public class BatteryBar extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - private static final String PREF_BATT_BAR = "statusbar_battery_bar"; - - private SwitchPreferenceCompat mBatteryBar; - - private boolean mIsBarSwitchingMode = false; - private Handler mHandler; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.battery_bar); - - PreferenceScreen prefSet = getPreferenceScreen(); - ContentResolver resolver = getActivity().getContentResolver(); - - int intColor; - String hexColor; - - mBatteryBar = (SwitchPreferenceCompat) findPreference(PREF_BATT_BAR); - mHandler = new Handler(); - - boolean showing = Settings.System.getIntForUser(resolver, - Settings.System.STATUSBAR_BATTERY_BAR, 0, UserHandle.USER_CURRENT) != 0; - mBatteryBar.setChecked(showing); - mBatteryBar.setOnPreferenceChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ContentResolver resolver = getActivity().getContentResolver(); - if (preference == mBatteryBar) { - if (mIsBarSwitchingMode) { - return false; - } - mIsBarSwitchingMode = true; - boolean value = ((Boolean)newValue); - Settings.System.putIntForUser(resolver, Settings.System.STATUSBAR_BATTERY_BAR, - value ? 1 : 0, UserHandle.USER_CURRENT); - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mIsBarSwitchingMode = false; - boolean showing = Settings.System.getIntForUser(resolver, - Settings.System.STATUSBAR_BATTERY_BAR, 0, UserHandle.USER_CURRENT) != 0; - mBatteryBar.setChecked(showing); - } - }, 1500); - return true; - } - return false; - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/statusbar/BatteryBar.kt b/src/com/rising/settings/fragments/statusbar/BatteryBar.kt new file mode 100644 index 00000000..aa29b066 --- /dev/null +++ b/src/com/rising/settings/fragments/statusbar/BatteryBar.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.statusbar + +import android.content.ContentResolver +import android.content.Context +import android.content.res.Resources +import android.os.Bundle +import android.os.Handler +import android.os.UserHandle +import android.provider.Settings + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.SwitchPreferenceCompat + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.colorpicker.ColorPickerPreference +import com.android.settings.preferences.CustomSeekBarPreference + +class BatteryBar : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private const val PREF_BATT_BAR = "statusbar_battery_bar" + } + + private lateinit var mBatteryBar: SwitchPreferenceCompat + private var mIsBarSwitchingMode = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.battery_bar) + + val prefSet = preferenceScreen + val resolver = activity?.contentResolver + + mBatteryBar = findCachedPreference(PREF_BATT_BAR)!! + + val showing = Settings.System.getIntForUser(resolver, + Settings.System.STATUSBAR_BATTERY_BAR, 0, UserHandle.USER_CURRENT) != 0 + mBatteryBar.isChecked = showing + mBatteryBar.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val resolver = activity?.contentResolver + if (preference == mBatteryBar) { + if (mIsBarSwitchingMode) { + return false + } + mIsBarSwitchingMode = true + val value = newValue as Boolean + Settings.System.putIntForUser(resolver, Settings.System.STATUSBAR_BATTERY_BAR, + if (value) 1 else 0, UserHandle.USER_CURRENT) + postDelayedSafe({ + mIsBarSwitchingMode = false + if (isFragmentReady()) { + val showing = Settings.System.getIntForUser(resolver, + Settings.System.STATUSBAR_BATTERY_BAR, 0, UserHandle.USER_CURRENT) != 0 + mBatteryBar.isChecked = showing + } + }, 1500) + return true + } + return false + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/statusbar/Clock.java b/src/com/rising/settings/fragments/statusbar/Clock.java deleted file mode 100644 index b6ef752d..00000000 --- a/src/com/rising/settings/fragments/statusbar/Clock.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.statusbar; - -import android.app.AlertDialog; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.format.DateFormat; -import android.view.Menu; -import android.widget.EditText; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.settings.preferences.CustomSeekBarPreference; -import com.android.settings.preferences.SystemSettingListPreference; - -import java.util.Date; - -import lineageos.preference.LineageSystemSettingListPreference; -import lineageos.providers.LineageSettings; - -public class Clock extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener { - - private static final String TAG = "Clock"; - - private static final String STATUS_BAR_AM_PM = "status_bar_am_pm"; - private static final String CLOCK_DATE_DISPLAY = "status_bar_clock_date_display"; - private static final String CLOCK_DATE_POSITION = "status_bar_clock_date_position"; - private static final String CLOCK_DATE_STYLE = "status_bar_clock_date_style"; - private static final String CLOCK_DATE_FORMAT = "status_bar_clock_date_format"; - private static final String CLOCK_SECONDS = "status_bar_clock_seconds"; - - private static final int CLOCK_DATE_STYLE_LOWERCASE = 1; - private static final int CLOCK_DATE_STYLE_UPPERCASE = 2; - private static final int CUSTOM_CLOCK_DATE_FORMAT_INDEX = 18; - - private LineageSystemSettingListPreference mStatusBarAmPm; - private SystemSettingListPreference mClockDateDisplay; - private SystemSettingListPreference mClockDatePosition; - private SystemSettingListPreference mClockDateStyle; - private ListPreference mClockDateFormat; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.status_bar_clock); - - ContentResolver resolver = getActivity().getContentResolver(); - - mStatusBarAmPm = - (LineageSystemSettingListPreference) findPreference(STATUS_BAR_AM_PM); - - if (DateFormat.is24HourFormat(getActivity())) { - mStatusBarAmPm.setEnabled(false); - mStatusBarAmPm.setSummary(R.string.status_bar_am_pm_info); - } - - int dateDisplay = Settings.System.getIntForUser(resolver, - Settings.System.STATUS_BAR_CLOCK_DATE_DISPLAY, 0, UserHandle.USER_CURRENT); - - mClockDateDisplay = (SystemSettingListPreference) findPreference(CLOCK_DATE_DISPLAY); - mClockDateDisplay.setOnPreferenceChangeListener(this); - - mClockDatePosition = (SystemSettingListPreference) findPreference(CLOCK_DATE_POSITION); - mClockDatePosition.setEnabled(dateDisplay > 0); - mClockDatePosition.setOnPreferenceChangeListener(this); - - mClockDateStyle = (SystemSettingListPreference) findPreference(CLOCK_DATE_STYLE); - mClockDateStyle.setEnabled(dateDisplay > 0); - mClockDateStyle.setOnPreferenceChangeListener(this); - - mClockDateFormat = (ListPreference) findPreference(CLOCK_DATE_FORMAT); - if (mClockDateFormat.getValue() == null) { - mClockDateFormat.setValue("EEE"); - } - parseClockDateFormats(); - mClockDateFormat.setEnabled(dateDisplay > 0); - mClockDateFormat.setOnPreferenceChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - AlertDialog dialog; - ContentResolver resolver = getActivity().getContentResolver(); - if (preference == mClockDateDisplay) { - int val = Integer.parseInt((String) newValue); - if (val == 0) { - mClockDatePosition.setEnabled(false); - mClockDateStyle.setEnabled(false); - mClockDateFormat.setEnabled(false); - } else { - mClockDatePosition.setEnabled(true); - mClockDateStyle.setEnabled(true); - mClockDateFormat.setEnabled(true); - } - return true; - } else if (preference == mClockDatePosition) { - parseClockDateFormats(); - return true; - } else if (preference == mClockDateStyle) { - parseClockDateFormats(); - return true; - } else if (preference == mClockDateFormat) { - int index = mClockDateFormat.findIndexOfValue((String) newValue); - - if (index == CUSTOM_CLOCK_DATE_FORMAT_INDEX) { - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); - alert.setTitle(R.string.status_bar_date_string_edittext_title); - alert.setMessage(R.string.status_bar_date_string_edittext_summary); - - final EditText input = new EditText(getActivity()); - String oldText = Settings.System.getString( - resolver, - Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT); - if (oldText != null) { - input.setText(oldText); - } - alert.setView(input); - - alert.setPositiveButton(R.string.menu_save, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialogInterface, int whichButton) { - String value = input.getText().toString(); - if (value.equals("")) { - return; - } - Settings.System.putString(resolver, - Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT, value); - - return; - } - }); - - alert.setNegativeButton(R.string.menu_cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialogInterface, int which) { - return; - } - }); - dialog = alert.create(); - dialog.show(); - } else { - if ((String) newValue != null) { - Settings.System.putString(resolver, - Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT, (String) newValue); - } - } - return true; - } - return false; - } - - private void parseClockDateFormats() { - String[] dateEntries = getResources().getStringArray( - R.array.status_bar_date_format_entries_values); - CharSequence parsedDateEntries[]; - parsedDateEntries = new String[dateEntries.length]; - Date now = new Date(); - - int lastEntry = dateEntries.length - 1; - int dateFormat = Settings.System.getIntForUser(getActivity() - .getContentResolver(), Settings.System.STATUS_BAR_CLOCK_DATE_STYLE, 0, UserHandle.USER_CURRENT); - for (int i = 0; i < dateEntries.length; i++) { - if (i == lastEntry) { - parsedDateEntries[i] = dateEntries[i]; - } else { - String newDate; - CharSequence dateString = DateFormat.format(dateEntries[i], now); - if (dateFormat == CLOCK_DATE_STYLE_LOWERCASE) { - newDate = dateString.toString().toLowerCase(); - } else if (dateFormat == CLOCK_DATE_STYLE_UPPERCASE) { - newDate = dateString.toString().toUpperCase(); - } else { - newDate = dateString.toString(); - } - - parsedDateEntries[i] = newDate; - } - } - mClockDateFormat.setEntries(parsedDateEntries); - } - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/statusbar/Clock.kt b/src/com/rising/settings/fragments/statusbar/Clock.kt new file mode 100644 index 00000000..f53c58a5 --- /dev/null +++ b/src/com/rising/settings/fragments/statusbar/Clock.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016-2024 crDroid Android 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.rising.settings.fragments.statusbar + +import android.app.AlertDialog +import android.content.ContentResolver +import android.content.Context +import android.content.DialogInterface +import android.content.DialogInterface.OnCancelListener +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings +import android.text.format.DateFormat +import android.view.Menu +import android.widget.EditText + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.settings.preferences.CustomSeekBarPreference +import com.android.settings.preferences.SystemSettingListPreference + +import java.util.Date + +import lineageos.preference.LineageSystemSettingListPreference +import lineageos.providers.LineageSettings + +class Clock : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + private const val TAG = "Clock" + + private const val STATUS_BAR_AM_PM = "status_bar_am_pm" + private const val CLOCK_DATE_DISPLAY = "status_bar_clock_date_display" + private const val CLOCK_DATE_POSITION = "status_bar_clock_date_position" + private const val CLOCK_DATE_STYLE = "status_bar_clock_date_style" + private const val CLOCK_DATE_FORMAT = "status_bar_clock_date_format" + private const val CLOCK_SECONDS = "status_bar_clock_seconds" + + private const val CLOCK_DATE_STYLE_LOWERCASE = 1 + private const val CLOCK_DATE_STYLE_UPPERCASE = 2 + private const val CUSTOM_CLOCK_DATE_FORMAT_INDEX = 18 + } + + private lateinit var mStatusBarAmPm: LineageSystemSettingListPreference + private lateinit var mClockDateDisplay: SystemSettingListPreference + private lateinit var mClockDatePosition: SystemSettingListPreference + private lateinit var mClockDateStyle: SystemSettingListPreference + private lateinit var mClockDateFormat: ListPreference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.status_bar_clock) + + val resolver = activity?.contentResolver + + mStatusBarAmPm = findCachedPreference(STATUS_BAR_AM_PM)!! + + if (DateFormat.is24HourFormat(activity)) { + mStatusBarAmPm.isEnabled = false + mStatusBarAmPm.setSummary(R.string.status_bar_am_pm_info) + } + + val dateDisplay = Settings.System.getIntForUser(resolver, + Settings.System.STATUS_BAR_CLOCK_DATE_DISPLAY, 0, UserHandle.USER_CURRENT) + + mClockDateDisplay = findCachedPreference(CLOCK_DATE_DISPLAY)!! + mClockDateDisplay.onPreferenceChangeListener = this + + mClockDatePosition = findCachedPreference(CLOCK_DATE_POSITION)!! + mClockDatePosition.isEnabled = dateDisplay > 0 + mClockDatePosition.onPreferenceChangeListener = this + + mClockDateStyle = findCachedPreference(CLOCK_DATE_STYLE)!! + mClockDateStyle.isEnabled = dateDisplay > 0 + mClockDateStyle.onPreferenceChangeListener = this + + mClockDateFormat = findCachedPreference(CLOCK_DATE_FORMAT)!! + if (mClockDateFormat.value == null) { + mClockDateFormat.value = "EEE" + } + parseClockDateFormats() + mClockDateFormat.isEnabled = dateDisplay > 0 + mClockDateFormat.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val resolver = activity?.contentResolver + when (preference) { + mClockDateDisplay -> { + val value = (newValue as String).toInt() + if (value == 0) { + mClockDatePosition.isEnabled = false + mClockDateStyle.isEnabled = false + mClockDateFormat.isEnabled = false + } else { + mClockDatePosition.isEnabled = true + mClockDateStyle.isEnabled = true + mClockDateFormat.isEnabled = true + } + return true + } + mClockDatePosition -> { + parseClockDateFormats() + return true + } + mClockDateStyle -> { + parseClockDateFormats() + return true + } + mClockDateFormat -> { + val index = mClockDateFormat.findIndexOfValue(newValue as String) + + if (index == CUSTOM_CLOCK_DATE_FORMAT_INDEX) { + val alert = AlertDialog.Builder(activity) + alert.setTitle(R.string.status_bar_date_string_edittext_title) + alert.setMessage(R.string.status_bar_date_string_edittext_summary) + + val input = EditText(activity) + val oldText = Settings.System.getString( + resolver, + Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT) + if (oldText != null) { + input.setText(oldText) + } + alert.setView(input) + + alert.setPositiveButton(R.string.menu_save) { _, _ -> + val value = input.text.toString() + if (value.isNotEmpty()) { + Settings.System.putString(resolver, + Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT, value) + } + } + + alert.setNegativeButton(R.string.menu_cancel) { _, _ -> + // Do nothing + } + val dialog = alert.create() + dialog.show() + } else { + if (newValue.isNotEmpty()) { + Settings.System.putString(resolver, + Settings.System.STATUS_BAR_CLOCK_DATE_FORMAT, newValue) + } + } + return true + } + } + return false + } + + private fun parseClockDateFormats() { + val dateEntries = resources.getStringArray(R.array.status_bar_date_format_entries_values) + val parsedDateEntries = Array(dateEntries.size) { "" } + val now = Date() + + val lastEntry = dateEntries.size - 1 + val dateFormat = Settings.System.getIntForUser(activity?.contentResolver, + Settings.System.STATUS_BAR_CLOCK_DATE_STYLE, 0, UserHandle.USER_CURRENT) + + for (i in dateEntries.indices) { + if (i == lastEntry) { + parsedDateEntries[i] = dateEntries[i] + } else { + val dateString = DateFormat.format(dateEntries[i], now) + val newDate = when (dateFormat) { + CLOCK_DATE_STYLE_LOWERCASE -> dateString.toString().lowercase() + CLOCK_DATE_STYLE_UPPERCASE -> dateString.toString().uppercase() + else -> dateString.toString() + } + parsedDateEntries[i] = newDate + } + } + mClockDateFormat.entries = parsedDateEntries + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.java b/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.java deleted file mode 100644 index 067d1df2..00000000 --- a/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2017-2024 crDroid Android 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.rising.settings.fragments.statusbar; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.internal.logging.nano.MetricsProto; - -public class NetworkTrafficSettings extends SettingsPreferenceFragment { - - private static final String TAG = "NetworkTrafficSettings"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.network_traffic_settings); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.kt b/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.kt new file mode 100644 index 00000000..0a907308 --- /dev/null +++ b/src/com/rising/settings/fragments/statusbar/NetworkTrafficSettings.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017-2024 crDroid Android 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.rising.settings.fragments.statusbar + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings + +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.internal.logging.nano.MetricsProto + +class NetworkTrafficSettings : OptimizedSettingsFragment() { + + companion object { + private const val TAG = "NetworkTrafficSettings" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.network_traffic_settings) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.java b/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.java deleted file mode 100644 index 525277cb..00000000 --- a/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Project Kaleidoscope - * SPDX-License-Identifier: Apache-2.0 - */ -package com.rising.settings.fragments.statusbar; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class StatusbarLyricSettings extends SettingsPreferenceFragment { - - public static final String TAG = "StatusbarLyricSettings"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.status_bar_lyric_settings); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.status_bar_lyric_settings) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.kt b/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.kt new file mode 100644 index 00000000..52b9f91b --- /dev/null +++ b/src/com/rising/settings/fragments/statusbar/StatusbarLyricSettings.kt @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2022 Project Kaleidoscope + * SPDX-License-Identifier: Apache-2.0 + */ +package com.rising.settings.fragments.statusbar + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.UserHandle +import android.provider.Settings + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class StatusbarLyricSettings : OptimizedSettingsFragment() { + + companion object { + const val TAG = "StatusbarLyricSettings" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.status_bar_lyric_settings) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context) + return keys + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.status_bar_lyric_settings) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/ui/IconShapes.java b/src/com/rising/settings/fragments/ui/IconShapes.java deleted file mode 100644 index 9c4ac603..00000000 --- a/src/com/rising/settings/fragments/ui/IconShapes.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui; - -import static com.android.internal.util.android.ThemeUtils.ICON_SHAPE_KEY; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.graphics.ColorUtils; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.Utils; - -import com.bumptech.glide.Glide; - -import com.android.internal.util.android.ThemeUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class IconShapes extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - - private String mCategory = ICON_SHAPE_KEY; - - private List mPkgs; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_icon_shape_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "android"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String pkg = mPkgs.get(position); - - holder.image.setBackgroundDrawable(mThemeUtils.createShapeDrawable(pkg)); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("android"); - - holder.name.setText("android".equals(pkg) ? "Default" : getLabel(holder.name.getContext(), pkg)); - - final boolean isDefault = "android".equals(currentPackageName) && "android".equals(pkg); - final int color = ColorUtils.setAlphaComponent( - Utils.getColorAttrDefaultColor(getContext(), android.R.attr.colorAccent), - pkg.equals(currentPackageName) || isDefault ? 170 : 75); - holder.image.setBackgroundTintList(ColorStateList.valueOf(color)); - - holder.itemView.findViewById(R.id.option_tile).setBackgroundDrawable(null); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image = (ImageView) itemView.findViewById(R.id.option_thumbnail); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pkg.equals("android") ? Resources.getSystem() - : pm.getResourcesForApplication(pkg); - return res.getDrawable(res.getIdentifier(drawableName, "drawable", pkg)); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "android"); - } -} diff --git a/src/com/rising/settings/fragments/ui/IconShapes.kt b/src/com/rising/settings/fragments/ui/IconShapes.kt new file mode 100644 index 00000000..fcdacf91 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/IconShapes.kt @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui + +import com.android.internal.util.android.ThemeUtils.ICON_SHAPE_KEY + +import android.content.ContentResolver +import android.content.Context +import android.content.res.ColorStateList +import android.content.res.Resources +import android.content.pm.PackageManager +import android.graphics.drawable.AnimationDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.ShapeDrawable +import android.os.Bundle +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.view.Gravity +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.FrameLayout +import android.widget.TextView +import android.text.TextUtils +import androidx.preference.PreferenceViewHolder +import android.view.ViewGroup.LayoutParams + +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.core.graphics.ColorUtils +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import androidx.recyclerview.widget.RecyclerView +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.PreferenceScreen + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.Indexable +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settingslib.Utils + +import com.bumptech.glide.Glide + +import com.android.internal.util.android.ThemeUtils + +import org.json.JSONObject +import org.json.JSONException + +class IconShapes : OptimizedSettingsFragment() { + + private lateinit var mRecyclerView: RecyclerView + override var mThemeUtils: ThemeUtils? = null + private val mCategory = ICON_SHAPE_KEY + private lateinit var mPkgs: List + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_icon_shape_title) + + mThemeUtils = ThemeUtils.getInstance(activity) + mPkgs = mThemeUtils?.getOverlayPackagesForCategory(mCategory, "android") ?: emptyList() + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 3) + mRecyclerView.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity!!) + mRecyclerView.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(val context: Context) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.item_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val pkg = mPkgs[position] + + holder.image.background = mThemeUtils?.createShapeDrawable(pkg) + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory) + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "android" + + holder.name.text = if (pkg == "android") "Default" else getLabel(holder.name.context, pkg) + + val isDefault = currentPackageName == "android" && pkg == "android" + val color = ColorUtils.setAlphaComponent( + Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent), + if (pkg == currentPackageName || isDefault) 170 else 75 + ) + holder.image.backgroundTintList = ColorStateList.valueOf(color) + + holder.itemView.findViewById(R.id.option_tile).background = null + holder.itemView.setOnClickListener { + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs.size + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView = itemView.findViewById(R.id.option_label) + val image: ImageView = itemView.findViewById(R.id.option_thumbnail) + } + } + + private fun getDrawable(context: Context, pkg: String, drawableName: String): Drawable? { + return try { + val pm = context.packageManager + val res = if (pkg == "android") { + Resources.getSystem() + } else { + pm.getResourcesForApplication(pkg) + } + res.getDrawable(res.getIdentifier(drawableName, "drawable", pkg)) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun getLabel(context: Context, pkg: String): String { + val pm = context.packageManager + return try { + pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString() + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + mThemeUtils?.setOverlayEnabled(mCategory, mPkgs[position], "android") + } +} diff --git a/src/com/rising/settings/fragments/ui/NavbarStyles.java b/src/com/rising/settings/fragments/ui/NavbarStyles.java deleted file mode 100644 index 7313b1c7..00000000 --- a/src/com/rising/settings/fragments/ui/NavbarStyles.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; - -import com.bumptech.glide.Glide; - -import com.android.internal.util.android.ThemeUtils; -import com.android.internal.util.android.Utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class NavbarStyles extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.navbar"; - - private List mPkgs; - private String mLauncherPackage; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_navbar_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mLauncherPackage = Utils.isPackageInstalled(getContext(), "com.google.android.apps.nexuslauncher", false) - ? "com.google.android.apps.nexuslauncher" - : "com.android.launcher3"; - - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, mLauncherPackage); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.navbar_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String navPkg = mPkgs.get(position); - - holder.image1.setBackgroundDrawable(getDrawable(holder.image1.getContext(), navPkg, "ic_sysbar_back")); - holder.image2.setBackgroundDrawable(getDrawable(holder.image2.getContext(), navPkg, "ic_sysbar_home")); - holder.image3.setBackgroundDrawable(getDrawable(holder.image3.getContext(), navPkg, "ic_sysbar_recent")); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory, mLauncherPackage).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse(mLauncherPackage); - - holder.name.setText(mLauncherPackage.equals(navPkg) ? "Default" : getLabel(holder.name.getContext(), navPkg)); - - if (currentPackageName.equals(navPkg)) { - mAppliedPkg = navPkg; - if (mSelectedPkg == null) { - mSelectedPkg = navPkg; - } - } - - holder.itemView.setActivated(navPkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(navPkg, true); - mSelectedPkg = navPkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image1; - ImageView image2; - ImageView image3; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image1 = (ImageView) itemView.findViewById(R.id.image1); - image2 = (ImageView) itemView.findViewById(R.id.image2); - image3 = (ImageView) itemView.findViewById(R.id.image3); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - if (pkg.equals("com.android.launcher3") || pkg.equals("com.google.android.apps.nexuslauncher")) - pkg = "com.android.settings"; - try { - PackageManager pm = context.getPackageManager(); - Resources res = pm.getResourcesForApplication(pkg); - int resId = res.getIdentifier(drawableName, "drawable", pkg); - return res.getDrawable(resId); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), mLauncherPackage); - } -} diff --git a/src/com/rising/settings/fragments/ui/NavbarStyles.kt b/src/com/rising/settings/fragments/ui/NavbarStyles.kt new file mode 100644 index 00000000..46c5fd20 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/NavbarStyles.kt @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.internal.util.android.ThemeUtils +import com.android.internal.util.android.Utils + +class NavbarStyles : OptimizedSettingsFragment() { + + private var mRecyclerView: RecyclerView? = null + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.navbar" + + private var mPkgs: List? = null + private var mLauncherPackage: String? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_navbar_title) + + mThemeUtils = ThemeUtils.getInstance(activity) + mLauncherPackage = if (Utils.isPackageInstalled(requireContext(), "com.google.android.apps.nexuslauncher", false)) { + "com.google.android.apps.nexuslauncher" + } else { + "com.android.launcher3" + } + + mPkgs = mThemeUtils?.getOverlayPackagesForCategory(mCategory, mLauncherPackage) + } + + override fun onCreateView( + @NonNull inflater: LayoutInflater, + @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 2) + mRecyclerView?.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity) + mRecyclerView?.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(private val context: Context?) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.navbar_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val navPkg = mPkgs?.get(position) ?: return + + holder.image1?.background = getDrawable(holder.image1?.context, navPkg, "ic_sysbar_back") + holder.image2?.background = getDrawable(holder.image2?.context, navPkg, "ic_sysbar_home") + holder.image3?.background = getDrawable(holder.image3?.context, navPkg, "ic_sysbar_recent") + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory, mLauncherPackage) + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: mLauncherPackage + + holder.name?.text = if (mLauncherPackage == navPkg) "Default" else getLabel(holder.name?.context, navPkg) + + if (currentPackageName == navPkg) { + mAppliedPkg = navPkg + if (mSelectedPkg == null) { + mSelectedPkg = navPkg + } + } + + holder.itemView.isActivated = navPkg == mSelectedPkg + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(navPkg, true) + mSelectedPkg = navPkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs?.size ?: 0 + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView? = itemView.findViewById(R.id.option_label) + val image1: ImageView? = itemView.findViewById(R.id.image1) + val image2: ImageView? = itemView.findViewById(R.id.image2) + val image3: ImageView? = itemView.findViewById(R.id.image3) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val index = mPkgs?.indexOf(pkg) ?: -1 + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context?, pkg: String, drawableName: String): Drawable? { + val actualPkg = if (pkg == "com.android.launcher3" || pkg == "com.google.android.apps.nexuslauncher") { + "com.android.settings" + } else { + pkg + } + + return try { + val pm = context?.packageManager + val res = pm?.getResourcesForApplication(actualPkg) + val resId = res?.getIdentifier(drawableName, "drawable", actualPkg) ?: 0 + res?.getDrawable(resId) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun getLabel(context: Context?, pkg: String): String { + val pm = context?.packageManager + return try { + pm?.getApplicationInfo(pkg, 0)?.loadLabel(pm)?.toString() ?: pkg + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + val pkg = mPkgs?.get(position) + if (pkg != null) { + mThemeUtils?.setOverlayEnabled(mCategory, pkg, mLauncherPackage) + } + } +} diff --git a/src/com/rising/settings/fragments/ui/Settings.java b/src/com/rising/settings/fragments/ui/Settings.java deleted file mode 100644 index 30516d47..00000000 --- a/src/com/rising/settings/fragments/ui/Settings.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.Bundle; -import android.os.UserHandle; - -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; - -import com.android.internal.util.android.SystemRestartUtils; -import com.android.settings.preferences.SystemSettingListPreference; -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -import java.util.List; - -@SearchIndexable -public class Settings extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - - public static final String SETTINGS_DASHBOARD_STYLE = "settings_dashboard_style"; - - private SystemSettingListPreference mSettingsDashBoardStyle; - - private static final String TAG = "Settings"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.rising_settings_settingsui); - mSettingsDashBoardStyle = (SystemSettingListPreference) findPreference(SETTINGS_DASHBOARD_STYLE); - mSettingsDashBoardStyle.setOnPreferenceChangeListener(this); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } - - public boolean onPreferenceChange(Preference preference, Object objValue) { - final String key = preference.getKey(); - ContentResolver resolver = getActivity().getContentResolver(); - if (preference == mSettingsDashBoardStyle){ - SystemRestartUtils.showSettingsRestartDialog(getContext()); - return true; - } - return false; - } - - /** - * For search - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.rising_settings_settingsui) { - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - - return keys; - } - }; -} diff --git a/src/com/rising/settings/fragments/ui/Settings.kt b/src/com/rising/settings/fragments/ui/Settings.kt new file mode 100644 index 00000000..365d3e50 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/Settings.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023-2024 the risingOS Android 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.rising.settings.fragments.ui + +import android.content.ContentResolver +import android.content.Context +import android.os.Bundle +import android.os.UserHandle + +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener + +import com.android.internal.util.android.SystemRestartUtils +import com.android.settings.preferences.SystemSettingListPreference +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.SearchIndexable + +@SearchIndexable +class Settings : OptimizedSettingsFragment(), Preference.OnPreferenceChangeListener { + + companion object { + const val SETTINGS_DASHBOARD_STYLE = "settings_dashboard_style" + private const val TAG = "Settings" + + /** + * For search + */ + @JvmField + val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.rising_settings_settingsui) { + override fun getNonIndexableKeys(context: Context): List { + val keys = super.getNonIndexableKeys(context) + return keys + } + } + } + + private lateinit var mSettingsDashBoardStyle: SystemSettingListPreference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.rising_settings_settingsui) + mSettingsDashBoardStyle = findCachedPreference(SETTINGS_DASHBOARD_STYLE)!! + mSettingsDashBoardStyle.onPreferenceChangeListener = this + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } + + override fun onPreferenceChange(preference: Preference, objValue: Any): Boolean { + val key = preference.key + val resolver = activity?.contentResolver + if (preference == mSettingsDashBoardStyle) { + SystemRestartUtils.showSettingsRestartDialog(requireContext()) + return true + } + return false + } +} diff --git a/src/com/rising/settings/fragments/ui/SignalIcons.java b/src/com/rising/settings/fragments/ui/SignalIcons.java deleted file mode 100644 index 1dd30064..00000000 --- a/src/com/rising/settings/fragments/ui/SignalIcons.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; - -import com.bumptech.glide.Glide; - -import com.android.internal.util.android.ThemeUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class SignalIcons extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.signal_icon"; - - private List mPkgs; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_signal_icon_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "android"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.icon_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String iconPkg = mPkgs.get(position); - - holder.image1.setBackgroundDrawable(getDrawable(holder.image1.getContext(), iconPkg, "ic_signal_cellular_0_5_bar")); - holder.image2.setBackgroundDrawable(getDrawable(holder.image2.getContext(), iconPkg, "ic_signal_cellular_1_5_bar")); - holder.image3.setBackgroundDrawable(getDrawable(holder.image3.getContext(), iconPkg, "ic_signal_cellular_3_5_bar")); - holder.image4.setBackgroundDrawable(getDrawable(holder.image4.getContext(), iconPkg, "ic_signal_cellular_5_5_bar")); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("android"); - - holder.name.setText("android".equals(iconPkg) ? "Default" : getLabel(holder.name.getContext(), iconPkg)); - - if (currentPackageName.equals(iconPkg)) { - mAppliedPkg = iconPkg; - if (mSelectedPkg == null) { - mSelectedPkg = iconPkg; - } - } - - holder.itemView.setActivated(iconPkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(iconPkg, true); - mSelectedPkg = iconPkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image1; - ImageView image2; - ImageView image3; - ImageView image4; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image1 = (ImageView) itemView.findViewById(R.id.image1); - image2 = (ImageView) itemView.findViewById(R.id.image2); - image3 = (ImageView) itemView.findViewById(R.id.image3); - image4 = (ImageView) itemView.findViewById(R.id.image4); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pkg.equals("android") ? Resources.getSystem() - : pm.getResourcesForApplication(pkg); - int resId = res.getIdentifier(drawableName, "drawable", pkg); - return res.getDrawable(resId); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "android"); - } -} diff --git a/src/com/rising/settings/fragments/ui/SignalIcons.kt b/src/com/rising/settings/fragments/ui/SignalIcons.kt new file mode 100644 index 00000000..eacff84b --- /dev/null +++ b/src/com/rising/settings/fragments/ui/SignalIcons.kt @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.internal.util.android.ThemeUtils + +class SignalIcons : OptimizedSettingsFragment() { + + private var mRecyclerView: RecyclerView? = null + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.signal_icon" + + private var mPkgs: List? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_signal_icon_title) + + mThemeUtils = ThemeUtils.getInstance(activity) + mPkgs = mThemeUtils?.getOverlayPackagesForCategory(mCategory, "android") + } + + override fun onCreateView( + @NonNull inflater: LayoutInflater, + @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 3) + mRecyclerView?.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity) + mRecyclerView?.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(private val context: Context?) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.icon_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val iconPkg = mPkgs?.get(position) ?: return + + holder.image1?.background = getDrawable(holder.image1?.context, iconPkg, "ic_signal_cellular_0_5_bar") + holder.image2?.background = getDrawable(holder.image2?.context, iconPkg, "ic_signal_cellular_1_5_bar") + holder.image3?.background = getDrawable(holder.image3?.context, iconPkg, "ic_signal_cellular_3_5_bar") + holder.image4?.background = getDrawable(holder.image4?.context, iconPkg, "ic_signal_cellular_5_5_bar") + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory, "android") + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "android" + + holder.name?.text = if ("android" == iconPkg) "Default" else getLabel(holder.name?.context, iconPkg) + + if (currentPackageName == iconPkg) { + mAppliedPkg = iconPkg + if (mSelectedPkg == null) { + mSelectedPkg = iconPkg + } + } + + holder.itemView.isActivated = iconPkg == mSelectedPkg + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(iconPkg, true) + mSelectedPkg = iconPkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs?.size ?: 0 + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView? = itemView.findViewById(R.id.option_label) + val image1: ImageView? = itemView.findViewById(R.id.image1) + val image2: ImageView? = itemView.findViewById(R.id.image2) + val image3: ImageView? = itemView.findViewById(R.id.image3) + val image4: ImageView? = itemView.findViewById(R.id.image4) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val index = mPkgs?.indexOf(pkg) ?: -1 + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context?, pkg: String, drawableName: String): Drawable? { + return try { + val pm = context?.packageManager + val res = if (pkg == "android") { + Resources.getSystem() + } else { + pm?.getResourcesForApplication(pkg) + } + val resId = res?.getIdentifier(drawableName, "drawable", pkg) ?: 0 + res?.getDrawable(resId) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun getLabel(context: Context?, pkg: String): String { + val pm = context?.packageManager + return try { + pm?.getApplicationInfo(pkg, 0)?.loadLabel(pm)?.toString() ?: pkg + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + val pkg = mPkgs?.get(position) + if (pkg != null) { + mThemeUtils?.setOverlayEnabled(mCategory, pkg, "android") + } + } +} diff --git a/src/com/rising/settings/fragments/ui/SmartPixels.java b/src/com/rising/settings/fragments/ui/SmartPixels.java deleted file mode 100644 index 3bd2fb5a..00000000 --- a/src/com/rising/settings/fragments/ui/SmartPixels.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2018-2022 crDroid Android 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.rising.settings.fragments.ui; - -import android.content.Context; -import android.content.ContentResolver; -import android.content.res.Resources; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; - -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.SwitchPreference; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -public class SmartPixels extends SettingsPreferenceFragment { - - private static final String TAG = "SmartPixels"; - - private static final String SMART_PIXELS_FOOTER = "smart_pixels_footer"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.smart_pixels); - - findPreference(SMART_PIXELS_FOOTER).setTitle(R.string.smart_pixels_warning_text); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/ui/SmartPixels.kt b/src/com/rising/settings/fragments/ui/SmartPixels.kt new file mode 100644 index 00000000..148f1db2 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/SmartPixels.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018-2022 crDroid Android 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.rising.settings.fragments.ui + +import android.content.Context +import android.content.ContentResolver +import android.content.res.Resources +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.UserHandle +import android.provider.Settings + +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.SwitchPreference + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +class SmartPixels : OptimizedSettingsFragment() { + + companion object { + private const val TAG = "SmartPixels" + private const val SMART_PIXELS_FOOTER = "smart_pixels_footer" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + addPreferencesFromResource(R.xml.smart_pixels) + + findCachedPreference(SMART_PIXELS_FOOTER)?.setTitle(R.string.smart_pixels_warning_text) + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/fragments/ui/StatusbarIcons.java b/src/com/rising/settings/fragments/ui/StatusbarIcons.java deleted file mode 100644 index e963ccac..00000000 --- a/src/com/rising/settings/fragments/ui/StatusbarIcons.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; - -import com.bumptech.glide.Glide; - -import com.android.internal.util.android.ThemeUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class StatusbarIcons extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.icon_pack.android"; - - private List mPkgs; - - Map overlayMap = new HashMap(); - { - overlayMap.put("com.android.settings", "android.theme.customization.icon_pack.settings"); - overlayMap.put("com.android.systemui", "android.theme.customization.icon_pack.systemui"); - overlayMap.put("com.android.launcher3", "android.theme.customization.icon_pack.launcher"); - overlayMap.put("com.android.wallpaper", "android.theme.customization.icon_pack.themepicker"); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_icon_pack_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "android"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.icon_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String iconPkg = mPkgs.get(position); - - holder.image1.setBackgroundDrawable(getDrawable(holder.image1.getContext(), iconPkg, "ic_wifi_signal_4")); - holder.image2.setBackgroundDrawable(getDrawable(holder.image2.getContext(), iconPkg, "ic_signal_cellular_4_4_bar")); - holder.image3.setBackgroundDrawable(getDrawable(holder.image3.getContext(), iconPkg, "ic_qs_airplane")); - holder.image4.setBackgroundDrawable(getDrawable(holder.image4.getContext(), iconPkg, "ic_qs_flashlight")); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("android"); - - holder.name.setText("android".equals(iconPkg) ? "Default" : getLabel(holder.name.getContext(), iconPkg)); - - if (currentPackageName.equals(iconPkg)) { - mAppliedPkg = iconPkg; - if (mSelectedPkg == null) { - mSelectedPkg = iconPkg; - } - } - - holder.itemView.setActivated(iconPkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(iconPkg, true); - mSelectedPkg = iconPkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image1; - ImageView image2; - ImageView image3; - ImageView image4; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image1 = (ImageView) itemView.findViewById(R.id.image1); - image2 = (ImageView) itemView.findViewById(R.id.image2); - image3 = (ImageView) itemView.findViewById(R.id.image3); - image4 = (ImageView) itemView.findViewById(R.id.image4); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pkg.equals("android") ? Resources.getSystem() - : pm.getResourcesForApplication(pkg); - int resId = res.getIdentifier(drawableName, "drawable", pkg); - return res.getDrawable(resId); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "android"); - String pattern = "android".equals(mPkgs.get(position)) ? "" - : mPkgs.get(position).split("\\.")[4]; - for (Map.Entry entry : overlayMap.entrySet()) { - enableOverlay(entry.getValue(), entry.getKey(), pattern); - } - } - - public void enableOverlay(String category, String target, String pattern) { - if (pattern.isEmpty()) { - mThemeUtils.setOverlayEnabled(category, "android", "android"); - return; - } - for (String pkg: mThemeUtils.getOverlayPackagesForCategory(category, target)) { - if (pkg.contains(pattern)) { - mThemeUtils.setOverlayEnabled(category, pkg, target); - } - } - } -} diff --git a/src/com/rising/settings/fragments/ui/StatusbarIcons.kt b/src/com/rising/settings/fragments/ui/StatusbarIcons.kt new file mode 100644 index 00000000..19db16a0 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/StatusbarIcons.kt @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.internal.util.android.ThemeUtils + +class StatusbarIcons : OptimizedSettingsFragment() { + + private var mRecyclerView: RecyclerView? = null + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.icon_pack.android" + + private var mPkgs: List? = null + + private val overlayMap = mapOf( + "com.android.settings" to "android.theme.customization.icon_pack.settings", + "com.android.systemui" to "android.theme.customization.icon_pack.systemui", + "com.android.launcher3" to "android.theme.customization.icon_pack.launcher", + "com.android.wallpaper" to "android.theme.customization.icon_pack.themepicker" + ) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_icon_pack_title) + + mThemeUtils = ThemeUtils.getInstance(activity) + mPkgs = mThemeUtils?.getOverlayPackagesForCategory(mCategory, "android") + } + + override fun onCreateView( + @NonNull inflater: LayoutInflater, + @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 3) + mRecyclerView?.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity) + mRecyclerView?.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(private val context: Context?) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.icon_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val iconPkg = mPkgs?.get(position) ?: return + + holder.image1?.background = getDrawable(holder.image1?.context, iconPkg, "ic_wifi_signal_4") + holder.image2?.background = getDrawable(holder.image2?.context, iconPkg, "ic_signal_cellular_4_4_bar") + holder.image3?.background = getDrawable(holder.image3?.context, iconPkg, "ic_qs_airplane") + holder.image4?.background = getDrawable(holder.image4?.context, iconPkg, "ic_qs_flashlight") + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory, "android") + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "android" + + holder.name?.text = if ("android" == iconPkg) "Default" else getLabel(holder.name?.context, iconPkg) + + if (currentPackageName == iconPkg) { + mAppliedPkg = iconPkg + if (mSelectedPkg == null) { + mSelectedPkg = iconPkg + } + } + + holder.itemView.isActivated = iconPkg == mSelectedPkg + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(iconPkg, true) + mSelectedPkg = iconPkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs?.size ?: 0 + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView? = itemView.findViewById(R.id.option_label) + val image1: ImageView? = itemView.findViewById(R.id.image1) + val image2: ImageView? = itemView.findViewById(R.id.image2) + val image3: ImageView? = itemView.findViewById(R.id.image3) + val image4: ImageView? = itemView.findViewById(R.id.image4) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val index = mPkgs?.indexOf(pkg) ?: -1 + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context?, pkg: String, drawableName: String): Drawable? { + return try { + val pm = context?.packageManager + val res = if (pkg == "android") { + Resources.getSystem() + } else { + pm?.getResourcesForApplication(pkg) + } + val resId = res?.getIdentifier(drawableName, "drawable", pkg) ?: 0 + res?.getDrawable(resId) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun getLabel(context: Context?, pkg: String): String { + val pm = context?.packageManager + return try { + pm?.getApplicationInfo(pkg, 0)?.loadLabel(pm)?.toString() ?: pkg + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + val selectedPkg = mPkgs?.get(position) ?: return + mThemeUtils?.setOverlayEnabled(mCategory, selectedPkg, "android") + + val pattern = if ("android" == selectedPkg) { + "" + } else { + selectedPkg.split(".").getOrNull(4) ?: "" + } + + overlayMap.forEach { (target, category) -> + enableOverlay(category, target, pattern) + } + } + + private fun enableOverlay(category: String, target: String, pattern: String) { + if (pattern.isEmpty()) { + mThemeUtils?.setOverlayEnabled(category, "android", "android") + return + } + + mThemeUtils?.getOverlayPackagesForCategory(category, target)?.forEach { pkg -> + if (pkg.contains(pattern)) { + mThemeUtils?.setOverlayEnabled(category, pkg, target) + } + } + } +} diff --git a/src/com/rising/settings/fragments/ui/UIStyles.java b/src/com/rising/settings/fragments/ui/UIStyles.java deleted file mode 100644 index bebe0d73..00000000 --- a/src/com/rising/settings/fragments/ui/UIStyles.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2021 AospExtended ROM 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; - -import com.android.internal.util.android.ThemeUtils; - -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class UIStyles extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.style.android"; - - private List mPkgs; - - private ExecutorService mExecutor = Executors.newSingleThreadExecutor(); - private Handler mHandler = new Handler(); - private final AtomicBoolean mApplyingOverlays = new AtomicBoolean(false); - - Map overlayMap = new HashMap(); - { - overlayMap.put("com.android.settings", "android.theme.customization.style.settings"); - overlayMap.put("com.android.systemui", "android.theme.customization.style.systemui"); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_ui_style_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "android"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 1); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fonts_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String pkg = mPkgs.get(position); - String label = getLabel(holder.itemView.getContext(), pkg); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("android"); - - holder.title.setText("android".equals(pkg) ? "Default" : label); - holder.title.setTextSize(20); - holder.name.setVisibility(View.GONE); - - if (currentPackageName.equals(pkg)) { - mAppliedPkg = pkg; - if (mSelectedPkg == null) { - mSelectedPkg = pkg; - } - } - - holder.itemView.setActivated(pkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mApplyingOverlays.get()) return; - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(pkg, true); - mSelectedPkg = pkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - TextView title; - public CustomViewHolder(View itemView) { - super(itemView); - title = (TextView) itemView.findViewById(R.id.option_title); - name = (TextView) itemView.findViewById(R.id.option_label); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mApplyingOverlays.set(true); - mExecutor.execute(() -> { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "android"); - String pattern = "android".equals(mPkgs.get(position)) ? "" - : mPkgs.get(position).split("\\.")[4]; - for (Map.Entry entry : overlayMap.entrySet()) { - enableOverlay(entry.getValue(), entry.getKey(), pattern); - } - mHandler.post(() -> mApplyingOverlays.set(false)); - }); - } - - public void enableOverlay(String category, String target, String pattern) { - if (pattern.isEmpty()) { - mThemeUtils.setOverlayEnabled(category, "android", "android"); - return; - } - for (String pkg: mThemeUtils.getOverlayPackagesForCategory(category, target)) { - if (pkg.contains(pattern)) { - mThemeUtils.setOverlayEnabled(category, pkg, target); - } - } - } -} diff --git a/src/com/rising/settings/fragments/ui/UIStyles.kt b/src/com/rising/settings/fragments/ui/UIStyles.kt new file mode 100644 index 00000000..c0bc6a66 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/UIStyles.kt @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2021 AospExtended ROM 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.rising.settings.fragments.ui + +import android.content.ContentResolver +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.content.pm.PackageManager +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.provider.SearchIndexableResource +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.view.Gravity +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.FrameLayout +import android.widget.TextView +import android.text.TextUtils +import androidx.preference.PreferenceViewHolder +import android.view.ViewGroup.LayoutParams + +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import androidx.recyclerview.widget.RecyclerView +import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener +import androidx.preference.PreferenceScreen + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.android.settings.search.BaseSearchIndexProvider +import com.android.settingslib.search.Indexable +import com.rising.settings.fragments.OptimizedSettingsFragment +import java.lang.ref.WeakReference + +import com.android.internal.util.android.ThemeUtils + +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + +import org.json.JSONObject +import org.json.JSONException + +class UIStyles : OptimizedSettingsFragment() { + + private lateinit var mRecyclerView: RecyclerView + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.style.android" + private lateinit var mPkgs: List + + private val mExecutor: ExecutorService = Executors.newSingleThreadExecutor() + private val mApplyingOverlays = AtomicBoolean(false) + + private val overlayMap = mapOf( + "com.android.settings" to "android.theme.customization.style.settings", + "com.android.systemui" to "android.theme.customization.style.systemui" + ) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_ui_style_title) + + activity?.let { + mThemeUtils = ThemeUtils.getInstance(it) + } + mThemeUtils?.let { + mPkgs = it.getOverlayPackagesForCategory(mCategory, "android") + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 1) + mRecyclerView.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity!!) + mRecyclerView.adapter = mAdapter + + return view + } + + override fun onDestroy() { + super.onDestroy() + // Cleanup executor + if (!mExecutor.isShutdown) { + mExecutor.shutdown() + } + mThemeUtils = null + mApplyingOverlays.set(false) + } + + override fun onDetach() { + super.onDetach() + // Additional cleanup + mApplyingOverlays.set(false) + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(val context: Context) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.fonts_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val pkg = mPkgs[position] + val label = getLabel(holder.itemView.context, pkg) + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory) + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "android" + + holder.title.text = if (pkg == "android") "Default" else label + holder.title.textSize = 20f + holder.name.visibility = View.GONE + + if (currentPackageName == pkg) { + mAppliedPkg = pkg + if (mSelectedPkg == null) { + mSelectedPkg = pkg + } + } + + holder.itemView.isActivated = pkg == mSelectedPkg + holder.itemView.setOnClickListener { + if (mApplyingOverlays.get()) return@setOnClickListener + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(pkg, true) + mSelectedPkg = pkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs.size + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView = itemView.findViewById(R.id.option_label) + val title: TextView = itemView.findViewById(R.id.option_title) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val index = mPkgs.indexOf(pkg) + if (index < 0) { + return + } + val holder = mRecyclerView.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getLabel(context: Context, pkg: String): String { + val pm = context.packageManager + return try { + pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString() + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + mApplyingOverlays.set(true) + mExecutor.execute { + mThemeUtils?.setOverlayEnabled(mCategory, mPkgs[position], "android") + val pattern = if (mPkgs[position] == "android") { + "" + } else { + mPkgs[position].split(".")[4] + } + for ((target, category) in overlayMap) { + enableOverlay(category, target, pattern) + } + postDelayedSafe({ mApplyingOverlays.set(false) }, 0) + } + } + + private fun enableOverlay(category: String, target: String, pattern: String) { + if (pattern.isEmpty()) { + mThemeUtils?.setOverlayEnabled(category, "android", "android") + return + } + mThemeUtils?.getOverlayPackagesForCategory(category, target)?.forEach { pkg -> + if (pkg.contains(pattern)) { + mThemeUtils?.setOverlayEnabled(category, pkg, target) + } + } + } +} diff --git a/src/com/rising/settings/fragments/ui/WifiIcons.java b/src/com/rising/settings/fragments/ui/WifiIcons.java deleted file mode 100644 index 07545546..00000000 --- a/src/com/rising/settings/fragments/ui/WifiIcons.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.content.pm.PackageManager; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Gravity; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.FrameLayout; -import android.widget.TextView; -import android.text.TextUtils; -import androidx.preference.PreferenceViewHolder; -import android.view.ViewGroup.LayoutParams; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; -import com.android.settings.SettingsPreferenceFragment; - -import com.bumptech.glide.Glide; - -import com.android.internal.util.android.ThemeUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Arrays; - -import org.json.JSONObject; -import org.json.JSONException; - -public class WifiIcons extends SettingsPreferenceFragment { - - private RecyclerView mRecyclerView; - private ThemeUtils mThemeUtils; - private String mCategory = "android.theme.customization.wifi_icon"; - - private List mPkgs; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.theme_customization_wifi_icon_title); - - mThemeUtils = ThemeUtils.getInstance(getActivity()); - mPkgs = mThemeUtils.getOverlayPackagesForCategory(mCategory, "android"); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate( - R.layout.item_view, container, false); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); - mRecyclerView.setLayoutManager(gridLayoutManager); - Adapter mAdapter = new Adapter(getActivity()); - mRecyclerView.setAdapter(mAdapter); - - return view; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.VIEW_UNKNOWN; - } - - @Override - public void onResume() { - super.onResume(); - } - - public class Adapter extends RecyclerView.Adapter { - Context context; - String mSelectedPkg; - String mAppliedPkg; - - public Adapter(Context context) { - this.context = context; - } - - @Override - public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.icon_option, parent, false); - CustomViewHolder vh = new CustomViewHolder(v); - return vh; - } - - @Override - public void onBindViewHolder(CustomViewHolder holder, final int position) { - String iconPkg = mPkgs.get(position); - - holder.image1.setBackgroundDrawable(getDrawable(holder.image1.getContext(), iconPkg, "ic_wifi_signal_0")); - holder.image2.setBackgroundDrawable(getDrawable(holder.image2.getContext(), iconPkg, "ic_wifi_signal_2")); - holder.image3.setBackgroundDrawable(getDrawable(holder.image3.getContext(), iconPkg, "ic_wifi_signal_3")); - holder.image4.setBackgroundDrawable(getDrawable(holder.image4.getContext(), iconPkg, "ic_wifi_signal_4")); - - String currentPackageName = mThemeUtils.getOverlayInfos(mCategory).stream() - .filter(info -> info.isEnabled()) - .map(info -> info.packageName) - .findFirst() - .orElse("android"); - - holder.name.setText("android".equals(iconPkg) ? "Default" : getLabel(holder.name.getContext(), iconPkg)); - - if (currentPackageName.equals(iconPkg)) { - mAppliedPkg = iconPkg; - if (mSelectedPkg == null) { - mSelectedPkg = iconPkg; - } - } - - holder.itemView.setActivated(iconPkg == mSelectedPkg); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - updateActivatedStatus(mSelectedPkg, false); - updateActivatedStatus(iconPkg, true); - mSelectedPkg = iconPkg; - enableOverlays(position); - } - }); - } - - @Override - public int getItemCount() { - return mPkgs.size(); - } - - public class CustomViewHolder extends RecyclerView.ViewHolder { - TextView name; - ImageView image1; - ImageView image2; - ImageView image3; - ImageView image4; - public CustomViewHolder(View itemView) { - super(itemView); - name = (TextView) itemView.findViewById(R.id.option_label); - image1 = (ImageView) itemView.findViewById(R.id.image1); - image2 = (ImageView) itemView.findViewById(R.id.image2); - image3 = (ImageView) itemView.findViewById(R.id.image3); - image4 = (ImageView) itemView.findViewById(R.id.image4); - } - } - - private void updateActivatedStatus(String pkg, boolean isActivated) { - int index = mPkgs.indexOf(pkg); - if (index < 0) { - return; - } - RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); - if (holder != null && holder.itemView != null) { - holder.itemView.setActivated(isActivated); - } - } - } - - public Drawable getDrawable(Context context, String pkg, String drawableName) { - try { - PackageManager pm = context.getPackageManager(); - Resources res = pkg.equals("android") ? Resources.getSystem() - : pm.getResourcesForApplication(pkg); - int resId = res.getIdentifier(drawableName, "drawable", pkg); - return res.getDrawable(resId); - } - catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0) - .loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return pkg; - } - - public void enableOverlays(int position) { - mThemeUtils.setOverlayEnabled(mCategory, mPkgs.get(position), "android"); - } -} diff --git a/src/com/rising/settings/fragments/ui/WifiIcons.kt b/src/com/rising/settings/fragments/ui/WifiIcons.kt new file mode 100644 index 00000000..249b6784 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/WifiIcons.kt @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2022 crDroid Android 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.rising.settings.fragments.ui + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.android.internal.util.android.ThemeUtils + +class WifiIcons : OptimizedSettingsFragment() { + + private var mRecyclerView: RecyclerView? = null + override var mThemeUtils: ThemeUtils? = null + private val mCategory = "android.theme.customization.wifi_icon" + + private var mPkgs: List? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activity?.setTitle(R.string.theme_customization_wifi_icon_title) + + mThemeUtils = ThemeUtils.getInstance(activity) + mPkgs = mThemeUtils?.getOverlayPackagesForCategory(mCategory, "android") + } + + override fun onCreateView( + @NonNull inflater: LayoutInflater, + @Nullable container: ViewGroup?, + @Nullable savedInstanceState: Bundle? + ): View { + val view = inflater.inflate(R.layout.item_view, container, false) + + mRecyclerView = view.findViewById(R.id.recycler_view) + val gridLayoutManager = GridLayoutManager(activity, 3) + mRecyclerView?.layoutManager = gridLayoutManager + val mAdapter = Adapter(activity) + mRecyclerView?.adapter = mAdapter + + return view + } + + override fun getMetricsCategory(): Int { + return MetricsEvent.VIEW_UNKNOWN + } + + override fun onResume() { + super.onResume() + } + + inner class Adapter(private val context: Context?) : RecyclerView.Adapter() { + private var mSelectedPkg: String? = null + private var mAppliedPkg: String? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.icon_option, parent, false) + return CustomViewHolder(v) + } + + override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { + val iconPkg = mPkgs?.get(position) ?: return + + holder.image1?.background = getDrawable(holder.image1?.context, iconPkg, "ic_wifi_signal_0") + holder.image2?.background = getDrawable(holder.image2?.context, iconPkg, "ic_wifi_signal_2") + holder.image3?.background = getDrawable(holder.image3?.context, iconPkg, "ic_wifi_signal_3") + holder.image4?.background = getDrawable(holder.image4?.context, iconPkg, "ic_wifi_signal_4") + + val currentPackageName = mThemeUtils?.getOverlayInfos(mCategory) + ?.filter { it.isEnabled } + ?.map { it.packageName } + ?.firstOrNull() ?: "android" + + holder.name?.text = if ("android" == iconPkg) "Default" else getLabel(holder.name?.context, iconPkg) + + if (currentPackageName == iconPkg) { + mAppliedPkg = iconPkg + if (mSelectedPkg == null) { + mSelectedPkg = iconPkg + } + } + + holder.itemView.isActivated = iconPkg == mSelectedPkg + holder.itemView.setOnClickListener { + updateActivatedStatus(mSelectedPkg, false) + updateActivatedStatus(iconPkg, true) + mSelectedPkg = iconPkg + enableOverlays(position) + } + } + + override fun getItemCount(): Int { + return mPkgs?.size ?: 0 + } + + inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val name: TextView? = itemView.findViewById(R.id.option_label) + val image1: ImageView? = itemView.findViewById(R.id.image1) + val image2: ImageView? = itemView.findViewById(R.id.image2) + val image3: ImageView? = itemView.findViewById(R.id.image3) + val image4: ImageView? = itemView.findViewById(R.id.image4) + } + + private fun updateActivatedStatus(pkg: String?, isActivated: Boolean) { + val index = mPkgs?.indexOf(pkg) ?: -1 + if (index < 0) { + return + } + val holder = mRecyclerView?.findViewHolderForAdapterPosition(index) + holder?.itemView?.isActivated = isActivated + } + } + + private fun getDrawable(context: Context?, pkg: String, drawableName: String): Drawable? { + return try { + val pm = context?.packageManager + val res = if (pkg == "android") { + Resources.getSystem() + } else { + pm?.getResourcesForApplication(pkg) + } + val resId = res?.getIdentifier(drawableName, "drawable", pkg) ?: 0 + res?.getDrawable(resId) + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + null + } + } + + private fun getLabel(context: Context?, pkg: String): String { + val pm = context?.packageManager + return try { + pm?.getApplicationInfo(pkg, 0)?.loadLabel(pm)?.toString() ?: pkg + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + pkg + } + } + + private fun enableOverlays(position: Int) { + val pkg = mPkgs?.get(position) + if (pkg != null) { + mThemeUtils?.setOverlayEnabled(mCategory, pkg, "android") + } + } +} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.java b/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.java deleted file mode 100644 index 386052f5..00000000 --- a/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts; - -import android.content.Context; -import android.graphics.Typeface; -import android.util.SparseArray; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import com.android.settings.R; - -import androidx.core.content.ContextCompat; - -import java.util.List; - -public class FontArrayAdapter extends ArrayAdapter { - private FontManager fontManager; - private List fontPackageNames; - private List typefaces; - private Context mContext; - private boolean mIsNightMode; - - public FontArrayAdapter(Context context, int textViewResourceId, - List objects, FontManager fontManager, boolean nightMode) { - super(context, textViewResourceId, objects); - this.mContext = context; - this.fontPackageNames = objects; - this.fontManager = fontManager; - this.typefaces = fontManager.getFonts(); - this.mIsNightMode = nightMode; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView view = (TextView) super.getView(position, convertView, parent); - Typeface typeface = getTypefaceForPosition(position); - if (typeface != null) { - view.setTypeface(typeface); - } - view.setText(getLabelForPosition(position)); - view.setTextColor(ContextCompat.getColor(mContext, mIsNightMode - ? R.color.font_drop_down_bg_light - : R.color.font_drop_down_bg_dark)); - return view; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - TextView view = (TextView) super.getDropDownView(position, convertView, parent); - Typeface typeface = getTypefaceForPosition(position); - if (typeface != null) { - view.setTypeface(typeface); - } - view.setText(getLabelForPosition(position)); - view.setTextColor(ContextCompat.getColor(mContext, mIsNightMode - ? R.color.font_drop_down_bg_light - : R.color.font_drop_down_bg_dark)); - return view; - } - - private String getLabelForPosition(int position) { - return fontManager.getLabel(mContext, getFontPackageName(position)); - } - - private Typeface getTypefaceForPosition(int position) { - return fontManager.getTypeface(getContext(), getFontPackageName(position)); - } - - private String getFontPackageName(int position) { - return fontPackageNames.get(position); - } -} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.kt b/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.kt new file mode 100644 index 00000000..55d3eee5 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/fonts/FontArrayAdapter.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts + +import android.content.Context +import android.graphics.Typeface +import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.TextView + +import com.android.settings.R + +import androidx.core.content.ContextCompat + +class FontArrayAdapter( + context: Context, + textViewResourceId: Int, + private val fontPackageNames: List, + private val fontManager: FontManager, + private val mIsNightMode: Boolean +) : ArrayAdapter(context, textViewResourceId, fontPackageNames) { + + private val mContext = context + private val typefaces = fontManager.fonts + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = super.getView(position, convertView, parent) as TextView + val typeface = getTypefaceForPosition(position) + if (typeface != null) { + view.typeface = typeface + } + view.text = getLabelForPosition(position) + view.setTextColor(ContextCompat.getColor(mContext, + if (mIsNightMode) R.color.font_drop_down_bg_light else R.color.font_drop_down_bg_dark)) + return view + } + + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = super.getDropDownView(position, convertView, parent) as TextView + val typeface = getTypefaceForPosition(position) + if (typeface != null) { + view.typeface = typeface + } + view.text = getLabelForPosition(position) + view.setTextColor(ContextCompat.getColor(mContext, + if (mIsNightMode) R.color.font_drop_down_bg_light else R.color.font_drop_down_bg_dark)) + return view + } + + private fun getLabelForPosition(position: Int): String { + return fontManager.getLabel(mContext, getFontPackageName(position)) + } + + private fun getTypefaceForPosition(position: Int): Typeface? { + return fontManager.getTypeface(context, getFontPackageName(position)) + } + + private fun getFontPackageName(position: Int): String { + return fontPackageNames[position] + } +} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontManager.java b/src/com/rising/settings/fragments/ui/fonts/FontManager.java deleted file mode 100644 index 967b9095..00000000 --- a/src/com/rising/settings/fragments/ui/fonts/FontManager.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.content.om.OverlayInfo; -import android.graphics.Typeface; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import com.android.internal.util.android.ThemeUtils; - -public class FontManager { - - private final static String DEFAULT_FONT_PACKAGE = "android"; - private final static String FONT_OVERLAY_CATEGORY = "android.theme.customization.font"; - private final static String LOCKSCREEN_FONT_OVERLAY_CATEGORY = "android.theme.customization.lockscreen_clock_font"; - private final static String THEME_RESOURCE_FONT_FAMILY = "config_bodyFontFamily"; - private final static String THEME_RESOURCE_CLOCK_FONT_FAMILY = "config_clockFontFamily"; - private static final String THEME_RESOURCE_HEADLINE_FONT_FAMILY = "config_headlineFontFamily"; - - private static final Set HEADLINE_FONT_LABEL_MAP = new HashSet<>(); - - private ThemeUtils mThemeUtils; - private boolean isLockscreen; - - static { - HEADLINE_FONT_LABEL_MAP.add("NothingDot57"); - } - - public FontManager(Context context, boolean lockscreen) { - mThemeUtils = ThemeUtils.getInstance(context); - isLockscreen = lockscreen; - } - - /** - * Get all available fonts and return as a list of typefaces. - */ - public List getFonts() { - return mThemeUtils.getFonts(); - } - - /** - * Get all available font packages. - */ - public List getAllFontPackages() { - return mThemeUtils.getOverlayPackagesForCategory(isLockscreen ? LOCKSCREEN_FONT_OVERLAY_CATEGORY : FONT_OVERLAY_CATEGORY, DEFAULT_FONT_PACKAGE); - } - - /** - * Get the currently selected font package. - */ - public String getCurrentFontPackage() { - List overlayInfos = mThemeUtils.getOverlayInfos(isLockscreen ? LOCKSCREEN_FONT_OVERLAY_CATEGORY : FONT_OVERLAY_CATEGORY); - return overlayInfos.stream() - .filter(OverlayInfo::isEnabled) - .map(OverlayInfo::getPackageName) - .findFirst() - .orElse(DEFAULT_FONT_PACKAGE); - } - - /** - * Enable a selected font package. - */ - public void enableFontPackage(int position) { - if (position < 0 || position >= getAllFontPackages().size()) { - throw new IllegalArgumentException("Invalid font package position: " + position); - } - String selectedPackage = getAllFontPackages().get(position); - mThemeUtils.setOverlayEnabled(isLockscreen ? LOCKSCREEN_FONT_OVERLAY_CATEGORY : FONT_OVERLAY_CATEGORY, selectedPackage, DEFAULT_FONT_PACKAGE); - } - - /** - * Gets the font package label. - */ - public String getLabel(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - return pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString(); - } catch (PackageManager.NameNotFoundException e) {} - return pkg; - } - - /** - * Gets the font package typeface. - */ - public Typeface getTypeface(Context context, String pkg) { - PackageManager pm = context.getPackageManager(); - try { - Resources res = pkg.equals(DEFAULT_FONT_PACKAGE) ? Resources.getSystem() - : pm.getResourcesForApplication(pkg); - String label = getLabel(context, pkg); - String identifier = isLockscreen ? THEME_RESOURCE_CLOCK_FONT_FAMILY : THEME_RESOURCE_FONT_FAMILY; - if (!isLockscreen && HEADLINE_FONT_LABEL_MAP.contains(label)) { - identifier = THEME_RESOURCE_HEADLINE_FONT_FAMILY; - } - return Typeface.create(res.getString( - res.getIdentifier(identifier, "string", pkg)), Typeface.NORMAL); - } catch (PackageManager.NameNotFoundException e) {} - return null; - } -} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontManager.kt b/src/com/rising/settings/fragments/ui/fonts/FontManager.kt new file mode 100644 index 00000000..d24a3f1d --- /dev/null +++ b/src/com/rising/settings/fragments/ui/fonts/FontManager.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.content.om.OverlayInfo +import android.graphics.Typeface + +import com.android.internal.util.android.ThemeUtils + +class FontManager(context: Context, private val isLockscreen: Boolean) { + + companion object { + private const val DEFAULT_FONT_PACKAGE = "android" + private const val FONT_OVERLAY_CATEGORY = "android.theme.customization.font" + private const val LOCKSCREEN_FONT_OVERLAY_CATEGORY = "android.theme.customization.lockscreen_clock_font" + private const val THEME_RESOURCE_FONT_FAMILY = "config_bodyFontFamily" + private const val THEME_RESOURCE_CLOCK_FONT_FAMILY = "config_clockFontFamily" + private const val THEME_RESOURCE_HEADLINE_FONT_FAMILY = "config_headlineFontFamily" + + private val HEADLINE_FONT_LABEL_MAP = setOf("NothingDot57") + } + + private val mThemeUtils = ThemeUtils.getInstance(context) + + /** + * Get all available fonts and return as a list of typefaces. + */ + val fonts: List + get() = mThemeUtils.fonts + + /** + * Get all available font packages. + */ + val allFontPackages: List + get() = mThemeUtils.getOverlayPackagesForCategory( + if (isLockscreen) LOCKSCREEN_FONT_OVERLAY_CATEGORY else FONT_OVERLAY_CATEGORY, + DEFAULT_FONT_PACKAGE + ) + + /** + * Get the currently selected font package. + */ + val currentFontPackage: String + get() { + val overlayInfos = mThemeUtils.getOverlayInfos( + if (isLockscreen) LOCKSCREEN_FONT_OVERLAY_CATEGORY else FONT_OVERLAY_CATEGORY + ) + return overlayInfos + .filter { it.isEnabled } + .map { it.packageName } + .firstOrNull() ?: DEFAULT_FONT_PACKAGE + } + + /** + * Enable a selected font package. + */ + fun enableFontPackage(position: Int) { + val packages = allFontPackages + if (position < 0 || position >= packages.size) { + throw IllegalArgumentException("Invalid font package position: $position") + } + val selectedPackage = packages[position] + mThemeUtils.setOverlayEnabled( + if (isLockscreen) LOCKSCREEN_FONT_OVERLAY_CATEGORY else FONT_OVERLAY_CATEGORY, + selectedPackage, + DEFAULT_FONT_PACKAGE + ) + } + + /** + * Gets the font package label. + */ + fun getLabel(context: Context, pkg: String): String { + val pm = context.packageManager + return try { + pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString() + } catch (e: PackageManager.NameNotFoundException) { + pkg + } + } + + /** + * Gets the font package typeface. + */ + fun getTypeface(context: Context?, pkg: String): Typeface? { + if (context == null) return null + val pm = context.packageManager + return try { + val res = if (pkg == DEFAULT_FONT_PACKAGE) { + Resources.getSystem() + } else { + pm.getResourcesForApplication(pkg) + } + val label = getLabel(context, pkg) + val identifier = when { + isLockscreen -> THEME_RESOURCE_CLOCK_FONT_FAMILY + !isLockscreen && HEADLINE_FONT_LABEL_MAP.contains(label) -> THEME_RESOURCE_HEADLINE_FONT_FAMILY + else -> THEME_RESOURCE_FONT_FAMILY + } + Typeface.create( + res.getString(res.getIdentifier(identifier, "string", pkg)), + Typeface.NORMAL + ) + } catch (e: PackageManager.NameNotFoundException) { + null + } + } +} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.java b/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.java deleted file mode 100644 index aece4259..00000000 --- a/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.Typeface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.TextView; -import android.text.SpannableString; -import android.text.Spannable; -import android.text.style.ForegroundColorSpan; -import android.util.TypedValue; - -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; - -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; - -import java.util.List; - -public class FontPickerPreview extends SettingsPreferenceFragment { - - private TextView fontSelector; - private TextView previewText; - private FontManager fontManager; - private ExtendedFloatingActionButton applyFab; - private int currentFontPosition = -1; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - fontManager = new FontManager(getActivity(), false); - getActivity().setTitle(getActivity().getString(R.string.font_styles_title)); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.font_picker_preview, container, false); - - fontSelector = rootView.findViewById(R.id.font_selector); - previewText = rootView.findViewById(R.id.font_preview_text); - - String text = previewText.getText().toString(); - SpannableString spannableString = new SpannableString(text); - TypedValue typedValue = new TypedValue(); - getActivity().getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); - int colorAccent = typedValue.data; - int startIndex = text.indexOf("A"); - int endIndex = text.length(); - spannableString.setSpan( - new ForegroundColorSpan(colorAccent), - startIndex, - endIndex, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ); - previewText.setText(spannableString); - - List fontPackageNames = fontManager.getAllFontPackages(); - - int backgroundColor = ContextCompat.getColor(getContext(), - isNightMode() ? R.color.font_drop_down_bg_dark : R.color.font_drop_down_bg_light); - fontSelector.setTextColor(ContextCompat.getColor(getContext(), isNightMode() - ? R.color.font_drop_down_bg_light - : R.color.font_drop_down_bg_dark)); - fontSelector.setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); - - fontSelector.setOnClickListener(v -> { - View popupView = LayoutInflater.from(getActivity()).inflate(R.layout.popup_font_selector, null); - PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); - - ListView fontListView = popupView.findViewById(R.id.font_list_view); - FontArrayAdapter fontAdapter = new FontArrayAdapter( - getActivity(), - android.R.layout.simple_list_item_1, - fontPackageNames, - fontManager, - isNightMode() - ); - fontListView.setAdapter(fontAdapter); - - fontListView.setOnItemClickListener((parent, view, position, id) -> { - currentFontPosition = position; - String fontPackage = fontPackageNames.get(currentFontPosition); - applyFontToPreview(fontPackage); - fontSelector.setText(fontManager.getLabel(getContext(), fontPackage)); - popupWindow.dismiss(); - }); - - popupView.setBackgroundResource(R.drawable.custom_background); - Drawable backgroundDrawable = popupView.getBackground(); - if (backgroundDrawable != null) { - backgroundDrawable.setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP); - } - popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - popupWindow.setOutsideTouchable(true); - popupWindow.setFocusable(true); - popupWindow.showAsDropDown(v, 0, 10); - }); - - applyFab = rootView.findViewById(R.id.apply_extended_fab); - applyFab.setOnClickListener(view -> { - if (currentFontPosition != -1) { - fontManager.enableFontPackage(currentFontPosition); - } - }); - - String currentFontPackage = fontManager.getCurrentFontPackage(); - currentFontPosition = fontPackageNames.indexOf(currentFontPackage); - if (currentFontPosition != -1) { - fontSelector.setText(fontManager.getLabel(getContext(), fontPackageNames.get(currentFontPosition))); - applyFontToPreview(fontPackageNames.get(currentFontPosition)); - } - - return rootView; - } - - private boolean isNightMode() { - int nightModeFlags = getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - return nightModeFlags == Configuration.UI_MODE_NIGHT_YES; - } - - private void applyFontToPreview(String fontPackage) { - Typeface typeface = fontManager.getTypeface(getContext(), fontPackage); - if (typeface != null) { - previewText.setTypeface(typeface); - } else { - previewText.setTypeface(Typeface.create("googlesans", Typeface.NORMAL)); - } - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } -} diff --git a/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.kt b/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.kt new file mode 100644 index 00000000..6841c0a2 --- /dev/null +++ b/src/com/rising/settings/fragments/ui/fonts/FontPickerPreview.kt @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2023 The risingOS Android 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.rising.settings.fragments.ui.fonts + +import android.content.Context +import android.content.res.Configuration +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import android.graphics.drawable.ColorDrawable +import android.graphics.Typeface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ListView +import android.widget.PopupWindow +import android.widget.TextView +import android.text.SpannableString +import android.text.Spannable +import android.text.style.ForegroundColorSpan +import android.util.TypedValue + +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment + +import com.android.internal.logging.nano.MetricsProto +import com.android.settings.R +import com.rising.settings.fragments.OptimizedSettingsFragment + +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton + +class FontPickerPreview : OptimizedSettingsFragment() { + + private lateinit var fontSelector: TextView + private lateinit var previewText: TextView + private lateinit var fontManager: FontManager + private lateinit var applyFab: ExtendedFloatingActionButton + private var currentFontPosition = -1 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + fontManager = FontManager(requireActivity(), false) + activity?.title = activity?.getString(R.string.font_styles_title) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val rootView = inflater.inflate(R.layout.font_picker_preview, container, false) + + fontSelector = rootView.findViewById(R.id.font_selector) + previewText = rootView.findViewById(R.id.font_preview_text) + + val text = previewText.text.toString() + val spannableString = SpannableString(text) + val typedValue = TypedValue() + activity?.theme?.resolveAttribute(android.R.attr.colorAccent, typedValue, true) + val colorAccent = typedValue.data + val startIndex = text.indexOf("A") + val endIndex = text.length + spannableString.setSpan( + ForegroundColorSpan(colorAccent), + startIndex, + endIndex, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + previewText.text = spannableString + + val fontPackageNames = fontManager.allFontPackages + + val backgroundColor = ContextCompat.getColor(requireContext(), + if (isNightMode()) R.color.font_drop_down_bg_dark else R.color.font_drop_down_bg_light) + fontSelector.setTextColor(ContextCompat.getColor(requireContext(), + if (isNightMode()) R.color.font_drop_down_bg_light else R.color.font_drop_down_bg_dark)) + fontSelector.backgroundTintList = ColorStateList.valueOf(backgroundColor) + + fontSelector.setOnClickListener { v -> + val popupView = LayoutInflater.from(activity).inflate(R.layout.popup_font_selector, null) + val popupWindow = PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true) + + val fontListView = popupView.findViewById(R.id.font_list_view) + val fontAdapter = FontArrayAdapter( + activity!!, + android.R.layout.simple_list_item_1, + fontPackageNames, + fontManager, + isNightMode() + ) + fontListView.adapter = fontAdapter + + fontListView.setOnItemClickListener { _, _, position, _ -> + currentFontPosition = position + val fontPackage = fontPackageNames[currentFontPosition] + applyFontToPreview(fontPackage) + fontSelector.text = fontManager.getLabel(requireContext(), fontPackage) + popupWindow.dismiss() + } + + popupView.setBackgroundResource(R.drawable.custom_background) + val backgroundDrawable = popupView.background + backgroundDrawable?.setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP) + popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + popupWindow.isOutsideTouchable = true + popupWindow.isFocusable = true + popupWindow.showAsDropDown(v, 0, 10) + } + + applyFab = rootView.findViewById(R.id.apply_extended_fab) + applyFab.setOnClickListener { + if (currentFontPosition != -1) { + fontManager.enableFontPackage(currentFontPosition) + } + } + + val currentFontPackage = fontManager.currentFontPackage + currentFontPosition = fontPackageNames.indexOf(currentFontPackage) + if (currentFontPosition != -1) { + fontSelector.text = fontManager.getLabel(requireContext(), fontPackageNames[currentFontPosition]) + applyFontToPreview(fontPackageNames[currentFontPosition]) + } + + return rootView + } + + private fun isNightMode(): Boolean { + val nightModeFlags = requireContext().resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) + return nightModeFlags?.equals(Configuration.UI_MODE_NIGHT_YES) == true + } + + private fun applyFontToPreview(fontPackage: String) { + val typeface = fontManager.getTypeface(requireContext(), fontPackage) + if (typeface != null) { + previewText.typeface = typeface + } else { + previewText.typeface = Typeface.create("googlesans", Typeface.NORMAL) + } + } + + override fun getMetricsCategory(): Int { + return MetricsProto.MetricsEvent.VIEW_UNKNOWN + } +} diff --git a/src/com/rising/settings/utils/BuildOptimizations.kt b/src/com/rising/settings/utils/BuildOptimizations.kt new file mode 100644 index 00000000..ae352c64 --- /dev/null +++ b/src/com/rising/settings/utils/BuildOptimizations.kt @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2024 the risingOS Android 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.rising.settings.utils + +import android.os.SystemProperties +import android.util.Log + +/** + * Build-time and runtime optimizations for the Personalizations app. + * This class provides utilities for enabling/disabling performance features + * based on build configuration and system properties. + */ +object BuildOptimizations { + + private const val TAG = "PersonalizationsBuildOpt" + + // System properties for performance tuning + private const val PROP_PERFORMANCE_MODE = "persist.personalizations.performance_mode" + private const val PROP_DEBUG_PERFORMANCE = "persist.personalizations.debug_perf" + private const val PROP_CACHE_ENABLED = "persist.personalizations.cache_enabled" + private const val PROP_ANIMATION_OPTIMIZATION = "persist.personalizations.anim_opt" + + // Performance modes + const val PERFORMANCE_MODE_BALANCED = 0 + const val PERFORMANCE_MODE_PERFORMANCE = 1 + const val PERFORMANCE_MODE_BATTERY = 2 + + // Cache settings + private const val DEFAULT_CACHE_SIZE = 50 + private const val PERFORMANCE_CACHE_SIZE = 100 + private const val BATTERY_CACHE_SIZE = 25 + + /** + * Get the current performance mode + */ + @JvmStatic + fun getPerformanceMode(): Int { + return SystemProperties.getInt(PROP_PERFORMANCE_MODE, PERFORMANCE_MODE_BALANCED) + } + + /** + * Check if performance debugging is enabled + */ + @JvmStatic + fun isPerformanceDebugEnabled(): Boolean { + return SystemProperties.getBoolean(PROP_DEBUG_PERFORMANCE, false) + } + + /** + * Check if caching is enabled + */ + @JvmStatic + fun isCacheEnabled(): Boolean { + return SystemProperties.getBoolean(PROP_CACHE_ENABLED, true) + } + + /** + * Check if animation optimizations are enabled + */ + @JvmStatic + fun isAnimationOptimizationEnabled(): Boolean { + return SystemProperties.getBoolean(PROP_ANIMATION_OPTIMIZATION, true) + } + + /** + * Get optimal cache size based on performance mode + */ + @JvmStatic + fun getOptimalCacheSize(): Int { + if (!isCacheEnabled()) { + return 0 + } + + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> PERFORMANCE_CACHE_SIZE + PERFORMANCE_MODE_BATTERY -> BATTERY_CACHE_SIZE + PERFORMANCE_MODE_BALANCED -> DEFAULT_CACHE_SIZE + else -> DEFAULT_CACHE_SIZE + } + } + + /** + * Get animation frame rate target based on performance mode + */ + @JvmStatic + fun getTargetFrameRate(): Int { + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> 60 // 60 FPS for performance mode + PERFORMANCE_MODE_BATTERY -> 30 // 30 FPS for battery mode + PERFORMANCE_MODE_BALANCED -> 45 // 45 FPS for balanced mode + else -> 45 + } + } + + /** + * Get animation duration multiplier based on performance mode + */ + @JvmStatic + fun getAnimationDurationMultiplier(): Float { + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> 0.8f // Faster animations + PERFORMANCE_MODE_BATTERY -> 1.2f // Slower animations to save battery + PERFORMANCE_MODE_BALANCED -> 1.0f // Normal speed + else -> 1.0f + } + } + + /** + * Check if background processing should be enabled + */ + @JvmStatic + fun shouldUseBackgroundProcessing(): Boolean { + val mode = getPerformanceMode() + return mode == PERFORMANCE_MODE_PERFORMANCE || mode == PERFORMANCE_MODE_BALANCED + } + + /** + * Get the optimal thread pool size for background tasks + */ + @JvmStatic + fun getOptimalThreadPoolSize(): Int { + val processors = Runtime.getRuntime().availableProcessors() + + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> maxOf(2, processors) // Use all available processors + PERFORMANCE_MODE_BATTERY -> 1 // Single thread to save battery + PERFORMANCE_MODE_BALANCED -> maxOf(1, processors / 2) // Use half the processors + else -> maxOf(1, processors / 2) + } + } + + /** + * Check if memory leak detection should be enabled + */ + @JvmStatic + fun shouldEnableMemoryLeakDetection(): Boolean { + return isPerformanceDebugEnabled() + } + + /** + * Get the optimal garbage collection hint frequency + */ + @JvmStatic + fun getGCHintInterval(): Long { + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> 30000L // 30 seconds - less frequent GC hints + PERFORMANCE_MODE_BATTERY -> 10000L // 10 seconds - more frequent to free memory + PERFORMANCE_MODE_BALANCED -> 20000L // 20 seconds - balanced approach + else -> 20000L + } + } + + /** + * Check if resource preloading should be enabled + */ + @JvmStatic + fun shouldPreloadResources(): Boolean { + return getPerformanceMode() == PERFORMANCE_MODE_PERFORMANCE + } + + /** + * Get the optimal bitmap cache size in bytes + */ + @JvmStatic + fun getBitmapCacheSize(): Int { + val runtime = Runtime.getRuntime() + val maxMemory = runtime.maxMemory() + + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> (maxMemory / 6).toInt() // Use 1/6 of available memory + PERFORMANCE_MODE_BATTERY -> (maxMemory / 12).toInt() // Use 1/12 of available memory + PERFORMANCE_MODE_BALANCED -> (maxMemory / 8).toInt() // Use 1/8 of available memory + else -> (maxMemory / 8).toInt() + } + } + + /** + * Log current optimization settings + */ + @JvmStatic + fun logOptimizationSettings() { + if (!isPerformanceDebugEnabled()) { + return + } + + Log.d(TAG, "Performance Optimization Settings:") + Log.d(TAG, " Performance Mode: ${getPerformanceMode()}") + Log.d(TAG, " Cache Enabled: ${isCacheEnabled()}") + Log.d(TAG, " Cache Size: ${getOptimalCacheSize()}") + Log.d(TAG, " Target Frame Rate: ${getTargetFrameRate()}") + Log.d(TAG, " Animation Duration Multiplier: ${getAnimationDurationMultiplier()}") + Log.d(TAG, " Background Processing: ${shouldUseBackgroundProcessing()}") + Log.d(TAG, " Thread Pool Size: ${getOptimalThreadPoolSize()}") + Log.d(TAG, " Memory Leak Detection: ${shouldEnableMemoryLeakDetection()}") + Log.d(TAG, " GC Hint Interval: ${getGCHintInterval()}ms") + Log.d(TAG, " Resource Preloading: ${shouldPreloadResources()}") + Log.d(TAG, " Bitmap Cache Size: ${getBitmapCacheSize() / 1024 / 1024}MB") + } + + /** + * Apply runtime optimizations based on current settings + */ + @JvmStatic + fun applyRuntimeOptimizations() { + logOptimizationSettings() + + // Enable performance monitoring if debug is enabled + if (isPerformanceDebugEnabled()) { + PerformanceMonitor.setDebugEnabled(true) + MemoryLeakDetector.setDebugEnabled(true) + } + + // Log memory status + if (isPerformanceDebugEnabled()) { + PerformanceMonitor.getInstance().logMemoryUsage("app_startup") + } + } + + /** + * Get recommended ProGuard/R8 optimization level + */ + @JvmStatic + fun getRecommendedOptimizationLevel(): String { + return when (getPerformanceMode()) { + PERFORMANCE_MODE_PERFORMANCE -> "aggressive" // Maximum optimization + PERFORMANCE_MODE_BATTERY -> "conservative" // Minimal optimization to preserve battery + PERFORMANCE_MODE_BALANCED -> "balanced" // Standard optimization + else -> "balanced" + } + } +} diff --git a/src/com/rising/settings/utils/MemoryLeakDetector.kt b/src/com/rising/settings/utils/MemoryLeakDetector.kt new file mode 100644 index 00000000..310ae3e8 --- /dev/null +++ b/src/com/rising/settings/utils/MemoryLeakDetector.kt @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2024 the risingOS Android 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.rising.settings.utils + +import android.app.Activity +import android.os.Handler +import android.util.Log +import androidx.fragment.app.Fragment +import java.lang.ref.WeakReference +import java.util.concurrent.ConcurrentHashMap + +/** + * Utility class to detect potential memory leaks in fragments and activities. + * Tracks references and reports potential leaks when objects should have been garbage collected. + */ +class MemoryLeakDetector private constructor() { + + companion object { + private const val TAG = "MemoryLeakDetector" + private const val DEBUG = false // Set to true for leak detection + private const val LEAK_CHECK_DELAY = 5000L // 5 seconds + + // Singleton instance + @Volatile + private var sInstance: MemoryLeakDetector? = null + + @JvmStatic + fun getInstance(): MemoryLeakDetector { + return sInstance ?: synchronized(this) { + sInstance ?: MemoryLeakDetector().also { sInstance = it } + } + } + + /** + * Enable or disable leak detection + */ + @JvmStatic + fun setDebugEnabled(enabled: Boolean) { + // This would typically be controlled by a system property or build flag + // For now, it's controlled by the DEBUG constant + } + } + + // Track weak references to fragments and activities + private val mTrackedObjects = ConcurrentHashMap>() + + // Track creation times + private val mCreationTimes = ConcurrentHashMap() + + // Handler for delayed leak checks + private val mHandler = Handler() + + /** + * Start tracking a fragment for potential memory leaks + */ + fun trackFragment(fragment: Fragment?) { + if (!DEBUG || fragment == null) return + + val key = "${fragment.javaClass.simpleName}@${System.identityHashCode(fragment)}" + mTrackedObjects[key] = WeakReference(fragment) + mCreationTimes[key] = System.currentTimeMillis() + + Log.d(TAG, "Started tracking fragment: $key") + } + + /** + * Start tracking an activity for potential memory leaks + */ + fun trackActivity(activity: Activity?) { + if (!DEBUG || activity == null) return + + val key = "${activity.javaClass.simpleName}@${System.identityHashCode(activity)}" + mTrackedObjects[key] = WeakReference(activity) + mCreationTimes[key] = System.currentTimeMillis() + + Log.d(TAG, "Started tracking activity: $key") + } + + /** + * Stop tracking an object and schedule a leak check + */ + fun stopTracking(obj: Any?) { + if (!DEBUG || obj == null) return + + val key = "${obj.javaClass.simpleName}@${System.identityHashCode(obj)}" + + Log.d(TAG, "Stopped tracking: $key") + + // Schedule a delayed check to see if the object was garbage collected + mHandler.postDelayed({ checkForLeak(key) }, LEAK_CHECK_DELAY) + } + + /** + * Check if an object has been garbage collected + */ + private fun checkForLeak(key: String) { + val ref = mTrackedObjects[key] + if (ref != null) { + val obj = ref.get() + if (obj != null) { + // Object still exists - potential memory leak + val creationTime = mCreationTimes[key] + val age = if (creationTime != null) System.currentTimeMillis() - creationTime else 0 + + Log.w(TAG, "POTENTIAL MEMORY LEAK: $key still exists after " + + "${age / 1000} seconds") + + // Additional checks for common leak causes + when (obj) { + is Fragment -> checkFragmentLeaks(obj, key) + is Activity -> checkActivityLeaks(obj, key) + } + } else { + // Object was garbage collected - good! + Log.d(TAG, "Object successfully garbage collected: $key") + } + + // Clean up tracking data + mTrackedObjects.remove(key) + mCreationTimes.remove(key) + } + } + + /** + * Check for common fragment memory leak patterns + */ + private fun checkFragmentLeaks(fragment: Fragment, key: String) { + try { + // Check if fragment is still attached when it shouldn't be + if (fragment.isAdded) { + Log.w(TAG, "Fragment $key is still attached - possible leak") + } + + // Check if fragment has a context when it shouldn't + if (fragment.context != null) { + Log.w(TAG, "Fragment $key still has context - possible leak") + } + + // Check if fragment has an activity reference + if (fragment.activity != null) { + Log.w(TAG, "Fragment $key still has activity reference - possible leak") + } + + } catch (e: Exception) { + Log.e(TAG, "Error checking fragment leaks for $key", e) + } + } + + /** + * Check for common activity memory leak patterns + */ + private fun checkActivityLeaks(activity: Activity, key: String) { + try { + // Check if activity is still running when it shouldn't be + if (!activity.isFinishing && !activity.isDestroyed) { + Log.w(TAG, "Activity $key is still running - possible leak") + } + + } catch (e: Exception) { + Log.e(TAG, "Error checking activity leaks for $key", e) + } + } + + /** + * Force garbage collection and check all tracked objects + */ + fun forceLeakCheck() { + if (!DEBUG) return + + Log.d(TAG, "Forcing leak check for ${mTrackedObjects.size} tracked objects") + + // Force garbage collection + System.gc() + + // Wait a bit for GC to complete + mHandler.postDelayed({ + val keys = mTrackedObjects.keys.toSet() + for (key in keys) { + checkForLeak(key) + } + }, 1000) + } + + /** + * Get the number of currently tracked objects + */ + fun getTrackedObjectCount(): Int { + return mTrackedObjects.size + } + + /** + * Clear all tracking data + */ + fun clearAll() { + mTrackedObjects.clear() + mCreationTimes.clear() + mHandler.removeCallbacksAndMessages(null) + } + + /** + * Log statistics about tracked objects + */ + fun logStatistics() { + if (!DEBUG) return + + Log.d(TAG, "Memory leak detector statistics:") + Log.d(TAG, " Tracked objects: ${mTrackedObjects.size}") + + val currentTime = System.currentTimeMillis() + var oldObjects = 0 + + for ((_, creationTime) in mCreationTimes) { + val age = currentTime - creationTime + if (age > 30000) { // Objects older than 30 seconds + oldObjects++ + } + } + + Log.d(TAG, " Objects older than 30s: $oldObjects") + + if (oldObjects > 0) { + Log.w(TAG, "Found $oldObjects old objects - potential memory leaks") + } + } +} diff --git a/src/com/rising/settings/utils/PerformanceMonitor.kt b/src/com/rising/settings/utils/PerformanceMonitor.kt new file mode 100644 index 00000000..0846cf19 --- /dev/null +++ b/src/com/rising/settings/utils/PerformanceMonitor.kt @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2024 the risingOS Android 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.rising.settings.utils + +import android.os.Debug +import android.os.SystemClock +import android.util.Log +import java.util.concurrent.ConcurrentHashMap + +/** + * Performance monitoring utility for tracking memory usage, execution times, + * and identifying performance bottlenecks in the Personalizations app. + */ +class PerformanceMonitor private constructor() { + + companion object { + private const val TAG = "PersonalizationsPerf" + private const val DEBUG = false // Set to true for performance logging + + // Singleton instance + @Volatile + private var sInstance: PerformanceMonitor? = null + + @JvmStatic + fun getInstance(): PerformanceMonitor { + return sInstance ?: synchronized(this) { + sInstance ?: PerformanceMonitor().also { sInstance = it } + } + } + + /** + * Enable or disable debug logging + */ + @JvmStatic + fun setDebugEnabled(enabled: Boolean) { + // This would typically be controlled by a system property or build flag + // For now, it's controlled by the DEBUG constant + } + } + + // Track timing operations + private val mTimingMap = ConcurrentHashMap() + + // Track memory usage + private val mMemoryMap = ConcurrentHashMap() + + /** + * Start timing an operation + */ + fun startTiming(operationName: String) { + if (!DEBUG) return + + mTimingMap[operationName] = SystemClock.elapsedRealtime() + logMemoryUsage("${operationName}_start") + } + + /** + * End timing an operation and log the result + */ + fun endTiming(operationName: String) { + if (!DEBUG) return + + val startTime = mTimingMap.remove(operationName) + if (startTime != null) { + val duration = SystemClock.elapsedRealtime() - startTime + Log.d(TAG, "$operationName took ${duration}ms") + + // Log warning for slow operations + if (duration > 100) { + Log.w(TAG, "SLOW OPERATION: $operationName took ${duration}ms") + } + } + + logMemoryUsage("${operationName}_end") + } + + /** + * Log current memory usage + */ + fun logMemoryUsage(checkpoint: String) { + if (!DEBUG) return + + val runtime = Runtime.getRuntime() + val usedMemory = runtime.totalMemory() - runtime.freeMemory() + val maxMemory = runtime.maxMemory() + + // Convert to MB for readability + val usedMB = usedMemory / (1024 * 1024) + val maxMB = maxMemory / (1024 * 1024) + + Log.d(TAG, "$checkpoint - Memory: ${usedMB}MB / ${maxMB}MB" + + " (${usedMB * 100 / maxMB}%)") + + // Store for comparison + mMemoryMap[checkpoint] = usedMemory + + // Log warning for high memory usage + if (usedMB * 100 / maxMB > 80) { + Log.w(TAG, "HIGH MEMORY USAGE at $checkpoint: ${usedMB}MB") + } + } + + /** + * Log memory difference between two checkpoints + */ + fun logMemoryDifference(startCheckpoint: String, endCheckpoint: String) { + if (!DEBUG) return + + val startMemory = mMemoryMap[startCheckpoint] + val endMemory = mMemoryMap[endCheckpoint] + + if (startMemory != null && endMemory != null) { + val difference = endMemory - startMemory + val differenceMB = difference / (1024 * 1024) + + if (difference > 0) { + Log.d(TAG, "Memory increased by ${differenceMB}MB from " + + "$startCheckpoint to $endCheckpoint") + + // Log warning for significant memory increases + if (differenceMB > 10) { + Log.w(TAG, "MEMORY LEAK POTENTIAL: ${differenceMB}MB increase") + } + } else { + Log.d(TAG, "Memory decreased by ${kotlin.math.abs(differenceMB)}MB from " + + "$startCheckpoint to $endCheckpoint") + } + } + } + + /** + * Force garbage collection and log memory before/after + */ + fun forceGCAndLog(context: String) { + if (!DEBUG) return + + logMemoryUsage("${context}_before_gc") + System.gc() + + // Wait a bit for GC to complete + try { + Thread.sleep(100) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + } + + logMemoryUsage("${context}_after_gc") + } + + /** + * Log native heap information + */ + fun logNativeHeap(context: String) { + if (!DEBUG) return + + val nativeHeapSize = Debug.getNativeHeapSize() / (1024 * 1024) + val nativeHeapAllocated = Debug.getNativeHeapAllocatedSize() / (1024 * 1024) + val nativeHeapFree = Debug.getNativeHeapFreeSize() / (1024 * 1024) + + Log.d(TAG, "$context - Native Heap: ${nativeHeapAllocated}MB allocated, " + + "${nativeHeapFree}MB free, ${nativeHeapSize}MB total") + } + + /** + * Clear all stored timing and memory data + */ + fun clearData() { + mTimingMap.clear() + mMemoryMap.clear() + } + + /** + * Utility method to wrap operations with timing + */ + fun timeOperation(operationName: String, operation: Runnable) { + startTiming(operationName) + try { + operation.run() + } finally { + endTiming(operationName) + } + } + + /** + * Utility method to wrap operations with timing (Kotlin lambda version) + */ + inline fun timeOperation(operationName: String, operation: () -> Unit) { + startTiming(operationName) + try { + operation() + } finally { + endTiming(operationName) + } + } + + /** + * Log fragment lifecycle events for performance tracking + */ + fun logFragmentLifecycle(fragmentName: String, lifecycleEvent: String) { + if (!DEBUG) return + + Log.d(TAG, "$fragmentName - $lifecycleEvent") + logMemoryUsage("${fragmentName}_$lifecycleEvent") + } + + /** + * Log animation performance metrics + */ + fun logAnimationPerformance(animationName: String, frameCount: Long, totalTime: Long) { + if (!DEBUG) return + + if (totalTime > 0) { + val fps = (frameCount * 1000) / totalTime + Log.d(TAG, "$animationName - $frameCount frames in ${totalTime}ms" + + " (avg $fps FPS)") + + if (fps < 30) { + Log.w(TAG, "LOW FPS ANIMATION: $animationName only $fps FPS") + } + } + } +} diff --git a/src/com/rising/settings/utils/RuntimeOptimizer.kt b/src/com/rising/settings/utils/RuntimeOptimizer.kt new file mode 100644 index 00000000..93b64645 --- /dev/null +++ b/src/com/rising/settings/utils/RuntimeOptimizer.kt @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2024 the risingOS Android 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.rising.settings.utils + +import android.app.ActivityManager +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.Log +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong + +/** + * Runtime performance optimizer that dynamically adjusts performance parameters + * based on device capabilities and current system state. + */ +class RuntimeOptimizer private constructor() { + + companion object { + private const val TAG = "RuntimeOptimizer" + private const val DEBUG = false + + // Singleton instance + @Volatile + private var sInstance: RuntimeOptimizer? = null + + @JvmStatic + fun getInstance(): RuntimeOptimizer { + return sInstance ?: synchronized(this) { + sInstance ?: RuntimeOptimizer().also { sInstance = it } + } + } + } + + // Performance monitoring + private val mOptimizationActive = AtomicBoolean(false) + private val mLastOptimizationTime = AtomicLong(0) + + // Device capabilities + private var mDeviceMemoryClass: Int = 0 + private var mProcessorCount: Int = 0 + private var mIsLowRamDevice: Boolean = false + + // Optimization parameters + private var mOptimalCacheSize: Int = 0 + private var mOptimalThreadPoolSize: Int = 0 + private var mOptimalGCInterval: Long = 0 + + /** + * Initialize the optimizer with device capabilities + */ + fun initialize(context: Context?) { + if (context == null) return + + val am = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager + if (am != null) { + mDeviceMemoryClass = am.memoryClass + mIsLowRamDevice = am.isLowRamDevice + } + + mProcessorCount = Runtime.getRuntime().availableProcessors() + + calculateOptimalParameters() + + if (DEBUG) { + Log.d(TAG, "RuntimeOptimizer initialized:") + Log.d(TAG, " Memory Class: ${mDeviceMemoryClass}MB") + Log.d(TAG, " Processor Count: $mProcessorCount") + Log.d(TAG, " Low RAM Device: $mIsLowRamDevice") + Log.d(TAG, " Optimal Cache Size: $mOptimalCacheSize") + Log.d(TAG, " Optimal Thread Pool Size: $mOptimalThreadPoolSize") + } + } + + /** + * Calculate optimal parameters based on device capabilities + */ + private fun calculateOptimalParameters() { + // Calculate optimal cache size based on available memory + mOptimalCacheSize = if (mIsLowRamDevice) { + maxOf(10, mDeviceMemoryClass / 8) // Conservative for low RAM + } else { + maxOf(25, mDeviceMemoryClass / 4) // More aggressive for high RAM + } + + // Calculate optimal thread pool size + mOptimalThreadPoolSize = if (mIsLowRamDevice) { + maxOf(1, mProcessorCount / 2) + } else { + maxOf(2, mProcessorCount) + } + + // Calculate optimal GC interval + mOptimalGCInterval = if (mIsLowRamDevice) { + 10000L // 10 seconds for low RAM devices + } else { + 30000L // 30 seconds for normal devices + } + } + + /** + * Get optimal cache size for the current device + */ + fun getOptimalCacheSize(): Int { + return mOptimalCacheSize + } + + /** + * Get optimal thread pool size for the current device + */ + fun getOptimalThreadPoolSize(): Int { + return mOptimalThreadPoolSize + } + + /** + * Get optimal garbage collection interval + */ + fun getOptimalGCInterval(): Long { + return mOptimalGCInterval + } + + /** + * Check if device is low on memory + */ + fun isLowMemory(context: Context?): Boolean { + if (context == null) return false + + val am = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager + if (am != null) { + val memInfo = ActivityManager.MemoryInfo() + am.getMemoryInfo(memInfo) + return memInfo.lowMemory + } + return false + } + + /** + * Optimize performance based on current system state + */ + fun optimizePerformance(context: Context?) { + if (mOptimizationActive.get()) { + return // Already optimizing + } + + val currentTime = System.currentTimeMillis() + if (currentTime - mLastOptimizationTime.get() < 5000) { + return // Don't optimize too frequently + } + + mOptimizationActive.set(true) + mLastOptimizationTime.set(currentTime) + + try { + // Check memory pressure and adjust accordingly + if (isLowMemory(context)) { + performLowMemoryOptimization() + } else { + performNormalOptimization() + } + } finally { + mOptimizationActive.set(false) + } + } + + /** + * Perform optimizations for low memory conditions + */ + private fun performLowMemoryOptimization() { + if (DEBUG) { + Log.d(TAG, "Performing low memory optimization") + } + + // Suggest garbage collection + Runtime.getRuntime().gc() + + // Clear performance monitor caches if available + PerformanceMonitor.getInstance().clearData() + + // Force memory leak detector to check + MemoryLeakDetector.getInstance().forceLeakCheck() + } + + /** + * Perform normal optimizations + */ + private fun performNormalOptimization() { + if (DEBUG) { + Log.d(TAG, "Performing normal optimization") + } + + // Log current memory usage + PerformanceMonitor.getInstance().logMemoryUsage("runtime_optimization") + } + + /** + * Get recommended animation duration multiplier based on device performance + */ + fun getAnimationDurationMultiplier(): Float { + return when { + mIsLowRamDevice -> 1.2f // Slower animations for low-end devices + mProcessorCount >= 8 -> 0.8f // Faster animations for high-end devices + else -> 1.0f // Normal speed for mid-range devices + } + } + + /** + * Check if background processing should be limited + */ + fun shouldLimitBackgroundProcessing(): Boolean { + return mIsLowRamDevice || mProcessorCount < 4 + } + + /** + * Get recommended frame rate target based on device capabilities + */ + fun getRecommendedFrameRate(): Int { + return when { + mIsLowRamDevice -> 30 // 30 FPS for low-end devices + mProcessorCount >= 8 && mDeviceMemoryClass >= 512 -> 60 // 60 FPS for high-end devices + else -> 45 // 45 FPS for mid-range devices + } + } + + /** + * Schedule periodic optimization + */ + fun schedulePeriodicOptimization(context: Context?) { + val handler = Handler(Looper.getMainLooper()) + + val optimizationRunnable = object : Runnable { + override fun run() { + optimizePerformance(context) + // Schedule next optimization + handler.postDelayed(this, getOptimalGCInterval()) + } + } + + // Start periodic optimization + handler.postDelayed(optimizationRunnable, getOptimalGCInterval()) + } + + /** + * Get device performance tier + */ + fun getDevicePerformanceTier(): Int { + return when { + mIsLowRamDevice || mProcessorCount < 4 || mDeviceMemoryClass < 256 -> 1 // Low-end + mProcessorCount >= 8 && mDeviceMemoryClass >= 512 -> 3 // High-end + else -> 2 // Mid-range + } + } + + /** + * Apply device-specific optimizations + */ + fun applyDeviceOptimizations() { + val tier = getDevicePerformanceTier() + + if (DEBUG) { + Log.d(TAG, "Applying optimizations for performance tier: $tier") + } + + // Apply optimizations based on device tier + when (tier) { + 1 -> { // Low-end + // Apply low-end optimizations - disable debug features + if (BuildOptimizations.shouldEnableMemoryLeakDetection()) { + MemoryLeakDetector.setDebugEnabled(false) + } + } + 2 -> { // Mid-range + // Default settings + } + 3 -> { // High-end + // Enable all optimizations + } + } + } + + /** + * Get memory usage statistics + */ + fun getMemoryStats(): String { + val runtime = Runtime.getRuntime() + val totalMemory = runtime.totalMemory() + val freeMemory = runtime.freeMemory() + val usedMemory = totalMemory - freeMemory + val maxMemory = runtime.maxMemory() + + return String.format("Memory: %dMB used / %dMB max (%.1f%%)", + usedMemory / (1024 * 1024), + maxMemory / (1024 * 1024), + (usedMemory * 100.0f) / maxMemory) + } +} From e256bb287a36b788eb0e112c5a7fd3cfa735b054 Mon Sep 17 00:00:00 2001 From: rmp22 <195054967+rmp22@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:37:38 +0800 Subject: [PATCH 10/24] notification row transparency switch Change-Id: I07e610dc32cc0256e67ea9d0968cefd817d82866 --- res/values/custom_strings.xml | 4 ++++ res/xml/rising_settings_notification.xml | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 7faed10a..3752cc68 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,10 @@ limitations under the License. --> + + Notification row transparency + Show translucent quicksettings notifications + Three finger swipe Swipe down with three fingers to perform actions. diff --git a/res/xml/rising_settings_notification.xml b/res/xml/rising_settings_notification.xml index 50a2cabc..a4781c37 100644 --- a/res/xml/rising_settings_notification.xml +++ b/res/xml/rising_settings_notification.xml @@ -29,7 +29,14 @@ android:title="@string/notification_sound_vib_screen_on_title" android:summary="@string/notification_sound_vib_screen_on_summary" android:defaultValue="true" - lineage:position="solo" /> + lineage:position="top" /> + + Date: Wed, 3 Sep 2025 10:53:55 +0530 Subject: [PATCH 11/24] pulse: Set default interval for seekbar prefs Signed-off-by: Pranav Vashi --- res/xml/pulse_settings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/xml/pulse_settings.xml b/res/xml/pulse_settings.xml index c2ceb800..46403116 100644 --- a/res/xml/pulse_settings.xml +++ b/res/xml/pulse_settings.xml @@ -103,6 +103,7 @@ android:defaultValue="14" android:max="30" settings:min="1" + settings:interval="1" settings:units="@string/unit_pixels" android:dependency="pulse_fading_bars_category" lineage:position="top"/> @@ -123,6 +124,7 @@ android:defaultValue="4" android:max="8" settings:min="4" + settings:interval="1" settings:units="@string/unit_pixels" android:dependency="pulse_fading_bars_category"/> @@ -132,6 +134,7 @@ android:defaultValue="1" android:max="4" settings:min="0" + settings:interval="1" settings:units="@string/unit_pixels" android:dependency="pulse_fading_bars_category"/> @@ -141,6 +144,7 @@ android:defaultValue="4" android:max="6" settings:min="2" + settings:interval="1" android:dependency="pulse_fading_bars_category" lineage:position="bottom"/> @@ -163,6 +167,7 @@ android:defaultValue="200" android:max="255" settings:min="0" + settings:interval="1" android:dependency="pulse_2"/> From 18eb4ee26fd4ab28b9220b1b9a2eb4ac9088daf2 Mon Sep 17 00:00:00 2001 From: Ido Ben-Hur Date: Mon, 15 Sep 2025 01:08:44 +0900 Subject: [PATCH 12/24] Allow disabling time to full on keyguard [2/2] --- res/values/custom_strings.xml | 4 ++++ res/xml/rising_settings_lockscreen.xml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 3752cc68..38f1ab8c 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,10 @@ limitations under the License. --> + + Lock screen charging time + Display the remaining time for charging to finish + Notification row transparency Show translucent quicksettings notifications diff --git a/res/xml/rising_settings_lockscreen.xml b/res/xml/rising_settings_lockscreen.xml index 95384678..ccf48389 100644 --- a/res/xml/rising_settings_lockscreen.xml +++ b/res/xml/rising_settings_lockscreen.xml @@ -43,6 +43,12 @@ lineage:position="top" /> + + Date: Mon, 15 Sep 2025 02:54:27 +0900 Subject: [PATCH 13/24] Enable PIF by default [2/2] --- res/xml/rising_settings_spoof.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/xml/rising_settings_spoof.xml b/res/xml/rising_settings_spoof.xml index 92be77d6..571d90bb 100644 --- a/res/xml/rising_settings_spoof.xml +++ b/res/xml/rising_settings_spoof.xml @@ -34,7 +34,7 @@ android:key="persist.sys.pixelprops.gms" android:title="@string/gms_spoof_title" android:summary="@string/gms_spoof_summary" - android:defaultValue="false" /> + android:defaultValue="true" /> Date: Tue, 22 Jul 2025 15:21:46 +0800 Subject: [PATCH 14/24] power off verify Change-Id: Ibc9a9a1de7ffc198f98a2170a382147695b6b86c Signed-off-by: rmp22 <195054967+rmp22@users.noreply.github.com> --- res/raw-night/nt_power_off_verify.json | 1 + res/raw/nt_power_off_verify.json | 1 + res/values/custom_strings.xml | 5 +++++ res/xml/power_off_verify.xml | 15 +++++++++++++++ 4 files changed, 22 insertions(+) create mode 100644 res/raw-night/nt_power_off_verify.json create mode 100644 res/raw/nt_power_off_verify.json create mode 100644 res/xml/power_off_verify.xml diff --git a/res/raw-night/nt_power_off_verify.json b/res/raw-night/nt_power_off_verify.json new file mode 100644 index 00000000..24ac0b22 --- /dev/null +++ b/res/raw-night/nt_power_off_verify.json @@ -0,0 +1 @@ +{"nm":"Dark","ddd":0,"h":278,"w":366,"meta":{"g":"LottieFiles Figma v67"},"layers":[{"ty":4,"nm":"bar","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[17,1.5],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[17,1.5],"t":408},{"s":[17,1.5],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,245.5],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[183,245.5],"t":408},{"s":[183,245.5],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":408},{"s":[{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5687,0.5647,0.5804],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.5687,0.5647,0.5804],"t":408},{"s":[0.5687,0.5647,0.5804],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":1},{"ty":0,"nm":"Frame 427322354","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,115],"t":408},{"s":[55,115],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[183,139],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[183,139],"t":408},{"s":[183,139],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"masksProperties":[{"nm":"","inv":false,"mode":"a","x":{"a":0,"k":0},"o":{"a":0,"k":100},"pt":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":456}]}}],"w":366,"h":278,"refId":"1","ind":2}],"v":"5.7.0","fr":60,"op":408.06,"ip":0,"assets":[{"nm":"[Asset] Frame 427322354","id":"1","layers":[{"ty":0,"nm":"Frame 427322356","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[35,39],"t":408},{"s":[35,39],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,111],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,111],"t":408},{"s":[55,111],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"w":366,"h":278,"refId":"2","ind":1},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,115],"t":408},{"s":[55,115],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,115],"t":408},{"s":[55,115],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}],"t":456}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.1942,0.1942,0.1942],"t":408},{"s":[0.1942,0.1942,0.1942],"t":456}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":2},{"ty":4,"nm":"Subtract","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":276},{"s":[2.5,1.25],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":276},{"s":[55,53.25],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":276},{"s":[0.8922,0.8922,0.8922],"t":396}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":3},{"ty":4,"nm":"Line 2 (Stroke)","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":276},{"s":[0.5,0.5],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":276},{"s":[57,55],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":276},{"s":[-90],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":276},{"s":[0.8922,0.8922,0.8922],"t":396}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":4},{"ty":4,"nm":"Line 1 (Stroke)","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":276},{"s":[0.5,0.5],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":276},{"s":[53,55],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":276},{"s":[0.8922,0.8922,0.8922],"t":396}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":5},{"ty":4,"nm":"Rectangle 4979","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":276},{"s":[4,3.5],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":276},{"s":[55.5,59.5],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":276},{"s":[{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}],"t":396}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":276},{"s":[1],"t":396}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8922,0.8922,0.8922],"t":276},{"s":[0.8922,0.8922,0.8922],"t":396}]}}],"ind":6},{"ty":4,"nm":"Rectangle 160","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":276},{"s":[2,32],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,106.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,106.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":276},{"s":[25,138],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":276},{"s":[1,1,1],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":7},{"ty":0,"nm":"Group 1","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":396},{"s":[33,33],"t":456.06}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396},{"s":[100,100],"t":456.06}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":396},{"s":[55,138],"t":456.06}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"w":366,"h":278,"refId":"3","ind":8},{"ty":4,"nm":"Rectangle 161","sr":1,"st":0,"op":409.06,"ip":174,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":276},{"s":[2,30],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[27.5,168],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":276},{"s":[57,168],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":276},{"s":[90],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":276},{"s":[1,1,1],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":9},{"ty":4,"nm":"Shutting down...","sr":1,"st":0,"op":409.06,"ip":276,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[38.5,6],"t":276},{"s":[38.5,6],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,115],"t":276},{"s":[55.5,115],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.39,0.17],[0.22,0.3],[0.03,0.41],[0,0],[-0.16,-0.18],[-0.25,-0.09],[-0.28,0],[-0.26,0.11],[-0.15,0.2],[0,0.26],[0.13,0.15],[0.22,0.09],[0.26,0.07],[0,0],[0.33,0.31],[0,0.48],[-0.22,0.31],[-0.38,0.17],[-0.47,0],[-0.37,-0.17],[-0.21,-0.29],[-0.01,-0.37],[0,0],[0.3,0.19],[0.43,0],[0.24,-0.1],[0.13,-0.18],[0,-0.23],[-0.16,-0.16],[-0.21,-0.09],[-0.18,-0.05],[0,0],[-0.23,-0.09],[-0.21,-0.15],[-0.14,-0.23],[0,-0.34],[0.21,-0.32],[0.39,-0.19],[0.56,0]],"o":[[-0.52,0],[-0.38,-0.17],[-0.22,-0.31],[0,0],[0.03,0.27],[0.16,0.18],[0.25,0.08],[0.33,0],[0.26,-0.11],[0.15,-0.2],[0,-0.23],[-0.13,-0.15],[-0.22,-0.09],[0,0],[-0.59,-0.17],[-0.33,-0.31],[0,-0.41],[0.22,-0.31],[0.38,-0.17],[0.48,0],[0.37,0.17],[0.21,0.29],[0,0],[-0.04,-0.35],[-0.3,-0.2],[-0.31,0],[-0.23,0.1],[-0.13,0.18],[0,0.25],[0.16,0.15],[0.22,0.08],[0,0],[0.2,0.05],[0.24,0.09],[0.21,0.15],[0.14,0.23],[0,0.4],[-0.21,0.32],[-0.39,0.19],[0,0]],"v":[[3.21,10.13],[1.84,9.87],[0.94,9.17],[0.57,8.1],[1.52,8.1],[1.8,8.77],[2.41,9.17],[3.21,9.3],[4.09,9.14],[4.72,8.68],[4.95,8],[4.75,7.43],[4.22,7.07],[3.51,6.82],[2.63,6.57],[1.26,5.86],[0.77,4.67],[1.1,3.6],[2,2.88],[3.27,2.63],[4.54,2.88],[5.41,3.57],[5.75,4.56],[4.84,4.56],[4.34,3.74],[3.24,3.45],[2.42,3.6],[1.87,4.02],[1.67,4.63],[1.91,5.24],[2.47,5.61],[3.06,5.81],[3.79,6.01],[4.43,6.22],[5.11,6.59],[5.64,7.16],[5.85,8.02],[5.54,9.09],[4.64,9.85],[3.21,10.13]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.39,0.17],[0.22,0.3],[0.03,0.41],[0,0],[-0.16,-0.18],[-0.25,-0.09],[-0.28,0],[-0.26,0.11],[-0.15,0.2],[0,0.26],[0.13,0.15],[0.22,0.09],[0.26,0.07],[0,0],[0.33,0.31],[0,0.48],[-0.22,0.31],[-0.38,0.17],[-0.47,0],[-0.37,-0.17],[-0.21,-0.29],[-0.01,-0.37],[0,0],[0.3,0.19],[0.43,0],[0.24,-0.1],[0.13,-0.18],[0,-0.23],[-0.16,-0.16],[-0.21,-0.09],[-0.18,-0.05],[0,0],[-0.23,-0.09],[-0.21,-0.15],[-0.14,-0.23],[0,-0.34],[0.21,-0.32],[0.39,-0.19],[0.56,0]],"o":[[-0.52,0],[-0.38,-0.17],[-0.22,-0.31],[0,0],[0.03,0.27],[0.16,0.18],[0.25,0.08],[0.33,0],[0.26,-0.11],[0.15,-0.2],[0,-0.23],[-0.13,-0.15],[-0.22,-0.09],[0,0],[-0.59,-0.17],[-0.33,-0.31],[0,-0.41],[0.22,-0.31],[0.38,-0.17],[0.48,0],[0.37,0.17],[0.21,0.29],[0,0],[-0.04,-0.35],[-0.3,-0.2],[-0.31,0],[-0.23,0.1],[-0.13,0.18],[0,0.25],[0.16,0.15],[0.22,0.08],[0,0],[0.2,0.05],[0.24,0.09],[0.21,0.15],[0.14,0.23],[0,0.4],[-0.21,0.32],[-0.39,0.19],[0,0]],"v":[[3.21,10.13],[1.84,9.87],[0.94,9.17],[0.57,8.1],[1.52,8.1],[1.8,8.77],[2.41,9.17],[3.21,9.3],[4.09,9.14],[4.72,8.68],[4.95,8],[4.75,7.43],[4.22,7.07],[3.51,6.82],[2.63,6.57],[1.26,5.86],[0.77,4.67],[1.1,3.6],[2,2.88],[3.27,2.63],[4.54,2.88],[5.41,3.57],[5.75,4.56],[4.84,4.56],[4.34,3.74],[3.24,3.45],[2.42,3.6],[1.87,4.02],[1.67,4.63],[1.91,5.24],[2.47,5.61],[3.06,5.81],[3.79,6.01],[4.43,6.22],[5.11,6.59],[5.64,7.16],[5.85,8.02],[5.54,9.09],[4.64,9.85],[3.21,10.13]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.39,0.17],[0.22,0.3],[0.03,0.41],[0,0],[-0.16,-0.18],[-0.25,-0.09],[-0.28,0],[-0.26,0.11],[-0.15,0.2],[0,0.26],[0.13,0.15],[0.22,0.09],[0.26,0.07],[0,0],[0.33,0.31],[0,0.48],[-0.22,0.31],[-0.38,0.17],[-0.47,0],[-0.37,-0.17],[-0.21,-0.29],[-0.01,-0.37],[0,0],[0.3,0.19],[0.43,0],[0.24,-0.1],[0.13,-0.18],[0,-0.23],[-0.16,-0.16],[-0.21,-0.09],[-0.18,-0.05],[0,0],[-0.23,-0.09],[-0.21,-0.15],[-0.14,-0.23],[0,-0.34],[0.21,-0.32],[0.39,-0.19],[0.56,0]],"o":[[-0.52,0],[-0.38,-0.17],[-0.22,-0.31],[0,0],[0.03,0.27],[0.16,0.18],[0.25,0.08],[0.33,0],[0.26,-0.11],[0.15,-0.2],[0,-0.23],[-0.13,-0.15],[-0.22,-0.09],[0,0],[-0.59,-0.17],[-0.33,-0.31],[0,-0.41],[0.22,-0.31],[0.38,-0.17],[0.48,0],[0.37,0.17],[0.21,0.29],[0,0],[-0.04,-0.35],[-0.3,-0.2],[-0.31,0],[-0.23,0.1],[-0.13,0.18],[0,0.25],[0.16,0.15],[0.22,0.08],[0,0],[0.2,0.05],[0.24,0.09],[0.21,0.15],[0.14,0.23],[0,0.4],[-0.21,0.32],[-0.39,0.19],[0,0]],"v":[[3.21,10.13],[1.84,9.87],[0.94,9.17],[0.57,8.1],[1.52,8.1],[1.8,8.77],[2.41,9.17],[3.21,9.3],[4.09,9.14],[4.72,8.68],[4.95,8],[4.75,7.43],[4.22,7.07],[3.51,6.82],[2.63,6.57],[1.26,5.86],[0.77,4.67],[1.1,3.6],[2,2.88],[3.27,2.63],[4.54,2.88],[5.41,3.57],[5.75,4.56],[4.84,4.56],[4.34,3.74],[3.24,3.45],[2.42,3.6],[1.87,4.02],[1.67,4.63],[1.91,5.24],[2.47,5.61],[3.06,5.81],[3.79,6.01],[4.43,6.22],[5.11,6.59],[5.64,7.16],[5.85,8.02],[5.54,9.09],[4.64,9.85],[3.21,10.13]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[8.07,6.73],[8.07,10],[7.19,10],[7.19,2.72],[8.07,2.72],[8.07,5.86],[7.92,5.86],[8.62,4.79],[9.71,4.47],[10.67,4.7],[11.32,5.39],[11.56,6.53],[11.56,10],[10.67,10],[10.67,6.61],[10.34,5.62],[9.44,5.26],[8.74,5.43],[8.25,5.93],[8.07,6.73]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[8.07,6.73],[8.07,10],[7.19,10],[7.19,2.72],[8.07,2.72],[8.07,5.86],[7.92,5.86],[8.62,4.79],[9.71,4.47],[10.67,4.7],[11.32,5.39],[11.56,6.53],[11.56,10],[10.67,10],[10.67,6.61],[10.34,5.62],[9.44,5.26],[8.74,5.43],[8.25,5.93],[8.07,6.73]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.28,0.15],[0.16,0.31],[0,0.46],[0,0],[0,0],[0,0],[-0.22,-0.24],[-0.38,0],[-0.21,0.11],[-0.12,0.22],[0,0.31],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.31,-0.21],[0.4,0]],"o":[[-0.37,0],[-0.28,-0.15],[-0.15,-0.31],[0,0],[0,0],[0,0],[0,0.42],[0.22,0.24],[0.26,0],[0.21,-0.11],[0.12,-0.22],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.17,0.51],[-0.31,0.21],[0,0]],"v":[[14.96,10.07],[13.98,9.84],[13.34,9.16],[13.11,8.01],[13.11,4.54],[13.98,4.54],[13.98,7.93],[14.32,8.92],[15.22,9.28],[15.92,9.11],[16.41,8.61],[16.59,7.81],[16.59,4.54],[17.48,4.54],[17.48,10],[16.63,10],[16.63,8.68],[16.74,8.68],[16.02,9.76],[14.96,10.07]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.28,0.15],[0.16,0.31],[0,0.46],[0,0],[0,0],[0,0],[-0.22,-0.24],[-0.38,0],[-0.21,0.11],[-0.12,0.22],[0,0.31],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.31,-0.21],[0.4,0]],"o":[[-0.37,0],[-0.28,-0.15],[-0.15,-0.31],[0,0],[0,0],[0,0],[0,0.42],[0.22,0.24],[0.26,0],[0.21,-0.11],[0.12,-0.22],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.17,0.51],[-0.31,0.21],[0,0]],"v":[[14.96,10.07],[13.98,9.84],[13.34,9.16],[13.11,8.01],[13.11,4.54],[13.98,4.54],[13.98,7.93],[14.32,8.92],[15.22,9.28],[15.92,9.11],[16.41,8.61],[16.59,7.81],[16.59,4.54],[17.48,4.54],[17.48,10],[16.63,10],[16.63,8.68],[16.74,8.68],[16.02,9.76],[14.96,10.07]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.17,4.54],[21.17,5.29],[18.35,5.29],[18.35,4.54],[21.17,4.54]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.17,4.54],[21.17,5.29],[18.35,5.29],[18.35,4.54],[21.17,4.54]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[-0.1,-0.11],[-0.23,0],[-0.08,0.01],[-0.07,0.01],[0,0],[0.12,-0.02],[0.11,0],[0.26,0.25],[0,0.45],[0,0]],"o":[[0,0],[0,0],[0,0.24],[0.1,0.11],[0.06,0],[0.09,-0.01],[0,0],[-0.09,0.03],[-0.11,0.02],[-0.47,0],[-0.26,-0.25],[0,0],[0,0]],"v":[[19.17,3.24],[20.05,3.24],[20.05,8.58],[20.2,9.12],[20.69,9.29],[20.9,9.27],[21.14,9.23],[21.32,9.97],[21.01,10.04],[20.67,10.07],[19.57,9.7],[19.17,8.65],[19.17,3.24]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[-0.1,-0.11],[-0.23,0],[-0.08,0.01],[-0.07,0.01],[0,0],[0.12,-0.02],[0.11,0],[0.26,0.25],[0,0.45],[0,0]],"o":[[0,0],[0,0],[0,0.24],[0.1,0.11],[0.06,0],[0.09,-0.01],[0,0],[-0.09,0.03],[-0.11,0.02],[-0.47,0],[-0.26,-0.25],[0,0],[0,0]],"v":[[19.17,3.24],[20.05,3.24],[20.05,8.58],[20.2,9.12],[20.69,9.29],[20.9,9.27],[21.14,9.23],[21.32,9.97],[21.01,10.04],[20.67,10.07],[19.57,9.7],[19.17,8.65],[19.17,3.24]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[24.2,4.54],[24.2,5.29],[21.38,5.29],[21.38,4.54],[24.2,4.54]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[24.2,4.54],[24.2,5.29],[21.38,5.29],[21.38,4.54],[24.2,4.54]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[-0.1,-0.11],[-0.23,0],[-0.08,0.01],[-0.07,0.01],[0,0],[0.12,-0.02],[0.11,0],[0.26,0.25],[0,0.45],[0,0]],"o":[[0,0],[0,0],[0,0.24],[0.1,0.11],[0.06,0],[0.09,-0.01],[0,0],[-0.09,0.03],[-0.11,0.02],[-0.47,0],[-0.26,-0.25],[0,0],[0,0]],"v":[[22.2,3.24],[23.08,3.24],[23.08,8.58],[23.22,9.12],[23.72,9.29],[23.93,9.27],[24.17,9.23],[24.35,9.97],[24.04,10.04],[23.7,10.07],[22.59,9.7],[22.2,8.65],[22.2,3.24]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[-0.1,-0.11],[-0.23,0],[-0.08,0.01],[-0.07,0.01],[0,0],[0.12,-0.02],[0.11,0],[0.26,0.25],[0,0.45],[0,0]],"o":[[0,0],[0,0],[0,0.24],[0.1,0.11],[0.06,0],[0.09,-0.01],[0,0],[-0.09,0.03],[-0.11,0.02],[-0.47,0],[-0.26,-0.25],[0,0],[0,0]],"v":[[22.2,3.24],[23.08,3.24],[23.08,8.58],[23.22,9.12],[23.72,9.29],[23.93,9.27],[24.17,9.23],[24.35,9.97],[24.04,10.04],[23.7,10.07],[22.59,9.7],[22.2,8.65],[22.2,3.24]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.32,10],[25.32,4.54],[26.2,4.54],[26.2,10],[25.32,10]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.32,10],[25.32,4.54],[26.2,4.54],[26.2,10],[25.32,10]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.12,0.11],[0,0.16],[-0.12,0.11],[-0.17,0],[-0.12,-0.11],[0,-0.16],[0.12,-0.11],[0.17,0]],"o":[[-0.17,0],[-0.12,-0.11],[0,-0.16],[0.12,-0.11],[0.17,0],[0.12,0.11],[0,0.16],[-0.12,0.11],[0,0]],"v":[[25.77,3.65],[25.34,3.48],[25.16,3.07],[25.34,2.66],[25.77,2.49],[26.2,2.66],[26.38,3.07],[26.2,3.48],[25.77,3.65]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.12,0.11],[0,0.16],[-0.12,0.11],[-0.17,0],[-0.12,-0.11],[0,-0.16],[0.12,-0.11],[0.17,0]],"o":[[-0.17,0],[-0.12,-0.11],[0,-0.16],[0.12,-0.11],[0.17,0],[0.12,0.11],[0,0.16],[-0.12,0.11],[0,0]],"v":[[25.77,3.65],[25.34,3.48],[25.16,3.07],[25.34,2.66],[25.77,2.49],[26.2,2.66],[26.38,3.07],[26.2,3.48],[25.77,3.65]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[28.62,6.73],[28.62,10],[27.74,10],[27.74,4.54],[28.59,4.54],[28.59,5.86],[28.47,5.86],[29.18,4.79],[30.26,4.47],[31.23,4.7],[31.88,5.39],[32.11,6.53],[32.11,10],[31.23,10],[31.23,6.61],[30.9,5.62],[30,5.26],[29.3,5.43],[28.8,5.93],[28.62,6.73]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[28.62,6.73],[28.62,10],[27.74,10],[27.74,4.54],[28.59,4.54],[28.59,5.86],[28.47,5.86],[29.18,4.79],[30.26,4.47],[31.23,4.7],[31.88,5.39],[32.11,6.53],[32.11,10],[31.23,10],[31.23,6.61],[30.9,5.62],[30,5.26],[29.3,5.43],[28.8,5.93],[28.62,6.73]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.3,0.1],[0.2,0.17],[0.11,0.2],[0,0],[-0.11,-0.13],[-0.2,-0.09],[-0.32,0],[-0.28,0.21],[0,0.45],[0,0],[0,0],[0.11,-0.14],[0.21,-0.11],[0.35,0],[0.35,0.21],[0.2,0.4],[0,0.57],[-0.2,0.41],[-0.35,0.23],[-0.45,0],[-0.21,-0.12],[-0.11,-0.15],[-0.06,-0.1],[0,0],[0,0],[0,0],[0,0],[0.21,-0.3],[0.36,-0.14],[0.44,0]],"o":[[-0.4,0],[-0.29,-0.1],[-0.2,-0.17],[0,0],[0.08,0.1],[0.12,0.13],[0.2,0.09],[0.44,0],[0.28,-0.21],[0,0],[0,0],[-0.06,0.1],[-0.11,0.14],[-0.21,0.11],[-0.44,0],[-0.35,-0.21],[-0.2,-0.4],[0,-0.56],[0.2,-0.42],[0.35,-0.23],[0.35,0],[0.21,0.11],[0.11,0.15],[0,0],[0,0],[0,0],[0,0],[0,0.47],[-0.21,0.3],[-0.36,0.14],[0,0]],"v":[[35.86,12.16],[34.81,12],[34.08,11.6],[33.62,11.04],[34.33,10.59],[34.62,10.93],[35.09,11.25],[35.86,11.39],[36.94,11.08],[37.36,10.09],[37.36,9],[37.28,9],[37.02,9.37],[36.53,9.75],[35.69,9.91],[34.52,9.6],[33.69,8.7],[33.39,7.25],[33.69,5.78],[34.51,4.81],[35.71,4.47],[36.55,4.65],[37.04,5.04],[37.3,5.42],[37.39,5.42],[37.39,4.54],[38.24,4.54],[38.24,10.14],[37.92,11.29],[37.07,11.95],[35.86,12.16]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.3,0.1],[0.2,0.17],[0.11,0.2],[0,0],[-0.11,-0.13],[-0.2,-0.09],[-0.32,0],[-0.28,0.21],[0,0.45],[0,0],[0,0],[0.11,-0.14],[0.21,-0.11],[0.35,0],[0.35,0.21],[0.2,0.4],[0,0.57],[-0.2,0.41],[-0.35,0.23],[-0.45,0],[-0.21,-0.12],[-0.11,-0.15],[-0.06,-0.1],[0,0],[0,0],[0,0],[0,0],[0.21,-0.3],[0.36,-0.14],[0.44,0]],"o":[[-0.4,0],[-0.29,-0.1],[-0.2,-0.17],[0,0],[0.08,0.1],[0.12,0.13],[0.2,0.09],[0.44,0],[0.28,-0.21],[0,0],[0,0],[-0.06,0.1],[-0.11,0.14],[-0.21,0.11],[-0.44,0],[-0.35,-0.21],[-0.2,-0.4],[0,-0.56],[0.2,-0.42],[0.35,-0.23],[0.35,0],[0.21,0.11],[0.11,0.15],[0,0],[0,0],[0,0],[0,0],[0,0.47],[-0.21,0.3],[-0.36,0.14],[0,0]],"v":[[35.86,12.16],[34.81,12],[34.08,11.6],[33.62,11.04],[34.33,10.59],[34.62,10.93],[35.09,11.25],[35.86,11.39],[36.94,11.08],[37.36,10.09],[37.36,9],[37.28,9],[37.02,9.37],[36.53,9.75],[35.69,9.91],[34.52,9.6],[33.69,8.7],[33.39,7.25],[33.69,5.78],[34.51,4.81],[35.71,4.47],[36.55,4.65],[37.04,5.04],[37.3,5.42],[37.39,5.42],[37.39,4.54],[38.24,4.54],[38.24,10.14],[37.92,11.29],[37.07,11.95],[35.86,12.16]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.23,0.15],[-0.12,0.28],[0,0.4],[0.12,0.29],[0.23,0.17],[0.34,0],[0.23,-0.18],[0.12,-0.3],[0,-0.36],[-0.12,-0.29],[-0.23,-0.16],[-0.34,0]],"o":[[0.33,0],[0.23,-0.15],[0.12,-0.29],[0,-0.39],[-0.11,-0.3],[-0.23,-0.17],[-0.34,0],[-0.23,0.18],[-0.11,0.3],[0,0.37],[0.12,0.29],[0.23,0.16],[0,0]],"v":[[35.84,9.13],[36.68,8.91],[37.2,8.25],[37.37,7.23],[37.2,6.21],[36.68,5.51],[35.84,5.26],[34.98,5.53],[34.45,6.24],[34.28,7.23],[34.46,8.22],[34.98,8.89],[35.84,9.13]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[-0.23,0.15],[-0.12,0.28],[0,0.4],[0.12,0.29],[0.23,0.17],[0.34,0],[0.23,-0.18],[0.12,-0.3],[0,-0.36],[-0.12,-0.29],[-0.23,-0.16],[-0.34,0]],"o":[[0.33,0],[0.23,-0.15],[0.12,-0.29],[0,-0.39],[-0.11,-0.3],[-0.23,-0.17],[-0.34,0],[-0.23,0.18],[-0.11,0.3],[0,0.37],[0.12,0.29],[0.23,0.16],[0,0]],"v":[[35.84,9.13],[36.68,8.91],[37.2,8.25],[37.37,7.23],[37.2,6.21],[36.68,5.51],[35.84,5.26],[34.98,5.53],[34.45,6.24],[34.28,7.23],[34.46,8.22],[34.98,8.89],[35.84,9.13]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.35,0.23],[0.2,0.42],[0,0.58],[-0.2,0.42],[-0.35,0.23],[-0.45,0],[-0.21,-0.12],[-0.11,-0.15],[-0.06,-0.1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.12,-0.15],[0.21,-0.12],[0.35,0]],"o":[[-0.45,0],[-0.35,-0.23],[-0.2,-0.42],[0,-0.58],[0.2,-0.42],[0.35,-0.23],[0.35,0],[0.21,0.12],[0.11,0.15],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.06,0.1],[-0.11,0.15],[-0.21,0.12],[0,0]],"v":[[44.64,10.12],[43.44,9.77],[42.63,8.79],[42.33,7.29],[42.63,5.79],[43.45,4.81],[44.65,4.47],[45.49,4.65],[45.97,5.05],[46.23,5.42],[46.3,5.42],[46.3,2.72],[47.18,2.72],[47.18,10],[46.33,10],[46.33,9.16],[46.23,9.16],[45.97,9.54],[45.48,9.94],[44.64,10.12]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.35,0.23],[0.2,0.42],[0,0.58],[-0.2,0.42],[-0.35,0.23],[-0.45,0],[-0.21,-0.12],[-0.11,-0.15],[-0.06,-0.1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.12,-0.15],[0.21,-0.12],[0.35,0]],"o":[[-0.45,0],[-0.35,-0.23],[-0.2,-0.42],[0,-0.58],[0.2,-0.42],[0.35,-0.23],[0.35,0],[0.21,0.12],[0.11,0.15],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.06,0.1],[-0.11,0.15],[-0.21,0.12],[0,0]],"v":[[44.64,10.12],[43.44,9.77],[42.63,8.79],[42.33,7.29],[42.63,5.79],[43.45,4.81],[44.65,4.47],[45.49,4.65],[45.97,5.05],[46.23,5.42],[46.3,5.42],[46.3,2.72],[47.18,2.72],[47.18,10],[46.33,10],[46.33,9.16],[46.23,9.16],[45.97,9.54],[45.48,9.94],[44.64,10.12]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.23,0.17],[-0.12,0.31],[0,0.4],[0.12,0.3],[0.23,0.17],[0.34,0],[0.23,-0.18],[0.11,-0.31],[0,-0.38],[-0.11,-0.31],[-0.23,-0.19],[-0.34,0]],"o":[[0.33,0],[0.23,-0.18],[0.12,-0.31],[0,-0.4],[-0.11,-0.3],[-0.23,-0.17],[-0.35,0],[-0.23,0.18],[-0.11,0.3],[0,0.38],[0.12,0.31],[0.23,0.18],[0,0]],"v":[[44.78,9.33],[45.62,9.07],[46.13,8.34],[46.31,7.28],[46.13,6.22],[45.62,5.51],[44.78,5.26],[43.91,5.53],[43.4,6.25],[43.23,7.28],[43.4,8.32],[43.92,9.06],[44.78,9.33]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[-0.23,0.17],[-0.12,0.31],[0,0.4],[0.12,0.3],[0.23,0.17],[0.34,0],[0.23,-0.18],[0.11,-0.31],[0,-0.38],[-0.11,-0.31],[-0.23,-0.19],[-0.34,0]],"o":[[0.33,0],[0.23,-0.18],[0.12,-0.31],[0,-0.4],[-0.11,-0.3],[-0.23,-0.17],[-0.35,0],[-0.23,0.18],[-0.11,0.3],[0,0.38],[0.12,0.31],[0.23,0.18],[0,0]],"v":[[44.78,9.33],[45.62,9.07],[46.13,8.34],[46.31,7.28],[46.13,6.22],[45.62,5.51],[44.78,5.26],[43.91,5.53],[43.4,6.25],[43.23,7.28],[43.4,8.32],[43.92,9.06],[44.78,9.33]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.37,0.23],[0.21,0.42],[0,0.56],[-0.21,0.42],[-0.37,0.23],[-0.49,0],[-0.37,-0.23],[-0.21,-0.43],[0,-0.57],[0.21,-0.42],[0.37,-0.23],[0.5,0]],"o":[[-0.49,0],[-0.37,-0.23],[-0.21,-0.42],[0,-0.57],[0.21,-0.43],[0.37,-0.23],[0.5,0],[0.37,0.23],[0.21,0.42],[0,0.56],[-0.21,0.42],[-0.37,0.23],[0,0]],"v":[[50.94,10.12],[49.64,9.77],[48.77,8.78],[48.46,7.3],[48.77,5.82],[49.64,4.82],[50.94,4.47],[52.25,4.82],[53.13,5.82],[53.44,7.3],[53.13,8.78],[52.25,9.77],[50.94,10.12]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.37,0.23],[0.21,0.42],[0,0.56],[-0.21,0.42],[-0.37,0.23],[-0.49,0],[-0.37,-0.23],[-0.21,-0.43],[0,-0.57],[0.21,-0.42],[0.37,-0.23],[0.5,0]],"o":[[-0.49,0],[-0.37,-0.23],[-0.21,-0.42],[0,-0.57],[0.21,-0.43],[0.37,-0.23],[0.5,0],[0.37,0.23],[0.21,0.42],[0,0.56],[-0.21,0.42],[-0.37,0.23],[0,0]],"v":[[50.94,10.12],[49.64,9.77],[48.77,8.78],[48.46,7.3],[48.77,5.82],[49.64,4.82],[50.94,4.47],[52.25,4.82],[53.13,5.82],[53.44,7.3],[53.13,8.78],[52.25,9.77],[50.94,10.12]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.24,0.19],[-0.11,0.31],[0,0.36],[0.11,0.31],[0.24,0.19],[0.37,0],[0.23,-0.19],[0.11,-0.31],[0,-0.36],[-0.11,-0.31],[-0.23,-0.19],[-0.36,0]],"o":[[0.37,0],[0.24,-0.19],[0.11,-0.31],[0,-0.36],[-0.11,-0.31],[-0.24,-0.19],[-0.36,0],[-0.23,0.19],[-0.11,0.31],[0,0.36],[0.11,0.31],[0.23,0.19],[0,0]],"v":[[50.94,9.33],[51.85,9.05],[52.38,8.31],[52.55,7.3],[52.38,6.3],[51.85,5.55],[50.94,5.26],[50.04,5.55],[49.52,6.29],[49.35,7.3],[49.52,8.31],[50.04,9.05],[50.94,9.33]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[-0.24,0.19],[-0.11,0.31],[0,0.36],[0.11,0.31],[0.24,0.19],[0.37,0],[0.23,-0.19],[0.11,-0.31],[0,-0.36],[-0.11,-0.31],[-0.23,-0.19],[-0.36,0]],"o":[[0.37,0],[0.24,-0.19],[0.11,-0.31],[0,-0.36],[-0.11,-0.31],[-0.24,-0.19],[-0.36,0],[-0.23,0.19],[-0.11,0.31],[0,0.36],[0.11,0.31],[0.23,0.19],[0,0]],"v":[[50.94,9.33],[51.85,9.05],[52.38,8.31],[52.55,7.3],[52.38,6.3],[51.85,5.55],[50.94,5.26],[50.04,5.55],[49.52,6.29],[49.35,7.3],[49.52,8.31],[50.04,9.05],[50.94,9.33]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-0.1,-0.41],[-0.1,-0.52],[0,0],[-0.1,0.41],[-0.09,0.35],[0,0],[0,0],[0,0],[-0.1,-0.41],[-0.1,-0.51],[0,0],[-0.1,0.41],[-0.09,0.34],[0,0],[0,0],[0,0],[0,0],[0,0],[0.07,0.26],[0.07,0.27],[0.07,0.28],[0,0],[0.07,-0.28],[0.07,-0.26],[0.07,-0.24],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0.09,0.33],[0.1,0.41],[0,0],[0.1,-0.5],[0.1,-0.41],[0,0],[0,0],[0,0],[0.09,0.34],[0.1,0.41],[0,0],[0.1,-0.5],[0.1,-0.41],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.07,-0.25],[-0.07,-0.26],[-0.07,-0.27],[0,0],[-0.07,0.28],[-0.07,0.27],[-0.07,0.26],[0,0],[0,0],[0,0]],"v":[[55.76,10],[54.1,4.54],[55.03,4.54],[55.7,6.92],[55.99,8.03],[56.3,9.43],[56.15,9.43],[56.45,8.06],[56.74,6.92],[57.39,4.54],[58.33,4.54],[58.97,6.92],[59.26,8.05],[59.56,9.43],[59.4,9.43],[59.71,8.06],[60,6.92],[60.67,4.54],[61.6,4.54],[59.95,10],[59.07,10],[58.36,7.53],[58.15,6.76],[57.95,5.96],[57.75,5.13],[57.95,5.13],[57.75,5.96],[57.55,6.77],[57.34,7.53],[56.63,10],[55.76,10]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-0.1,-0.41],[-0.1,-0.52],[0,0],[-0.1,0.41],[-0.09,0.35],[0,0],[0,0],[0,0],[-0.1,-0.41],[-0.1,-0.51],[0,0],[-0.1,0.41],[-0.09,0.34],[0,0],[0,0],[0,0],[0,0],[0,0],[0.07,0.26],[0.07,0.27],[0.07,0.28],[0,0],[0.07,-0.28],[0.07,-0.26],[0.07,-0.24],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0.09,0.33],[0.1,0.41],[0,0],[0.1,-0.5],[0.1,-0.41],[0,0],[0,0],[0,0],[0.09,0.34],[0.1,0.41],[0,0],[0.1,-0.5],[0.1,-0.41],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.07,-0.25],[-0.07,-0.26],[-0.07,-0.27],[0,0],[-0.07,0.28],[-0.07,0.27],[-0.07,0.26],[0,0],[0,0],[0,0]],"v":[[55.76,10],[54.1,4.54],[55.03,4.54],[55.7,6.92],[55.99,8.03],[56.3,9.43],[56.15,9.43],[56.45,8.06],[56.74,6.92],[57.39,4.54],[58.33,4.54],[58.97,6.92],[59.26,8.05],[59.56,9.43],[59.4,9.43],[59.71,8.06],[60,6.92],[60.67,4.54],[61.6,4.54],[59.95,10],[59.07,10],[58.36,7.53],[58.15,6.76],[57.95,5.96],[57.75,5.13],[57.95,5.13],[57.75,5.96],[57.55,6.77],[57.34,7.53],[56.63,10],[55.76,10]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[63.59,6.73],[63.59,10],[62.71,10],[62.71,4.54],[63.56,4.54],[63.56,5.86],[63.44,5.86],[64.15,4.79],[65.23,4.47],[66.2,4.7],[66.85,5.39],[67.08,6.53],[67.08,10],[66.2,10],[66.2,6.61],[65.87,5.62],[64.97,5.26],[64.27,5.43],[63.77,5.93],[63.59,6.73]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.31,0.21],[-0.41,0],[-0.28,-0.15],[-0.15,-0.31],[0,-0.46],[0,0],[0,0],[0,0],[0.22,0.24],[0.38,0],[0.21,-0.11],[0.12,-0.22],[0,-0.31]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.17,-0.5],[0.31,-0.21],[0.37,0],[0.28,0.15],[0.16,0.3],[0,0],[0,0],[0,0],[0,-0.42],[-0.22,-0.24],[-0.26,0],[-0.21,0.11],[-0.12,0.22],[0,0]],"v":[[63.59,6.73],[63.59,10],[62.71,10],[62.71,4.54],[63.56,4.54],[63.56,5.86],[63.44,5.86],[64.15,4.79],[65.23,4.47],[66.2,4.7],[66.85,5.39],[67.08,6.53],[67.08,10],[66.2,10],[66.2,6.61],[65.87,5.62],[64.97,5.26],[64.27,5.43],[63.77,5.93],[63.59,6.73]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[69.29,10.06],[68.82,9.87],[68.63,9.4],[68.82,8.94],[69.29,8.75],[69.76,8.94],[69.95,9.4],[69.76,9.87],[69.29,10.06]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[69.29,10.06],[68.82,9.87],[68.63,9.4],[68.82,8.94],[69.29,8.75],[69.76,8.94],[69.95,9.4],[69.76,9.87],[69.29,10.06]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[72.17,10.06],[71.7,9.87],[71.51,9.4],[71.7,8.94],[72.17,8.75],[72.64,8.94],[72.83,9.4],[72.64,9.87],[72.17,10.06]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[72.17,10.06],[71.7,9.87],[71.51,9.4],[71.7,8.94],[72.17,8.75],[72.64,8.94],[72.83,9.4],[72.64,9.87],[72.17,10.06]]}],"t":396}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[],"o":[],"v":[]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[75.05,10.06],[74.58,9.87],[74.39,9.4],[74.58,8.94],[75.05,8.75],[75.52,8.94],[75.71,9.4],[75.52,9.87],[75.05,10.06]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0]],"o":[[-0.18,0],[-0.13,-0.13],[0,-0.18],[0.13,-0.13],[0.18,0],[0.13,0.13],[0,0.18],[-0.13,0.13],[0,0]],"v":[[75.05,10.06],[74.58,9.87],[74.39,9.4],[74.58,8.94],[75.05,8.75],[75.52,8.94],[75.71,9.4],[75.52,9.87],[75.05,10.06]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":276},{"s":[1,1,1],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":10},{"ty":4,"nm":"Frame 427322354 Bg","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,115],"t":408},{"s":[55,115],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,115],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[55,115],"t":408},{"s":[55,115],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":456}]}}],"ind":11}]},{"nm":"[Asset] Frame 427322356","id":"2","layers":[{"ty":4,"nm":"Ellipse 21629","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13,13],"t":408},{"s":[13,13],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,51],"t":408},{"s":[51,51],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.2824,0.2824,0.2824],"t":408},{"s":[0.2824,0.2824,0.2824],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":1},{"ty":4,"nm":"Ellipse 21628","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13,13],"t":408},{"s":[13,13],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,51],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,51],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,51],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,51],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19,51],"t":408},{"s":[19,51],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.3765,0.3765,0.3765],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.3765,0.3765,0.3765],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.2824,0.2824,0.2824],"t":408},{"s":[0.2824,0.2824,0.2824],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":2},{"ty":4,"nm":"Ellipse 21627","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13,13],"t":408},{"s":[13,13],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,19],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,19],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,19],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,19],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,19],"t":408},{"s":[51,19],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.2824,0.2824,0.2824],"t":408},{"s":[0.2824,0.2824,0.2824],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":3},{"ty":4,"nm":"Ellipse 21626","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13,13],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13,13],"t":408},{"s":[13,13],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,19],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,19],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,19],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19,19],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19,19],"t":408},{"s":[19,19],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8432,0.0981,0.1295],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8432,0.0981,0.1295],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8432,0.0981,0.1295],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.8432,0.0981,0.1295],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.8432,0.0981,0.1295],"t":408},{"s":[0.8432,0.0981,0.1295],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":4},{"ty":4,"nm":"Rectangle 156","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[35,39],"t":408},{"s":[35,39],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[35,39],"t":408},{"s":[35,39],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":408},{"s":[{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}],"t":456}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1942,0.1942,0.1942],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.1942,0.1942,0.1942],"t":408},{"s":[0.1942,0.1942,0.1942],"t":456}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}}],"ind":5},{"ty":4,"nm":"Frame 427322356 Bg","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[35,39],"t":408},{"s":[35,39],"t":456}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":408},{"s":[100,100],"t":456}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[35,39],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[35,39],"t":408},{"s":[35,39],"t":456}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":408},{"s":[0],"t":456}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396.06},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":72},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}],"t":456}]}}],"ind":6}]},{"nm":"[Asset] Group 1","id":"3","layers":[{"ty":4,"nm":"Ellipse 581","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":276},{"s":[63,3],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":1},{"ty":4,"nm":"Ellipse 582","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":276},{"s":[33,3],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":2},{"ty":4,"nm":"Ellipse 588","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":276},{"s":[3,33],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":3},{"ty":4,"nm":"Ellipse 587","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":276},{"s":[33,33],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":4},{"ty":4,"nm":"Ellipse 586","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":276},{"s":[63,33],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":5},{"ty":4,"nm":"Ellipse 585","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":276},{"s":[63,63],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":6},{"ty":4,"nm":"Ellipse 584","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":276},{"s":[33,63],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":7},{"ty":4,"nm":"Ellipse 583","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":276},{"s":[3,63],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":8},{"ty":4,"nm":"Ellipse 572","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":276},{"s":[100,100],"t":396}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"s":[0],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"s":[100],"t":396}]}}],"ind":9}]}]} \ No newline at end of file diff --git a/res/raw/nt_power_off_verify.json b/res/raw/nt_power_off_verify.json new file mode 100644 index 00000000..1049a581 --- /dev/null +++ b/res/raw/nt_power_off_verify.json @@ -0,0 +1 @@ +{"nm":"Flow 4","ddd":0,"h":278,"w":366,"meta":{"g":"LottieFiles Figma v70"},"layers":[{"ty":4,"nm":"bar","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[17,1.5]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[183,245.5]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-0.83],[0,0],[0.83,0],[0,0],[0,0.83],[0,0],[-0.83,0],[0,0]],"o":[[0,0],[0,0.83],[0,0],[-0.83,0],[0,0],[0,-0.83],[0,0],[0.83,0]],"v":[[34,1.5],[34,1.5],[32.5,3],[1.5,3],[0,1.5],[0,1.5],[1.5,0],[32.5,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.5687,0.5647,0.5804]},"r":1,"o":{"a":0,"k":100}}],"ind":1},{"ty":0,"nm":"Frame 427322354","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[55,115]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[183,139]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"masksProperties":[{"nm":"","inv":false,"mode":"a","x":{"a":0,"k":0},"o":{"a":0,"k":100},"pt":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":408},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}],"t":456}]}}],"w":366,"h":278,"refId":"1","ind":2}],"v":"5.7.0","fr":60,"op":408.06,"ip":0,"assets":[{"nm":"[Asset] Frame 427322354","id":"1","layers":[{"ty":0,"nm":"Frame 427322356","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[35,39]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[55,111]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"w":366,"h":278,"refId":"2","ind":1},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[55,115]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[55,115]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,5.73],[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0]],"o":[[0,0],[5.81,0],[0,0],[0,-5.73],[0,0],[-5.81,0],[0,0],[0,5.73],[0,0]],"v":[[14.98,225.5],[95.02,225.5],[105.5,215.1],[105.5,14.9],[95.02,4.5],[14.98,4.5],[4.5,14.9],[4.5,215.1],[14.98,225.5]]}}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,8.23],[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0]],"o":[[0,0],[8.27,0],[0,0],[0,-8.23],[0,0],[-8.27,0],[0,0],[0,8.23],[0,0]],"v":[[14.98,230],[95.02,230],[110,215.1],[110,14.9],[95.02,0],[14.98,0],[0,14.9],[0,215.1],[14.98,230]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.7844,0.7844,0.7844]},"r":2,"o":{"a":0,"k":100}}],"ind":2},{"ty":4,"nm":"Subtract","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2.5,1.25],"t":276},{"s":[2.5,1.25],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,53.25],"t":276},{"s":[55,53.25],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[1.38,0],[0,-1.38],[0,0],[-0.83,0],[0,-0.83]],"o":[[0,0],[0,-1.38],[-1.38,0],[0,0],[0,-0.83],[0.83,0],[0,0]],"v":[[4,2.5],[5,2.5],[2.5,0],[0,2.5],[1,2.5],[2.5,1],[4,2.5]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":2,"o":{"a":0,"k":100}}],"ind":3},{"ty":4,"nm":"Line 2 (Stroke)","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":276},{"s":[0.5,0.5],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,55],"t":276},{"s":[57,55],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[-90],"t":276},{"s":[-90],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,1],[0,1],[0,0],[1,0],[1,1]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":2,"o":{"a":0,"k":100}}],"ind":4},{"ty":4,"nm":"Line 1 (Stroke)","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5,0.5],"t":276},{"s":[0.5,0.5],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[53,55],"t":276},{"s":[53,55],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1,0],[1,1],[0,1],[0,0],[1,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":2,"o":{"a":0,"k":100}}],"ind":5},{"ty":4,"nm":"Rectangle 4979","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[4,3.5],"t":276},{"s":[4,3.5],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55.5,59.5],"t":276},{"s":[55.5,59.5],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-0.4714285714285715],[0,0],[0.48125000000000007,0],[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0]],"o":[[0,0],[0,0.4714285714285715],[0,0],[-0.48125000000000007,0],[0,0],[0,-0.4714285714285715],[0,0],[0.48125000000000007,0]],"v":[[7,0.8571428571428572],[7,5.142857142857143],[6.125,6],[0.875,6],[0,5.142857142857143],[0,0.8571428571428572],[0.875,0],[6.125,0]]}}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":0,"k":100},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1],"t":276},{"s":[1],"t":396}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]}}],"ind":6},{"ty":4,"nm":"Rectangle 160","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,32],"t":276},{"s":[2,32],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,106.5],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,106.5],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[25,138],"t":276},{"s":[25,138],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,64],[0,64],[0,0]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":276},{"s":[0,0,0],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":7},{"ty":0,"nm":"Group 1","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":396},{"s":[33,33],"t":456.06}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[55,138],"t":396},{"s":[55,138],"t":456.06}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"w":366,"h":278,"refId":"3","ind":8},{"ty":4,"nm":"Rectangle 161","sr":1,"st":0,"op":409.06,"ip":174,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,0.5],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[2,30],"t":276},{"s":[2,30],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[27.5,168],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[57,168],"t":276},{"s":[57,168],"t":396}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[90],"t":276},{"s":[90],"t":396}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[20],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,1],[0,1],[0,0]]}],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":276},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4,0],[4,60],[0,60],[0,0]]}],"t":396}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,0,0],"t":276},{"s":[0,0,0],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":9},{"ty":4,"nm":"Frame 427322354 Bg","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[55,115]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[55,115]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[110,0],[110,230],[0,230],[0,0]]}}}],"ind":10}]},{"nm":"[Asset] Frame 427322356","id":"2","layers":[{"ty":4,"nm":"Ellipse 21629","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[13,13]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[51,51]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.2824,0.2824,0.2824]},"r":1,"o":{"a":0,"k":100}}],"ind":1},{"ty":4,"nm":"Ellipse 21628","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[13,13]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[19,51]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.3765,0.3765,0.3765],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.3765,0.3765,0.3765],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.2824,0.2824,0.2824],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.2824,0.2824,0.2824],"t":408},{"s":[0.2824,0.2824,0.2824],"t":456}]},"r":1,"o":{"a":0,"k":100}}],"ind":2},{"ty":4,"nm":"Ellipse 21627","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[13,13]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[51,19]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.2824,0.2824,0.2824]},"r":1,"o":{"a":0,"k":100}}],"ind":3},{"ty":4,"nm":"Ellipse 21626","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[13,13]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[19,19]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[7.18,0],[0,7.18],[-7.18,0],[0,-7.18]],"o":[[0,7.18],[-7.18,0],[0,-7.18],[7.18,0],[0,0]],"v":[[26,13],[13,26],[0,13],[13,0],[26,13]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.8432,0.0981,0.1295]},"r":1,"o":{"a":0,"k":100}}],"ind":4},{"ty":4,"nm":"Rectangle 156","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[35,39]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[35,39]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-2.94],[0,0],[2.94,0],[0,0],[0,2.94],[0,0],[-2.94,0],[0,0]],"o":[[0,0],[0,2.94],[0,0],[-2.94,0],[0,0],[0,-2.94],[0,0],[2.94,0]],"v":[[70,5.32],[70,72.68],[64.68,78],[5.32,78],[0,72.68],[0,5.32],[5.32,0],[64.68,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.1942,0.1942,0.1942]},"r":1,"o":{"a":0,"k":100}}],"ind":5},{"ty":4,"nm":"Frame 427322356 Bg","sr":1,"st":0,"op":409.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[35,39]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[35,39]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":54},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":72},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":174.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":240.06},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":396},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":408},{"s":[100],"t":456}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[70,0],[70,78],[0,78],[0,0]]}}}],"ind":6}]},{"nm":"[Asset] Group 1","id":"3","layers":[{"ty":4,"nm":"Ellipse 581","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,3],"t":276},{"s":[63,3],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":1},{"ty":4,"nm":"Ellipse 582","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,3],"t":276},{"s":[33,3],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":2},{"ty":4,"nm":"Ellipse 588","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,33],"t":276},{"s":[3,33],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":3},{"ty":4,"nm":"Ellipse 587","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,33],"t":276},{"s":[33,33],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":4},{"ty":4,"nm":"Ellipse 586","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,33],"t":276},{"s":[63,33],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":5},{"ty":4,"nm":"Ellipse 585","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[63,63],"t":276},{"s":[63,63],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":6},{"ty":4,"nm":"Ellipse 584","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,63],"t":276},{"s":[33,63],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":7},{"ty":4,"nm":"Ellipse 583","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,63],"t":276},{"s":[3,63],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":8},{"ty":4,"nm":"Ellipse 572","sr":1,"st":0,"op":409.06,"ip":108,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[3,3],"t":276},{"s":[3,3],"t":396}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":276},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":396},{"s":[0],"t":456.06}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[1.66,0],[0,1.66],[-1.66,0],[0,-1.66]],"o":[[0,1.66],[-1.66,0],[0,-1.66],[1.66,0],[0,0]],"v":[[6,3],[3,6],[0,3],[3,0],[6,3]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":108},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":156},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":174},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":192},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":240},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.5726,0.5726,0.5726],"t":276},{"s":[0.5726,0.5726,0.5726],"t":396}]},"r":1,"o":{"a":0,"k":100}}],"ind":9}]}]} \ No newline at end of file diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 38f1ab8c..97a33381 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,11 @@ limitations under the License. --> + + Power off verification protects your device by preventing others from turning it off immediately after it\'s lost, increasing the chances of recovery. You only need to enter your lock screen password when powering off or restarting the phone from the lock screen. + When your device is locked, you\'ll need to use your password to power off or restart. + Power off verify + Lock screen charging time Display the remaining time for charging to finish diff --git a/res/xml/power_off_verify.xml b/res/xml/power_off_verify.xml new file mode 100644 index 00000000..c547ef52 --- /dev/null +++ b/res/xml/power_off_verify.xml @@ -0,0 +1,15 @@ + + + + + + From 7fedfb36e5ab4dc0566a266716b9ba6139c187f4 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Sun, 31 Aug 2025 03:52:06 +0900 Subject: [PATCH 15/24] Update tensor codes for P10 [1/2] --- src/com/rising/settings/fragments/Spoof.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/rising/settings/fragments/Spoof.kt b/src/com/rising/settings/fragments/Spoof.kt index 8e5ee976..304415aa 100644 --- a/src/com/rising/settings/fragments/Spoof.kt +++ b/src/com/rising/settings/fragments/Spoof.kt @@ -117,7 +117,7 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene mTensorFeaturesToggle = findPreference(SYS_ENABLE_TENSOR_FEATURES) val model = SystemProperties.get("ro.product.model") - val isTensorDevice = model.matches(Regex("Pixel [6-9][a-zA-Z ]*")) + val isTensorDevice = model.matches(Regex("Pixel (6|7|8|9|10)[a-zA-Z ]*")) val isPixelGmsEnabled = SystemProperties.getBoolean(SYS_GMS_SPOOF, true) // Default to Pixel GMS if (DeviceUtils.isCurrentlySupportedPixel()) { @@ -178,7 +178,7 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene } private fun isMainlineTensorModel(model: String): Boolean { - return model.matches(Regex("Pixel [8-9][a-zA-Z ]*")) + return model.matches(Regex("Pixel (8|9|10)[a-zA-Z ]*")) } private fun openFileSelector(requestCode: Int) { From 9b942bd1aa2d35e1fbf7d0d704f9af9009b3fed8 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Sun, 24 Aug 2025 10:44:08 +0530 Subject: [PATCH 16/24] Add new QS brightness slider shapes Signed-off-by: Pranav Vashi --- res/values/custom_arrays.xml | 15 +++++++++++++++ res/values/custom_strings.xml | 6 ++++++ res/xml/rising_settings_qs.xml | 11 ++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index 65bc71ea..f6945036 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -15,6 +15,21 @@ limitations under the License. --> + + + @string/default_value + @string/quick_settings_tile_shape_circle + @string/quick_settings_tile_shape_rounded_square + @string/quick_settings_tile_shape_square + + + + 0 + 1 + 2 + 3 + + Default diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 97a33381..39cf8a47 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -15,6 +15,12 @@ limitations under the License. --> + + New QS Brightness slider shape + Circle + Rounded square + Square + Power off verification protects your device by preventing others from turning it off immediately after it\'s lost, increasing the chances of recovery. You only need to enter your lock screen password when powering off or restarting the phone from the lock screen. When your device is locked, you\'ll need to use your password to power off or restart. diff --git a/res/xml/rising_settings_qs.xml b/res/xml/rising_settings_qs.xml index 3e80df22..d645f73b 100644 --- a/res/xml/rising_settings_qs.xml +++ b/res/xml/rising_settings_qs.xml @@ -32,7 +32,16 @@ android:title="@string/qs_refactor_title" android:summary="@string/qs_refactor_summary" android:defaultValue="true" - lineage:position="solo" /> + lineage:position="top" /> + + From 244849637e55023eee25b680f1fdf766d947430e Mon Sep 17 00:00:00 2001 From: Joey Huab Date: Mon, 22 Sep 2025 22:42:03 +0900 Subject: [PATCH 17/24] Drop Play store spoof [2/2] --- res/xml/rising_settings_spoof.xml | 4 ++-- src/com/rising/settings/fragments/Spoof.kt | 20 ++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/res/xml/rising_settings_spoof.xml b/res/xml/rising_settings_spoof.xml index 571d90bb..812e5cbb 100644 --- a/res/xml/rising_settings_spoof.xml +++ b/res/xml/rising_settings_spoof.xml @@ -88,11 +88,11 @@ android:defaultValue="false" /> - + android:defaultValue="false" />--> { + mQsbSpoof, mSnapSpoof -> { SystemRestartUtils.showSystemRestartDialog(requireContext()) return true } - mTensorFeaturesToggle -> { + mTensorSpoof -> { val enabled = newValue as Boolean - SystemProperties.set(SYS_ENABLE_TENSOR_FEATURES, if (enabled) "true" else "false") + SystemProperties.set(SYS_TENSOR_SPOOF, if (enabled) "true" else "false") SystemRestartUtils.showSystemRestartDialog(requireContext()) return true } From 5fd1a6541c5fca7b15543da0027324e85f69d8ef Mon Sep 17 00:00:00 2001 From: huoyan1231 <53113734+huoyan1231@users.noreply.github.com> Date: Wed, 24 Sep 2025 20:50:17 +0800 Subject: [PATCH 18/24] add some zh-cn translate --- res/values-zh-rCN/custom_strings.xml | 99 ++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/res/values-zh-rCN/custom_strings.xml b/res/values-zh-rCN/custom_strings.xml index 9a3d7869..2621ac76 100644 --- a/res/values-zh-rCN/custom_strings.xml +++ b/res/values-zh-rCN/custom_strings.xml @@ -15,6 +15,105 @@ limitations under the License. --> + + + 新的快速设置亮度滑条样式 + 圆形 + 圆角方形 + 方形 + + + 关机验证会保护你的设备不会在遗失后立刻被他人关机, 增加你找回它的可能性。你只会在锁屏时尝试关机会被要求输入你的锁屏密码 + 当你的设备锁定时,你需要验证你的密码来关机/重启 + 关机验证 + + + 锁屏充电时间 + 显示距离充满剩余的时间 + + + 通知透明 + 在通知后方使用透明背景 + + + 三指下滑 + 使用三根手指下滑执行一些操作 + 三指长按 + 使用三根手指点按并下滑进行区域截图 + 禁用电源+音量下键 + 禁用使用电源+音量键进行截图的功能 + + + 声音 + 锁屏音效 + 解锁音效 + + + 息屏壁纸 + 当息屏显示启用时显示壁纸 + + + 弹出显示 + 在一个浮动的小窗口中打开程序 + 手势 + 全局手势 + Open any apps with Pop-Up View by swiping from bottom corner of the screen to middle + 管理固定的应用 + 自定义在菜单中显示的应用 + 显示更多应用 + Add more quarter circles in gesture menu + Digital assistant gesture will be disabled with Global Gesture enabled. + 迷你窗口 + 自动静音 + 当应用切换至迷你小窗时自动静音 + 应用在切换回浮动模式时自动取消静音 + 非窗口区域 + 单机操作 + 双击操作 + 切换至迷你小窗 + 关闭浮动窗口 + 无动作 + LightWeight open + 打开通知(竖屏) + 在竖屏下使用浮动窗口打开通知 + 打开通知(横屏) + 在横屏下使用浮动窗口打开通知 + 黑名单应用 + 在打开这些程序的通知时不使用浮动窗口 + + + 防止意外唤醒 + 使用距离传感器防止意外唤醒 + + + 使用新的快速设置 + 一些功能可能无法在新的快速设置下工作 + 快速设置重构 + + + 系统 + Pixel props + 对来自Google应用伪装为最新的Pixel设备 + 存储加密 + 声明设备的存储加密状态为加密 + 特定应用 + Google app + 将设备伪装为最新的Pixel以启用Pixel独占功能 + Play商店 + 将设备伪装为最新的Pixel设备 + Google相册 + 将设备伪装为Pixel XL + Snapchat + 将设备伪装为Pixel XL来修复可能存在的问题 + Keybox attestation override + Load a custom keybox XML to override device key attestation + Custom keybox XML loaded. Delete to clear. + Clear keybox data + Not an XML file. Choose a valid keybox XML. + Invalid keybox XML: required fields missing + Keybox loaded + Keybox cleared + 状态栏图标自定义颜色 启用状态栏图标自定义颜色功能 From be2ff21a58a2ff9b604cb887c721e04359f71f73 Mon Sep 17 00:00:00 2001 From: Arman Altafi <84268732+Arman-ATI@users.noreply.github.com> Date: Thu, 25 Sep 2025 00:30:08 +0330 Subject: [PATCH 19/24] Add fluid power menu style --- res/values/custom_arrays.xml | 2 ++ res/values/custom_strings.xml | 5 +++-- src/com/rising/settings/fragments/Themes.kt | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml index f6945036..76708f5e 100644 --- a/res/values/custom_arrays.xml +++ b/res/values/custom_arrays.xml @@ -287,6 +287,7 @@ @string/powermenu_style2 @string/powermenu_style3 @string/powermenu_style4 + @string/powermenu_style5 @@ -295,6 +296,7 @@ 2 3 4 + 5 diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 39cf8a47..38816a25 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -321,8 +321,9 @@ Power Menu Style Cyberpunk Duoline - IOS - Layers + Fluid (Transparent) + IOS + Layers QS Header clock style diff --git a/src/com/rising/settings/fragments/Themes.kt b/src/com/rising/settings/fragments/Themes.kt index 31e6ae09..42d632dd 100644 --- a/src/com/rising/settings/fragments/Themes.kt +++ b/src/com/rising/settings/fragments/Themes.kt @@ -52,6 +52,7 @@ class Themes : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListen private val NOTIF_OVERLAYS = arrayOf( "com.android.theme.notification.cyberpunk", "com.android.theme.notification.duoline", + "com.android.theme.powermenu.fluid", "com.android.theme.notification.ios", "com.android.theme.notification.layers" ) From d8eedc5ce2f1194a617dfd173cdc93a7b6e6988d Mon Sep 17 00:00:00 2001 From: Ghosuto Date: Sat, 27 Sep 2025 16:41:02 +0000 Subject: [PATCH 20/24] Spoof: Replace system restart with targeted package killing for PIF updates Change-Id: I7a0d78398d6d84e758cbfad5a499cf077f17f221 Signed-off-by: Ghosuto --- src/com/rising/settings/fragments/Spoof.kt | 38 ++++++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/com/rising/settings/fragments/Spoof.kt b/src/com/rising/settings/fragments/Spoof.kt index 7edcc9d5..cd7afd3b 100644 --- a/src/com/rising/settings/fragments/Spoof.kt +++ b/src/com/rising/settings/fragments/Spoof.kt @@ -16,6 +16,7 @@ package com.rising.settings.fragments import android.app.Activity +import android.app.ActivityManager import android.app.AlertDialog import android.content.ContentResolver import android.content.Context @@ -240,6 +241,27 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene .show() } + /** + * Kill packages that need to be restarted to pick up new PIF properties + */ + private fun killGMSPackages() { + try { + val am = requireContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val packages = arrayOf( + "com.google.android.gms", + "com.android.vending" + ) + for (pkg in packages) { + am.javaClass + .getMethod("forceStopPackage", String::class.java) + .invoke(am, pkg) + Log.i(TAG, "$pkg process killed") + } + } catch (e: Exception) { + Log.e(TAG, "Failed to kill packages", e) + } + } + private fun updatePropertiesFromUrl(urlString: String) { Thread { try { @@ -263,6 +285,7 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene mHandler.post { val toastMessage = getString(R.string.toast_spoofing_success, spoofedModel) Toast.makeText(requireContext(), toastMessage, Toast.LENGTH_LONG).show() + killGMSPackages() } } } finally { @@ -274,9 +297,6 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene Toast.makeText(requireContext(), R.string.toast_spoofing_failure, Toast.LENGTH_LONG).show() } } - mHandler.postDelayed({ - SystemRestartUtils.showSystemRestartDialog(requireContext()) - }, 1250) }.start() } @@ -295,13 +315,13 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene Log.d(TAG, "Setting PIF property: persist.sys.pihooks_$key = $value") SystemProperties.set("persist.sys.pihooks_$key", value) } + killGMSPackages() + Toast.makeText(requireContext(), "PIF JSON loaded and packages refreshed", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Log.e(TAG, "Error reading PIF JSON or setting properties", e) + Toast.makeText(requireContext(), "Error loading PIF JSON", Toast.LENGTH_SHORT).show() } - mHandler.postDelayed({ - SystemRestartUtils.showSystemRestartDialog(requireContext()) - }, 1250) } override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { @@ -309,7 +329,11 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene val resolver = context.contentResolver when (preference) { - mGmsSpoof, mGoogleSpoof, mGphotosSpoof, mGamePropsSpoof, + mGmsSpoof -> { + killGMSPackages() + return true + } + mGoogleSpoof, mGphotosSpoof, mGamePropsSpoof, mQsbSpoof, mSnapSpoof -> { SystemRestartUtils.showSystemRestartDialog(requireContext()) return true From d4a597ac2198c7cfdb4aab528a95473d009c9cfe Mon Sep 17 00:00:00 2001 From: Ghosuto Date: Sat, 27 Sep 2025 16:45:23 +0000 Subject: [PATCH 21/24] spoof: Add toggle for spoof private key keybox validation Change-Id: Ieaaa5d0e8a27b9a64b235ba91d90516933c8967e --- res/values/custom_strings.xml | 2 ++ res/xml/rising_settings_spoof.xml | 6 ++++++ src/com/rising/settings/fragments/Spoof.kt | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml index 38816a25..0d3ecff9 100644 --- a/res/values/custom_strings.xml +++ b/res/values/custom_strings.xml @@ -137,6 +137,8 @@ Invalid keybox XML: required fields missing Keybox loaded Keybox cleared + Private Keybox spoof + Spoof the private key only if you have a valid Keybox for proper Strong Integrity. Screen Off AOD diff --git a/res/xml/rising_settings_spoof.xml b/res/xml/rising_settings_spoof.xml index 812e5cbb..af5fe4ce 100644 --- a/res/xml/rising_settings_spoof.xml +++ b/res/xml/rising_settings_spoof.xml @@ -29,6 +29,12 @@ android:key="keybox_data_setting" android:title="@string/keybox_data_title" /> + + { + killGMSPackages() + return true + } } return false } From a1bdaa3bf08e2a632b602463edc178e10ef0533e Mon Sep 17 00:00:00 2001 From: Joey Huab Date: Sat, 27 Sep 2025 16:48:28 +0000 Subject: [PATCH 22/24] spoof: Extend targeted package killing to QSB, Photos and Snapchat --- src/com/rising/settings/fragments/Spoof.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/com/rising/settings/fragments/Spoof.kt b/src/com/rising/settings/fragments/Spoof.kt index 1c8a9a1f..0c7816c0 100644 --- a/src/com/rising/settings/fragments/Spoof.kt +++ b/src/com/rising/settings/fragments/Spoof.kt @@ -252,8 +252,11 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene try { val am = requireContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val packages = arrayOf( + "com.google.android.apps.photos", "com.google.android.gms", - "com.android.vending" + "com.google.android.googlequicksearchbox", + "com.android.vending", + "com.snapchat.android" ) for (pkg in packages) { am.javaClass @@ -333,12 +336,11 @@ class Spoof : SettingsPreferenceFragment(), Preference.OnPreferenceChangeListene val resolver = context.contentResolver when (preference) { - mGmsSpoof -> { + mGmsSpoof, mGphotosSpoof, mQsbSpoof, mSnapSpoof -> { killGMSPackages() return true } - mGoogleSpoof, mGphotosSpoof, mGamePropsSpoof, - mQsbSpoof, mSnapSpoof -> { + mGoogleSpoof, mGamePropsSpoof -> { SystemRestartUtils.showSystemRestartDialog(requireContext()) return true } From 6898bdfc559617aa9bf6f568120fe14091f1a49c Mon Sep 17 00:00:00 2001 From: huoyan1231 <53113734+huoyan1231@users.noreply.github.com> Date: Sat, 27 Sep 2025 14:09:53 +0800 Subject: [PATCH 23/24] update zh-CN translate --- res/values-zh-rCN/custom_strings.xml | 140 ++++++++++++++++++++------- 1 file changed, 103 insertions(+), 37 deletions(-) diff --git a/res/values-zh-rCN/custom_strings.xml b/res/values-zh-rCN/custom_strings.xml index 2621ac76..a13be264 100644 --- a/res/values-zh-rCN/custom_strings.xml +++ b/res/values-zh-rCN/custom_strings.xml @@ -57,29 +57,29 @@ 在一个浮动的小窗口中打开程序 手势 全局手势 - Open any apps with Pop-Up View by swiping from bottom corner of the screen to middle + 通过从屏幕下方角落向中心滑动来使用浮动窗口启动任意应用 管理固定的应用 自定义在菜单中显示的应用 显示更多应用 Add more quarter circles in gesture menu - Digital assistant gesture will be disabled with Global Gesture enabled. + 当全局手势启用时,数字助理手势将被禁用 迷你窗口 自动静音 当应用切换至迷你小窗时自动静音 应用在切换回浮动模式时自动取消静音 非窗口区域 - 单机操作 + 单击操作 双击操作 切换至迷你小窗 关闭浮动窗口 无动作 - LightWeight open + 从通知启动 打开通知(竖屏) 在竖屏下使用浮动窗口打开通知 打开通知(横屏) 在横屏下使用浮动窗口打开通知 黑名单应用 - 在打开这些程序的通知时不使用浮动窗口 + 在打开来自这些程序的通知时不使用浮动窗口 防止意外唤醒 @@ -105,14 +105,55 @@ 将设备伪装为Pixel XL Snapchat 将设备伪装为Pixel XL来修复可能存在的问题 - Keybox attestation override - Load a custom keybox XML to override device key attestation - Custom keybox XML loaded. Delete to clear. - Clear keybox data - Not an XML file. Choose a valid keybox XML. - Invalid keybox XML: required fields missing - Keybox loaded - Keybox cleared + Keybox覆盖 + 加载一个自定义的Keybox.xml文件 + 自定义Keybox已加载,删除以清除 + 清除Keybox + 不是一个xml文件,请选择一个有效的Keybox.xml + 无效的Keybox.xml: 缺少必要的条目 + keybx已加载 + Keybox已清楚 + + + 禁用投屏确认 + + + USB设置 + 选择通过USB连接设备时的默认行为 + + + 禁用指纹锁定 + 在30秒后或多次解锁失败时仍然保持指纹解锁可用 + + + 为VPN禁用 + 当连接至VPN时自动禁用私人DNS\n将会在断开VPN后自动恢复 + + + 逐渐增加铃声音量 + 开始音量 + 增加至最大音量的时间 + + + 每次连接都使用随机的MAC (默认值) + 为每个网络使用不同的MAC + 使用设备MAC + + + 降低屏幕刷新率 + 当省电模式启用时将屏幕刷新率降低至60hz + + + 无限制录屏 + 移除单个屏幕录制的15GiB文件大小限制\n可能导致非常大的录制文件输出 + + + 根据时间表自动启用极暗 + 禁用 + + + 长按搜索 + 按住home键或小白条以使用你的屏幕内容进行搜索 状态栏图标自定义颜色 @@ -120,7 +161,7 @@ 状态栏图标颜色设置 自定义状态栏图标的显示颜色 - + 状态栏歌词 在状态栏显示歌词 (需应用支持) 歌词选项 @@ -146,8 +187,33 @@ 在新的虚线背景和简单的箭头样式之间切换 + 状态栏进度条 + 状态栏进度条设置 正在运行部件 在状态栏中显示正在进行的活动 (如下载) 的进度指示器 + 进度条透明度 + 调整进度条部件的透明度 + 小型进度指示器 + 在进度条中使用小型的环形指示器 + 显示媒体进度 + "在状态栏中显示媒体播放进度 + + "状态栏进度条将实时显示当前正在进行的媒体播放和上传/下载进度显示 + + - 🎵 显示媒体播放进度: + • 当音乐或视频正在播放时显示播放进度 + • 点击可以打开播放控制(上一首/下一首音乐) + • 双击以切换播放/暂停 + • 向左/向右滑动以切换至上一首/下一首曲目 + • 长按可打开正在播放媒体的应用 + + - 📥 显示下载/上传进度: + • 显示当前正在进行的上传/下载进度 + • 当没有检测到活跃的传输活动时自动隐藏 + • 点击以打开正在进行传输的应用 + + 状态栏进度条将自动在媒体和下载进度中切换以确保您能获取最需要的信息" + 岛屿通知 @@ -471,9 +537,9 @@ 电源模式 - 启用每个应用的伪装 - 在 PixelProps 中启用每个应用程序的伪装选项 - 选择每个应用程序的 JSON 属性文件 + 对特定应用的伪装 + 在 PixelProps 中启用针对特定应用程序的伪装选项 + 选择用于这些应用的 JSON 属性文件 选择用于伪装游戏的 JSON 文件 @@ -515,8 +581,8 @@ 应用 - 音量声音触觉 - 调整音量时启用声音反馈 + 音量触觉 + 调整音量时启用震动反馈 可展开的音量条 展开音量条,而不是从底部显示 媒体输出图标 @@ -599,10 +665,10 @@ 设置网络和互联网连接 设置连接的设备 添加、配对蓝牙并配置设备连接 - risingOS 个性化 + RisingOS 个性化 更改图标、主题等 重置设置 - 这将会重置当前用户大部分的 risingOS 设置为默认值。您要继续吗? + 这将会重置当前用户大部分的 RisingOS 设置为默认值。您要继续吗? 搜索 @@ -633,8 +699,8 @@ 注意:虽然绕过某些限制可能会带来便利,但也可能导致潜在的隐私风险 - risingOS - risingOS 版本 + RisingOS + RisingOS 版本 构建类型 由维护者 #官方 @@ -726,20 +792,20 @@ 底部 探索功能 - - 关于 risingOS + + 关于 RisingOS 设备 - - 分享 risingOS - 让更多人了解 risingOS - 查看 #risingOS Android 的全部内容 @ https://rising.net/ - 分享 risingOS + + 分享 RisingOS + 让更多人了解 RisingOS + 查看 #RisingOS Android 的全部内容 @ https://rising.net/ + 分享 RisingOS - + GitHub 我们热爱开源,来看看我们的代码吧 - risingOS 社区 + RisingOS 社区 我们有 TG 群。加入我们! 更新频道 在 Telegram 上获取更新通知 @@ -752,10 +818,10 @@ 我们十分推荐这些服务器提供商 - + 支持我们 捐赠以支持开发 - risingOS 团队 + RisingOS 团队 捐赠支持服务器托管,网站正常运行时间和整体管理 @@ -1322,8 +1388,8 @@ 运行中服务快捷方式 设置快捷方式 - - risingOS 法律信息 + + RisingOS 法律信息 亮度滑块 @@ -1857,7 +1923,7 @@ 在状态栏左侧或右侧显示自定义 Logo Logo 位置 Logo 样式 - risingOS + RisingOS Android 阿迪达斯 外星人 From 393591cac062557d8b3827cb0754b89b1257d51d Mon Sep 17 00:00:00 2001 From: huoyan1231 <53113734+huoyan1231@users.noreply.github.com> Date: Sun, 28 Sep 2025 09:39:28 +0800 Subject: [PATCH 24/24] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=BC=9A?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E7=BC=BA=E5=B0=91=E7=9A=84=E6=94=B6=E5=B0=BE=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- res/values-zh-rCN/custom_strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-zh-rCN/custom_strings.xml b/res/values-zh-rCN/custom_strings.xml index a13be264..da65c996 100644 --- a/res/values-zh-rCN/custom_strings.xml +++ b/res/values-zh-rCN/custom_strings.xml @@ -213,7 +213,7 @@ • 点击以打开正在进行传输的应用 状态栏进度条将自动在媒体和下载进度中切换以确保您能获取最需要的信息" - + 岛屿通知