Implement Flash Notifications UI for Settings app.

Bug: 237628564
Test: make RunSettingsRoboTests ROBOTEST_FILTER=CameraFlashNotificationPreferenceControllerTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=ColorSelectorLayoutTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FlashNotificationsPreferenceControllerTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FlashNotificationsPreferenceFragmentTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FlashNotificationsPreviewPreferenceControllerTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FlashNotificationsPreviewPreferenceTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=FlashNotificationsUtilTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=ScreenFlashNotificationColorDialogFragmentTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=ScreenFlashNotificationColorTest
Change-Id: I0987590ddfcfd0873ec419db263f6a7eade81844
Signed-off-by: yw.bae <yw.bae@samsung.corp-partner.google.com>
Signed-off-by: Angela Wang <angelala@google.com>
This commit is contained in:
yw.bae
2023-01-06 22:49:14 +09:00
committed by Thomas Lin
parent 8750e58ed6
commit f763c25c1e
68 changed files with 4058 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<com.android.settingslib.widget.AdaptiveIconShapeDrawable
android:width="@dimen/accessibility_icon_size"
android:height="@dimen/accessibility_icon_size"
android:color="@color/accessibility_feature_background"/>
</item>
<item android:gravity="center">
<vector
android:width="@dimen/accessibility_icon_foreground_size"
android:height="@dimen/accessibility_icon_foreground_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z"/>
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_01" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_01" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_01_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_01_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_02" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_02" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_02_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_02_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_03" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_03" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_03_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_03_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_04" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_04" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_04_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_04_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_05" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_05" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_05_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_05_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_06" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_06" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_06_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_06_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_07" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_07" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_07_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_07_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_08" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_08" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_08_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_08_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_09" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_09" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_09_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_09_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_10" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_10" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_10_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_10_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_11" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_11" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_11_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_11_layer" />
</selector>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_12" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_outer_circle_size"
android:height="@dimen/screen_flash_color_button_outer_circle_size" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/screen_flash_color_button_outer_circle_stroke_width"
android:color="@color/screen_flash_color_button_outer_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/screen_flash_color_button_inner_circle_padding"
android:left="@dimen/screen_flash_color_button_inner_circle_padding"
android:right="@dimen/screen_flash_color_button_inner_circle_padding"
android:top="@dimen/screen_flash_color_button_inner_circle_padding">
<shape android:shape="oval">
<size
android:width="@dimen/screen_flash_color_button_inner_circle_size"
android:height="@dimen/screen_flash_color_button_inner_circle_size" />
<solid android:color="@color/screen_flash_preset_opaque_color_12" />
<stroke
android:width="@dimen/screen_flash_color_button_inner_circle_stroke"
android:color="@color/screen_flash_color_button_inner_circle_stroke_color" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/screen_flash_color_12_checked_layer" android:state_checked="true" />
<item android:drawable="@drawable/screen_flash_color_12_layer" />
</selector>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingVertical="@dimen/settingslib_switchbar_margin"
android:background="@android:color/transparent">
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right"
android:background="@drawable/settingslib_switch_bar_bg_on">
<TextView
android:id="@android:id/title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:paddingVertical="@dimen/settingslib_switch_title_margin"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceListItem"
android:hyphenationFrequency="normalFast"
android:lineBreakWordStyle="phrase"
style="@style/MainSwitchText.Settingslib"/>
</FrameLayout>
</FrameLayout>

View File

@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/color_selector_root_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<RadioButton
android:id="@+id/color_radio_button_00"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_01_selector"
android:contentDescription="@string/screen_flash_color_blue" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_01"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_02_selector"
android:contentDescription="@string/screen_flash_color_azure" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_02"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_03_selector"
android:contentDescription="@string/screen_flash_color_cyan" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_03"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_04_selector"
android:contentDescription="@string/screen_flash_color_spring_green" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<RadioButton
android:id="@+id/color_radio_button_04"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_05_selector"
android:contentDescription="@string/screen_flash_color_green" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_05"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_06_selector"
android:contentDescription="@string/screen_flash_color_chartreuse_green" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_06"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_07_selector"
android:contentDescription="@string/screen_flash_color_yellow" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_07"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_08_selector"
android:contentDescription="@string/screen_flash_color_orange" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<RadioButton
android:id="@+id/color_radio_button_08"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_09_selector"
android:contentDescription="@string/screen_flash_color_red" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_09"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_10_selector"
android:contentDescription="@string/screen_flash_color_rose" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_10"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_11_selector"
android:contentDescription="@string/screen_flash_color_magenta" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/color_radio_button_11"
android:layout_width="@dimen/screen_flash_color_button_frame_size"
android:layout_height="@dimen/screen_flash_color_button_frame_size"
android:button="@drawable/screen_flash_color_12_selector"
android:contentDescription="@string/screen_flash_color_violet" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="24dp">
<com.android.settings.accessibility.ColorSelectorLayout
android:id="@+id/color_selector_preference"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:layout_marginHorizontal="25dp"
android:layout_marginTop="21dp"
android:orientation="vertical" />
</LinearLayout>

View File

@@ -1415,4 +1415,19 @@
<item>persian</item>
</string-array>
<!-- Screen flash notification color when activating -->
<array name="screen_flash_notification_preset_opacity_colors">
<item>@color/screen_flash_preset_opacity_color_01</item>
<item>@color/screen_flash_preset_opacity_color_02</item>
<item>@color/screen_flash_preset_opacity_color_03</item>
<item>@color/screen_flash_preset_opacity_color_04</item>
<item>@color/screen_flash_preset_opacity_color_05</item>
<item>@color/screen_flash_preset_opacity_color_06</item>
<item>@color/screen_flash_preset_opacity_color_07</item>
<item>@color/screen_flash_preset_opacity_color_08</item>
<item>@color/screen_flash_preset_opacity_color_09</item>
<item>@color/screen_flash_preset_opacity_color_10</item>
<item>@color/screen_flash_preset_opacity_color_11</item>
<item>@color/screen_flash_preset_opacity_color_12</item>
</array>
</resources>

View File

