1 /*
2  * Copyright (C) 2015 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.messaging.util;
17 
18 import android.content.Context;
19 import android.content.res.Resources;
20 import androidx.core.view.accessibility.AccessibilityEventCompat;
21 import androidx.core.view.accessibility.AccessibilityRecordCompat;
22 import android.text.TextUtils;
23 import android.view.View;
24 import android.view.accessibility.AccessibilityEvent;
25 import android.view.accessibility.AccessibilityManager;
26 
27 import com.android.messaging.Factory;
28 import com.android.messaging.R;
29 
30 import javax.annotation.Nullable;
31 
32 public class AccessibilityUtil {
33     public static String sContentDescriptionDivider;
34 
isTouchExplorationEnabled(final Context context)35     public static boolean isTouchExplorationEnabled(final Context context) {
36         final AccessibilityManager accessibilityManager = (AccessibilityManager)
37                 context.getSystemService(Context.ACCESSIBILITY_SERVICE);
38         return accessibilityManager.isTouchExplorationEnabled();
39     }
40 
appendContentDescription(final Context context, final StringBuilder contentDescription, final String val)41     public static StringBuilder appendContentDescription(final Context context,
42             final StringBuilder contentDescription, final String val) {
43         if (sContentDescriptionDivider == null) {
44             sContentDescriptionDivider =
45                     context.getResources().getString(R.string.enumeration_comma);
46         }
47         if (contentDescription.length() != 0) {
48             contentDescription.append(sContentDescriptionDivider);
49         }
50         contentDescription.append(val);
51         return contentDescription;
52     }
53 
announceForAccessibilityCompat( final View view, @Nullable final AccessibilityManager accessibilityManager, final int textResourceId)54     public static void announceForAccessibilityCompat(
55             final View view, @Nullable final AccessibilityManager accessibilityManager,
56             final int textResourceId) {
57         final String text = Factory.get().getApplicationContext().getResources().getString(
58                 textResourceId);
59         announceForAccessibilityCompat(view, accessibilityManager, text);
60     }
61 
announceForAccessibilityCompat( final View view, @Nullable AccessibilityManager accessibilityManager, final CharSequence text)62     public static void announceForAccessibilityCompat(
63             final View view, @Nullable AccessibilityManager accessibilityManager,
64             final CharSequence text) {
65         final Context context = view.getContext().getApplicationContext();
66         if (accessibilityManager == null) {
67             accessibilityManager = (AccessibilityManager) context.getSystemService(
68                     Context.ACCESSIBILITY_SERVICE);
69         }
70 
71         if (!accessibilityManager.isEnabled()) {
72             return;
73         }
74 
75         // Jelly Bean added support for speaking text verbatim
76         final int eventType = OsUtil.isAtLeastJB() ? AccessibilityEvent.TYPE_ANNOUNCEMENT
77                 : AccessibilityEvent.TYPE_VIEW_FOCUSED;
78 
79         // Construct an accessibility event with the minimum recommended
80         // attributes. An event without a class name or package may be dropped.
81         final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
82         event.getText().add(text);
83         event.setEnabled(view.isEnabled());
84         event.setClassName(view.getClass().getName());
85         event.setPackageName(context.getPackageName());
86 
87         // JellyBean MR1 requires a source view to set the window ID.
88         final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
89         record.setSource(view);
90 
91         // Sends the event directly through the accessibility manager. If we only supported SDK 14+
92         // we could have done:
93         // getParent().requestSendAccessibilityEvent(this, event);
94         accessibilityManager.sendAccessibilityEvent(event);
95     }
96 
97     /**
98      * Check to see if the current layout is Right-to-Left. This check is only supported for
99      * API 17+.
100      * For earlier versions, this method will just return false.
101      * @return boolean Boolean indicating whether the currently locale is RTL.
102      */
isLayoutRtl(final View view)103     public static boolean isLayoutRtl(final View view) {
104         if (OsUtil.isAtLeastJB_MR1()) {
105             return View.LAYOUT_DIRECTION_RTL == view.getLayoutDirection();
106         } else {
107             return false;
108         }
109     }
110 
getVocalizedPhoneNumber(final Resources res, final String phoneNumber)111     public static String getVocalizedPhoneNumber(final Resources res, final String phoneNumber) {
112         if (TextUtils.isEmpty(phoneNumber)) {
113             return "";
114         }
115         final StringBuilder vocalizedPhoneNumber = new StringBuilder();
116         for (final char c : phoneNumber.toCharArray()) {
117             getVocalizedNumber(res, c, vocalizedPhoneNumber);
118         }
119         return vocalizedPhoneNumber.toString();
120     }
121 
getVocalizedNumber(final Resources res, final char c, final StringBuilder builder)122     public static void getVocalizedNumber(final Resources res, final char c,
123             final StringBuilder builder) {
124         switch (c) {
125             case '0':
126                 builder.append(res.getString(R.string.content_description_for_number_zero));
127                 builder.append(" ");
128                 return;
129             case '1':
130                 builder.append(res.getString(R.string.content_description_for_number_one));
131                 builder.append(" ");
132                 return;
133             case '2':
134                 builder.append(res.getString(R.string.content_description_for_number_two));
135                 builder.append(" ");
136                 return;
137             case '3':
138                 builder.append(res.getString(R.string.content_description_for_number_three));
139                 builder.append(" ");
140                 return;
141             case '4':
142                 builder.append(res.getString(R.string.content_description_for_number_four));
143                 builder.append(" ");
144                 return;
145             case '5':
146                 builder.append(res.getString(R.string.content_description_for_number_five));
147                 builder.append(" ");
148                 return;
149             case '6':
150                 builder.append(res.getString(R.string.content_description_for_number_six));
151                 builder.append(" ");
152                 return;
153             case '7':
154                 builder.append(res.getString(R.string.content_description_for_number_seven));
155                 builder.append(" ");
156                 return;
157             case '8':
158                 builder.append(res.getString(R.string.content_description_for_number_eight));
159                 builder.append(" ");
160                 return;
161             case '9':
162                 builder.append(res.getString(R.string.content_description_for_number_nine));
163                 builder.append(" ");
164                 return;
165             default:
166                 builder.append(c);
167                 return;
168         }
169     }
170 }
171