diff options
Diffstat (limited to 'core/java')
9 files changed, 153 insertions, 63 deletions
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 0941d71..2bec1c1 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -16,6 +16,7 @@ package android.os; +import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -91,7 +92,7 @@ public class FileUtils { } return result; } - + /** * Copy data from a source stream to destFile. * Return true if succeed, return false if failed. @@ -143,12 +144,16 @@ public class FileUtils { */ public static String readTextFile(File file, int max, String ellipsis) throws IOException { InputStream input = new FileInputStream(file); + // wrapping a BufferedInputStream around it because when reading /proc with unbuffered + // input stream, bytes read not equal to buffer size is not necessarily the correct + // indication for EOF; but it is true for BufferedInputStream due to its implementation. + BufferedInputStream bis = new BufferedInputStream(input); try { long size = file.length(); if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes if (size > 0 && (max == 0 || size < max)) max = (int) size; byte[] data = new byte[max + 1]; - int length = input.read(data); + int length = bis.read(data); if (length <= 0) return ""; if (length <= max) return new String(data, 0, length); if (ellipsis == null) return new String(data, 0, max); @@ -161,7 +166,7 @@ public class FileUtils { if (last != null) rolled = true; byte[] tmp = last; last = data; data = tmp; if (data == null) data = new byte[-max]; - len = input.read(data); + len = bis.read(data); } while (len == data.length); if (last == null && len <= 0) return ""; @@ -178,12 +183,13 @@ public class FileUtils { int len; byte[] data = new byte[1024]; do { - len = input.read(data); + len = bis.read(data); if (len > 0) contents.write(data, 0, len); } while (len == data.length); return contents.toString(); } } finally { + bis.close(); input.close(); } } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 2739cac..898c766 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -320,6 +320,8 @@ public class UserManager { * @return a value greater than or equal to 1 */ public static int getMaxSupportedUsers() { + // Don't allow multiple users on certain builds + if (android.os.Build.ID.startsWith("JVP")) return 1; return SystemProperties.getInt("fw.max_users", Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)); } diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index 357a16e..fe5cad4 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -97,9 +97,12 @@ class AccessibilityInjector { // Template for JavaScript that performs AndroidVox actions. private static final String ACCESSIBILITY_ANDROIDVOX_TEMPLATE = "(function() {" + - " if ((typeof(cvox) != 'undefined')"+ + " if ((typeof(cvox) != 'undefined')" + + " && (cvox != null)" + " && (typeof(cvox.ChromeVox) != 'undefined')" + + " && (cvox.ChromeVox != null)" + " && (typeof(cvox.AndroidVox) != 'undefined')" + + " && (cvox.AndroidVox != null)" + " && cvox.ChromeVox.isActive) {" + " return cvox.AndroidVox.performAction('%1s');" + " } else {" + @@ -110,9 +113,12 @@ class AccessibilityInjector { // JS code used to shut down an active AndroidVox instance. private static final String TOGGLE_CVOX_TEMPLATE = "javascript:(function() {" + - " if ((typeof(cvox) != 'undefined')"+ + " if ((typeof(cvox) != 'undefined')" + + " && (cvox != null)" + " && (typeof(cvox.ChromeVox) != 'undefined')" + - " && (typeof(cvox.ChromeVox.host) != 'undefined')) {" + + " && (cvox.ChromeVox != null)" + + " && (typeof(cvox.ChromeVox.host) != 'undefined')" + + " && (cvox.ChromeVox.host != null)) {" + " cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b);" + " }" + "})();"; @@ -132,33 +138,60 @@ class AccessibilityInjector { } /** + * If JavaScript is enabled, pauses or resumes AndroidVox. + * + * @param enabled Whether feedback should be enabled. + */ + public void toggleAccessibilityFeedback(boolean enabled) { + if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) { + return; + } + + toggleAndroidVox(enabled); + + if (!enabled && (mTextToSpeech != null)) { + mTextToSpeech.stop(); + } + } + + /** * Attempts to load scripting interfaces for accessibility. * <p> - * This should be called when the window is attached. - * </p> + * This should only be called before a page loads. */ - public void addAccessibilityApisIfNecessary() { + private void addAccessibilityApisIfNecessary() { if (!isAccessibilityEnabled() || !isJavaScriptEnabled()) { return; } addTtsApis(); addCallbackApis(); - toggleAndroidVox(true); } /** * Attempts to unload scripting interfaces for accessibility. * <p> - * This should be called when the window is detached. - * </p> + * This should only be called before a page loads. */ - public void removeAccessibilityApisIfNecessary() { - toggleAndroidVox(false); + private void removeAccessibilityApisIfNecessary() { removeTtsApis(); removeCallbackApis(); } + /** + * Destroys this accessibility injector. + */ + public void destroy() { + if (mTextToSpeech != null) { + mTextToSpeech.shutdown(); + mTextToSpeech = null; + } + + if (mCallback != null) { + mCallback = null; + } + } + private void toggleAndroidVox(boolean state) { if (!mAccessibilityScriptInjected) { return; @@ -517,7 +550,12 @@ class AccessibilityInjector { * settings. */ private boolean isJavaScriptEnabled() { - return mWebView.getSettings().getJavaScriptEnabled(); + final WebSettings settings = mWebView.getSettings(); + if (settings == null) { + return false; + } + + return settings.getJavaScriptEnabled(); } /** @@ -732,7 +770,7 @@ class AccessibilityInjector { private final String mInterfaceName; private boolean mResult = false; - private long mResultId = -1; + private int mResultId = -1; private CallbackHandler(String interfaceName) { mInterfaceName = interfaceName; @@ -784,34 +822,46 @@ class AccessibilityInjector { * @return Whether the result was received. */ private boolean waitForResultTimedLocked(int resultId) { - if (DEBUG) - Log.d(TAG, "Waiting for CVOX result..."); - long waitTimeMillis = RESULT_TIMEOUT; final long startTimeMillis = SystemClock.uptimeMillis(); + + if (DEBUG) + Log.d(TAG, "Waiting for CVOX result with ID " + resultId + "..."); + while (true) { + // Fail if we received a callback from the future. + if (mResultId > resultId) { + if (DEBUG) + Log.w(TAG, "Aborted CVOX result"); + return false; + } + + final long elapsedTimeMillis = (SystemClock.uptimeMillis() - startTimeMillis); + + // Succeed if we received the callback we were expecting. + if (DEBUG) + Log.w(TAG, "Check " + mResultId + " versus expected " + resultId); + if (mResultId == resultId) { + if (DEBUG) + Log.w(TAG, "Received CVOX result after " + elapsedTimeMillis + " ms"); + return true; + } + + final long waitTimeMillis = (RESULT_TIMEOUT - elapsedTimeMillis); + + // Fail if we've already exceeded the timeout. + if (waitTimeMillis <= 0) { + if (DEBUG) + Log.w(TAG, "Timed out while waiting for CVOX result"); + return false; + } + try { - if (mResultId == resultId) { - if (DEBUG) - Log.w(TAG, "Received CVOX result"); - return true; - } - if (mResultId > resultId) { - if (DEBUG) - Log.w(TAG, "Obsolete CVOX result"); - return false; - } - final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; - waitTimeMillis = RESULT_TIMEOUT - elapsedTimeMillis; - if (waitTimeMillis <= 0) { - if (DEBUG) - Log.w(TAG, "Timed out while waiting for CVOX result"); - return false; - } + if (DEBUG) + Log.w(TAG, "Start waiting..."); mResultLock.wait(waitTimeMillis); } catch (InterruptedException ie) { if (DEBUG) Log.w(TAG, "Interrupted while waiting for CVOX result"); - /* ignore */ } } } @@ -827,11 +877,11 @@ class AccessibilityInjector { @SuppressWarnings("unused") public void onResult(String id, String result) { if (DEBUG) - Log.w(TAG, "Saw CVOX result of '" + result + "'"); - final long resultId; + Log.w(TAG, "Saw CVOX result of '" + result + "' for ID " + id); + final int resultId; try { - resultId = Long.parseLong(id); + resultId = Integer.parseInt(id); } catch (NumberFormatException e) { return; } @@ -840,6 +890,9 @@ class AccessibilityInjector { if (resultId > mResultId) { mResult = Boolean.parseBoolean(result); mResultId = resultId; + } else { + if (DEBUG) + Log.w(TAG, "Result with ID " + resultId + " was stale vesus " + mResultId); } mResultLock.notifyAll(); } diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 7d0d0ba..0f8966e 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -2132,6 +2132,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private void destroyJava() { mCallbackProxy.blockMessages(); + if (mAccessibilityInjector != null) { + mAccessibilityInjector.destroy(); + mAccessibilityInjector = null; + } if (mWebViewCore != null) { // Tell WebViewCore to destroy itself synchronized (this) { @@ -3967,8 +3971,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc // null, and that will be the case mWebView.setCertificate(null); - // reset the flag since we set to true in if need after - // loading is see onPageFinished(Url) if (isAccessibilityInjectionEnabled()) { getAccessibilityInjector().onPageStarted(url); } @@ -5397,7 +5399,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc if (mWebView.hasWindowFocus()) setActive(true); if (isAccessibilityInjectionEnabled()) { - getAccessibilityInjector().addAccessibilityApisIfNecessary(); + getAccessibilityInjector().toggleAccessibilityFeedback(true); } updateHwAccelerated(); @@ -5410,11 +5412,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc if (mWebView.hasWindowFocus()) setActive(false); if (isAccessibilityInjectionEnabled()) { - getAccessibilityInjector().removeAccessibilityApisIfNecessary(); - } else { - // Ensure the injector is cleared if we're detaching from the window - // and accessibility is disabled. - mAccessibilityInjector = null; + getAccessibilityInjector().toggleAccessibilityFeedback(false); } updateHwAccelerated(); diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java index a2a38dc..4e405f4 100644 --- a/core/java/com/android/internal/widget/RotarySelector.java +++ b/core/java/com/android/internal/widget/RotarySelector.java @@ -25,7 +25,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.drawable.Drawable; +import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -667,11 +669,16 @@ public class RotarySelector extends View { * Triggers haptic feedback. */ private synchronized void vibrate(long duration) { - if (mVibrator == null) { - mVibrator = (android.os.Vibrator) - getContext().getSystemService(Context.VIBRATOR_SERVICE); + final boolean hapticEnabled = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, + UserHandle.USER_CURRENT) != 0; + if (hapticEnabled) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) getContext() + .getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); } - mVibrator.vibrate(duration); } /** diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java index f535a08..aebc4f6 100644 --- a/core/java/com/android/internal/widget/SlidingTab.java +++ b/core/java/com/android/internal/widget/SlidingTab.java @@ -21,7 +21,9 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; @@ -811,11 +813,16 @@ public class SlidingTab extends ViewGroup { * Triggers haptic feedback. */ private synchronized void vibrate(long duration) { - if (mVibrator == null) { - mVibrator = (android.os.Vibrator) - getContext().getSystemService(Context.VIBRATOR_SERVICE); + final boolean hapticEnabled = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, + UserHandle.USER_CURRENT) != 0; + if (hapticEnabled) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) getContext() + .getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); } - mVibrator.vibrate(duration); } /** diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java index 2d89234..d33d50c 100644 --- a/core/java/com/android/internal/widget/WaveView.java +++ b/core/java/com/android/internal/widget/WaveView.java @@ -25,7 +25,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; +import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -573,11 +575,16 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen * Triggers haptic feedback. */ private synchronized void vibrate(long duration) { - if (mVibrator == null) { - mVibrator = (android.os.Vibrator) - getContext().getSystemService(Context.VIBRATOR_SERVICE); + final boolean hapticEnabled = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, + UserHandle.USER_CURRENT) != 0; + if (hapticEnabled) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) getContext() + .getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); } - mVibrator.vibrate(duration); } /** diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java index f507a79..0f49776 100644 --- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java +++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java @@ -31,7 +31,9 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -543,7 +545,10 @@ public class GlowPadView extends View { } private void vibrate() { - if (mVibrator != null) { + final boolean hapticEnabled = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, + UserHandle.USER_CURRENT) != 0; + if (mVibrator != null && hapticEnabled) { mVibrator.vibrate(mVibrationDuration); } } diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java index 7990b4c..e22d1e8 100644 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -32,7 +32,9 @@ import android.graphics.Canvas; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -593,7 +595,10 @@ public class MultiWaveView extends View { } private void vibrate() { - if (mVibrator != null) { + final boolean hapticEnabled = Settings.System.getIntForUser( + mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, + UserHandle.USER_CURRENT) != 0; + if (mVibrator != null && hapticEnabled) { mVibrator.vibrate(mVibrationDuration); } } |