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).
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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,7 +176,14 @@ public class AccessibilityFloatingMenuController implements
|
||||
|
||||
private void showFloatingMenu() {
|
||||
if (mFloatingMenu == null) {
|
||||
mFloatingMenu = new AccessibilityFloatingMenu(mContext);
|
||||
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();
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.DimenRes;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Provides the layout resources information of the {@link MenuView}.
|
||||
*/
|
||||
class MenuViewAppearance {
|
||||
private final Resources mRes;
|
||||
private int mTargetFeaturesSize;
|
||||
private int mSizeType;
|
||||
private int mSmallPadding;
|
||||
private int mLargePadding;
|
||||
private int mSmallIconSize;
|
||||
private int mLargeIconSize;
|
||||
private int mSmallSingleRadius;
|
||||
private int mSmallMultipleRadius;
|
||||
private int mLargeSingleRadius;
|
||||
private int mLargeMultipleRadius;
|
||||
private int mStrokeWidth;
|
||||
private int mStrokeColor;
|
||||
private int mInset;
|
||||
private int mElevation;
|
||||
private float[] mRadii;
|
||||
private Drawable mBackgroundDrawable;
|
||||
|
||||
@IntDef({
|
||||
SMALL,
|
||||
MenuSizeType.LARGE
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface MenuSizeType {
|
||||
int SMALL = 0;
|
||||
int LARGE = 1;
|
||||
}
|
||||
|
||||
MenuViewAppearance(Context context) {
|
||||
mRes = context.getResources();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void update() {
|
||||
mSmallPadding =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_padding);
|
||||
mLargePadding =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_large_padding);
|
||||
mSmallIconSize =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_width_height);
|
||||
mLargeIconSize =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_large_width_height);
|
||||
mSmallSingleRadius =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_single_radius);
|
||||
mSmallMultipleRadius = mRes.getDimensionPixelSize(
|
||||
R.dimen.accessibility_floating_menu_small_multiple_radius);
|
||||
mRadii = createRadii(getMenuRadius(mTargetFeaturesSize));
|
||||
mLargeSingleRadius =
|
||||
mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_large_single_radius);
|
||||
mLargeMultipleRadius = mRes.getDimensionPixelSize(
|
||||
R.dimen.accessibility_floating_menu_large_multiple_radius);
|
||||
mStrokeWidth = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_width);
|
||||
mStrokeColor = mRes.getColor(R.color.accessibility_floating_menu_stroke_dark);
|
||||
mInset = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset);
|
||||
mElevation = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
|
||||
final Drawable drawable =
|
||||
mRes.getDrawable(R.drawable.accessibility_floating_menu_background);
|
||||
mBackgroundDrawable = new InstantInsetLayerDrawable(new Drawable[]{drawable});
|
||||
}
|
||||
|
||||
void setSizeType(int sizeType) {
|
||||
mSizeType = sizeType;
|
||||
|
||||
mRadii = createRadii(getMenuRadius(mTargetFeaturesSize));
|
||||
}
|
||||
|
||||
void setTargetFeaturesSize(int targetFeaturesSize) {
|
||||
mTargetFeaturesSize = targetFeaturesSize;
|
||||
|
||||
mRadii = createRadii(getMenuRadius(targetFeaturesSize));
|
||||
}
|
||||
|
||||
Drawable getMenuBackground() {
|
||||
return mBackgroundDrawable;
|
||||
}
|
||||
|
||||
int getMenuElevation() {
|
||||
return mElevation;
|
||||
}
|
||||
|
||||
int getMenuHeight() {
|
||||
return calculateActualMenuHeight();
|
||||
}
|
||||
|
||||
int getMenuIconSize() {
|
||||
return mSizeType == SMALL ? mSmallIconSize : mLargeIconSize;
|
||||
}
|
||||
|
||||
int getMenuPadding() {
|
||||
return mSizeType == SMALL ? mSmallPadding : mLargePadding;
|
||||
}
|
||||
|
||||
int[] getMenuInsets() {
|
||||
return new int[]{mInset, 0, 0, 0};
|
||||
}
|
||||
|
||||
int getMenuStrokeWidth() {
|
||||
return mStrokeWidth;
|
||||
}
|
||||
|
||||
int getMenuStrokeColor() {
|
||||
return mStrokeColor;
|
||||
}
|
||||
|
||||
float[] getMenuRadii() {
|
||||
return mRadii;
|
||||
}
|
||||
|
||||
private int getMenuRadius(int itemCount) {
|
||||
return mSizeType == SMALL ? getSmallSize(itemCount) : getLargeSize(itemCount);
|
||||
}
|
||||
|
||||
@DimenRes
|
||||
private int getSmallSize(int itemCount) {
|
||||
return itemCount > 1 ? mSmallMultipleRadius : mSmallSingleRadius;
|
||||
}
|
||||
|
||||
@DimenRes
|
||||
private int getLargeSize(int itemCount) {
|
||||
return itemCount > 1 ? mLargeMultipleRadius : mLargeSingleRadius;
|
||||
}
|
||||
|
||||
private static float[] createRadii(float radius) {
|
||||
return new float[]{0.0f, 0.0f, radius, radius, radius, radius, 0.0f, 0.0f};
|
||||
}
|
||||
|
||||
private int calculateActualMenuHeight() {
|
||||
final int menuPadding = getMenuPadding();
|
||||
|
||||
return (menuPadding + getMenuIconSize()) * mTargetFeaturesSize + menuPadding;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 android.annotation.IntDef;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* The basic interactions with the child view {@link MenuView}.
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class MenuViewLayer extends FrameLayout {
|
||||
private final MenuView mMenuView;
|
||||
|
||||
@IntDef({
|
||||
LayerIndex.MENU_VIEW
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface LayerIndex {
|
||||
int MENU_VIEW = 0;
|
||||
}
|
||||
|
||||
MenuViewLayer(@NonNull Context context) {
|
||||
super(context);
|
||||
|
||||
final MenuViewModel menuViewModel = new MenuViewModel(context);
|
||||
final MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context);
|
||||
mMenuView = new MenuView(context, menuViewModel, menuViewAppearance);
|
||||
|
||||
addView(mMenuView, LayerIndex.MENU_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
mMenuView.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
mMenuView.hide();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/**
|
||||
* Controls the {@link MenuViewLayer} whether to be attached to the window via the interface
|
||||
* of {@link IAccessibilityFloatingMenu}.
|
||||
*/
|
||||
class MenuViewLayerController implements IAccessibilityFloatingMenu {
|
||||
private final WindowManager mWindowManager;
|
||||
private final MenuViewLayer mMenuViewLayer;
|
||||
private boolean mIsShowing;
|
||||
|
||||
MenuViewLayerController(Context context, WindowManager windowManager) {
|
||||
mWindowManager = windowManager;
|
||||
mMenuViewLayer = new MenuViewLayer(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mIsShowing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsShowing = true;
|
||||
mWindowManager.addView(mMenuViewLayer, createDefaultLayerLayoutParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsShowing = false;
|
||||
mWindowManager.removeView(mMenuViewLayer);
|
||||
}
|
||||
|
||||
private static WindowManager.LayoutParams createDefaultLayerLayoutParams() {
|
||||
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
params.privateFlags |= PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
|
||||
params.windowAnimations = android.R.style.Animation_Translucent;
|
||||
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The view model provides the menu information from the repository{@link MenuInfoRepository} for
|
||||
* the menu view{@link MenuView}.
|
||||
*/
|
||||
class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
|
||||
private final MutableLiveData<List<AccessibilityTarget>> mTargetFeaturesData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<Integer> mSizeTypeData = new MutableLiveData<>();
|
||||
private final MenuInfoRepository mInfoRepository;
|
||||
|
||||
MenuViewModel(Context context) {
|
||||
mInfoRepository = new MenuInfoRepository(context, /* settingsContentsChanged= */ this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures) {
|
||||
mTargetFeaturesData.setValue(newTargetFeatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSizeTypeChanged(int newSizeType) {
|
||||
mSizeTypeData.setValue(newSizeType);
|
||||
}
|
||||
|
||||
LiveData<Integer> getSizeTypeData() {
|
||||
mInfoRepository.loadMenuSizeType(mSizeTypeData::setValue);
|
||||
return mSizeTypeData;
|
||||
}
|
||||
|
||||
LiveData<List<AccessibilityTarget>> getTargetFeaturesData() {
|
||||
mInfoRepository.loadMenuTargetFeatures(mTargetFeaturesData::setValue);
|
||||
return mTargetFeaturesData;
|
||||
}
|
||||
|
||||
void registerContentObservers() {
|
||||
mInfoRepository.registerContentObservers();
|
||||
}
|
||||
|
||||
void unregisterContentObservers() {
|
||||
mInfoRepository.unregisterContentObservers();
|
||||
}
|
||||
}
|
||||
@@ -306,6 +306,10 @@ public class Flags {
|
||||
// 1500 - chooser
|
||||
public static final UnreleasedFlag CHOOSER_UNBUNDLED = new UnreleasedFlag(1500);
|
||||
|
||||
// 1600 - accessibility
|
||||
public static final UnreleasedFlag A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS =
|
||||
new UnreleasedFlag(1600);
|
||||
|
||||
// Pay no attention to the reflection behind the curtain.
|
||||
// ========================== Curtain ==========================
|
||||
// | |
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.systemui.accessibility.floatingmenu;
|
||||
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.android.systemui.flags.Flags.A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -27,10 +29,12 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -40,6 +44,7 @@ import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -53,7 +58,7 @@ import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Test for {@link AccessibilityFloatingMenuController}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@SmallTest
|
||||
public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
|
||||
|
||||
@@ -70,6 +75,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
|
||||
private KeyguardUpdateMonitorCallback mKeyguardCallback;
|
||||
private int mLastButtonMode;
|
||||
private String mLastButtonTargets;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -79,6 +86,11 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
|
||||
return getBaseContext();
|
||||
}
|
||||
};
|
||||
|
||||
mLastButtonTargets = Settings.Secure.getStringForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, UserHandle.USER_CURRENT);
|
||||
mLastButtonMode = Settings.Secure.getIntForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -87,6 +99,13 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
|
||||
mController.onAccessibilityButtonTargetsChanged("");
|
||||
mController = null;
|
||||
}
|
||||
|
||||
Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, mLastButtonTargets,
|
||||
UserHandle.USER_CURRENT);
|
||||
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mLastButtonMode,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -287,13 +306,50 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
|
||||
assertThat(mController.mFloatingMenu).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTargetsChanged_flingSpringAnimationsDisabled_floatingMenuIsCreated() {
|
||||
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
|
||||
UserHandle.USER_CURRENT);
|
||||
final FakeFeatureFlags featureFlags = new FakeFeatureFlags();
|
||||
featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, false);
|
||||
|
||||
mController = setUpController();
|
||||
mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
|
||||
|
||||
assertThat(mController.mFloatingMenu).isInstanceOf(AccessibilityFloatingMenu.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTargetsChanged_isFloatingViewLayerControllerCreated() {
|
||||
Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
|
||||
UserHandle.USER_CURRENT);
|
||||
final FakeFeatureFlags featureFlags = new FakeFeatureFlags();
|
||||
featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, true);
|
||||
|
||||
mController = setUpController(featureFlags);
|
||||
mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
|
||||
|
||||
assertThat(mController.mFloatingMenu).isInstanceOf(MenuViewLayerController.class);
|
||||
}
|
||||
|
||||
private AccessibilityFloatingMenuController setUpController() {
|
||||
final FakeFeatureFlags featureFlags = new FakeFeatureFlags();
|
||||
featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, false);
|
||||
return setUpController(featureFlags);
|
||||
}
|
||||
|
||||
private AccessibilityFloatingMenuController setUpController(FakeFeatureFlags featureFlags) {
|
||||
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
|
||||
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
|
||||
mTargetsObserver = spy(Dependency.get(AccessibilityButtonTargetsObserver.class));
|
||||
mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class));
|
||||
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
|
||||
final AccessibilityFloatingMenuController controller =
|
||||
new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
|
||||
mModeObserver, mKeyguardUpdateMonitor);
|
||||
new AccessibilityFloatingMenuController(mContextWrapper, windowManager,
|
||||
displayManager, mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor,
|
||||
featureFlags);
|
||||
controller.init();
|
||||
|
||||
return controller;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Tests for {@link MenuInfoRepository}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
public class MenuInfoRepositoryTest extends SysuiTestCase {
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged;
|
||||
|
||||
@Test
|
||||
public void menuSizeTypeChanged_verifyOnSizeTypeChanged() {
|
||||
final MenuInfoRepository menuInfoRepository =
|
||||
new MenuInfoRepository(mContext, mMockSettingsContentsChanged);
|
||||
|
||||
menuInfoRepository.mMenuSizeContentObserver.onChange(true);
|
||||
|
||||
verify(mMockSettingsContentsChanged).onSizeTypeChanged(anyInt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Tests for {@link MenuViewLayerController}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
public class MenuViewLayerControllerTest extends SysuiTestCase {
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private WindowManager mWindowManager;
|
||||
|
||||
private MenuViewLayerController mMenuViewLayerController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mMenuViewLayerController = new MenuViewLayerController(mContext, mWindowManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void show_shouldAddViewToWindow() {
|
||||
mMenuViewLayerController.show();
|
||||
|
||||
verify(mWindowManager).addView(any(View.class), any(ViewGroup.LayoutParams.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hide_menuIsShowing_removeViewFromWindow() {
|
||||
mMenuViewLayerController.show();
|
||||
|
||||
mMenuViewLayerController.hide();
|
||||
|
||||
verify(mWindowManager).removeView(any(View.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link MenuViewLayer}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@SmallTest
|
||||
public class MenuViewLayerTest extends SysuiTestCase {
|
||||
private MenuViewLayer mMenuViewLayer;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mMenuViewLayer = new MenuViewLayer(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttachedToWindow_menuIsVisible() {
|
||||
mMenuViewLayer.onAttachedToWindow();
|
||||
final View menuView = mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW);
|
||||
|
||||
assertThat(menuView.getVisibility()).isEqualTo(VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAttachedToWindow_menuIsGone() {
|
||||
mMenuViewLayer.onDetachedFromWindow();
|
||||
final View menuView = mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW);
|
||||
|
||||
assertThat(menuView.getVisibility()).isEqualTo(GONE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.app.UiModeManager.MODE_NIGHT_YES;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link MenuView}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@SmallTest
|
||||
public class MenuViewTest extends SysuiTestCase {
|
||||
private static final int INDEX_MENU_ITEM = 0;
|
||||
private int mNightMode;
|
||||
private UiModeManager mUiModeManager;
|
||||
private MenuView mMenuView;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mUiModeManager = mContext.getSystemService(UiModeManager.class);
|
||||
mNightMode = mUiModeManager.getNightMode();
|
||||
mUiModeManager.setNightMode(MODE_NIGHT_YES);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext);
|
||||
mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConfigurationChanged_updateViewModel() {
|
||||
mMenuView.onConfigurationChanged(/* newConfig= */ null);
|
||||
|
||||
verify(mMenuView).loadLayoutResources();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insetsOnDarkTheme_menuOnLeft_matchInsets() {
|
||||
mMenuView.onConfigurationChanged(/* newConfig= */ null);
|
||||
final InstantInsetLayerDrawable insetLayerDrawable =
|
||||
(InstantInsetLayerDrawable) mMenuView.getBackground();
|
||||
final boolean areInsetsMatched = insetLayerDrawable.getLayerInsetLeft(INDEX_MENU_ITEM) != 0
|
||||
&& insetLayerDrawable.getLayerInsetRight(INDEX_MENU_ITEM) == 0;
|
||||
|
||||
assertThat(areInsetsMatched).isTrue();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mUiModeManager.setNightMode(mNightMode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user