Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Side by Side Diff: ui/android/java/src/org/chromium/ui/base/WindowAndroid.java

Issue 1126563003: Fix Android accessibility focus not being drawn over transparent view. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@scroll_container
Patch Set: Consolidate code into refreshWillNotDraw Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.ui.base; 5 package org.chromium.ui.base;
6 6
7 import android.animation.Animator; 7 import android.animation.Animator;
8 import android.animation.AnimatorListenerAdapter; 8 import android.animation.AnimatorListenerAdapter;
9 import android.annotation.SuppressLint; 9 import android.annotation.SuppressLint;
10 import android.annotation.TargetApi;
10 import android.app.Activity; 11 import android.app.Activity;
11 import android.app.PendingIntent; 12 import android.app.PendingIntent;
12 import android.content.ContentResolver; 13 import android.content.ContentResolver;
13 import android.content.Context; 14 import android.content.Context;
14 import android.content.Intent; 15 import android.content.Intent;
16 import android.os.Build;
15 import android.os.Bundle; 17 import android.os.Bundle;
16 import android.util.Log; 18 import android.util.Log;
17 import android.util.SparseArray; 19 import android.util.SparseArray;
18 import android.view.View; 20 import android.view.View;
19 import android.view.ViewGroup; 21 import android.view.ViewGroup;
22 import android.view.accessibility.AccessibilityManager;
20 import android.widget.Toast; 23 import android.widget.Toast;
21 24
22 import org.chromium.base.CalledByNative; 25 import org.chromium.base.CalledByNative;
23 import org.chromium.base.JNINamespace; 26 import org.chromium.base.JNINamespace;
24 import org.chromium.ui.VSyncMonitor; 27 import org.chromium.ui.VSyncMonitor;
25 28
26 import java.lang.ref.WeakReference; 29 import java.lang.ref.WeakReference;
27 import java.util.HashMap; 30 import java.util.HashMap;
28 import java.util.HashSet; 31 import java.util.HashSet;
29 import java.util.LinkedList; 32 import java.util.LinkedList;
30 33
31 /** 34 /**
32 * The window base class that has the minimum functionality. 35 * The window base class that has the minimum functionality.
33 */ 36 */
34 @JNINamespace("ui") 37 @JNINamespace("ui")
35 public class WindowAndroid { 38 public class WindowAndroid {
36 private static final String TAG = "WindowAndroid"; 39 private static final String TAG = "WindowAndroid";
37 40
41 @TargetApi(Build.VERSION_CODES.KITKAT)
42 private class TouchExplorationMonitor {
43 // Listener that tells us when touch exploration is enabled or disabled.
44 private AccessibilityManager.TouchExplorationStateChangeListener mTouchE xplorationListener;
45
46 TouchExplorationMonitor() {
47 mTouchExplorationListener =
48 new AccessibilityManager.TouchExplorationStateChangeListener () {
49 public void onTouchExplorationStateChanged(boolean enabled) {
50 mIsTouchExplorationEnabled =
51 mAccessibilityManager.isTouchExplorationEnabled();
52 refreshWillNotDraw();
53 }
54 };
55 mAccessibilityManager.addTouchExplorationStateChangeListener(mTouchE xplorationListener);
56 }
57
58 void destroy() {
59 mAccessibilityManager.removeTouchExplorationStateChangeListener(
60 mTouchExplorationListener);
61 }
62 }
63
38 // Native pointer to the c++ WindowAndroid object. 64 // Native pointer to the c++ WindowAndroid object.
39 private long mNativeWindowAndroid = 0; 65 private long mNativeWindowAndroid = 0;
40 private final VSyncMonitor mVSyncMonitor; 66 private final VSyncMonitor mVSyncMonitor;
41 67
42 // A string used as a key to store intent errors in a bundle 68 // A string used as a key to store intent errors in a bundle
43 static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors"; 69 static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors";
44 70
45 // Error code returned when an Intent fails to start an Activity. 71 // Error code returned when an Intent fails to start an Activity.
46 public static final int START_INTENT_FAILURE = -1; 72 public static final int START_INTENT_FAILURE = -1;
47 73
48 protected Context mApplicationContext; 74 protected Context mApplicationContext;
49 protected SparseArray<IntentCallback> mOutstandingIntents; 75 protected SparseArray<IntentCallback> mOutstandingIntents;
50 76
51 // Ideally, this would be a SparseArray<String>, but there's no easy way to store a 77 // Ideally, this would be a SparseArray<String>, but there's no easy way to store a
52 // SparseArray<String> in a bundle during saveInstanceState(). So we use a H ashMap and suppress 78 // SparseArray<String> in a bundle during saveInstanceState(). So we use a H ashMap and suppress
53 // the Android lint warning "UseSparseArrays". 79 // the Android lint warning "UseSparseArrays".
54 protected HashMap<Integer, String> mIntentErrors; 80 protected HashMap<Integer, String> mIntentErrors;
55 81
56 // We track all animations over content and provide a drawing placeholder fo r them. 82 // We track all animations over content and provide a drawing placeholder fo r them.
57 private HashSet<Animator> mAnimationsOverContent = new HashSet<Animator>(); 83 private HashSet<Animator> mAnimationsOverContent = new HashSet<Animator>();
58 private View mAnimationPlaceholderView; 84 private View mAnimationPlaceholderView;
59 85
60 private ViewGroup mKeyboardAccessoryView; 86 private ViewGroup mKeyboardAccessoryView;
61 87
62 private boolean mIsKeyboardShowing = false; 88 private boolean mIsKeyboardShowing = false;
63 89
90 // System accessibility service.
91 private final AccessibilityManager mAccessibilityManager;
92
93 // Whether touch exploration is enabled.
94 private boolean mIsTouchExplorationEnabled;
95
96 // On KitKat and higher, a class that monitors the touch exploration state.
97 private TouchExplorationMonitor mTouchExplorationMonitor;
98
64 /** 99 /**
65 * An interface to notify listeners of changes in the soft keyboard's visibi lity. 100 * An interface to notify listeners of changes in the soft keyboard's visibi lity.
66 */ 101 */
67 public interface KeyboardVisibilityListener { 102 public interface KeyboardVisibilityListener {
68 public void keyboardVisibilityChanged(boolean isShowing); 103 public void keyboardVisibilityChanged(boolean isShowing);
69 } 104 }
70 private LinkedList<KeyboardVisibilityListener> mKeyboardVisibilityListeners = 105 private LinkedList<KeyboardVisibilityListener> mKeyboardVisibilityListeners =
71 new LinkedList<KeyboardVisibilityListener>(); 106 new LinkedList<KeyboardVisibilityListener>();
72 107
73 private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listen er() { 108 private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listen er() {
(...skipping 18 matching lines...) Expand all
92 /** 127 /**
93 * @param context The application context. 128 * @param context The application context.
94 */ 129 */
95 @SuppressLint("UseSparseArrays") 130 @SuppressLint("UseSparseArrays")
96 public WindowAndroid(Context context) { 131 public WindowAndroid(Context context) {
97 assert context == context.getApplicationContext(); 132 assert context == context.getApplicationContext();
98 mApplicationContext = context; 133 mApplicationContext = context;
99 mOutstandingIntents = new SparseArray<IntentCallback>(); 134 mOutstandingIntents = new SparseArray<IntentCallback>();
100 mIntentErrors = new HashMap<Integer, String>(); 135 mIntentErrors = new HashMap<Integer, String>();
101 mVSyncMonitor = new VSyncMonitor(context, mVSyncListener); 136 mVSyncMonitor = new VSyncMonitor(context, mVSyncListener);
137 mAccessibilityManager = (AccessibilityManager)
138 context.getSystemService(Context.ACCESSIBILITY_SERVICE);
102 } 139 }
103 140
104 /** 141 /**
105 * Shows an intent and returns the results to the callback object. 142 * Shows an intent and returns the results to the callback object.
106 * @param intent The PendingIntent that needs to be shown. 143 * @param intent The PendingIntent that needs to be shown.
107 * @param callback The object that will receive the results for the intent. 144 * @param callback The object that will receive the results for the intent.
108 * @param errorId The ID of error string to be show if activity is paused b efore intent 145 * @param errorId The ID of error string to be show if activity is paused b efore intent
109 * results, or null if no message is required. 146 * results, or null if no message is required.
110 * @return Whether the intent was shown. 147 * @return Whether the intent was shown.
111 */ 148 */
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 } 347 }
311 348
312 /** 349 /**
313 * Destroys the c++ WindowAndroid object if one has been created. 350 * Destroys the c++ WindowAndroid object if one has been created.
314 */ 351 */
315 public void destroy() { 352 public void destroy() {
316 if (mNativeWindowAndroid != 0) { 353 if (mNativeWindowAndroid != 0) {
317 nativeDestroy(mNativeWindowAndroid); 354 nativeDestroy(mNativeWindowAndroid);
318 mNativeWindowAndroid = 0; 355 mNativeWindowAndroid = 0;
319 } 356 }
357
358 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
359 if (mTouchExplorationMonitor != null) mTouchExplorationMonitor.destr oy();
360 }
320 } 361 }
321 362
322 /** 363 /**
323 * Returns a pointer to the c++ AndroidWindow object and calls the initializ er if 364 * Returns a pointer to the c++ AndroidWindow object and calls the initializ er if
324 * the object has not been previously initialized. 365 * the object has not been previously initialized.
325 * @return A pointer to the c++ AndroidWindow. 366 * @return A pointer to the c++ AndroidWindow.
326 */ 367 */
327 public long getNativePointer() { 368 public long getNativePointer() {
328 if (mNativeWindowAndroid == 0) { 369 if (mNativeWindowAndroid == 0) {
329 mNativeWindowAndroid = nativeInit(); 370 mNativeWindowAndroid = nativeInit();
330 } 371 }
331 return mNativeWindowAndroid; 372 return mNativeWindowAndroid;
332 } 373 }
333 374
334 /** 375 /**
335 * Set the animation placeholder view, which we set to 'draw' during animati ons, such that 376 * Set the animation placeholder view, which we set to 'draw' during animati ons, such that
336 * animations aren't clipped by the SurfaceView 'hole'. This can be the Surf aceView itself 377 * animations aren't clipped by the SurfaceView 'hole'. This can be the Surf aceView itself
337 * or a view directly on top of it. This could be extended to many views if we ever need it. 378 * or a view directly on top of it. This could be extended to many views if we ever need it.
338 */ 379 */
339 public void setAnimationPlaceholderView(View view) { 380 public void setAnimationPlaceholderView(View view) {
340 mAnimationPlaceholderView = view; 381 mAnimationPlaceholderView = view;
382
383 // The accessibility focus ring also gets clipped by the SurfaceView 'ho le', so
384 // make sure the animation placeholder view is in place if touch explora tion is on.
385 mIsTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEna bled();
386 refreshWillNotDraw();
387 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
388 mTouchExplorationMonitor = new TouchExplorationMonitor();
389 }
341 } 390 }
342 391
343 /** 392 /**
344 * Sets the keyboard accessory view. 393 * Sets the keyboard accessory view.
345 * @param view This view sits at the bottom of the content area and pushes t he content up rather 394 * @param view This view sits at the bottom of the content area and pushes t he content up rather
346 * than overlaying it. Currently used as a container for Autofil l suggestions. 395 * than overlaying it. Currently used as a container for Autofil l suggestions.
347 */ 396 */
348 public void setKeyboardAccessoryView(ViewGroup view) { 397 public void setKeyboardAccessoryView(ViewGroup view) {
349 mKeyboardAccessoryView = view; 398 mKeyboardAccessoryView = view;
350 } 399 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 if (animation.isStarted()) throw new IllegalArgumentException("Already s tarted."); 452 if (animation.isStarted()) throw new IllegalArgumentException("Already s tarted.");
404 boolean added = mAnimationsOverContent.add(animation); 453 boolean added = mAnimationsOverContent.add(animation);
405 if (!added) throw new IllegalArgumentException("Already Added."); 454 if (!added) throw new IllegalArgumentException("Already Added.");
406 455
407 // We start the animation in this method to help guarantee that we never get stuck in this 456 // We start the animation in this method to help guarantee that we never get stuck in this
408 // state or leak objects into the set. Starting the animation here shoul d guarantee that we 457 // state or leak objects into the set. Starting the animation here shoul d guarantee that we
409 // get an onAnimationEnd callback, and remove this animation. 458 // get an onAnimationEnd callback, and remove this animation.
410 animation.start(); 459 animation.start();
411 460
412 // When the first animation starts, make the placeholder 'draw' itself. 461 // When the first animation starts, make the placeholder 'draw' itself.
413 if (mAnimationPlaceholderView.willNotDraw()) { 462 refreshWillNotDraw();
414 mAnimationPlaceholderView.setWillNotDraw(false);
415 }
416 463
417 // When the last animation ends, remove the placeholder view, 464 // When the last animation ends, remove the placeholder view,
418 // returning to the default optimized state. 465 // returning to the default optimized state.
419 animation.addListener(new AnimatorListenerAdapter() { 466 animation.addListener(new AnimatorListenerAdapter() {
420 @Override 467 @Override
421 public void onAnimationEnd(Animator animation) { 468 public void onAnimationEnd(Animator animation) {
422 animation.removeListener(this); 469 animation.removeListener(this);
423 mAnimationsOverContent.remove(animation); 470 mAnimationsOverContent.remove(animation);
424 if (mAnimationsOverContent.isEmpty()) { 471 refreshWillNotDraw();
425 mAnimationPlaceholderView.setWillNotDraw(true);
426 }
427 } 472 }
428 }); 473 });
429 } 474 }
430 475
476 /**
477 * Update whether the placeholder is 'drawn' based on whether an animation i s running
478 * or touch exploration is enabled - if either of those are true, we call
479 * setWillNotDraw(false) to ensure that the animation is drawn over the Surf aceView,
480 * and otherwise we call setWillNotDraw(true).
481 */
482 private void refreshWillNotDraw() {
483 boolean willNotDraw = !mIsTouchExplorationEnabled && mAnimationsOverCont ent.isEmpty();
484 if (mAnimationPlaceholderView.willNotDraw() != willNotDraw) {
485 mAnimationPlaceholderView.setWillNotDraw(willNotDraw);
486 }
487 }
488
431 private native long nativeInit(); 489 private native long nativeInit();
432 private native void nativeOnVSync(long nativeWindowAndroid, 490 private native void nativeOnVSync(long nativeWindowAndroid,
433 long vsyncTimeMicros, 491 long vsyncTimeMicros,
434 long vsyncPeriodMicros); 492 long vsyncPeriodMicros);
435 private native void nativeOnActivityPaused(long nativeWindowAndroid); 493 private native void nativeOnActivityPaused(long nativeWindowAndroid);
436 private native void nativeOnActivityResumed(long nativeWindowAndroid); 494 private native void nativeOnActivityResumed(long nativeWindowAndroid);
437 private native void nativeDestroy(long nativeWindowAndroid); 495 private native void nativeDestroy(long nativeWindowAndroid);
438 496
439 } 497 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698