@@ -181,4 +181,37 @@
<color name="udfps_enroll_progress">#699FF3</color>
<color name="udfps_enroll_progress_help">#70699FF3</color>
<color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
<!-- Flash notifications colors -->
<!-- Screen flash notification color selected stroke in color selection dialog -->
<color name="screen_flash_color_button_inner_circle_stroke_color">#D4D4D4</color>
<color name="screen_flash_color_button_outer_circle_stroke_color">#000000</color>
<!-- Screen flash notification color options in color selection dialog -->
<color name="screen_flash_preset_opaque_color_01">#0000FE</color> <!-- 100% Blue -->
<color name="screen_flash_preset_opaque_color_02">#0080FF</color> <!-- 100% Azure -->
<color name="screen_flash_preset_opaque_color_03">#00FFFF</color> <!-- 100% Cyan -->
<color name="screen_flash_preset_opaque_color_04">#00FF7F</color> <!-- 100% Spring green -->
<color name="screen_flash_preset_opaque_color_05">#00FF01</color> <!-- 100% Green -->
<color name="screen_flash_preset_opaque_color_06">#80FF00</color> <!-- 100% Chartreuse green -->
<color name="screen_flash_preset_opaque_color_07">#FFFF00</color> <!-- 100% Yellow -->
<color name="screen_flash_preset_opaque_color_08">#FF7F00</color> <!-- 100% Orange -->
<color name="screen_flash_preset_opaque_color_09">#FE0000</color> <!-- 100% Red -->
<color name="screen_flash_preset_opaque_color_10">#FF017E</color> <!-- 100% Rose -->
<color name="screen_flash_preset_opaque_color_11">#FF00FE</color> <!-- 100% Magenta -->
<color name="screen_flash_preset_opaque_color_12">#7F00FF</color> <!-- 100% Violet -->
<!-- Screen flash notification color when activating -->
<color name="screen_flash_preset_opacity_color_01">#4D0000FE</color> <!-- 30% Blue -->
<color name="screen_flash_preset_opacity_color_02">#660080FF</color> <!-- 40% Azure -->
<color name="screen_flash_preset_opacity_color_03">#4D00FFFF</color> <!-- 30% Cyan -->
<color name="screen_flash_preset_opacity_color_04">#6600FF7F</color> <!-- 40% Spring green -->
<color name="screen_flash_preset_opacity_color_05">#6600FF01</color> <!-- 40% Green -->
<color name="screen_flash_preset_opacity_color_06">#6680FF00</color> <!-- 40% Chartreuse green -->
<color name="screen_flash_preset_opacity_color_07">#66FFFF00</color> <!-- 40% Yellow -->
<color name="screen_flash_preset_opacity_color_08">#66FF7F00</color> <!-- 40% Orange -->
<color name="screen_flash_preset_opacity_color_09">#66FE0000</color> <!-- 40% Red -->
<color name="screen_flash_preset_opacity_color_10">#4DFF017E</color> <!-- 30% Rose -->
<color name="screen_flash_preset_opacity_color_11">#4DFF00FE</color> <!-- 30% Magenta -->
<color name="screen_flash_preset_opacity_color_12">#667F00FF</color> <!-- 40% Violet -->
</resources>

View File

@@ -416,4 +416,12 @@
<!-- Default margin for side fps enroll find sensor lottie -->
<dimen name="sfps_enroll_find_sensor_lottie_margin">0dp</dimen>
<!-- Flash notifications dimensions -->
<dimen name="screen_flash_color_button_frame_size">38dp</dimen>
<dimen name="screen_flash_color_button_outer_circle_size">38dp</dimen>
<dimen name="screen_flash_color_button_outer_circle_stroke_width">2dp</dimen>
<dimen name="screen_flash_color_button_inner_circle_size">32dp</dimen>
<dimen name="screen_flash_color_button_inner_circle_padding">3dp</dimen>
<dimen name="screen_flash_color_button_inner_circle_stroke">1dp</dimen>
</resources>

View File

@@ -6476,6 +6476,8 @@
<string name="help_url_timeout" translatable="false"></string>
<!-- Help URL, Accessibility Color Inversion [DO NOT TRANSLATE] -->
<string name="help_url_color_inversion" translatable="false"></string>
<!-- Help URL, Accessibility Flash Notification [DO NOT TRANSLATE] -->
<string name="help_url_flash_notifications" translatable="false"></string>
<string name="help_url_system_dashboard" translatable="false"></string>
<string name="help_url_double_tap_screen" translatable="false"></string>
<string name="help_url_account_detail" translatable="false"></string>
@@ -11739,4 +11741,56 @@
<!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_label">Fingerprint sensor</string>
<!-- Accessibility Flash Notification -->
<!-- Title of the Flash Notification entry [CHAR LIMIT=NONE] -->
<string name="flash_notifications_title">Flash notifications</string>
<!-- Summary of the Flash Notification preference if all flash alerts are off. [CHAR LIMIT=60] -->
<string name="flash_notifications_summary_off">Off</string>
<!-- Summary of the Flash Notification preference if only camera flash is on. [CHAR LIMIT=60] -->
<string name="flash_notifications_summary_on_camera">On / camera flash</string>
<!-- Summary of the Flash Notification preference if only screen flash is on. [CHAR LIMIT=60] -->
<string name="flash_notifications_summary_on_screen">On / screen flash</string>
<!-- Summary of the Flash Notification preference if both flash alerts are on. [CHAR LIMIT=60] -->
<string name="flash_notifications_summary_on_camera_and_screen">On / camera and screen flash</string>
<!-- Introduction in Flash Notification page to introduce flash notifications feature. [CHAR LIMIT=NONE] -->
<string name="flash_notifications_intro">Flash the camera light or the screen when you receive notifications or when alarms sound.</string>
<!-- Notes in Flash Notification page footer for something should be aware. [CHAR LIMIT=NONE] -->
<string name="flash_notifications_note">Use flash notifications with caution if your are light sensitive</string>
<!-- Label of the button to preview the selected Flash Notification effects. [CHAR LIMIT=20]-->
<string name="flash_notifications_preview">Preview</string>
<!-- Title of the camera flash in Flash Notification page. [CHAR LIMIT=60] -->
<string name="camera_flash_notification_title">Camera flash notification</string>
<!-- Title of the screen flash in Flash Notification page. [CHAR LIMIT=60] -->
<string name="screen_flash_notification_title">Screen flash notification</string>
<!-- Title of the screen flash color selection dialog. [CHAR LIMIT=NONE] -->
<string name="screen_flash_notification_color_title">Screen flash color</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_blue">Blue</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_azure">Azure</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_cyan">Cyan</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_spring_green">Spring green</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_green">Green</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_chartreuse_green">Chartreuse green</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_yellow">Yellow</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_orange">Orange</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_red">Red</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_rose">Rose</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_magenta">Magenta</string>
<!-- Label of the color option show in the summary of screen flash preference. [CHAR LIMIT=60] -->
<string name="screen_flash_color_violet">Violet</string>
<!-- Button to save the selection in screen flash color selection dialog. [CHAR LIMIT=20] -->
<string name="color_selector_dialog_done">Done</string>
<!-- Button to close the dialog without saving in screen flash color selection dialog. [CHAR LIMIT=20] -->
<string name="color_selector_dialog_cancel">Cancel</string>
</resources>

View File

@@ -150,6 +150,14 @@
settings:searchable="true"
settings:controller="com.android.settings.accessibility.AudioDescriptionPreferenceController"/>
<Preference
android:fragment="com.android.settings.accessibility.FlashNotificationsPreferenceFragment"
android:icon="@drawable/ic_flash_notification"
android:key="flash_notifications_preference"
android:persistent="false"
android:title="@string/flash_notifications_title"
settings:controller="com.android.settings.accessibility.FlashNotificationsPreferenceController" />
<Preference
android:key="hearing_aid_preference"
android:icon="@drawable/ic_hearing_aid"

View File

