Draw the accessibility focus rectangle properly

Previously, the accessibility focus rectangle was only visible when it
overlapped with the m_editText View of QtActivityDelegate. The reason for
this is not completely verified, but this is the most likely reason:

  * The SurfaceView and QtLayout (ViewGroup) does not do any drawing
    themselves. Due to this their default value of the View::willNotDraw
    property is true.  Because of this Android might assume there is no
    content for the focus indicator to surround. (This was verified with
    setting the willNotDraw property to false on the accessibility view);

  * Another possible reason could be that overlays does not work for
    SurfaceView. It is documented that overlays does not work for
    SurfaceViews, so therefore it tried to use the overlay of another
    view. For some reason it picked the m_editText overlay instead of the
    QtLayout overlay.

    See here about overlay:
    http://developer.android.com/reference/android/view/View.html#getOverlay()

The solution is to add another View that covers the whole screen, which
will be used solely by android to draw the accessibility focus indicator.

In addition, we change the QtAccessibilityDelegate to no longer have the
SurfaceView as a host, but have the m_accView as a
host (the host can be freely changed, since all accessibility nodes are
virtualized through the delegate anyway)

For the record, this will be the current ordering of views in QtLayout:
(back-to-front order):
                                Qty     Default Qty
* Surface View(s)               >= 1    1
* Accessibility View            == 1    1
* Native View(s)                >= 0    1
* m_editText View               == 1    1
where the m_editText migth be interleaved among the Native Views.

[ChangeLog][Android][Accessibility] Fixed an issue where the accessibility
focus rectangle was not drawn properly

Task-number: QTBUG-38869
Change-Id: I64d6b6ec45b27d0d93ac9dd840de764c18c55d04
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
This commit is contained in:
Jan Arve Saether 2014-11-05 11:44:00 +01:00 committed by Jan Arve Sæther
parent 2df293267e
commit e682ea6f78
2 changed files with 42 additions and 23 deletions

View File

@ -80,6 +80,7 @@ import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
@ -126,6 +127,7 @@ public class QtActivityDelegate
private boolean m_quitApp = true;
private Process m_debuggerProcess = null; // debugger process
private View m_dummyView = null;
private View m_accView = null;
private boolean m_keyboardIsVisible = false;
public boolean m_backKeyPressedSent = false;
private long m_showHideTimeStamp = System.nanoTime();
@ -1178,10 +1180,48 @@ public class QtActivityDelegate
// Native views are always inserted in the end of the stack (i.e., on top).
// All other views are stacked based on the order they are created.
final int index = getSurfaceCount();
m_layout.addView(surface, index);
final int surfaceCount = getSurfaceCount();
m_layout.addView(surface, surfaceCount);
m_surfaces.put(id, surface);
// Initialize Accessibility
// The accessibility code depends on android API level 16, so dynamically resolve it
if (android.os.Build.VERSION.SDK_INT >= 16) {
if (m_accView == null) {
try {
View accView = new View(m_activity);
accView.setId(View.NO_ID);
// ### Keep this for debugging for a while. It allows us to visually see that our View
// ### is on top of the surface(s)
// ColorDrawable color = new ColorDrawable(0x80ff8080); //0xAARRGGBB
// accView.setBackground(color);
final String a11yDelegateClassName = "org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate";
Class<?> qtDelegateClass = Class.forName(a11yDelegateClassName);
Constructor constructor = qtDelegateClass.getConstructor(Class.forName("android.view.View"));
Object accessibilityDelegate = constructor.newInstance(accView);
Class a11yDelegateClass = Class.forName("android.view.View$AccessibilityDelegate");
Method setDelegateMethod = accView.getClass().getMethod("setAccessibilityDelegate", a11yDelegateClass);
setDelegateMethod.invoke(accView, accessibilityDelegate);
// if all is fine, add it to the layout
m_layout.addView(accView, surfaceCount + 1,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
m_accView = accView;
} catch (ClassNotFoundException e) {
// Class not found is fine since we are compatible with Android API < 16, but the function will
// only be available with that API level.
} catch (Exception e) {
// Unknown exception means something went wrong.
Log.w("Qt A11y", "Unknown exception: " + e.toString());
}
}
}
}
public void setSurfaceGeometry(int id, int x, int y, int w, int h) {
@ -1225,7 +1265,6 @@ public class QtActivityDelegate
return m_surfaces.size();
}
public void bringChildToFront(int id)
{
View view = m_surfaces.get(id);

View File

@ -88,26 +88,6 @@ public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
public void surfaceCreated(SurfaceHolder holder)
{
QtNative.setSurface(getId(), holder.getSurface(), getWidth(), getHeight());
// Initialize Accessibility
// The accessibility code depends on android API level 16, so dynamically resolve it
if (android.os.Build.VERSION.SDK_INT >= 16) {
try {
final String a11yDelegateClassName = "org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate";
Class<?> qtDelegateClass = Class.forName(a11yDelegateClassName);
Constructor constructor = qtDelegateClass.getConstructor(Class.forName("android.view.View"));
m_accessibilityDelegate = constructor.newInstance(this);
Class a11yDelegateClass = Class.forName("android.view.View$AccessibilityDelegate");
Method setDelegateMethod = this.getClass().getMethod("setAccessibilityDelegate", a11yDelegateClass);
setDelegateMethod.invoke(this, m_accessibilityDelegate);
} catch (ClassNotFoundException e) {
// Class not found is fine since we are compatible with Android API < 16, but the function will
// only be available with that API level.
} catch (Exception e) {
// Unknown exception means something went wrong.
Log.w("Qt A11y", "Unknown exception: " + e.toString());
}
}
}
@Override