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