| /* |
| * 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.systemui.accessibility.floatingmenu; |
| |
| import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; |
| |
| import android.content.Context; |
| import android.os.UserHandle; |
| import android.text.TextUtils; |
| |
| import androidx.annotation.MainThread; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.keyguard.KeyguardUpdateMonitor; |
| import com.android.keyguard.KeyguardUpdateMonitorCallback; |
| import com.android.systemui.accessibility.AccessibilityButtonModeObserver; |
| import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode; |
| import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; |
| import com.android.systemui.dagger.SysUISingleton; |
| |
| import javax.inject.Inject; |
| |
| /** A controller to handle the lifecycle of accessibility floating menu. */ |
| @MainThread |
| @SysUISingleton |
| public class AccessibilityFloatingMenuController implements |
| AccessibilityButtonModeObserver.ModeChangedListener, |
| AccessibilityButtonTargetsObserver.TargetsChangedListener { |
| |
| private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; |
| private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; |
| private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; |
| |
| private Context mContext; |
| @VisibleForTesting |
| IAccessibilityFloatingMenu mFloatingMenu; |
| private int mBtnMode; |
| private String mBtnTargets; |
| private boolean mIsKeyguardVisible; |
| private boolean mIsAccessibilityManagerServiceReady; |
| |
| @VisibleForTesting |
| final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() { |
| // Accessibility floating menu needs to retrieve information from |
| // AccessibilityManagerService, and it would be ready before onUserUnlocked(). |
| @Override |
| public void onUserUnlocked() { |
| mIsAccessibilityManagerServiceReady = true; |
| handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); |
| } |
| |
| // Keyguard state would be changed before AccessibilityManagerService is ready to retrieve, |
| // need to wait until receive onUserUnlocked(). |
| @Override |
| public void onKeyguardVisibilityChanged(boolean showing) { |
| mIsKeyguardVisible = showing; |
| if (mIsAccessibilityManagerServiceReady) { |
| handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); |
| } |
| } |
| |
| @Override |
| public void onUserSwitching(int userId) { |
| destroyFloatingMenu(); |
| } |
| |
| @Override |
| public void onUserSwitchComplete(int userId) { |
| mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); |
| mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); |
| mBtnTargets = |
| mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); |
| handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); |
| } |
| }; |
| |
| @Inject |
| public AccessibilityFloatingMenuController(Context context, |
| AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, |
| AccessibilityButtonModeObserver accessibilityButtonModeObserver, |
| KeyguardUpdateMonitor keyguardUpdateMonitor) { |
| mContext = context; |
| mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; |
| mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; |
| mKeyguardUpdateMonitor = keyguardUpdateMonitor; |
| |
| init(); |
| } |
| |
| /** |
| * Handles visibility of the accessibility floating menu when accessibility button mode changes. |
| * |
| * @param mode Current accessibility button mode. |
| */ |
| @Override |
| public void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode) { |
| mBtnMode = mode; |
| handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); |
| } |
| |
| /** |
| * Handles visibility of the accessibility floating menu when accessibility button targets |
| * changes. |
| * List should come from {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. |
| * @param targets Current accessibility button list. |
| */ |
| @Override |
| public void onAccessibilityButtonTargetsChanged(String targets) { |
| mBtnTargets = targets; |
| handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); |
| } |
| |
| private void init() { |
| mIsKeyguardVisible = false; |
| mIsAccessibilityManagerServiceReady = false; |
| mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); |
| mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); |
| registerContentObservers(); |
| } |
| |
| private void registerContentObservers() { |
| mAccessibilityButtonModeObserver.addListener(this); |
| mAccessibilityButtonTargetsObserver.addListener(this); |
| mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback); |
| } |
| |
| /** |
| * Handles the accessibility floating menu visibility with the given values. |
| * |
| * @param keyguardVisible the keyguard visibility status. Not show the |
| * {@link AccessibilityFloatingMenu} when keyguard appears. |
| * @param mode accessibility button mode {@link AccessibilityButtonMode} |
| * @param targets accessibility button list; it should comes from |
| * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. |
| */ |
| private void handleFloatingMenuVisibility(boolean keyguardVisible, |
| @AccessibilityButtonMode int mode, String targets) { |
| if (keyguardVisible) { |
| destroyFloatingMenu(); |
| return; |
| } |
| |
| if (shouldShowFloatingMenu(mode, targets)) { |
| showFloatingMenu(); |
| } else { |
| destroyFloatingMenu(); |
| } |
| } |
| |
| private boolean shouldShowFloatingMenu(@AccessibilityButtonMode int mode, String targets) { |
| return mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU && !TextUtils.isEmpty(targets); |
| } |
| |
| private void showFloatingMenu() { |
| if (mFloatingMenu == null) { |
| mFloatingMenu = new AccessibilityFloatingMenu(mContext); |
| } |
| |
| mFloatingMenu.show(); |
| } |
| |
| private void destroyFloatingMenu() { |
| if (mFloatingMenu == null) { |
| return; |
| } |
| |
| mFloatingMenu.hide(); |
| mFloatingMenu = null; |
| } |
| } |