PageRenderTime 36ms CodeModel.GetById 18ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/TalkBack/src/com/google/android/marvin/talkback/Utils.java

http://eyes-free.googlecode.com/
Java | 290 lines | 178 code | 31 blank | 81 comment | 74 complexity | 77961e5a762938672fceb15cbb861664 MD5 | raw file
  1/*
  2 * Copyright (C) 2010 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
 17package com.google.android.marvin.talkback;
 18
 19import android.content.Context;
 20import android.content.pm.PackageInfo;
 21import android.content.pm.PackageManager;
 22import android.content.pm.PackageManager.NameNotFoundException;
 23import android.content.res.Resources;
 24import android.os.Bundle;
 25import android.text.TextUtils;
 26import android.util.Log;
 27import android.view.accessibility.AccessibilityEvent;
 28import android.view.accessibility.AccessibilityNodeInfo;
 29
 30import java.util.ArrayList;
 31import java.util.HashMap;
 32import java.util.List;
 33import java.util.Map;
 34
 35/**
 36 * This class contains utility methods.
 37 *
 38 * @author svetoslavganov@google.com (Svetoslav R. Ganov)
 39 * @author alanv@google.com (Alan Viverette)
 40 */
 41public class Utils {
 42    private static final Context CONTEXT = TalkBackService.asContext();
 43    private static final CharSequence SEPARATOR = " ";
 44
 45    /** Invalid version code for a package. */
 46    public static final int INVALID_VERSION_CODE = -1;
 47
 48    /**
 49     * @return The package version code or {@link #INVALID_VERSION_CODE} if the
 50     *         package does not exist.
 51     */
 52    public static int getVersionCode(Context context, String packageName) {
 53        final PackageManager packageManager = context.getPackageManager();
 54
 55        try {
 56            final PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
 57            return packageInfo.versionCode;
 58        } catch (NameNotFoundException e) {
 59            LogUtils.log(Utils.class, Log.ERROR, "Could not find package: %s\n%s", packageName,
 60                    e.toString());
 61            return INVALID_VERSION_CODE;
 62        }
 63    }
 64
 65    /**
 66     * @return The package version name or <code>null</code> if the package does
 67     *         not exist.
 68     */
 69    public static String getVersionName(Context context, String packageName) {
 70        final PackageManager packageManager = context.getPackageManager();
 71
 72        try {
 73            final PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
 74            return packageInfo.versionName;
 75        } catch (NameNotFoundException e) {
 76            LogUtils.log(Utils.class, Log.ERROR, "Could not find package: %s\n%s", packageName,
 77                    e.toString());
 78            return null;
 79        }
 80    }
 81
 82    /**
 83    /**
 84     * Returns {@code true} if the specified node is a view group or has
 85     * children.
 86     *
 87     * @param node The node to test.
 88     * @return {@code true} if the specified node is a view group or has
 89     *         children.
 90     */
 91    public static boolean isViewGroup(AccessibilityEvent event, AccessibilityNodeInfo node) {
 92        if (event != null && Utils.eventMatchesClassByType(event, android.view.ViewGroup.class)) {
 93            return true;
 94        }
 95
 96        if (node != null
 97                && ((node.getChildCount() > 0) || AccessibilityNodeInfoUtils
 98                        .nodeMatchesClassByType(node, android.view.ViewGroup.class))) {
 99            return true;
100        }
101
102        return false;
103    }
104
105    /**
106     * Determines if the generating class of an {@link AccessibilityEvent}
107     * matches a given {@link Class} by type.
108     *
109     * @param event An {@link AccessibilityEvent} dispatched by the
110     *            accessibility framework.
111     * @param clazz A {@link Class} to match by type or inherited type.
112     * @return {@code true} if the {@link AccessibilityNodeInfo} object matches
113     *         the {@link Class} by type or inherited type, {@code false}
114     *         otherwise.
115     */
116    public static boolean eventMatchesClassByType(AccessibilityEvent event, Class<?> clazz) {
117        if (event == null || clazz == null) {
118            return false;
119        }
120
121        final ClassLoadingManager classLoader = ClassLoadingManager.getInstance();
122        final CharSequence className = event.getClassName();
123        final Class<?> nodeClass = classLoader.loadOrGetCachedClass(CONTEXT, className, null);
124
125        if (nodeClass == null) {
126            return false;
127        }
128
129        return clazz.isAssignableFrom(nodeClass);
130    }
131
132    /**
133     * Gets the text of an <code>event</code> by concatenating the text members
134     * (regardless of their priority) using space as a delimiter.
135     *
136     * @param context The context from which to load required resources.
137     * @param event The event.
138     * @return The event text.
139     */
140    public static CharSequence getEventText(Context context, AccessibilityEvent event) {
141        final CharSequence contentDescription = event.getContentDescription();
142
143        if (!TextUtils.isEmpty(contentDescription)) {
144            return new StringBuilder(contentDescription);
145        } else {
146            return getEventAggregateText(context, event);
147        }
148    }
149
150    /**
151     * Gets the text of an <code>event</code> by concatenating the text members
152     * (regardless of their priority) using space as a delimiter.
153     *
154     * @param context The context from which to load required resources.
155     * @param event The event.
156     * @return The event text.
157     */
158    public static CharSequence getEventAggregateText(Context context, AccessibilityEvent event) {
159        final StringBuilder aggregator = new StringBuilder();
160        final List<CharSequence> eventText = event.getText();
161
162        for (CharSequence text : event.getText()) {
163            aggregator.append(text);
164            aggregator.append(SEPARATOR);
165        }
166
167        return aggregator;
168    }
169
170    /**
171     * Loads a map of key strings to value strings from array resources.
172     *
173     * @param context The parent context.
174     * @param keysResource A resource identifier for the array of key strings.
175     * @param valuesResource A resource identifier for the array of value
176     *            strings.
177     * @return A map of keys to values.
178     */
179    public static Map<String, String> loadMapFromStringArrays(Context context, int keysResource,
180            int valuesResource) {
181        final Resources res = context.getResources();
182        final String[] keys = res.getStringArray(keysResource);
183        final String[] values = res.getStringArray(valuesResource);
184
185        if (keys.length != values.length) {
186            throw new IllegalArgumentException("Array size mismatch");
187        }
188
189        final Map<String, String> map = new HashMap<String, String>();
190
191        for (int i = 0; i < keys.length; i++) {
192            map.put(keys[i], values[i]);
193        }
194
195        return map;
196    }
197
198    /**
199     * @return If the <code>first</code> event is equal to the
200     *         <code>second</code>.
201     */
202    public static boolean accessibilityEventEquals(AccessibilityEvent first,
203            AccessibilityEvent second) {
204        if (first == null || second == null) {
205            return false;
206        }
207        if (first.getEventType() != second.getEventType()) {
208            return false;
209        }
210        if (first.getPackageName() == null) {
211            if (second.getPackageName() != null) {
212                return false;
213            }
214        } else if (!first.getPackageName().equals(second.getPackageName())) {
215            return false;
216        }
217        if (first.getClassName() == null) {
218            if (second.getClassName() != null) {
219                return false;
220            }
221        } else if (!first.getClassName().equals(second.getClassName())) {
222            return false;
223        }
224        if (!first.getText().equals(second.getText())) { // never null
225            return false;
226        }
227        if (first.getContentDescription() == null) {
228            if (second.getContentDescription() != null) {
229                return false;
230            }
231        } else if (!first.getContentDescription().equals(second.getContentDescription())) {
232            return false;
233        }
234        if (first.getBeforeText() == null) {
235            if (second.getBeforeText() != null) {
236                return false;
237            }
238        } else if (!first.getBeforeText().equals(second.getBeforeText())) {
239            return false;
240        }
241        if (first.getParcelableData() != null) {
242            // do not compare parcelable data it may not implement equals
243            // correctly
244
245            return false;
246        }
247        if (first.getAddedCount() != second.getAddedCount()) {
248            return false;
249        }
250        if (first.isChecked() != second.isChecked()) {
251            return false;
252        }
253        if (first.isEnabled() != second.isEnabled()) {
254            return false;
255        }
256        if (first.getFromIndex() != second.getFromIndex()) {
257            return false;
258        }
259        if (first.isFullScreen() != second.isFullScreen()) {
260            return false;
261        }
262        if (first.getCurrentItemIndex() != second.getCurrentItemIndex()) {
263            return false;
264        }
265        if (first.getItemCount() != second.getItemCount()) {
266            return false;
267        }
268        if (first.isPassword() != second.isPassword()) {
269            return false;
270        }
271        if (first.getRemovedCount() != second.getRemovedCount()) {
272            return false;
273        }
274        if (first.getEventTime() != second.getEventTime()) {
275            return false;
276        }
277        return true;
278    }
279
280    public static void addToListOrCreate(Bundle bundle, String listKey, int value) {
281        ArrayList<Integer> list = bundle.getIntegerArrayList(listKey);
282
283        if (list == null) {
284            list = new ArrayList<Integer>();
285            bundle.putIntegerArrayList(listKey, list);
286        }
287
288        list.add(value);
289    }
290}