• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.car.ui.utils;
17 
18 import static android.os.Build.VERSION_CODES.R;
19 
20 import android.annotation.TargetApi;
21 import android.content.Context;
22 import android.text.TextUtils;
23 import android.view.View;
24 import android.view.accessibility.AccessibilityEvent;
25 import android.view.accessibility.AccessibilityManager;
26 import android.view.accessibility.AccessibilityNodeInfo;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.VisibleForTesting;
30 
31 /** Helper class to toggle direct manipulation mode. */
32 public final class DirectManipulationHelper {
33 
34     /**
35      * ContentDescription for a {@link View} to support direct manipulation mode. It's also used as
36      * class name of {@link AccessibilityEvent} to indicate that the AccessibilityEvent represents
37      * a request to toggle direct manipulation mode.
38      */
39     @VisibleForTesting
40     public static final String DIRECT_MANIPULATION =
41             "com.android.car.ui.utils.DIRECT_MANIPULATION";
42 
43     /** This is a utility class. */
DirectManipulationHelper()44     private DirectManipulationHelper() {
45     }
46 
47     /**
48      * Enables or disables direct manipulation mode. This method sends an {@link AccessibilityEvent}
49      * to tell {@link com.android.car.rotary.RotaryService} to enter or exit direct manipulation
50      * mode. Typically pressing the center button of the rotary controller with a direct
51      * manipulation view focused will enter direct manipulation mode, while pressing the Back button
52      * will exit direct manipulation mode.
53      *
54      * @param view   the direct manipulation view
55      * @param enable true to enter direct manipulation mode, false to exit direct manipulation mode
56      * @return whether the AccessibilityEvent was sent
57      */
enableDirectManipulationMode(@onNull View view, boolean enable)58     public static boolean enableDirectManipulationMode(@NonNull View view, boolean enable) {
59         AccessibilityManager accessibilityManager = (AccessibilityManager)
60                 view.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
61         if (accessibilityManager == null || !accessibilityManager.isEnabled()) {
62             return false;
63         }
64         AccessibilityEvent event = AccessibilityEvent.obtain();
65         event.setClassName(DIRECT_MANIPULATION);
66         event.setSource(view);
67         event.setEventType(enable
68                 ? AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
69                 : AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
70         accessibilityManager.sendAccessibilityEvent(event);
71         return true;
72     }
73 
74     /** Returns whether the given {@code event} is for direct manipulation. */
isDirectManipulation(@onNull AccessibilityEvent event)75     public static boolean isDirectManipulation(@NonNull AccessibilityEvent event) {
76         return TextUtils.equals(DIRECT_MANIPULATION, event.getClassName());
77     }
78 
79     /** Returns whether the given {@code node} supports rotate directly. */
80     @TargetApi(R)
supportRotateDirectly(@onNull AccessibilityNodeInfo node)81     public static boolean supportRotateDirectly(@NonNull AccessibilityNodeInfo node) {
82         return TextUtils.equals(DIRECT_MANIPULATION, node.getContentDescription());
83     }
84 
85     /**
86      * Sets whether the given {@code view} supports rotate directly.
87      * <p>
88      * If the view supports rotate directly, when it's focused but not in direct manipulation mode,
89      * clicking the center button of the rotary controller will make RotaryService enter direct
90      * manipulation mode. In this mode, the view's selected state is toggled, and only controller
91      * rotation and Back button press are supported.
92      * <ul>
93      *   <li>When the controller is rotated, the view will be asked to perform ACTION_SCROLL_FORWARD
94      *       or ACTION_SCROLL_BACKWARD.
95      *   <li>When Back button is pressed, RotaryService will toggle off the view's selected state
96      *       and exit this mode.
97      * </ul>
98      * To support controller nudges as well in direct manipulation mode, use {@link
99      * #enableDirectManipulationMode} instead.
100      */
101     @TargetApi(R)
setSupportsRotateDirectly(@onNull View view, boolean enable)102     public static void setSupportsRotateDirectly(@NonNull View view, boolean enable) {
103         view.setContentDescription(enable ? DIRECT_MANIPULATION : null);
104     }
105 
106     /**
107      * Returns whether the given {@code node} supports rotate directly.
108      *
109      * @deprecated use {@link #supportRotateDirectly} instead
110      */
111     @Deprecated
supportDirectManipulation(@onNull AccessibilityNodeInfo node)112     public static boolean supportDirectManipulation(@NonNull AccessibilityNodeInfo node) {
113         return supportRotateDirectly(node);
114     }
115 
116     /**
117      * Sets whether the given {@code view} supports rotate directly.
118      *
119      * @deprecated use {@link #setSupportsRotateDirectly} instead
120      */
121     @Deprecated
setSupportsDirectManipulation(@onNull View view, boolean enable)122     public static void setSupportsDirectManipulation(@NonNull View view, boolean enable) {
123         setSupportsRotateDirectly(view, enable);
124     }
125 }
126