Add the preference controller to control accessibility button preview preference
* Create FloatingMenuLayerDrawable class to handle the preview layer drawable
cherry picked from commit 603014760f
Bug: 173940869
Test: atest AccessibilityButtonPreviewPreferenceControllerTest FloatingMenuLayerDrawableTest
Change-Id: Ia3d030547b377e87c505b2310f559f7f3876ecd5
Merged-In: Ia3d030547b377e87c505b2310f559f7f3876ecd5
This commit is contained in:
70
res/drawable/accessibility_button_navigation.xml
Normal file
70
res/drawable/accessibility_button_navigation.xml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="125dp"
|
||||||
|
android:height="153dp"
|
||||||
|
android:viewportWidth="125"
|
||||||
|
android:viewportHeight="153">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h125v153h-125z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,0h125v153h-125z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M7.4,-62.9L117.6,-62.9A6.3,6.3 0,0 1,123.9 -56.6L123.9,145.6A6.3,6.3 0,0 1,117.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"
|
||||||
|
android:strokeWidth="1.8"
|
||||||
|
android:fillColor="#DADCE0"
|
||||||
|
android:strokeColor="#BDC1C6"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M7.4,-62.9L116.6,-62.9A6.3,6.3 0,0 1,122.9 -56.6L122.9,145.6A6.3,6.3 0,0 1,116.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"
|
||||||
|
android:fillColor="#F8F9FA"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<path
|
||||||
|
android:pathData="M7,126H118V140.6C118,143.582 115.582,146 112.6,146H12.4C9.418,146 7,143.582 7,140.6V126Z"
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:fillAlpha="0.87"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M63.5,138.688C64.713,138.688 65.697,137.708 65.697,136.5C65.697,135.292 64.713,134.312 63.5,134.312C62.286,134.312 61.303,135.292 61.303,136.5C61.303,137.708 62.286,138.688 63.5,138.688Z"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#9AA0A6"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M33.694,133.953C33.827,133.876 33.994,133.972 33.994,134.126V138.874C33.994,139.028 33.827,139.125 33.694,139.047L29.604,136.673C29.471,136.596 29.471,136.404 29.604,136.327L33.694,133.953Z"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#9AA0A6"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M96.111,131.2C96.111,131.86 95.611,132.4 95,132.4C94.389,132.4 93.889,131.86 93.889,131.2C93.889,130.54 94.389,130 95,130C95.611,130 96.111,130.54 96.111,131.2ZM95,133C96.572,133 98.272,132.82 99.722,132.4L100,133.6C98.967,133.9 97.778,134.098 96.667,134.2V142H95.556V138.4H94.444V142H93.333V134.2C92.222,134.098 91.033,133.9 90,133.6L90.278,132.4C91.728,132.82 93.428,133 95,133Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M94.5,135.5m-15.5,0a15.5,15.5 0,1 1,31 0a15.5,15.5 0,1 1,-31 0"
|
||||||
|
android:strokeWidth="4"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#4285F4"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
45
res/drawable/accessibility_button_preview_base.xml
Normal file
45
res/drawable/accessibility_button_preview_base.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="125dp"
|
||||||
|
android:height="153dp"
|
||||||
|
android:viewportWidth="125"
|
||||||
|
android:viewportHeight="153">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h125v153h-125z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,0h125v153h-125z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M7.4,-62.9L117.6,-62.9A6.3,6.3 0,0 1,123.9 -56.6L123.9,145.6A6.3,6.3 0,0 1,117.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"
|
||||||
|
android:strokeWidth="1.8"
|
||||||
|
android:fillColor="#DADCE0"
|
||||||
|
android:strokeColor="#BDC1C6"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M7.4,-62.9L116.6,-62.9A6.3,6.3 0,0 1,122.9 -56.6L122.9,145.6A6.3,6.3 0,0 1,116.6 151.9L7.4,151.9A6.3,6.3 0,0 1,1.1 145.6L1.1,-56.6A6.3,6.3 0,0 1,7.4 -62.9z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"
|
||||||
|
android:fillColor="#F8F9FA"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="125dp"
|
||||||
|
android:height="153dp"
|
||||||
|
android:viewportWidth="125"
|
||||||
|
android:viewportHeight="153">
|
||||||
|
<path
|
||||||
|
android:pathData="M0,0h125v153h-125z"
|
||||||
|
android:fillColor="#00000000"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M89,95h29v34h-29z"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M105,97.5L131,97.5A14.5,14.5 0,0 1,145.5 112L145.5,112A14.5,14.5 0,0 1,131 126.5L105,126.5A14.5,14.5 0,0 1,90.5 112L90.5,112A14.5,14.5 0,0 1,105 97.5z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:strokeColor="#DADCE0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M105.4,112m-11.2,0a11.2,11.2 0,1 1,22.4 0a11.2,11.2 0,1 1,-22.4 0"
|
||||||
|
android:fillColor="#80868B"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M106.467,107.733C106.467,108.32 105.987,108.8 105.4,108.8C104.814,108.8 104.334,108.32 104.334,107.733C104.334,107.147 104.814,106.667 105.4,106.667C105.987,106.667 106.467,107.147 106.467,107.733ZM105.4,109.333C106.91,109.333 108.542,109.173 109.934,108.8L110.2,109.867C109.208,110.133 108.067,110.309 107,110.4V117.333H105.934V114.133H104.867V117.333H103.8V110.4C102.734,110.309 101.592,110.133 100.6,109.867L100.867,108.8C102.259,109.173 103.891,109.333 105.4,109.333Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="125dp"
|
||||||
|
android:height="153dp"
|
||||||
|
android:viewportWidth="125"
|
||||||
|
android:viewportHeight="153">
|
||||||
|
<path
|
||||||
|
android:pathData="M0,0h125v153h-125z"
|
||||||
|
android:fillColor="#00000000"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M89,106h29v22h-29z"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M111,107.5L137,107.5A9.5,9.5 0,0 1,146.5 117L146.5,117A9.5,9.5 0,0 1,137 126.5L111,126.5A9.5,9.5 0,0 1,101.5 117L101.5,117A9.5,9.5 0,0 1,111 107.5z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:strokeColor="#DADCE0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M111.168,116.968m-7.168,0a7.168,7.168 0,1 1,14.336 0a7.168,7.168 0,1 1,-14.336 0"
|
||||||
|
android:fillColor="#80868B"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M111.851,114.237C111.851,114.612 111.543,114.92 111.168,114.92C110.792,114.92 110.485,114.612 110.485,114.237C110.485,113.861 110.792,113.554 111.168,113.554C111.543,113.554 111.851,113.861 111.851,114.237ZM111.168,115.261C112.134,115.261 113.178,115.158 114.069,114.92L114.24,115.602C113.605,115.773 112.875,115.886 112.192,115.944V120.381H111.509V118.333H110.827V120.381H110.144V115.944C109.461,115.886 108.731,115.773 108.096,115.602L108.267,114.92C109.157,115.158 110.202,115.261 111.168,115.261Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
33
res/layout/accessibility_button_preview.xml
Normal file
33
res/layout/accessibility_button_preview.xml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:importantForAccessibility="noHideDescendants">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/preview_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/accessibility_button_preview_height"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="false"
|
||||||
|
android:adjustViewBounds="true"/>
|
||||||
|
</FrameLayout>
|
@@ -57,6 +57,8 @@
|
|||||||
|
|
||||||
<dimen name="color_mode_preview_height">320dp</dimen>
|
<dimen name="color_mode_preview_height">320dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="accessibility_button_preview_height">200dp</dimen>
|
||||||
|
|
||||||
<dimen name="ring_progress_bar_thickness">4dp</dimen>
|
<dimen name="ring_progress_bar_thickness">4dp</dimen>
|
||||||
|
|
||||||
<!-- Weight of the left pane in a multi-pane preference layout. -->
|
<!-- Weight of the left pane in a multi-pane preference layout. -->
|
||||||
|
@@ -19,6 +19,15 @@
|
|||||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
android:title="@string/accessibility_button_title">
|
android:title="@string/accessibility_button_title">
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.LayoutPreference
|
||||||
|
android:key="caption_preview"
|
||||||
|
android:title="@string/summary_placeholder"
|
||||||
|
android:layout="@layout/accessibility_button_preview"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:searchable="false"
|
||||||
|
android:persistent="false"
|
||||||
|
settings:controller="com.android.settings.accessibility.AccessibilityButtonPreviewPreferenceController"/>
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:entries="@array/accessibility_button_location_selector_titles"
|
android:entries="@array/accessibility_button_location_selector_titles"
|
||||||
android:entryValues="@array/accessibility_button_location_selector_values"
|
android:entryValues="@array/accessibility_button_location_selector_values"
|
||||||
|
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||||
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
|
/** Preference controller that controls the preview effect in accessibility button page. */
|
||||||
|
public class AccessibilityButtonPreviewPreferenceController extends BasePreferenceController
|
||||||
|
implements LifecycleObserver, OnResume, OnPause {
|
||||||
|
|
||||||
|
private static final int SMALL_SIZE = 0;
|
||||||
|
private static final float DEFAULT_OPACITY = 0.55f;
|
||||||
|
private static final int DEFAULT_SIZE = 0;
|
||||||
|
|
||||||
|
private final ContentResolver mContentResolver;
|
||||||
|
@VisibleForTesting
|
||||||
|
final ContentObserver mContentObserver;
|
||||||
|
private FloatingMenuLayerDrawable mFloatingMenuPreviewDrawable;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
ImageView mPreview;
|
||||||
|
|
||||||
|
public AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
mContentResolver = context.getContentResolver();
|
||||||
|
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
updatePreviewPreference();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
final LayoutPreference preference = screen.findPreference(getPreferenceKey());
|
||||||
|
mPreview = preference.findViewById(R.id.preview_image);
|
||||||
|
|
||||||
|
updatePreviewPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
mContentResolver.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
|
||||||
|
/* notifyForDescendants= */ false, mContentObserver);
|
||||||
|
mContentResolver.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
|
||||||
|
/* notifyForDescendants= */ false, mContentObserver);
|
||||||
|
mContentResolver.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
|
||||||
|
/* notifyForDescendants= */ false, mContentObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePreviewPreference() {
|
||||||
|
if (AccessibilityUtil.isFloatingMenuEnabled(mContext)) {
|
||||||
|
final int size = Settings.Secure.getInt(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, DEFAULT_SIZE);
|
||||||
|
final int opacity = (int) (Settings.Secure.getFloat(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY) * 100);
|
||||||
|
final int floatingMenuIconId = (size == SMALL_SIZE)
|
||||||
|
? R.drawable.accessibility_button_preview_small_floating_menu
|
||||||
|
: R.drawable.accessibility_button_preview_large_floating_menu;
|
||||||
|
|
||||||
|
mPreview.setImageDrawable(getFloatingMenuPreviewDrawable(floatingMenuIconId, opacity));
|
||||||
|
// Only change opacity(alpha) would not invoke redraw view, need to invalidate manually.
|
||||||
|
mPreview.invalidate();
|
||||||
|
} else {
|
||||||
|
mPreview.setImageDrawable(
|
||||||
|
mContext.getDrawable(R.drawable.accessibility_button_navigation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable getFloatingMenuPreviewDrawable(int resId, int opacity) {
|
||||||
|
if (mFloatingMenuPreviewDrawable == null) {
|
||||||
|
mFloatingMenuPreviewDrawable = FloatingMenuLayerDrawable.createLayerDrawable(
|
||||||
|
mContext, resId, opacity);
|
||||||
|
} else {
|
||||||
|
mFloatingMenuPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mFloatingMenuPreviewDrawable;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.LayerDrawable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** LayerDrawable that contains device icon as background and floating menu icon as foreground. */
|
||||||
|
public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||||
|
|
||||||
|
private FloatingMenuLayerDrawableState mState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new layer drawable with the list of specified layers.
|
||||||
|
*
|
||||||
|
* @param layers a list of drawables to use as layers in this new drawable,
|
||||||
|
* must be non-null
|
||||||
|
*/
|
||||||
|
private FloatingMenuLayerDrawable(@NonNull Drawable[] layers) {
|
||||||
|
super(layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the {@link LayerDrawable} that contains device icon as background and floating menu
|
||||||
|
* icon with given {@code opacity} value as foreground.
|
||||||
|
*
|
||||||
|
* @param context the valid context used to get the icon
|
||||||
|
* @param resId the resource ID of the floating menu icon
|
||||||
|
* @param opacity the opacity to apply to the given icon
|
||||||
|
* @return the drawable that combines the device icon and the floating menu icon
|
||||||
|
*/
|
||||||
|
public static FloatingMenuLayerDrawable createLayerDrawable(Context context, int resId,
|
||||||
|
int opacity) {
|
||||||
|
final Drawable bg = context.getDrawable(R.drawable.accessibility_button_preview_base);
|
||||||
|
final FloatingMenuLayerDrawable basicDrawable = new FloatingMenuLayerDrawable(
|
||||||
|
new Drawable[]{bg, null});
|
||||||
|
|
||||||
|
basicDrawable.updateLayerDrawable(context, resId, opacity);
|
||||||
|
return basicDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the drawable with given {@code resId} drawable and {@code opacity}(alpha)
|
||||||
|
* value at index 1 layer.
|
||||||
|
*
|
||||||
|
* @param context the valid context used to get the icon
|
||||||
|
* @param resId the resource ID of the floating menu icon
|
||||||
|
* @param opacity the opacity to apply to the given icon
|
||||||
|
*/
|
||||||
|
public void updateLayerDrawable(Context context, int resId, int opacity) {
|
||||||
|
final Drawable icon = context.getDrawable(resId);
|
||||||
|
icon.setAlpha(opacity);
|
||||||
|
this.setDrawable(/* index= */ 1, icon);
|
||||||
|
this.setConstantState(context, resId, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstantState getConstantState() {
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stores the constant state and data to the given drawable. */
|
||||||
|
private void setConstantState(Context context, int resId, int opacity) {
|
||||||
|
mState = new FloatingMenuLayerDrawableState(context, resId, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@link ConstantState} to store the data of {@link FloatingMenuLayerDrawable}. */
|
||||||
|
@VisibleForTesting
|
||||||
|
static class FloatingMenuLayerDrawableState extends ConstantState {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final int mResId;
|
||||||
|
private final int mOpacity;
|
||||||
|
|
||||||
|
FloatingMenuLayerDrawableState(Context context, int resId, int opacity) {
|
||||||
|
mContext = context;
|
||||||
|
mResId = resId;
|
||||||
|
mOpacity = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Drawable newDrawable() {
|
||||||
|
return createLayerDrawable(mContext, mResId, mOpacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChangingConfigurations() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final FloatingMenuLayerDrawableState that = (FloatingMenuLayerDrawableState) o;
|
||||||
|
return mResId == that.mResId
|
||||||
|
&& mOpacity == that.mOpacity
|
||||||
|
&& Objects.equals(mContext, that.mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mContext, mResId, mOpacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
|
||||||
|
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Tests for {@link AccessibilityButtonPreviewPreferenceController}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class AccessibilityButtonPreviewPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockitoRule mocks = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
@Mock
|
||||||
|
private ContentResolver mContentResolver;
|
||||||
|
private AccessibilityButtonPreviewPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||||
|
mController = new AccessibilityButtonPreviewPreferenceController(mContext, "test_key");
|
||||||
|
mController.mPreview = new ImageView(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onChange_a11yBtnModeNavigationBar_getNavigationBarDrawable() {
|
||||||
|
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
|
||||||
|
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
|
||||||
|
|
||||||
|
mController.mContentObserver.onChange(false);
|
||||||
|
|
||||||
|
final Drawable navigationBarDrawable = mContext.getDrawable(
|
||||||
|
R.drawable.accessibility_button_navigation);
|
||||||
|
assertThat(mController.mPreview.getDrawable().getConstantState()).isEqualTo(
|
||||||
|
navigationBarDrawable.getConstantState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onChange_updatePreviewPreferenceWithConfig_expectedPreviewDrawable() {
|
||||||
|
Settings.Secure.putInt(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
|
||||||
|
Settings.Secure.putInt(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, /* small size */ 0);
|
||||||
|
Settings.Secure.putFloat(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.1f);
|
||||||
|
|
||||||
|
mController.mContentObserver.onChange(false);
|
||||||
|
|
||||||
|
final Drawable smallFloatingMenuWithTenOpacityDrawable =
|
||||||
|
FloatingMenuLayerDrawable.createLayerDrawable(mContext,
|
||||||
|
R.drawable.accessibility_button_preview_small_floating_menu, 10);
|
||||||
|
assertThat(mController.mPreview.getDrawable().getConstantState()).isEqualTo(
|
||||||
|
smallFloatingMenuWithTenOpacityDrawable.getConstantState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onResume_registerSpecificContentObserver() {
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mContentResolver).registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false,
|
||||||
|
mController.mContentObserver);
|
||||||
|
verify(mContentResolver).registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE), false,
|
||||||
|
mController.mContentObserver);
|
||||||
|
verify(mContentResolver).registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
|
||||||
|
false,
|
||||||
|
mController.mContentObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPause_unregisterContentObserver() {
|
||||||
|
mController.onPause();
|
||||||
|
|
||||||
|
verify(mContentResolver).unregisterContentObserver(mController.mContentObserver);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Tests for {@link FloatingMenuLayerDrawable}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class FloatingMenuLayerDrawableTest {
|
||||||
|
|
||||||
|
private static final int TEST_RES_ID =
|
||||||
|
com.android.internal.R.drawable.ic_accessibility_magnification;
|
||||||
|
private static final int TEST_RES_ID_2 =
|
||||||
|
com.android.internal.R.drawable.ic_accessibility_color_inversion;
|
||||||
|
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createLayerDrawable_configCorrect() {
|
||||||
|
final Drawable expected1stDrawable = mContext.getDrawable(
|
||||||
|
R.drawable.accessibility_button_preview_base);
|
||||||
|
final Drawable expected2ndDrawable = mContext.getDrawable(TEST_RES_ID);
|
||||||
|
|
||||||
|
final FloatingMenuLayerDrawable actualDrawable =
|
||||||
|
FloatingMenuLayerDrawable.createLayerDrawable(mContext, TEST_RES_ID,
|
||||||
|
/* opacity= */ 27);
|
||||||
|
|
||||||
|
final Drawable actual1stDrawable = actualDrawable.getDrawable(0);
|
||||||
|
final Drawable actual2ndDrawable = actualDrawable.getDrawable(1);
|
||||||
|
// These are VectorDrawables, so it can use getConstantState() to compare.
|
||||||
|
assertThat(actual1stDrawable.getConstantState()).isEqualTo(
|
||||||
|
expected1stDrawable.getConstantState());
|
||||||
|
assertThat(actual2ndDrawable.getConstantState()).isEqualTo(
|
||||||
|
expected2ndDrawable.getConstantState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateLayerDrawable_expectedFloatingMenuLayerDrawableState() {
|
||||||
|
final FloatingMenuLayerDrawable originalDrawable =
|
||||||
|
FloatingMenuLayerDrawable.createLayerDrawable(mContext, TEST_RES_ID, /* opacity= */
|
||||||
|
72);
|
||||||
|
|
||||||
|
originalDrawable.updateLayerDrawable(mContext, TEST_RES_ID_2, /* opacity= */ 27);
|
||||||
|
|
||||||
|
assertThat(originalDrawable.getConstantState()).isEqualTo(
|
||||||
|
new FloatingMenuLayerDrawable.FloatingMenuLayerDrawableState(mContext,
|
||||||
|
TEST_RES_ID_2, /* opacity= */ 27));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user