Skip to content

Commit 4c38e24

Browse files
Charles ChenAndroid (Google) Code Review
authored andcommitted
Merge "Don't alter accessibility JS APIs unless a page is about to load." into jb-mr1-dev
2 parents c378656 + 03e636f commit 4c38e24

File tree

2 files changed

+96
-45
lines changed

2 files changed

+96
-45
lines changed

core/java/android/webkit/AccessibilityInjector.java

Lines changed: 90 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,12 @@ class AccessibilityInjector {
9797
// Template for JavaScript that performs AndroidVox actions.
9898
private static final String ACCESSIBILITY_ANDROIDVOX_TEMPLATE =
9999
"(function() {" +
100-
" if ((typeof(cvox) != 'undefined')"+
100+
" if ((typeof(cvox) != 'undefined')" +
101+
" && (cvox != null)" +
101102
" && (typeof(cvox.ChromeVox) != 'undefined')" +
103+
" && (cvox.ChromeVox != null)" +
102104
" && (typeof(cvox.AndroidVox) != 'undefined')" +
105+
" && (cvox.AndroidVox != null)" +
103106
" && cvox.ChromeVox.isActive) {" +
104107
" return cvox.AndroidVox.performAction('%1s');" +
105108
" } else {" +
@@ -110,9 +113,12 @@ class AccessibilityInjector {
110113
// JS code used to shut down an active AndroidVox instance.
111114
private static final String TOGGLE_CVOX_TEMPLATE =
112115
"javascript:(function() {" +
113-
" if ((typeof(cvox) != 'undefined')"+
116+
" if ((typeof(cvox) != 'undefined')" +
117+
" && (cvox != null)" +
114118
" && (typeof(cvox.ChromeVox) != 'undefined')" +
115-
" && (typeof(cvox.ChromeVox.host) != 'undefined')) {" +
119+
" && (cvox.ChromeVox != null)" +
120+
" && (typeof(cvox.ChromeVox.host) != 'undefined')" +
121+
" && (cvox.ChromeVox.host != null)) {" +
116122
" cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b);" +
117123
" }" +
118124
"})();";
@@ -131,34 +137,61 @@ public AccessibilityInjector(WebViewClassic webViewClassic) {
131137
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
132138
}
133139

140+
/**
141+
* If JavaScript is enabled, pauses or resumes AndroidVox.
142+
*
143+
* @param enabled Whether feedback should be enabled.
144+
*/
145+
public void toggleAccessibilityFeedback(boolean enabled) {
146+
if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) {
147+
return;
148+
}
149+
150+
toggleAndroidVox(enabled);
151+
152+
if (!enabled && (mTextToSpeech != null)) {
153+
mTextToSpeech.stop();
154+
}
155+
}
156+
134157
/**
135158
* Attempts to load scripting interfaces for accessibility.
136159
* <p>
137-
* This should be called when the window is attached.
138-
* </p>
160+
* This should only be called before a page loads.
139161
*/
140-
public void addAccessibilityApisIfNecessary() {
162+
private void addAccessibilityApisIfNecessary() {
141163
if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) {
142164
return;
143165
}
144166

145167
addTtsApis();
146168
addCallbackApis();
147-
toggleAndroidVox(true);
148169
}
149170

150171
/**
151172
* Attempts to unload scripting interfaces for accessibility.
152173
* <p>
153-
* This should be called when the window is detached.
154-
* </p>
174+
* This should only be called before a page loads.
155175
*/
156-
public void removeAccessibilityApisIfNecessary() {
157-
toggleAndroidVox(false);
176+
private void removeAccessibilityApisIfNecessary() {
158177
removeTtsApis();
159178
removeCallbackApis();
160179
}
161180

181+
/**
182+
* Destroys this accessibility injector.
183+
*/
184+
public void destroy() {
185+
if (mTextToSpeech != null) {
186+
mTextToSpeech.shutdown();
187+
mTextToSpeech = null;
188+
}
189+
190+
if (mCallback != null) {
191+
mCallback = null;
192+
}
193+
}
194+
162195
private void toggleAndroidVox(boolean state) {
163196
if (!mAccessibilityScriptInjected) {
164197
return;
@@ -517,7 +550,12 @@ private String getScreenReaderInjectionUrl() {
517550
* settings.
518551
*/
519552
private boolean isJavaScriptEnabled() {
520-
return mWebView.getSettings().getJavaScriptEnabled();
553+
final WebSettings settings = mWebView.getSettings();
554+
if (settings == null) {
555+
return false;
556+
}
557+
558+
return settings.getJavaScriptEnabled();
521559
}
522560

523561
/**
@@ -732,7 +770,7 @@ private static class CallbackHandler {
732770
private final String mInterfaceName;
733771

734772
private boolean mResult = false;
735-
private long mResultId = -1;
773+
private int mResultId = -1;
736774

737775
private CallbackHandler(String interfaceName) {
738776
mInterfaceName = interfaceName;
@@ -784,34 +822,46 @@ private void clearResultLocked() {
784822
* @return Whether the result was received.
785823
*/
786824
private boolean waitForResultTimedLocked(int resultId) {
787-
if (DEBUG)
788-
Log.d(TAG, "Waiting for CVOX result...");
789-
long waitTimeMillis = RESULT_TIMEOUT;
790825
final long startTimeMillis = SystemClock.uptimeMillis();
826+
827+
if (DEBUG)
828+
Log.d(TAG, "Waiting for CVOX result with ID " + resultId + "...");
829+
791830
while (true) {
831+
// Fail if we received a callback from the future.
832+
if (mResultId > resultId) {
833+
if (DEBUG)
834+
Log.w(TAG, "Aborted CVOX result");
835+
return false;
836+
}
837+
838+
final long elapsedTimeMillis = (SystemClock.uptimeMillis() - startTimeMillis);
839+
840+
// Succeed if we received the callback we were expecting.
841+
if (DEBUG)
842+
Log.w(TAG, "Check " + mResultId + " versus expected " + resultId);
843+
if (mResultId == resultId) {
844+
if (DEBUG)
845+
Log.w(TAG, "Received CVOX result after " + elapsedTimeMillis + " ms");
846+
return true;
847+
}
848+
849+
final long waitTimeMillis = (RESULT_TIMEOUT - elapsedTimeMillis);
850+
851+
// Fail if we've already exceeded the timeout.
852+
if (waitTimeMillis <= 0) {
853+
if (DEBUG)
854+
Log.w(TAG, "Timed out while waiting for CVOX result");
855+
return false;
856+
}
857+
792858
try {
793-
if (mResultId == resultId) {
794-
if (DEBUG)
795-
Log.w(TAG, "Received CVOX result");
796-
return true;
797-
}
798-
if (mResultId > resultId) {
799-
if (DEBUG)
800-
Log.w(TAG, "Obsolete CVOX result");
801-
return false;
802-
}
803-
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
804-
waitTimeMillis = RESULT_TIMEOUT - elapsedTimeMillis;
805-
if (waitTimeMillis <= 0) {
806-
if (DEBUG)
807-
Log.w(TAG, "Timed out while waiting for CVOX result");
808-
return false;
809-
}
859+
if (DEBUG)
860+
Log.w(TAG, "Start waiting...");
810861
mResultLock.wait(waitTimeMillis);
811862
} catch (InterruptedException ie) {
812863
if (DEBUG)
813864
Log.w(TAG, "Interrupted while waiting for CVOX result");
814-
/* ignore */
815865
}
816866
}
817867
}
@@ -827,11 +877,11 @@ private boolean waitForResultTimedLocked(int resultId) {
827877
@SuppressWarnings("unused")
828878
public void onResult(String id, String result) {
829879
if (DEBUG)
830-
Log.w(TAG, "Saw CVOX result of '" + result + "'");
831-
final long resultId;
880+
Log.w(TAG, "Saw CVOX result of '" + result + "' for ID " + id);
881+
final int resultId;
832882

833883
try {
834-
resultId = Long.parseLong(id);
884+
resultId = Integer.parseInt(id);
835885
} catch (NumberFormatException e) {
836886
return;
837887
}
@@ -840,6 +890,9 @@ public void onResult(String id, String result) {
840890
if (resultId > mResultId) {
841891
mResult = Boolean.parseBoolean(result);
842892
mResultId = resultId;
893+
} else {
894+
if (DEBUG)
895+
Log.w(TAG, "Result with ID " + resultId + " was stale vesus " + mResultId);
843896
}
844897
mResultLock.notifyAll();
845898
}

core/java/android/webkit/WebViewClassic.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,10 @@ private void ensureFunctorDetached() {
21322132

21332133
private void destroyJava() {
21342134
mCallbackProxy.blockMessages();
2135+
if (mAccessibilityInjector != null) {
2136+
mAccessibilityInjector.destroy();
2137+
mAccessibilityInjector = null;
2138+
}
21352139
if (mWebViewCore != null) {
21362140
// Tell WebViewCore to destroy itself
21372141
synchronized (this) {
@@ -3967,8 +3971,6 @@ private boolean setContentScrollBy(int cx, int cy, boolean animate) {
39673971
// null, and that will be the case
39683972
mWebView.setCertificate(null);
39693973

3970-
// reset the flag since we set to true in if need after
3971-
// loading is see onPageFinished(Url)
39723974
if (isAccessibilityInjectionEnabled()) {
39733975
getAccessibilityInjector().onPageStarted(url);
39743976
}
@@ -5397,7 +5399,7 @@ public void onAttachedToWindow() {
53975399
if (mWebView.hasWindowFocus()) setActive(true);
53985400

53995401
if (isAccessibilityInjectionEnabled()) {
5400-
getAccessibilityInjector().addAccessibilityApisIfNecessary();
5402+
getAccessibilityInjector().toggleAccessibilityFeedback(true);
54015403
}
54025404

54035405
updateHwAccelerated();
@@ -5410,11 +5412,7 @@ public void onDetachedFromWindow() {
54105412
if (mWebView.hasWindowFocus()) setActive(false);
54115413

54125414
if (isAccessibilityInjectionEnabled()) {
5413-
getAccessibilityInjector().removeAccessibilityApisIfNecessary();
5414-
} else {
5415-
// Ensure the injector is cleared if we're detaching from the window
5416-
// and accessibility is disabled.
5417-
mAccessibilityInjector = null;
5415+
getAccessibilityInjector().toggleAccessibilityFeedback(false);
54185416
}
54195417

54205418
updateHwAccelerated();

0 commit comments

Comments
 (0)