Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7aa3c043 authored by PETER LIANG's avatar PETER LIANG Committed by Android (Google) Code Review
Browse files

Merge changes Id8085500,I986406b5,Ie9ee39c1

* changes:
  Refactor the design and improve the animations of Accessibility Floating Menu(3/n).
  Refactor the design and improve the animations of Accessibility Floating Menu(2/n).
  Refactor the design and improve the animations of Accessibility Floating Menu(1/n).
parents 4d05eedd b32a9d20
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -20,4 +20,7 @@
    <!-- Height of the background gradient behind the screenshot UI (taller in dark mode) -->
    <dimen name="screenshot_bg_protection_height">375dp</dimen>

    <!-- Accessibility floating menu -->
    <dimen name="accessibility_floating_menu_stroke_width">1dp</dimen>
    <dimen name="accessibility_floating_menu_stroke_inset">-2dp</dimen>
</resources>
 No newline at end of file
+2 −2
Original line number Diff line number Diff line
@@ -1323,8 +1323,8 @@

    <!-- Accessibility floating menu -->
    <dimen name="accessibility_floating_menu_elevation">3dp</dimen>
    <dimen name="accessibility_floating_menu_stroke_width">1dp</dimen>
    <dimen name="accessibility_floating_menu_stroke_inset">-2dp</dimen>
    <dimen name="accessibility_floating_menu_stroke_width">0dp</dimen>
    <dimen name="accessibility_floating_menu_stroke_inset">0dp</dimen>
    <dimen name="accessibility_floating_menu_margin">16dp</dimen>
    <dimen name="accessibility_floating_menu_small_padding">6dp</dimen>
    <dimen name="accessibility_floating_menu_small_width_height">36dp</dimen>
+26 −2
Original line number Diff line number Diff line
@@ -17,10 +17,17 @@
package com.android.systemui.accessibility.floatingmenu;

import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;

import static com.android.systemui.flags.Flags.A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS;

import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.view.Display;
import android.view.WindowManager;

import androidx.annotation.MainThread;

@@ -31,6 +38,7 @@ 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 com.android.systemui.flags.FeatureFlags;

import javax.inject.Inject;

@@ -46,6 +54,9 @@ public class AccessibilityFloatingMenuController implements
    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;

    private Context mContext;
    private final WindowManager mWindowManager;
    private final DisplayManager mDisplayManager;
    private final FeatureFlags mFeatureFlags;
    @VisibleForTesting
    IAccessibilityFloatingMenu mFloatingMenu;
    private int mBtnMode;
@@ -83,13 +94,19 @@ public class AccessibilityFloatingMenuController implements

    @Inject
    public AccessibilityFloatingMenuController(Context context,
            WindowManager windowManager,
            DisplayManager displayManager,
            AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
            KeyguardUpdateMonitor keyguardUpdateMonitor) {
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            FeatureFlags featureFlags) {
        mContext = context;
        mWindowManager = windowManager;
        mDisplayManager = displayManager;
        mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mFeatureFlags = featureFlags;

        mIsKeyguardVisible = false;
    }
@@ -159,8 +176,15 @@ public class AccessibilityFloatingMenuController implements

    private void showFloatingMenu() {
        if (mFloatingMenu == null) {
            if (mFeatureFlags.isEnabled(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS)) {
                final Display defaultDisplay = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
                mFloatingMenu = new MenuViewLayerController(
                        mContext.createWindowContext(defaultDisplay,
                                TYPE_NAVIGATION_BAR_PANEL, /* options= */ null), mWindowManager);
            } else {
                mFloatingMenu = new AccessibilityFloatingMenu(mContext);
            }
        }

        mFloatingMenu.show();
    }
+112 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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_FLOATING_MENU_SIZE;
import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;

import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;

import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;

import java.util.List;

/**
 * Stores and observe the settings contents for the menu view.
 */
class MenuInfoRepository {
    private final Context mContext;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final OnSettingsContentsChanged mSettingsContentsCallback;

    private final ContentObserver mMenuTargetFeaturesContentObserver =
            new ContentObserver(mHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    mSettingsContentsCallback.onTargetFeaturesChanged(
                            getTargets(mContext, ACCESSIBILITY_BUTTON));
                }
            };

    @VisibleForTesting
    final ContentObserver mMenuSizeContentObserver =
            new ContentObserver(mHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    mSettingsContentsCallback.onSizeTypeChanged(
                            getMenuSizeTypeFromSettings(mContext));
                }
            };

    MenuInfoRepository(Context context, OnSettingsContentsChanged settingsContentsChanged) {
        mContext = context;
        mSettingsContentsCallback = settingsContentsChanged;
    }

    void loadMenuTargetFeatures(OnInfoReady<List<AccessibilityTarget>> callback) {
        callback.onReady(getTargets(mContext, ACCESSIBILITY_BUTTON));
    }

    void loadMenuSizeType(OnInfoReady<Integer> callback) {
        callback.onReady(getMenuSizeTypeFromSettings(mContext));
    }

    void registerContentObservers() {
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
                /* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver,
                UserHandle.USER_CURRENT);
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(ENABLED_ACCESSIBILITY_SERVICES),
                /* notifyForDescendants */ false,
                mMenuTargetFeaturesContentObserver, UserHandle.USER_CURRENT);
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
                /* notifyForDescendants */ false, mMenuSizeContentObserver,
                UserHandle.USER_CURRENT);
    }

    void unregisterContentObservers() {
        mContext.getContentResolver().unregisterContentObserver(mMenuTargetFeaturesContentObserver);
        mContext.getContentResolver().unregisterContentObserver(mMenuSizeContentObserver);
    }

    interface OnSettingsContentsChanged {
        void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures);

        void onSizeTypeChanged(int newSizeType);
    }

    interface OnInfoReady<T> {
        void onReady(T info);
    }

    private static int getMenuSizeTypeFromSettings(Context context) {
        return Settings.Secure.getIntForUser(context.getContentResolver(),
                ACCESSIBILITY_FLOATING_MENU_SIZE, SMALL, UserHandle.USER_CURRENT);
    }
}
+153 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.view.ViewGroup.LayoutParams.WRAP_CONTENT;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.GradientDrawable;
import android.widget.FrameLayout;