@@ -119,6 +119,7 @@
android:fragment="com.android.settings.notification.zen.ZenModeSettings"
settings:controller="com.android.settings.notification.zen.ZenModePreferenceController"
/>
<SwitchPreference
android:key="lock_screen_show_only_unseen_notifs"
android:order="18"
@@ -126,6 +127,15 @@
android:summary="@string/unseen_notifs_lock_screen_summary"
settings:controller="com.android.settings.notification.ShowOnlyUnseenNotificationsOnLockscreenPreferenceController"
/>
<Preference
android:fragment="com.android.settings.accessibility.FlashNotificationsPreferenceFragment"
android:key="flash_notifications_preference"
android:order="18"
android:persistent="false"
android:title="@string/flash_notifications_title"
settings:controller="com.android.settings.accessibility.FlashNotificationsPreferenceController" />
<com.android.settingslib.RestrictedPreference
android:key="app_and_notif_cell_broadcast_settings"
android:order="19"

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/flash_notifications_title">
<com.android.settingslib.widget.TopIntroPreference
android:title="@string/flash_notifications_intro" />
<!-- TODO update when rawRes added
<com.android.settingslib.widget.IllustrationPreference
android:key="flash_notifications_guide_preference"
settings:lottie_rawRes="@raw/NOT ADDED"
settings:searchable="false" />
-->
<SwitchPreference
android:key="camera_flash_notification_preference"
android:persistent="false"
android:title="@string/camera_flash_notification_title"
settings:controller="com.android.settings.accessibility.CameraFlashNotificationPreferenceController" />
<com.android.settingslib.PrimarySwitchPreference
android:key="screen_flash_notification_preference"
android:persistent="false"
android:title="@string/screen_flash_notification_title"
settings:controller="com.android.settings.accessibility.ScreenFlashNotificationPreferenceController" />
<com.android.settings.accessibility.FlashNotificationsPreviewPreference
android:key="flash_notifications_preview"
android:title="@string/flash_notifications_preview"
settings:controller="com.android.settings.accessibility.FlashNotificationsPreviewPreferenceController" />
<com.android.settingslib.widget.FooterPreference
android:key="flash_notifications_footer"
android:selectable="false"
android:title="@string/flash_notifications_note"
settings:searchable="false" />
</PreferenceScreen>

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
/**
* Controller for Camera flash notification.
*/
public class CameraFlashNotificationPreferenceController extends TogglePreferenceController {
public CameraFlashNotificationPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return FlashNotificationsUtil.isTorchAvailable(mContext)
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
public boolean setChecked(boolean isChecked) {
return Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import com.android.settings.R;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Layout for Screen flash notification color picker.
*/
public class ColorSelectorLayout extends LinearLayout {
// Holds the checked id. The selection is empty by default
private int mCheckedId = -1;
// Tracks children radio buttons checked state
private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
private ColorSelectorLayout.OnCheckedChangeListener mOnCheckedChangeListener;
private final List<Integer> mRadioButtonResourceIds = Arrays.asList(
R.id.color_radio_button_00,
R.id.color_radio_button_01,
R.id.color_radio_button_02,
R.id.color_radio_button_03,
R.id.color_radio_button_04,
R.id.color_radio_button_05,
R.id.color_radio_button_06,
R.id.color_radio_button_07,
R.id.color_radio_button_08,
R.id.color_radio_button_09,
R.id.color_radio_button_10,
R.id.color_radio_button_11
);
private List<Integer> mColorList;
public ColorSelectorLayout(Context context) {
super(context);
mChildOnCheckedChangeListener = new CheckedStateTracker();
inflate(mContext, R.layout.layout_color_selector, this);
init();
mColorList = Arrays.stream(mContext.getResources()
.getIntArray(R.array.screen_flash_notification_preset_opacity_colors))
.boxed()
.collect(Collectors.toList());
}
public ColorSelectorLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mChildOnCheckedChangeListener = new CheckedStateTracker();
inflate(mContext, R.layout.layout_color_selector, this);
init();
mColorList = Arrays.stream(mContext.getResources()
.getIntArray(R.array.screen_flash_notification_preset_opacity_colors))
.boxed()
.collect(Collectors.toList());
}
private void init() {
for (int resId : mRadioButtonResourceIds) {
RadioButton radioButton = findViewById(resId);
if (radioButton != null) {
radioButton.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
}
}
}
void setOnCheckedChangeListener(ColorSelectorLayout.OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
void setCheckedColor(@ColorInt int color) {
int resId = getResId(mColorList.indexOf(color));
if (resId != NO_ID && resId == mCheckedId) return;
if (mCheckedId != NO_ID) {
setCheckedStateForView(mCheckedId, false);
}
if (resId != NO_ID) {
setCheckedStateForView(resId, true);
}
setCheckedId(resId);
}
int getCheckedColor(int defaultColor) {
int checkedItemIndex = mRadioButtonResourceIds.indexOf(mCheckedId);
if (checkedItemIndex < 0 || checkedItemIndex >= mColorList.size()) {
return defaultColor;
} else {
return mColorList.get(checkedItemIndex);
}
}
private int getResId(int index) {
if (index < 0 || index >= mRadioButtonResourceIds.size()) {
return NO_ID;
} else {
return mRadioButtonResourceIds.get(index);
}
}
private void setCheckedId(int resId) {
mCheckedId = resId;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this);
}
}
private void setCheckedStateForView(int viewId, boolean checked) {
final View checkedView = findViewById(viewId);
if (checkedView instanceof RadioButton) {
((RadioButton) checkedView).setChecked(checked);
}
}
interface OnCheckedChangeListener {
void onCheckedChanged(ColorSelectorLayout group);
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) {
return;
}
if (mCheckedId != NO_ID) {
setCheckedStateForView(mCheckedId, false);
}
int id = buttonView.getId();
setCheckedId(id);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
/**
* Controller for flash notifications.
*/
public class FlashNotificationsPreferenceController extends BasePreferenceController {
public FlashNotificationsPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public CharSequence getSummary() {
final int res;
switch (FlashNotificationsUtil.getFlashNotificationsState(mContext)) {
case FlashNotificationsUtil.State.CAMERA:
res = R.string.flash_notifications_summary_on_camera;
break;
case FlashNotificationsUtil.State.SCREEN:
res = R.string.flash_notifications_summary_on_screen;
break;
case FlashNotificationsUtil.State.CAMERA_SCREEN:
res = R.string.flash_notifications_summary_on_camera_and_screen;
break;
case FlashNotificationsUtil.State.OFF:
default:
res = R.string.flash_notifications_summary_off;
break;
}
return mContext.getString(res);
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
/**
* Fragment for flash notifications.
*/
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class FlashNotificationsPreferenceFragment extends DashboardFragment {
@Override
protected int getPreferenceScreenResId() {
return R.xml.flash_notifications_settings;
}
@Override
protected String getLogTag() {
return "FlashNotificationsPreferenceFragment";
}
@Override
public int getMetricsCategory() {
// TODO: Flash notifications have to add SettingsEnums.
return 0;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
use(ScreenFlashNotificationPreferenceController.class).setParentFragment(this);
}
@Override
public int getHelpResource() {
return R.string.help_url_flash_notifications;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.flash_notifications_settings);
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.Preference;
import com.android.settings.R;
/**
* Preference for Flash notifications preview.
*/
public class FlashNotificationsPreviewPreference extends Preference {
public FlashNotificationsPreviewPreference(Context context) {
super(context);
init();
}
public FlashNotificationsPreviewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FlashNotificationsPreviewPreference(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public FlashNotificationsPreviewPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setLayoutResource(R.layout.flash_notification_preview_preference);
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
/**
* Controller for flash notifications preview.
*/
public class FlashNotificationsPreviewPreferenceController extends
BasePreferenceController implements LifecycleEventObserver {
private Preference mPreference;
private final ContentResolver mContentResolver;
@VisibleForTesting
final ContentObserver mContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, @Nullable Uri uri) {
onSettingChanged();
}
};
public FlashNotificationsPreviewPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mContentResolver = context.getContentResolver();
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
onSettingChanged();
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (getPreferenceKey().equals(preference.getKey())) {
Intent intent = new Intent(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_SHORT_PREVIEW);
mContext.sendBroadcast(intent);
return true;
}
return super.handlePreferenceTreeClick(preference);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_RESUME) {
mContentResolver.registerContentObserver(
Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
mContentResolver.registerContentObserver(
Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
} else if (event == Lifecycle.Event.ON_PAUSE) {
mContentResolver.unregisterContentObserver(mContentObserver);
}
}
private void onSettingChanged() {
if (mPreference == null) return;
mPreference.setEnabled(FlashNotificationsUtil.getFlashNotificationsState(mContext)
!= FlashNotificationsUtil.State.OFF);
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
class FlashNotificationsUtil {
static final String LOG_TAG = "FlashNotificationsUtil";
static final String ACTION_FLASH_NOTIFICATION_START_PREVIEW =
"com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW";
static final String ACTION_FLASH_NOTIFICATION_STOP_PREVIEW =
"com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW";
static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR =
"com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_COLOR";
static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE =
"com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_TYPE";
static final String SETTING_KEY_CAMERA_FLASH_NOTIFICATION =
"camera_flash_notification";
static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION =
"screen_flash_notification";
static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR =
"screen_flash_notification_color_global";
static final int TYPE_SHORT_PREVIEW = 0;
static final int TYPE_LONG_PREVIEW = 1;
static final int DEFAULT_SCREEN_FLASH_COLOR =
ScreenFlashNotificationColor.YELLOW.mColorInt;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FlashNotificationsUtil.State.OFF,
FlashNotificationsUtil.State.CAMERA,
FlashNotificationsUtil.State.SCREEN,
FlashNotificationsUtil.State.CAMERA_SCREEN,
})
@interface State {
int OFF = 0;
int CAMERA = 1;
int SCREEN = 2;
int CAMERA_SCREEN = 3;
}
static boolean isTorchAvailable(@NonNull Context context) {
// TODO This is duplicated logic of FlashNotificationsController.getCameraId.
final CameraManager cameraManager = context.getSystemService(CameraManager.class);
if (cameraManager == null) return false;
try {
final String[] ids = cameraManager.getCameraIdList();
for (String id : ids) {
final CameraCharacteristics c = cameraManager.getCameraCharacteristics(id);
final Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (flashAvailable == null) continue;
final Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
if (lensFacing == null) continue;
if (flashAvailable && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
return true;
}
}
} catch (CameraAccessException ignored) {
Log.w(LOG_TAG, "Failed to get valid camera for camera flash notification.");
}
return false;
}
static ScreenFlashNotificationColor getScreenColor(@ColorInt int colorInt)
throws ScreenColorNotFoundException {
colorInt |= ScreenFlashNotificationColor.ALPHA_MASK;
for (ScreenFlashNotificationColor color : ScreenFlashNotificationColor.values()) {
if (colorInt == color.mOpaqueColorInt) {
return color;
}
}
throw new ScreenColorNotFoundException();
}
@NonNull
static String getColorDescriptionText(@NonNull Context context, @ColorInt int color) {
try {
return context.getString(getScreenColor(color).mStringRes);
} catch (ScreenColorNotFoundException e) {
return "";
}
}
@State
static int getFlashNotificationsState(Context context) {
if (context == null) {
return State.OFF;
}
final boolean isTorchAvailable = FlashNotificationsUtil.isTorchAvailable(context);
final boolean isCameraFlashEnabled = Settings.System.getInt(context.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
final boolean isScreenFlashEnabled = Settings.System.getInt(context.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
return ((isTorchAvailable && isCameraFlashEnabled) ? State.CAMERA : State.OFF)
| (isScreenFlashEnabled ? State.SCREEN : State.OFF);
}
static class ScreenColorNotFoundException extends Exception {
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import androidx.annotation.ColorInt;
import androidx.annotation.StringRes;
import com.android.settings.R;
enum ScreenFlashNotificationColor {
BLUE(0x4D0000FE, R.string.screen_flash_color_blue),
AZURE(0x660080FF, R.string.screen_flash_color_azure),
CYAN(0x4D00FFFF, R.string.screen_flash_color_cyan),
SPRING_GREEN(0x6600FF7F, R.string.screen_flash_color_spring_green),
GREEN(0x6600FF01, R.string.screen_flash_color_green),
CHARTREUSE_GREEN(0x6680FF00, R.string.screen_flash_color_chartreuse_green),
YELLOW(0x66FFFF00, R.string.screen_flash_color_yellow),
ORANGE(0x66FF7F00, R.string.screen_flash_color_orange),
RED(0x66FE0000, R.string.screen_flash_color_red),
ROSE(0x4DFF017E, R.string.screen_flash_color_rose),
MAGENTA(0x4DFF00FE, R.string.screen_flash_color_magenta),
VIOLET(0x667F00FF, R.string.screen_flash_color_violet);
static final int ALPHA_MASK = 0xFF000000;
final int mColorInt;
final int mOpaqueColorInt;
final int mStringRes;
ScreenFlashNotificationColor(@ColorInt int colorInt, @StringRes int stringRes) {
this.mColorInt = colorInt;
this.mStringRes = stringRes;
this.mOpaqueColorInt = colorInt | ALPHA_MASK;
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_STOP_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.android.settings.R;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Consumer;
/**
* DialogFragment for Screen flash notification color picker.
*/
public class ScreenFlashNotificationColorDialogFragment extends DialogFragment implements
ColorSelectorLayout.OnCheckedChangeListener {
private static final int PREVIEW_LONG_TIME_MS = 5000;
private static final int BETWEEN_STOP_AND_START_DELAY_MS = 250;
private static final int MARGIN_FOR_STOP_DELAY_MS = 100;
@ColorInt
private int mCurrentColor = Color.TRANSPARENT;
private Consumer<Integer> mConsumer;
private Timer mTimer = null;
private Boolean mIsPreview = false;
static ScreenFlashNotificationColorDialogFragment getInstance(int initialColor,
Consumer<Integer> colorConsumer) {
final ScreenFlashNotificationColorDialogFragment result =
new ScreenFlashNotificationColorDialogFragment();
result.mCurrentColor = initialColor;
result.mConsumer = colorConsumer != null ? colorConsumer : i -> {
};
return result;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final View dialogView = getLayoutInflater().inflate(R.layout.layout_color_selector_dialog,
null);
final ColorSelectorLayout colorSelectorLayout = dialogView.findViewById(
R.id.color_selector_preference);
if (colorSelectorLayout != null) {
colorSelectorLayout.setOnCheckedChangeListener(this);
colorSelectorLayout.setCheckedColor(mCurrentColor);
}
final AlertDialog createdDialog = new AlertDialog.Builder(getContext())
.setView(dialogView)
.setTitle(R.string.screen_flash_notification_color_title)
.setNeutralButton(R.string.flash_notifications_preview, null)
.setNegativeButton(R.string.color_selector_dialog_cancel, (dialog, which) -> {
})
.setPositiveButton(R.string.color_selector_dialog_done, (dialog, which) -> {
mCurrentColor = colorSelectorLayout.getCheckedColor(DEFAULT_SCREEN_FLASH_COLOR);
mConsumer.accept(mCurrentColor);
})
.create();
createdDialog.setOnShowListener(
dialogInterface -> createdDialog.getButton(AlertDialog.BUTTON_NEUTRAL)
.setOnClickListener(v -> showColor()));
return createdDialog;
}
@Override
public void onPause() {
super.onPause();
cancelPreviewTask();
}
@Override
public void onCheckedChanged(ColorSelectorLayout group) {
mCurrentColor = group.getCheckedColor(DEFAULT_SCREEN_FLASH_COLOR);
if (mIsPreview) {
showColor();
}
}
private void showColor() {
int startDelay = 0;
synchronized (this) {
if (mTimer != null) mTimer.cancel();
mTimer = new Timer();
if (mIsPreview) {
mTimer.schedule(getStopTask(), 0);
startDelay = BETWEEN_STOP_AND_START_DELAY_MS;
}
mTimer.schedule(getStartTask(), startDelay);
mTimer.schedule(getStopTask(),
startDelay + PREVIEW_LONG_TIME_MS + MARGIN_FOR_STOP_DELAY_MS);
}
}
private TimerTask getStartTask() {
return new TimerTask() {
@Override
public void run() {
synchronized (this) {
startPreviewLocked();
}
}
};
}
private TimerTask getStopTask() {
return new TimerTask() {
@Override
public void run() {
synchronized (this) {
stopPreviewLocked();
}
}
};
}
private void cancelPreviewTask() {
synchronized (this) {
if (mTimer != null) mTimer.cancel();
stopPreviewLocked();
}
}
private void startPreviewLocked() {
if (getContext() == null) return;
mIsPreview = true;
Intent intent = new Intent(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_LONG_PREVIEW);
intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR, mCurrentColor);
getContext().sendBroadcast(intent);
}
private void stopPreviewLocked() {
if (getContext() == null) return;
Intent stopIntent = new Intent(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW);
getContext().sendBroadcast(stopIntent);
mIsPreview = false;
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import android.content.Context;
import android.graphics.Color;
import android.provider.Settings;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import java.util.function.Consumer;
/**
* Controller for Screen flash notification.
*/
public class ScreenFlashNotificationPreferenceController extends TogglePreferenceController {
private Fragment mParentFragment;
private Preference mPreference;
public ScreenFlashNotificationPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
public void setParentFragment(Fragment parentFragment) {
this.mParentFragment = parentFragment;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
public boolean setChecked(boolean isChecked) {
if (isChecked) checkAndSetInitialColor();
return Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
@Override
public CharSequence getSummary() {
return FlashNotificationsUtil.getColorDescriptionText(mContext,
Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR));
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
refreshColorSummary();
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (getPreferenceKey().equals(preference.getKey()) && mParentFragment != null) {
final int initialColor = Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR,
DEFAULT_SCREEN_FLASH_COLOR);
final Consumer<Integer> consumer = color -> {
Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, color);
refreshColorSummary();
};
ScreenFlashNotificationColorDialogFragment
.getInstance(initialColor, consumer)
.show(mParentFragment.getParentFragmentManager(),
ScreenFlashNotificationColorDialogFragment.class.getSimpleName());
return true;
}
return super.handlePreferenceTreeClick(preference);
}
private void checkAndSetInitialColor() {
if (Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
== Color.TRANSPARENT) {
Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
}
}
private void refreshColorSummary() {
if (mPreference != null) mPreference.setSummary(getSummary());
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowFlashNotificationsUtils.class)
public class CameraFlashNotificationPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private CameraFlashNotificationPreferenceController mController;
private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContentResolver = mContext.getContentResolver();
mController = new CameraFlashNotificationPreferenceController(mContext, PREFERENCE_KEY);
}
@After
public void tearDown() {
ShadowFlashNotificationsUtils.reset();
}
@Test
public void getAvailabilityStatus_torchAvailable_assertAvailable() {
ShadowFlashNotificationsUtils.setIsTorchAvailable(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_torchUnavailable_assertUnsupportedOnDevice() {
ShadowFlashNotificationsUtils.setIsTorchAvailable(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void isChecked_setOff_assertFalse() {
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_setTrue_assertNotZero() {
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
0)).isNotEqualTo(0);
}
@Test
public void setChecked_setFalse_assertNotOne() {
mController.setChecked(false);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
1)).isNotEqualTo(1);
}
@Test
public void getSliceHighlightMenuRes() {
mController.getSliceHighlightMenuRes();
assertThat(mController.getSliceHighlightMenuRes())
.isEqualTo(R.string.menu_key_accessibility);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class ColorSelectorLayoutTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
ColorSelectorLayout mColorSelectorLayout;
@ColorInt
int mCheckedColor = Color.TRANSPARENT;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mColorSelectorLayout = new ColorSelectorLayout(mContext);
mColorSelectorLayout.setOnCheckedChangeListener(
layout -> mCheckedColor = layout.getCheckedColor(Color.TRANSPARENT));
}
@Test
public void setColor_checkColorChanged() {
mColorSelectorLayout.setCheckedColor(ScreenFlashNotificationColor.AZURE.mColorInt);
assertThat(mCheckedColor)
.isEqualTo(ScreenFlashNotificationColor.AZURE.mColorInt);
}
@Test
public void getCheckedColor_defaultValue() {
assertThat(mColorSelectorLayout.getCheckedColor(0xFF000000))
.isEqualTo(0xFF000000);
}
@Test
public void setSelectedColor_checkColorChanged() {
mColorSelectorLayout.setCheckedColor(ScreenFlashNotificationColor.AZURE.mColorInt);
assertThat(mColorSelectorLayout.getCheckedColor(0xFF000000))
.isEqualTo(ScreenFlashNotificationColor.AZURE.mColorInt);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.ShadowFlashNotificationsUtils.setFlashNotificationsState;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowFlashNotificationsUtils.class)
public class FlashNotificationsPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private FlashNotificationsPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mController = new FlashNotificationsPreferenceController(mContext, PREFERENCE_KEY);
}
@After
public void tearDown() {
ShadowFlashNotificationsUtils.reset();
}
@Test
public void getAvailabilityStatus() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getSummary_stateOff_assertOff() {
setFlashNotificationsState(FlashNotificationsUtil.State.OFF);
assertThat(mController.getSummary().toString()).isEqualTo(mContext.getString(
R.string.flash_notifications_summary_off));
}
@Test
public void getSummary_stateCamera_assertCamera() {
setFlashNotificationsState(FlashNotificationsUtil.State.CAMERA);
assertThat(mController.getSummary().toString()).isEqualTo(mContext.getString(
R.string.flash_notifications_summary_on_camera));
}
@Test
public void getSummary_stateScreen_assertScreen() {
setFlashNotificationsState(FlashNotificationsUtil.State.SCREEN);
assertThat(mController.getSummary().toString()).isEqualTo(mContext.getString(
R.string.flash_notifications_summary_on_screen));
}
@Test
public void getSummary_stateCameraScreen_assertCameraScreen() {
setFlashNotificationsState(FlashNotificationsUtil.State.CAMERA_SCREEN);
assertThat(mController.getSummary().toString()).isEqualTo(mContext.getString(
R.string.flash_notifications_summary_on_camera_and_screen));
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class FlashNotificationsPreferenceFragmentTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private FlashNotificationsPreferenceFragment mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = new FlashNotificationsPreferenceFragment();
}
@Test
public void getPreferenceScreenResId_isFlashNotificationsSettings() {
assertThat(mFragment.getPreferenceScreenResId())
.isEqualTo(R.xml.flash_notifications_settings);
}
@Test
public void getLogTag_isSpecifyTag() {
assertThat(mFragment.getLogTag()).isEqualTo("FlashNotificationsPreferenceFragment");
}
@Test
public void getMetricsCategory_isZero() {
assertThat(mFragment.getMetricsCategory()).isEqualTo(0); // TODO
}
@Test
public void onAttach_attachedTheTestFragment() {
ScreenFlashNotificationPreferenceController controller = mock(
ScreenFlashNotificationPreferenceController.class);
TestFlashNotificationsPreferenceFragment testFragment =
new TestFlashNotificationsPreferenceFragment(controller);
testFragment.onAttach(mContext);
verify(controller).setParentFragment(eq(testFragment));
}
@Test
public void getHelpResource_isExpectedResource() {
assertThat(mFragment.getHelpResource())
.isEqualTo(R.string.help_url_flash_notifications);
}
static class TestFlashNotificationsPreferenceFragment extends
FlashNotificationsPreferenceFragment {
final AbstractPreferenceController mController;
TestFlashNotificationsPreferenceFragment(AbstractPreferenceController controller) {
mController = controller;
}
@Override
protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
return (T) mController;
}
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import static com.android.settings.accessibility.ShadowFlashNotificationsUtils.setFlashNotificationsState;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowFlashNotificationsUtils.class)
public class FlashNotificationsPreviewPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private Preference mPreference;
@Spy
private ContentResolver mContentResolver = mContext.getContentResolver();
private FlashNotificationsPreviewPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mPreferenceScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference);
when(mPreference.getKey()).thenReturn(PREFERENCE_KEY);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mController = new FlashNotificationsPreviewPreferenceController(mContext, PREFERENCE_KEY);
}
@After
public void tearDown() {
ShadowFlashNotificationsUtils.reset();
}
@Test
public void testGetAvailabilityStatus() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void testDisplayPreference_torchPresent_cameraOff_screenOff_verifyDisabled() {
setFlashNotificationsState(FlashNotificationsUtil.State.OFF);
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setEnabled(eq(false));
}
@Test
public void testDisplayPreference_torchPresent_cameraOn_screenOff_verifyEnabled() {
setFlashNotificationsState(FlashNotificationsUtil.State.CAMERA);
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setEnabled(eq(true));
}
@Test
public void testDisplayPreference_torchPresent_cameraOff_screenOn_verifyEnabled() {
setFlashNotificationsState(FlashNotificationsUtil.State.SCREEN);
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setEnabled(eq(true));
}
@Test
public void testDisplayPreference_torchPresent_cameraOn_screenOn_verifyEnabled() {
setFlashNotificationsState(FlashNotificationsUtil.State.CAMERA_SCREEN);
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setEnabled(eq(true));
}
@Ignore
@Test
public void testHandlePreferenceTreeClick_invalidPreference() {
mController.handlePreferenceTreeClick(mock(Preference.class));
verify(mContext, never()).sendBroadcast(any());
}
@Test
public void handlePreferenceTreeClick_assertAction() {
mController.handlePreferenceTreeClick(mPreference);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendBroadcast(captor.capture());
Intent captured = captor.getValue();
assertThat(captured.getAction()).isEqualTo(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
}
@Test
public void handlePreferenceTreeClick_assertExtra() {
mController.handlePreferenceTreeClick(mPreference);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendBroadcast(captor.capture());
Intent captured = captor.getValue();
assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_LONG_PREVIEW))
.isEqualTo(TYPE_SHORT_PREVIEW);
}
@Test
public void onStateChanged_onResume_cameraUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
eq(Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION)), anyBoolean(),
eq(mController.mContentObserver));
}
@Test
public void onStateChanged_onResume_screenUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
eq(Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION)), anyBoolean(),
eq(mController.mContentObserver));
}
@Test
public void onStateChanged_onPause_verifyUnregister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_PAUSE);
verify(mContentResolver).unregisterContentObserver(eq(mController.mContentObserver));
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.util.AttributeSet;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class FlashNotificationsPreviewPreferenceTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private final AttributeSet mAttributeSet = Robolectric.buildAttributeSet().build();
@Test
public void constructor_assertLayoutResource_P00() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference(
mContext);
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference);
}
@Test
public void constructor_assertLayoutResource_P01() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference(
mContext, mAttributeSet);
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference);
}
@Test
public void constructor_assertLayoutResource_P02() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference(
mContext, mAttributeSet, 0);
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference);
}
@Test
public void constructor_assertLayoutResource_P03() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference(
mContext, mAttributeSet, 0, 0);
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference);
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.hardware.camera2.CameraCharacteristics.FLASH_INFO_AVAILABLE;
import static android.hardware.camera2.CameraCharacteristics.LENS_FACING;
import static android.hardware.camera2.CameraCharacteristics.LENS_FACING_BACK;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.getColorDescriptionText;
import static com.android.settings.accessibility.FlashNotificationsUtil.getFlashNotificationsState;
import static com.android.settings.accessibility.FlashNotificationsUtil.getScreenColor;
import static com.android.settings.accessibility.FlashNotificationsUtil.isTorchAvailable;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
import static org.robolectric.shadows.ShadowCameraCharacteristics.newCameraCharacteristics;
import android.content.ContentResolver;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowCameraCharacteristics;
import org.robolectric.shadows.ShadowCameraManager;
@RunWith(RobolectricTestRunner.class)
public class FlashNotificationsUtilTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private CameraManager mCameraManager = mContext.getSystemService(CameraManager.class);
private ShadowCameraManager mShadowCameraManager;
private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mShadowCameraManager = Shadows.shadowOf(mCameraManager);
mContentResolver = mContext.getContentResolver();
}
@Test
public void isTorchAvailable_nullCameraManager_assertFalse() {
when(mContext.getSystemService(CameraManager.class)).thenReturn(null);
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void isTorchAvailable_noCamera_assertFalse() {
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void isTorchAvailable_getCameraIdListThrowException_assertFalse()
throws CameraAccessException {
when(mCameraManager.getCameraIdList()).thenThrow(CameraAccessException.class);
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void isTorchAvailable_getCameraCharacteristicsThrowException_assertFalse()
throws CameraAccessException {
CameraCharacteristics cameraCharacteristics = newCameraCharacteristics();
mShadowCameraManager.addCamera("0", cameraCharacteristics);
when(mCameraManager.getCameraCharacteristics("0")).thenThrow(CameraAccessException.class);
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void isTorchAvailable_torchNotPresent_assertFalse() {
setTorchNotPresent();
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void isTorchAvailable_torchPresent_assertTrue() {
setTorchPresent();
assertThat(isTorchAvailable(mContext)).isTrue();
}
@Test
public void isTorchAvailable_lensFacingFront_assertFalse() {
CameraCharacteristics cameraCharacteristics = newCameraCharacteristics();
ShadowCameraCharacteristics shadowCameraCharacteristics = extract(cameraCharacteristics);
shadowCameraCharacteristics.set(FLASH_INFO_AVAILABLE, true);
shadowCameraCharacteristics.set(LENS_FACING, LENS_FACING_FRONT);
mShadowCameraManager.addCamera("0", cameraCharacteristics);
assertThat(isTorchAvailable(mContext)).isFalse();
}
@Test
public void getScreenColor_undefinedColor_throwException() {
assertThrows(FlashNotificationsUtil.ScreenColorNotFoundException.class, () ->
getScreenColor(0x4D0000FF));
}
@Test
public void getScreenColor_azureColor_returnAzure() throws Exception {
assertThat(getScreenColor(0x4D0000FF)).isEqualTo(ScreenFlashNotificationColor.AZURE);
}
@Test
public void getColorDescriptionText_undefinedColor_returnEmpty() {
assertThat(getColorDescriptionText(mContext, 0x4D0000FF)).isEqualTo("");
}
@Test
public void getColorDescriptionText_azureColor_returnAzureName() {
assertThat(getColorDescriptionText(mContext, ScreenFlashNotificationColor.AZURE.mColorInt))
.isEqualTo(mContext.getString(ScreenFlashNotificationColor.AZURE.mStringRes));
}
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOff_assertOff() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
}
@Test
public void getFlashNotificationsState_torchNotPresent_cameraOn_screenOff_assertOff() {
setTorchNotPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
}
@Test
public void getFlashNotificationsState_torchPresent_cameraOn_screenOff_assertCamera() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA);
}
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOn_assertScreen() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.SCREEN);
}
@Test
public void testGetFlashNotificationsState_torchPresent_cameraOn_screenOn_assertCameraScreen() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA_SCREEN);
}
private void setTorchPresent() {
CameraCharacteristics cameraCharacteristics = newCameraCharacteristics();
ShadowCameraCharacteristics shadowCameraCharacteristics = extract(cameraCharacteristics);
shadowCameraCharacteristics.set(FLASH_INFO_AVAILABLE, true);
shadowCameraCharacteristics.set(LENS_FACING, LENS_FACING_BACK);
mShadowCameraManager.addCamera("0", cameraCharacteristics);
}
private void setTorchNotPresent() {
CameraCharacteristics cameraCharacteristics = newCameraCharacteristics();
ShadowCameraCharacteristics shadowCameraCharacteristics = extract(cameraCharacteristics);
shadowCameraCharacteristics.set(FLASH_INFO_AVAILABLE, false);
mShadowCameraManager.addCamera("0", cameraCharacteristics);
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static android.content.DialogInterface.BUTTON_NEGATIVE;
import static android.content.DialogInterface.BUTTON_NEUTRAL;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_STOP_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import static com.android.settings.accessibility.ScreenFlashNotificationColor.AZURE;
import static com.android.settings.accessibility.ScreenFlashNotificationColor.BLUE;
import static com.android.settings.accessibility.ScreenFlashNotificationColor.CYAN;
import static com.android.settings.accessibility.ScreenFlashNotificationColor.ROSE;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.Shadows.shadowOf;
import android.content.Intent;
import android.graphics.Color;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowContextWrapper;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class ScreenFlashNotificationColorDialogFragmentTest {
private ShadowContextWrapper mShadowContextWrapper;
private ScreenFlashNotificationColorDialogFragment mDialogFragment;
private AlertDialog mAlertDialog;
private ColorSelectorLayout mColorSelectorLayout;
private int mCurrentColor;
@Before
public void setUp() {
FragmentActivity fragmentActivity = Robolectric.setupActivity(FragmentActivity.class);
mShadowContextWrapper = shadowOf(fragmentActivity);
mCurrentColor = ROSE.mColorInt;
mDialogFragment = ScreenFlashNotificationColorDialogFragment.getInstance(
mCurrentColor, selectedColor -> mCurrentColor = selectedColor
);
mDialogFragment.show(fragmentActivity.getSupportFragmentManager(), "test");
mAlertDialog = (AlertDialog) mDialogFragment.getDialog();
if (mAlertDialog != null) {
mColorSelectorLayout = mAlertDialog.findViewById(R.id.color_selector_preference);
}
}
@Test
public void test_assertShow() {
assertThat(mAlertDialog.isShowing()).isTrue();
}
@Test
public void clickNeutral_assertShow() {
performClickOnDialog(BUTTON_NEUTRAL);
assertThat(mAlertDialog.isShowing()).isTrue();
}
@Test
public void clickNeutral_assertStartPreview() throws InterruptedException {
performClickOnDialog(BUTTON_NEUTRAL);
Thread.sleep(100);
Intent captured = getLastCapturedIntent();
assertThat(captured.getAction()).isEqualTo(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_SHORT_PREVIEW))
.isEqualTo(TYPE_LONG_PREVIEW);
assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR, Color.TRANSPARENT))
.isEqualTo(ROSE.mColorInt);
}
@Test
public void clickNegative_assertNotShow() {
performClickOnDialog(BUTTON_NEGATIVE);
assertThat(mAlertDialog.isShowing()).isFalse();
}
@Test
public void clickPositive_assertNotShow() {
performClickOnDialog(BUTTON_POSITIVE);
assertThat(mAlertDialog.isShowing()).isFalse();
}
@Test
public void clickNeutralAndPause_assertStopPreview() throws InterruptedException {
performClickOnDialog(BUTTON_NEUTRAL);
Thread.sleep(100);
mDialogFragment.onPause();
Thread.sleep(100);
assertThat(getLastCapturedIntent().getAction())
.isEqualTo(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW);
}
@Test
public void clickNeutralAndClickNegative_assertStopPreview() throws InterruptedException {
performClickOnDialog(BUTTON_NEUTRAL);
Thread.sleep(100);
performClickOnDialog(BUTTON_NEGATIVE);
Thread.sleep(100);
assertThat(getLastCapturedIntent().getAction())
.isEqualTo(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW);
}
@Test
public void clickNeutralAndClickPositive_assertStopPreview() throws InterruptedException {
performClickOnDialog(BUTTON_NEUTRAL);
Thread.sleep(100);
performClickOnDialog(BUTTON_POSITIVE);
Thread.sleep(100);
assertThat(getLastCapturedIntent().getAction())
.isEqualTo(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW);
}
@Test
public void clickNeutralAndClickColor_assertStartPreview() throws InterruptedException {
performClickOnDialog(BUTTON_NEUTRAL);
Thread.sleep(100);
checkColorButton(CYAN);
Thread.sleep(500);
Intent captured = getLastCapturedIntent();
assertThat(captured.getAction()).isEqualTo(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_SHORT_PREVIEW))
.isEqualTo(TYPE_LONG_PREVIEW);
assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR, Color.TRANSPARENT))
.isEqualTo(CYAN.mColorInt);
}
@Test
public void clickColorAndClickNegative_assertColor() {
checkColorButton(AZURE);
performClickOnDialog(BUTTON_NEGATIVE);
assertThat(mCurrentColor).isEqualTo(ROSE.mColorInt);
}
@Test
public void clickColorAndClickPositive_assertColor() {
checkColorButton(BLUE);
performClickOnDialog(BUTTON_POSITIVE);
assertThat(mCurrentColor).isEqualTo(BLUE.mColorInt);
}
private void checkColorButton(ScreenFlashNotificationColor color) {
mColorSelectorLayout.setCheckedColor(color.mColorInt);
}
private void performClickOnDialog(int whichButton) {
mAlertDialog.getButton(whichButton).performClick();
}
private Intent getLastCapturedIntent() {
final List<Intent> capturedIntents = new ArrayList<>(
mShadowContextWrapper.getBroadcastIntents());
final int size = capturedIntents.size();
return capturedIntents.get(size - 1);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.ParameterizedRobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(ParameterizedRobolectricTestRunner.class)
public class ScreenFlashNotificationColorTest {
private static final int OPAQUE_COLOR_MASK = 0xFF000000;
@ParameterizedRobolectricTestRunner.Parameters(name = "Color: {0}")
public static List<?> params() {
final List<Object[]> list = new ArrayList<>();
for (ScreenFlashNotificationColor color : ScreenFlashNotificationColor.values()) {
list.add(new Object[]{color});
}
return list;
}
final ScreenFlashNotificationColor mColor;
public ScreenFlashNotificationColorTest(ScreenFlashNotificationColor color) {
mColor = color;
}
@Test
public void colorInt_assertNotTranslucent() {
assertThat(mColor.mColorInt & OPAQUE_COLOR_MASK).isNotEqualTo(0);
}
@Test
public void opaqueColorMask() {
assertThat(mColor.mOpaqueColorInt & OPAQUE_COLOR_MASK).isEqualTo(OPAQUE_COLOR_MASK);
}
@Test
public void stringRes_assertValid() {
assertThat(mColor.mStringRes).isNotEqualTo(0);
}
}

View File

@@ -0,0 +1,207 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Color;
import android.provider.Settings;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import java.util.function.Consumer;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ScreenFlashNotificationPreferenceControllerTest
.ShadowScreenFlashNotificationColorDialogFragment.class,
ShadowFlashNotificationsUtils.class,
})
public class ScreenFlashNotificationPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
private static final String COLOR_DESCRIPTION_TEXT = "Colorful";
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private Preference mPreference;
@Mock
private Fragment mParentFragment;
@Mock
private FragmentManager mFragmentManager;
@Mock
private ScreenFlashNotificationColorDialogFragment mDialogFragment;
private ScreenFlashNotificationPreferenceController mController;
private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FragmentActivity fragmentActivity = Robolectric.setupActivity(FragmentActivity.class);
Context context = fragmentActivity.getApplicationContext();
ShadowScreenFlashNotificationColorDialogFragment.setInstance(mDialogFragment);
ShadowFlashNotificationsUtils.setColorDescriptionText(COLOR_DESCRIPTION_TEXT);
mContentResolver = context.getContentResolver();
mController = new ScreenFlashNotificationPreferenceController(context, PREFERENCE_KEY);
when(mPreferenceScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference);
when(mPreference.getKey()).thenReturn(PREFERENCE_KEY);
mController.setParentFragment(mParentFragment);
when(mParentFragment.getParentFragmentManager()).thenReturn(mFragmentManager);
}
@After
public void tearDown() {
ShadowScreenFlashNotificationColorDialogFragment.reset();
}
@Test
public void getAvailabilityStatus() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void isChecked_setOff_assertFalse() {
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_whenTransparentColor_setTrue_assertNotTransparentColor() {
Settings.System.putInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
.isEqualTo(DEFAULT_SCREEN_FLASH_COLOR);
}
@Test
public void setChecked_whenNotTransparent_setTrue_assertSameColor() {
Settings.System.putInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
.isEqualTo(0x4D0000FF);
}
@Test
public void setChecked_setTrue_assertOn() {
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
0)).isEqualTo(1);
}
@Test
public void setChecked_setFalse_assertOff() {
mController.setChecked(false);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
1)).isEqualTo(0);
}
@Test
public void getSliceHighlightMenuRes() {
assertThat(mController.getSliceHighlightMenuRes())
.isEqualTo(R.string.menu_key_accessibility);
}
@Test
public void getSummary() {
assertThat(mController.getSummary()).isEqualTo(COLOR_DESCRIPTION_TEXT);
}
@Test
public void displayPreference() {
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setSummary(COLOR_DESCRIPTION_TEXT);
}
@Test
public void handlePreferenceTreeClick() {
mController.handlePreferenceTreeClick(mPreference);
verify(mDialogFragment).show(any(FragmentManager.class), anyString());
}
/**
* Note: Actually, shadow of ScreenFlashNotificationColorDialogFragment will not be used.
* Instance that returned with {@link #getInstance} should be set with {@link #setInstance}
*/
@Implements(ScreenFlashNotificationColorDialogFragment.class)
public static class ShadowScreenFlashNotificationColorDialogFragment {
static ScreenFlashNotificationColorDialogFragment sInstance = null;
@Implementation
protected static ScreenFlashNotificationColorDialogFragment getInstance(
int initialColor, Consumer<Integer> colorConsumer) {
return sInstance;
}
public static void setInstance(ScreenFlashNotificationColorDialogFragment instance) {
sInstance = instance;
}
@Resetter
public static void reset() {
sInstance = null;
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.State;
import android.content.Context;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@Implements(FlashNotificationsUtil.class)
public class ShadowFlashNotificationsUtils {
private static boolean sIsTorchAvailable;
private static int sState;
private static String sColorDescriptionText = "";
public static void setIsTorchAvailable(boolean isTorchAvailable) {
sIsTorchAvailable = isTorchAvailable;
}
@Implementation
protected static boolean isTorchAvailable(Context context) {
return sIsTorchAvailable;
}
public static void setFlashNotificationsState(@State int state) {
sState = state;
}
@State
@Implementation
protected static int getFlashNotificationsState(Context context) {
return sState;
}
public static void setColorDescriptionText(@NonNull String text) {
sColorDescriptionText = text;
}
@Implementation
@NonNull
protected static String getColorDescriptionText(@NonNull Context context, @ColorInt int color) {
return sColorDescriptionText;
}
@Resetter
public static void reset() {
sIsTorchAvailable = false;
sState = 0;
sColorDescriptionText = "";
}
}