Add new floating action menu for Accessibility targets. (1/n)
Goals:
- Trigger actions of accessibility features would be grouped into the floating menu.
Patch action:
1. Use current Accessibility Target functions to get the corresponding data.
2. The position of the floating menu is at the bottom-right corner of the screen initially.
3. Support dark theme.
Bug: 173958541
Test: atest AccessibilityFloatingMenuTest AccessibilityFloatingMenuViewTest
Change-Id: I28e729520d4eb8ecb0bcc41d4de9d1499380e7f5
Merged-In: I28e729520d4eb8ecb0bcc41d4de9d1499380e7f5
(cherry picked from commit 2be49c9be9)
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<layer-list
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/menu_background_item">
|
||||
<shape android:shape="rectangle">
|
||||
<corners
|
||||
android:bottomLeftRadius="@dimen/accessibility_floating_menu_single_radius"
|
||||
android:bottomRightRadius="0dp"
|
||||
android:topLeftRadius="@dimen/accessibility_floating_menu_single_radius"
|
||||
android:topRightRadius="0dp"/>
|
||||
<solid
|
||||
android:color="@color/accessibility_floating_menu_background"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/accessibility_floating_menu_padding"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<View
|
||||
android:id="@+id/icon_view"
|
||||
android:layout_width="@dimen/accessibility_floating_menu_width_height"
|
||||
android:layout_height="@dimen/accessibility_floating_menu_width_height"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/transparent_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/accessibility_floating_menu_padding"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -102,4 +102,6 @@
|
||||
<color name="privacy_circle_camera">#81C995</color> <!-- g300 -->
|
||||
<color name="privacy_circle_microphone_location">#FCAD70</color> <!--o300 -->
|
||||
|
||||
<!-- Accessibility floating menu -->
|
||||
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
|
||||
</resources>
|
||||
|
||||
@@ -274,4 +274,8 @@
|
||||
<!-- TODO(b/178093014) Colors for privacy dialog. These should be changed to the new palette -->
|
||||
<color name="privacy_circle_camera">#1E8E3E</color> <!-- g600 -->
|
||||
<color name="privacy_circle_microphone_location">#E8710A</color> <!--o600 -->
|
||||
|
||||
<!-- Accessibility floating menu -->
|
||||
<color name="accessibility_floating_menu_background">#CCFFFFFF</color> <!-- 80% -->
|
||||
<color name="accessibility_floating_menu_stroke_dark">#26FFFFFF</color> <!-- 15% -->
|
||||
</resources>
|
||||
|
||||
@@ -1356,6 +1356,16 @@
|
||||
<dimen name="people_space_image_radius">20dp</dimen>
|
||||
<dimen name="people_space_widget_background_padding">6dp</dimen>
|
||||
|
||||
<!-- Accessibility floating menu -->
|
||||
<dimen name="accessibility_floating_menu_elevation">5dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_stroke_width">1dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_stroke_inset">-2dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_margin">16dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_padding">6dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_width_height">36dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_single_radius">25dp</dimen>
|
||||
<dimen name="accessibility_floating_menu_multiple_radius">20dp</dimen>
|
||||
|
||||
<dimen name="rounded_slider_height">44dp</dimen>
|
||||
<!-- rounded_slider_height / 2 -->
|
||||
<dimen name="rounded_slider_corner_radius">22dp</dimen>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
|
||||
|
||||
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
|
||||
|
||||
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.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Contains logic for an accessibility floating menu view.
|
||||
*/
|
||||
public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
|
||||
private final Context mContext;
|
||||
private final AccessibilityFloatingMenuView mMenuView;
|
||||
|
||||
private final ContentObserver mContentObserver =
|
||||
new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
|
||||
}
|
||||
};
|
||||
|
||||
public AccessibilityFloatingMenu(Context context) {
|
||||
mContext = context;
|
||||
mMenuView = new AccessibilityFloatingMenuView(context);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AccessibilityFloatingMenu(Context context, AccessibilityFloatingMenuView menuView) {
|
||||
mContext = context;
|
||||
mMenuView = menuView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mMenuView.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
|
||||
mMenuView.show();
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
|
||||
/* notifyForDescendants */ false, mContentObserver,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMenuView.hide();
|
||||
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.DimenRes;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Accessibility floating menu is used for the actions of accessibility features, it's also the
|
||||
* action set.
|
||||
*
|
||||
* <p>The number of items would depend on strings key
|
||||
* {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}.
|
||||
*/
|
||||
public class AccessibilityFloatingMenuView extends FrameLayout {
|
||||
private static final float DEFAULT_LOCATION_Y_PERCENTAGE = 0.8f;
|
||||
private static final int INDEX_MENU_ITEM = 0;
|
||||
private boolean mIsShowing;
|
||||
private RecyclerView mListView;
|
||||
private final WindowManager.LayoutParams mLayoutParams;
|
||||
private final WindowManager mWindowManager;
|
||||
private final AccessibilityTargetAdapter mAdapter;
|
||||
private final List<AccessibilityTarget> mTargets = new ArrayList<>();
|
||||
|
||||
public AccessibilityFloatingMenuView(Context context) {
|
||||
super(context);
|
||||
|
||||
mWindowManager = context.getSystemService(WindowManager.class);
|
||||
mLayoutParams = createDefaultLayoutParams();
|
||||
mAdapter = new AccessibilityTargetAdapter(mTargets);
|
||||
|
||||
initListView(context, mAdapter);
|
||||
updateStroke();
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsShowing = true;
|
||||
mWindowManager.addView(this, mLayoutParams);
|
||||
}
|
||||
|
||||
void hide() {
|
||||
if (!isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsShowing = false;
|
||||
mWindowManager.removeView(this);
|
||||
}
|
||||
|
||||
boolean isShowing() {
|
||||
return mIsShowing;
|
||||
}
|
||||
|
||||
void onTargetsChanged(List<AccessibilityTarget> newTargets) {
|
||||
mTargets.clear();
|
||||
mTargets.addAll(newTargets);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
final boolean hasMoreItems = mAdapter.getItemCount() > 1;
|
||||
final int resId = hasMoreItems
|
||||
? R.dimen.accessibility_floating_menu_multiple_radius
|
||||
: R.dimen.accessibility_floating_menu_single_radius;
|
||||
setRadius(resId);
|
||||
}
|
||||
|
||||
private void setRadius(@DimenRes int radiusResId) {
|
||||
final float radius = getResources().getDimension(radiusResId);
|
||||
final float[] radii = new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
|
||||
getMenuGradientDrawable().setCornerRadii(radii);
|
||||
}
|
||||
|
||||
private void initListView(Context context, AccessibilityTargetAdapter adapter) {
|
||||
final Resources res = context.getResources();
|
||||
final int margin =
|
||||
res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin);
|
||||
final int elevation =
|
||||
res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
|
||||
final Drawable listViewBackground =
|
||||
context.getDrawable(R.drawable.accessibility_floating_menu_background);
|
||||
|
||||
mListView = new RecyclerView(context);
|
||||
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
||||
final LayoutParams layoutParams =
|
||||
new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.setMarginsRelative(margin, margin, /* end= */ 0, margin);
|
||||
mListView.setLayoutParams(layoutParams);
|
||||
mListView.setElevation(elevation);
|
||||
mListView.setBackground(listViewBackground);
|
||||
mListView.setAdapter(adapter);
|
||||
mListView.setLayoutManager(layoutManager);
|
||||
|
||||
addView(mListView);
|
||||
}
|
||||
|
||||
private WindowManager.LayoutParams createDefaultLayoutParams() {
|
||||
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
final DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
params.gravity = Gravity.START | Gravity.TOP;
|
||||
params.x = dm.widthPixels;
|
||||
params.y = (int) (dm.heightPixels * DEFAULT_LOCATION_Y_PERCENTAGE);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
updateLocation();
|
||||
updateColor();
|
||||
updateStroke();
|
||||
}
|
||||
|
||||
private LayerDrawable getMenuLayerDrawable() {
|
||||
return (LayerDrawable) mListView.getBackground();
|
||||
}
|
||||
|
||||
private GradientDrawable getMenuGradientDrawable() {
|
||||
return (GradientDrawable) getMenuLayerDrawable().getDrawable(INDEX_MENU_ITEM);
|
||||
}
|
||||
|
||||
private void updateLocation() {
|
||||
final DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
mLayoutParams.x = dm.widthPixels;
|
||||
mLayoutParams.y = (int) (dm.heightPixels * DEFAULT_LOCATION_Y_PERCENTAGE);
|
||||
mWindowManager.updateViewLayout(this, mLayoutParams);
|
||||
}
|
||||
|
||||
private void updateColor() {
|
||||
final int menuColorResId = R.color.accessibility_floating_menu_background;
|
||||
getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId));
|
||||
}
|
||||
|
||||
private void updateStroke() {
|
||||
final Resources res = getResources();
|
||||
final boolean isNightMode =
|
||||
(res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
|
||||
== Configuration.UI_MODE_NIGHT_YES;
|
||||
|
||||
final int inset =
|
||||
res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset);
|
||||
final int insetRight = isNightMode ? inset : 0;
|
||||
getMenuLayerDrawable().setLayerInset(INDEX_MENU_ITEM, 0, 0, insetRight, 0);
|
||||
|
||||
final int width =
|
||||
res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_width);
|
||||
final int strokeWidth = isNightMode ? width : 0;
|
||||
final int strokeColor = res.getColor(R.color.accessibility_floating_menu_stroke_dark);
|
||||
getMenuGradientDrawable().setStroke(strokeWidth, strokeColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An adapter which shows the set of accessibility targets that can be performed.
|
||||
*/
|
||||
public class AccessibilityTargetAdapter extends Adapter<ViewHolder> {
|
||||
|
||||
private final List<AccessibilityTarget> mTargets;
|
||||
public AccessibilityTargetAdapter(List<AccessibilityTarget> targets) {
|
||||
mTargets = targets;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
|
||||
final View root = LayoutInflater.from(parent.getContext()).inflate(
|
||||
R.layout.accessibility_floating_menu_item, parent,
|
||||
/* attachToRoot= */ false);
|
||||
|
||||
return new ViewHolder(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.mIconView.setBackground(mTargets.get(position).getIcon());
|
||||
|
||||
final boolean isFirstItem = (position == 0);
|
||||
final boolean isLastItem = (position == (getItemCount() - 1));
|
||||
final int padding = holder.itemView.getPaddingStart();
|
||||
final int paddingTop = isFirstItem ? padding : 0;
|
||||
final int paddingBottom = isLastItem ? padding : 0;
|
||||
holder.itemView.setPaddingRelative(padding, paddingTop, padding, paddingBottom);
|
||||
holder.itemView.setOnClickListener((v) -> mTargets.get(position).onSelected());
|
||||
holder.mDivider.setVisibility(isLastItem ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mTargets.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final View mIconView;
|
||||
final View mDivider;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mIconView = itemView.findViewById(R.id.icon_view);
|
||||
mDivider = itemView.findViewById(R.id.transparent_divider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface for managing the accessibility targets menu component.
|
||||
*/
|
||||
public interface IAccessibilityFloatingMenu {
|
||||
|
||||
/**
|
||||
* Checks if the menu was shown.
|
||||
*/
|
||||
boolean isShowing();
|
||||
|
||||
/**
|
||||
* Shows the accessibility targets menu.
|
||||
*/
|
||||
void show();
|
||||
|
||||
/**
|
||||
* Hides the accessibility targets menu.
|
||||
*/
|
||||
void hide();
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
||||
import android.content.Context;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Tests for {@link AccessibilityFloatingMenu}. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class AccessibilityFloatingMenuTest extends SysuiTestCase {
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
private AccessibilityFloatingMenuView mMenuView;
|
||||
private AccessibilityFloatingMenu mMenu;
|
||||
|
||||
@Before
|
||||
public void initMenu() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
final List<String> assignedTargets = new ArrayList<>();
|
||||
mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
|
||||
assignedTargets.add(MAGNIFICATION_CONTROLLER_NAME);
|
||||
doReturn(assignedTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets(
|
||||
anyInt());
|
||||
|
||||
mMenuView = new AccessibilityFloatingMenuView(mContext);
|
||||
mMenu = new AccessibilityFloatingMenu(mContext, mMenuView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showMenuView_success() {
|
||||
mMenu.show();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hideMenuView_success() {
|
||||
mMenu.show();
|
||||
mMenu.hide();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isFalse();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mMenu.hide();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Tests for {@link AccessibilityFloatingMenuView}. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
|
||||
private AccessibilityFloatingMenuView mMenuView;
|
||||
|
||||
@Mock
|
||||
private WindowManager mWindowManager;
|
||||
|
||||
private final List<AccessibilityTarget> mTargets = new ArrayList<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
final WindowManager wm = mContext.getSystemService(WindowManager.class);
|
||||
doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
|
||||
mWindowManager).getMaximumWindowMetrics();
|
||||
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
|
||||
|
||||
mTargets.add(mock(AccessibilityTarget.class));
|
||||
mMenuView = new AccessibilityFloatingMenuView(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initListView_success() {
|
||||
assertThat(mMenuView.getChildCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showMenuView_success() {
|
||||
mMenuView.show();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isTrue();
|
||||
verify(mWindowManager).addView(eq(mMenuView), any(WindowManager.LayoutParams.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showMenuView_showTwice_addViewOnce() {
|
||||
mMenuView.show();
|
||||
mMenuView.show();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isTrue();
|
||||
verify(mWindowManager, times(1)).addView(eq(mMenuView),
|
||||
any(WindowManager.LayoutParams.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hideMenuView_success() {
|
||||
mMenuView.show();
|
||||
mMenuView.hide();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isFalse();
|
||||
verify(mWindowManager).removeView(eq(mMenuView));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hideMenuView_hideTwice_removeViewOnce() {
|
||||
mMenuView.show();
|
||||
mMenuView.hide();
|
||||
mMenuView.hide();
|
||||
|
||||
assertThat(mMenuView.isShowing()).isFalse();
|
||||
verify(mWindowManager, times(1)).removeView(eq(mMenuView));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateListViewRadius_singleTarget_matchResult() {
|
||||
final float radius =
|
||||
getContext().getResources().getDimension(
|
||||
R.dimen.accessibility_floating_menu_single_radius);
|
||||
final float[] expectedRadii =
|
||||
new float[] {radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
|
||||
|
||||
mMenuView.onTargetsChanged(mTargets);
|
||||
final View view = mMenuView.getChildAt(0);
|
||||
final LayerDrawable layerDrawable = (LayerDrawable) view.getBackground();
|
||||
final GradientDrawable gradientDrawable =
|
||||
(GradientDrawable) layerDrawable.getDrawable(0);
|
||||
final float[] actualRadii = gradientDrawable.getCornerRadii();
|
||||
|
||||
assertThat(actualRadii).isEqualTo(expectedRadii);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user