import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.internal.accessibility.dialog.AccessibilityTarget;

import java.util.ArrayList;
import java.util.List;

/**
 * The container view displays the accessibility features.
 */
@SuppressLint("ViewConstructor")
class MenuView extends FrameLayout {
    private static final int INDEX_MENU_ITEM = 0;
    private final List<AccessibilityTarget> mTargetFeatures = new ArrayList<>();
    private final AccessibilityTargetAdapter mAdapter;
    private final MenuViewModel mMenuViewModel;
    private final RecyclerView mTargetFeaturesView;
    private final Observer<Integer> mSizeTypeObserver = this::onSizeTypeChanged;
    private final Observer<List<AccessibilityTarget>> mTargetFeaturesObserver =
            this::onTargetFeaturesChanged;
    private final MenuViewAppearance mMenuViewAppearance;

    MenuView(Context context, MenuViewModel menuViewModel, MenuViewAppearance menuViewAppearance) {
        super(context);

        mMenuViewModel = menuViewModel;
        mMenuViewAppearance = menuViewAppearance;
        mAdapter = new AccessibilityTargetAdapter(mTargetFeatures);
        mTargetFeaturesView = new RecyclerView(context);
        mTargetFeaturesView.setAdapter(mAdapter);
        mTargetFeaturesView.setLayoutManager(new LinearLayoutManager(context));
        setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
        // Avoid drawing out of bounds of the parent view
        setClipToOutline(true);
        loadLayoutResources();

        addView(mTargetFeaturesView);
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        loadLayoutResources();
    }

    @SuppressLint("NotifyDataSetChanged")
    private void onItemSizeChanged() {
        mAdapter.setItemPadding(mMenuViewAppearance.getMenuPadding());
        mAdapter.setIconWidthHeight(mMenuViewAppearance.getMenuIconSize());
        mAdapter.notifyDataSetChanged();
    }

    private void onSizeChanged() {
        final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
        layoutParams.height = mMenuViewAppearance.getMenuHeight();
        setLayoutParams(layoutParams);
    }

    private void onEdgeChanged() {
        final int[] insets = mMenuViewAppearance.getMenuInsets();
        getContainerViewInsetLayer().setLayerInset(INDEX_MENU_ITEM, insets[0], insets[1], insets[2],
                insets[3]);

        final GradientDrawable gradientDrawable = getContainerViewGradient();
        gradientDrawable.setCornerRadii(mMenuViewAppearance.getMenuRadii());
        gradientDrawable.setStroke(mMenuViewAppearance.getMenuStrokeWidth(),
                mMenuViewAppearance.getMenuStrokeColor());
    }

    @SuppressLint("NotifyDataSetChanged")
    private void onSizeTypeChanged(int newSizeType) {
        mMenuViewAppearance.setSizeType(newSizeType);

        mAdapter.setItemPadding(mMenuViewAppearance.getMenuPadding());
        mAdapter.setIconWidthHeight(mMenuViewAppearance.getMenuIconSize());
        mAdapter.notifyDataSetChanged();

        onSizeChanged();
        onEdgeChanged();
    }

    private void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures) {
        // TODO(b/252756133): Should update specific item instead of the whole list
        mTargetFeatures.clear();
        mTargetFeatures.addAll(newTargetFeatures);
        mMenuViewAppearance.setTargetFeaturesSize(mTargetFeatures.size());
        mAdapter.notifyDataSetChanged();

        onSizeChanged();
        onEdgeChanged();
    }

    void show() {
        mMenuViewModel.getTargetFeaturesData().observeForever(mTargetFeaturesObserver);
        mMenuViewModel.getSizeTypeData().observeForever(mSizeTypeObserver);
        setVisibility(VISIBLE);
        mMenuViewModel.registerContentObservers();
    }

    void hide() {
        setVisibility(GONE);
        mMenuViewModel.getTargetFeaturesData().removeObserver(mTargetFeaturesObserver);
        mMenuViewModel.getSizeTypeData().removeObserver(mSizeTypeObserver);
        mMenuViewModel.unregisterContentObservers();
    }

    void loadLayoutResources() {
        mMenuViewAppearance.update();

        setBackground(mMenuViewAppearance.getMenuBackground());
        setElevation(mMenuViewAppearance.getMenuElevation());
        onItemSizeChanged();
        onSizeChanged();
        onEdgeChanged();
    }

    private InstantInsetLayerDrawable getContainerViewInsetLayer() {
        return (InstantInsetLayerDrawable) getBackground();
    }

    private GradientDrawable getContainerViewGradient() {
        return (GradientDrawable) getContainerViewInsetLayer().getDrawable(INDEX_MENU_ITEM);
    }
}
Loading