OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |