Commit 9b015b54 authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Fix Android accessibility focus not being drawn over transparent view.

BUG=467550

Review URL: https://codereview.chromium.org/1126563003

Cr-Commit-Position: refs/heads/master@{#329484}
parent 07b68b6b
...@@ -7,16 +7,19 @@ package org.chromium.ui.base; ...@@ -7,16 +7,19 @@ package org.chromium.ui.base;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast; import android.widget.Toast;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
...@@ -35,6 +38,29 @@ import java.util.LinkedList; ...@@ -35,6 +38,29 @@ import java.util.LinkedList;
public class WindowAndroid { public class WindowAndroid {
private static final String TAG = "WindowAndroid"; private static final String TAG = "WindowAndroid";
@TargetApi(Build.VERSION_CODES.KITKAT)
private class TouchExplorationMonitor {
// Listener that tells us when touch exploration is enabled or disabled.
private AccessibilityManager.TouchExplorationStateChangeListener mTouchExplorationListener;
TouchExplorationMonitor() {
mTouchExplorationListener =
new AccessibilityManager.TouchExplorationStateChangeListener() {
public void onTouchExplorationStateChanged(boolean enabled) {
mIsTouchExplorationEnabled =
mAccessibilityManager.isTouchExplorationEnabled();
refreshWillNotDraw();
}
};
mAccessibilityManager.addTouchExplorationStateChangeListener(mTouchExplorationListener);
}
void destroy() {
mAccessibilityManager.removeTouchExplorationStateChangeListener(
mTouchExplorationListener);
}
}
// Native pointer to the c++ WindowAndroid object. // Native pointer to the c++ WindowAndroid object.
private long mNativeWindowAndroid = 0; private long mNativeWindowAndroid = 0;
private final VSyncMonitor mVSyncMonitor; private final VSyncMonitor mVSyncMonitor;
...@@ -61,6 +87,15 @@ public class WindowAndroid { ...@@ -61,6 +87,15 @@ public class WindowAndroid {
private boolean mIsKeyboardShowing = false; private boolean mIsKeyboardShowing = false;
// System accessibility service.
private final AccessibilityManager mAccessibilityManager;
// Whether touch exploration is enabled.
private boolean mIsTouchExplorationEnabled;
// On KitKat and higher, a class that monitors the touch exploration state.
private TouchExplorationMonitor mTouchExplorationMonitor;
/** /**
* An interface to notify listeners of changes in the soft keyboard's visibility. * An interface to notify listeners of changes in the soft keyboard's visibility.
*/ */
...@@ -99,6 +134,8 @@ public class WindowAndroid { ...@@ -99,6 +134,8 @@ public class WindowAndroid {
mOutstandingIntents = new SparseArray<IntentCallback>(); mOutstandingIntents = new SparseArray<IntentCallback>();
mIntentErrors = new HashMap<Integer, String>(); mIntentErrors = new HashMap<Integer, String>();
mVSyncMonitor = new VSyncMonitor(context, mVSyncListener); mVSyncMonitor = new VSyncMonitor(context, mVSyncListener);
mAccessibilityManager = (AccessibilityManager)
context.getSystemService(Context.ACCESSIBILITY_SERVICE);
} }
/** /**
...@@ -317,6 +354,10 @@ public class WindowAndroid { ...@@ -317,6 +354,10 @@ public class WindowAndroid {
nativeDestroy(mNativeWindowAndroid); nativeDestroy(mNativeWindowAndroid);
mNativeWindowAndroid = 0; mNativeWindowAndroid = 0;
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mTouchExplorationMonitor != null) mTouchExplorationMonitor.destroy();
}
} }
/** /**
...@@ -338,6 +379,14 @@ public class WindowAndroid { ...@@ -338,6 +379,14 @@ public class WindowAndroid {
*/ */
public void setAnimationPlaceholderView(View view) { public void setAnimationPlaceholderView(View view) {
mAnimationPlaceholderView = view; mAnimationPlaceholderView = view;
// The accessibility focus ring also gets clipped by the SurfaceView 'hole', so
// make sure the animation placeholder view is in place if touch exploration is on.
mIsTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
refreshWillNotDraw();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mTouchExplorationMonitor = new TouchExplorationMonitor();
}
} }
/** /**
...@@ -410,9 +459,7 @@ public class WindowAndroid { ...@@ -410,9 +459,7 @@ public class WindowAndroid {
animation.start(); animation.start();
// When the first animation starts, make the placeholder 'draw' itself. // When the first animation starts, make the placeholder 'draw' itself.
if (mAnimationPlaceholderView.willNotDraw()) { refreshWillNotDraw();
mAnimationPlaceholderView.setWillNotDraw(false);
}
// When the last animation ends, remove the placeholder view, // When the last animation ends, remove the placeholder view,
// returning to the default optimized state. // returning to the default optimized state.
...@@ -421,13 +468,24 @@ public class WindowAndroid { ...@@ -421,13 +468,24 @@ public class WindowAndroid {
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
animation.removeListener(this); animation.removeListener(this);
mAnimationsOverContent.remove(animation); mAnimationsOverContent.remove(animation);
if (mAnimationsOverContent.isEmpty()) { refreshWillNotDraw();
mAnimationPlaceholderView.setWillNotDraw(true);
}
} }
}); });
} }
/**
* Update whether the placeholder is 'drawn' based on whether an animation is running
* or touch exploration is enabled - if either of those are true, we call
* setWillNotDraw(false) to ensure that the animation is drawn over the SurfaceView,
* and otherwise we call setWillNotDraw(true).
*/
private void refreshWillNotDraw() {
boolean willNotDraw = !mIsTouchExplorationEnabled && mAnimationsOverContent.isEmpty();
if (mAnimationPlaceholderView.willNotDraw() != willNotDraw) {
mAnimationPlaceholderView.setWillNotDraw(willNotDraw);
}
}
private native long nativeInit(); private native long nativeInit();
private native void nativeOnVSync(long nativeWindowAndroid, private native void nativeOnVSync(long nativeWindowAndroid,
long vsyncTimeMicros, long vsyncTimeMicros,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment