1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.accessibility;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.database.ContentObserver;
22 import android.graphics.drawable.Drawable;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.provider.Settings;
26 import android.view.accessibility.AccessibilityManager;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.PreferenceScreen;
30 
31 import com.android.settings.R;
32 import com.android.settings.core.BasePreferenceController;
33 import com.android.settingslib.core.lifecycle.LifecycleObserver;
34 import com.android.settingslib.core.lifecycle.events.OnPause;
35 import com.android.settingslib.core.lifecycle.events.OnResume;
36 import com.android.settingslib.widget.IllustrationPreference;
37 
38 /** Preference controller that controls the preview effect in accessibility button page. */
39 public class AccessibilityButtonPreviewPreferenceController extends BasePreferenceController
40         implements LifecycleObserver, OnResume, OnPause {
41 
42     private static final int SMALL_SIZE = 0;
43     private static final float DEFAULT_OPACITY = 0.55f;
44     private static final int DEFAULT_SIZE = 0;
45 
46     private final ContentResolver mContentResolver;
47     @VisibleForTesting
48     final ContentObserver mContentObserver;
49     private AccessibilityLayerDrawable mAccessibilityPreviewDrawable;
50     @VisibleForTesting
51     IllustrationPreference mIllustrationPreference;
52 
53     private AccessibilityManager.TouchExplorationStateChangeListener
54             mTouchExplorationStateChangeListener;
55 
AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey)56     public AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey) {
57         super(context, preferenceKey);
58         mContentResolver = context.getContentResolver();
59         mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
60             @Override
61             public void onChange(boolean selfChange) {
62                 updatePreviewPreference();
63             }
64         };
65         mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
66             updatePreviewPreference();
67         };
68     }
69 
70     @Override
getAvailabilityStatus()71     public int getAvailabilityStatus() {
72         return AVAILABLE;
73     }
74 
75     @Override
displayPreference(PreferenceScreen screen)76     public void displayPreference(PreferenceScreen screen) {
77         super.displayPreference(screen);
78         mIllustrationPreference = screen.findPreference(getPreferenceKey());
79 
80         updatePreviewPreference();
81     }
82 
83     @Override
onResume()84     public void onResume() {
85         final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
86         am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
87 
88         mContentResolver.registerContentObserver(
89                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
90                 /* notifyForDescendants= */ false, mContentObserver);
91         mContentResolver.registerContentObserver(
92                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
93                 /* notifyForDescendants= */ false, mContentObserver);
94         mContentResolver.registerContentObserver(
95                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
96                 /* notifyForDescendants= */ false, mContentObserver);
97     }
98 
99     @Override
onPause()100     public void onPause() {
101         final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
102         am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
103 
104         mContentResolver.unregisterContentObserver(mContentObserver);
105     }
106 
updatePreviewPreference()107     private void updatePreviewPreference() {
108         if (AccessibilityUtil.isFloatingMenuEnabled(mContext)) {
109             final int size = Settings.Secure.getInt(mContentResolver,
110                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, DEFAULT_SIZE);
111             final int opacity = (int) (Settings.Secure.getFloat(mContentResolver,
112                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY) * 100);
113             final int floatingMenuIconId = (size == SMALL_SIZE)
114                     ? R.drawable.accessibility_button_preview_small_floating_menu
115                     : R.drawable.accessibility_button_preview_large_floating_menu;
116             mIllustrationPreference.setImageDrawable(
117                     getAccessibilityPreviewDrawable(floatingMenuIconId, opacity));
118         } else if (AccessibilityUtil.isGestureNavigateEnabled(mContext)) {
119             mIllustrationPreference.setImageDrawable(mContext.getDrawable(
120                     AccessibilityUtil.isTouchExploreEnabled(mContext)
121                             ? R.drawable.accessibility_button_preview_three_finger
122                             : R.drawable.accessibility_button_preview_two_finger));
123         } else {
124             mIllustrationPreference.setImageDrawable(
125                     mContext.getDrawable(R.drawable.accessibility_button_navigation));
126         }
127     }
128 
getAccessibilityPreviewDrawable(int resId, int opacity)129     private Drawable getAccessibilityPreviewDrawable(int resId, int opacity) {
130         if (mAccessibilityPreviewDrawable == null) {
131             mAccessibilityPreviewDrawable = AccessibilityLayerDrawable.createLayerDrawable(
132                     mContext, resId, opacity);
133         } else {
134             mAccessibilityPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
135             // Only change alpha (opacity) value did not change drawable id. It needs to force to
136             // redraw.
137             mAccessibilityPreviewDrawable.invalidateSelf();
138         }
139         return mAccessibilityPreviewDrawable;
140     }
141 }
142