Merge change 6252 into donut

* changes:
  Don't re-parse the framework resources all the time.
diff --git a/api/current.xml b/api/current.xml
index b1e042b..d028faa 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -139718,6 +139718,21 @@
 <parameter name="units" type="int">
 </parameter>
 </method>
+<method name="computeCurrentVelocity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="units" type="int">
+</parameter>
+<parameter name="maxVelocity" type="float">
+</parameter>
+</method>
 <method name="getXVelocity"
  return="float"
  abstract="false"
@@ -144121,6 +144136,17 @@
  visibility="public"
 >
 </method>
+<method name="getMaximumFlingVelocity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
 <method name="getMinimumFlingVelocity"
  return="int"
  abstract="false"
@@ -144187,6 +144213,17 @@
  visibility="public"
 >
 </method>
+<method name="getScaledMaximumFlingVelocity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getScaledMinimumFlingVelocity"
  return="int"
  abstract="false"
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 23f3e3c..1e558be 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -198,6 +198,7 @@
     private int mTouchSlopSquare;
     private int mDoubleTapSlopSquare;
     private int mMinimumFlingVelocity;
+    private int mMaximumFlingVelocity;
 
     private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
     private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
@@ -361,11 +362,13 @@
             doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
             //noinspection deprecation
             mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
+            mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
         } else {
             final ViewConfiguration configuration = ViewConfiguration.get(context);
             touchSlop = configuration.getScaledTouchSlop();
             doubleTapSlop = configuration.getScaledDoubleTapSlop();
             mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+            mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity();
         }
         mTouchSlopSquare = touchSlop * touchSlop;
         mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
@@ -505,7 +508,7 @@
 
                 // A fling must travel the minimum tap distance
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                 final float velocityY = velocityTracker.getYVelocity();
                 final float velocityX = velocityTracker.getXVelocity();
 
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index c708f54..5d89c46 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -165,7 +165,17 @@
             pastTime[i] = 0;
         }
     }
-    
+
+    /**
+     * Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum
+     * velocity of Float.MAX_VALUE.
+     * 
+     * @see #computeCurrentVelocity(int, float) 
+     */
+    public void computeCurrentVelocity(int units) {
+        computeCurrentVelocity(units, Float.MAX_VALUE);
+    }
+
     /**
      * Compute the current velocity based on the points that have been
      * collected.  Only call this when you actually want to retrieve velocity
@@ -175,8 +185,11 @@
      * 
      * @param units The units you would like the velocity in.  A value of 1
      * provides pixels per millisecond, 1000 provides pixels per second, etc.
+     * @param maxVelocity The maximum velocity that can be computed by this method.
+     * This value must be declared in the same unit as the units parameter. This value
+     * must be positive.
      */
-    public void computeCurrentVelocity(int units) {
+    public void computeCurrentVelocity(int units, float maxVelocity) {
         final float[] pastX = mPastX;
         final float[] pastY = mPastY;
         final long[] pastTime = mPastTime;
@@ -210,8 +223,8 @@
             if (accumY == 0) accumY = vel;
             else accumY = (accumY + vel) * .5f;
         }
-        mXVelocity = accumX;
-        mYVelocity = accumY;
+        mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity);
+        mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity);
         
         if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity="
                 + mXVelocity + " N=" + N);
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 8e1524b..0e36ec2 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -106,6 +106,11 @@
      * Minimum velocity to initiate a fling, as measured in pixels per second
      */
     private static final int MINIMUM_FLING_VELOCITY = 50;
+    
+    /**
+     * Maximum velocity to initiate a fling, as measured in pixels per second
+     */
+    private static final int MAXIMUM_FLING_VELOCITY = 4000;
 
     /**
      * The maximum size of View's drawing cache, expressed in bytes. This size
@@ -122,6 +127,7 @@
     private final int mEdgeSlop;
     private final int mFadingEdgeLength;
     private final int mMinimumFlingVelocity;
+    private final int mMaximumFlingVelocity;
     private final int mScrollbarSize;
     private final int mTouchSlop;
     private final int mDoubleTapSlop;
@@ -139,6 +145,7 @@
         mEdgeSlop = EDGE_SLOP;
         mFadingEdgeLength = FADING_EDGE_LENGTH;
         mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
+        mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
         mScrollbarSize = SCROLL_BAR_SIZE;
         mTouchSlop = TOUCH_SLOP;
         mDoubleTapSlop = DOUBLE_TAP_SLOP;
@@ -164,6 +171,7 @@
         mEdgeSlop = (int) (density * EDGE_SLOP + 0.5f);
         mFadingEdgeLength = (int) (density * FADING_EDGE_LENGTH + 0.5f);
         mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
+        mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mTouchSlop = (int) (density * TOUCH_SLOP + 0.5f);
         mDoubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f);
@@ -367,6 +375,23 @@
     }
 
     /**
+     * @return Maximum velocity to initiate a fling, as measured in pixels per second.
+     *
+     * @deprecated Use {@link #getScaledMaximumFlingVelocity()} instead.
+     */
+    @Deprecated
+    public static int getMaximumFlingVelocity() {
+        return MAXIMUM_FLING_VELOCITY;
+    }
+
+    /**
+     * @return Maximum velocity to initiate a fling, as measured in pixels per second.
+     */
+    public int getScaledMaximumFlingVelocity() {
+        return mMaximumFlingVelocity;
+    }
+    
+    /**
      * The maximum drawing cache size expressed in bytes.
      *
      * @return the maximum size of View's drawing cache expressed in bytes
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 429f0f9..fcf946f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -237,6 +237,7 @@
      * Helper class to get velocity for fling
      */
     VelocityTracker mVelocityTracker;
+    private int mMaximumFling;
 
     /**
      * Touch mode
@@ -676,7 +677,8 @@
         setClickable(true);
         setLongClickable(true);
 
-        final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+        final int slop = configuration.getScaledTouchSlop();
         mTouchSlopSquare = slop * slop;
         mMinLockSnapReverseDistance = slop;
         final float density = getContext().getResources().getDisplayMetrics().density;
@@ -692,6 +694,7 @@
         DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
         mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
         mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+        mMaximumFling = configuration.getScaledMaximumFlingVelocity();
     }
 
     /* package */void updateDefaultZoomDensity(int zoomDensity) {
@@ -4157,7 +4160,7 @@
         int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
         int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
 
-        mVelocityTracker.computeCurrentVelocity(1000);
+        mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling);
         int vx = (int) mVelocityTracker.getXVelocity();
         int vy = (int) mVelocityTracker.getYVelocity();
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 23a38db..f9ca8cb 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -438,6 +438,8 @@
     private InputConnectionWrapper mPublicInputConnection;
 
     private Runnable mClearScrollingCache;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     /**
      * Interface definition for a callback to be invoked when the list or grid
@@ -549,7 +551,10 @@
         setAlwaysDrawnWithCacheEnabled(false);
         setScrollingCacheEnabled(true);
 
-        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mDensityScale = getContext().getResources().getDisplayMetrics().density;
     }
 
@@ -2058,12 +2063,9 @@
                 break;
             case TOUCH_MODE_SCROLL:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
-                int initialVelocity = (int)velocityTracker.getYVelocity();
-
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        (getChildCount() > 0)) {
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                final int initialVelocity = (int) velocityTracker.getYVelocity();
+                if (Math.abs(initialVelocity) > mMinimumVelocity && (getChildCount() > 0)) {
                     if (mFlingRunnable == null) {
                         mFlingRunnable = new FlingRunnable();
                     }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 02fc7c6..f86b37c 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -114,6 +114,8 @@
     private boolean mSmoothScrollingEnabled = true;
 
     private int mTouchSlop;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     public HorizontalScrollView(Context context) {
         this(context, null);
@@ -179,7 +181,10 @@
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
-        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
     }
 
     @Override
@@ -477,12 +482,10 @@
                 break;
             case MotionEvent.ACTION_UP:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int initialVelocity = (int) velocityTracker.getXVelocity();
 
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        getChildCount() > 0) {
+                if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) {
                     fling(-initialVelocity);
                 }
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index c9b3751..90e1242 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -115,6 +115,8 @@
     private boolean mSmoothScrollingEnabled = true;
 
     private int mTouchSlop;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     public ScrollView(Context context) {
         this(context, null);
@@ -180,7 +182,10 @@
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
-        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
     }
 
     @Override
@@ -478,12 +483,10 @@
                 break;
             case MotionEvent.ACTION_UP:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int initialVelocity = (int) velocityTracker.getYVelocity();
 
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        getChildCount() > 0) {
+                if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) {
                     fling(-initialVelocity);
                 }
 
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 6d3a2d3..20dd8a6 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -55,6 +55,7 @@
     private SurfaceHolder mSurfaceHolder = null;
     private MediaPlayer mMediaPlayer = null;
     private boolean     mIsPrepared;
+    private boolean     mIsPlaybackCompleted;
     private int         mVideoWidth;
     private int         mVideoHeight;
     private int         mSurfaceWidth;
@@ -260,7 +261,7 @@
                         mSeekWhenPrepared = 0;
                     }
                     if (mStartWhenPrepared) {
-                        mMediaPlayer.start();
+                        start();
                         mStartWhenPrepared = false;
                         if (mMediaController != null) {
                             mMediaController.show();
@@ -281,7 +282,7 @@
                     mSeekWhenPrepared = 0;
                 }
                 if (mStartWhenPrepared) {
-                    mMediaPlayer.start();
+                    start();
                     mStartWhenPrepared = false;
                 }
             }
@@ -291,6 +292,7 @@
     private MediaPlayer.OnCompletionListener mCompletionListener =
         new MediaPlayer.OnCompletionListener() {
         public void onCompletion(MediaPlayer mp) {
+            mIsPlaybackCompleted = true;
             if (mMediaController != null) {
                 mMediaController.hide();
             }
@@ -405,7 +407,9 @@
                     mMediaPlayer.seekTo(mSeekWhenPrepared);
                     mSeekWhenPrepared = 0;
                 }
-                mMediaPlayer.start();
+                if (!mIsPlaybackCompleted) {
+                    start();
+                } 
                 if (mMediaController != null) {
                     mMediaController.show();
                 }
@@ -490,6 +494,7 @@
     }
     
     public void start() {
+        mIsPlaybackCompleted = false;
         if (mMediaPlayer != null && mIsPrepared) {
                 mMediaPlayer.start();
                 mStartWhenPrepared = false;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1ce9c76..9b9ba68 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1192,9 +1192,12 @@
     <!-- On the unlock pattern screen, shown when the user enters the wrong lock pattern and must try again. -->
     <string name="lockscreen_pattern_wrong">Sorry, try again</string>
 
-    <!-- When the lock screen is showing and the phone plugged in, show the current
-         charge %.  -->
+    <!-- When the lock screen is showing and the phone plugged in, and the battery
+         is not fully charged, show the current charge %.  -->
     <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>)</string>
+    <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
+         charged, say that it is charged. -->
+    <string name="lockscreen_charged">Charged.</string>
 
     <!-- When the lock screen is showing and the battery is low, warn user to plug
          in the phone soon. -->
@@ -1271,7 +1274,7 @@
 
     <!-- The text for the button in the notification window-shade that clears
          all of the currently visible notifications. -->
-    <string name="status_bar_clear_all_button">Clear notifications</string>
+    <string name="status_bar_clear_all_button">Clear</string>
 
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing. -->
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index 5dacc70..aea3f0b 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -23,6 +23,7 @@
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
 	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
 	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
 	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
 	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk
index 291f0b6..8c8fc32 100644
--- a/data/sounds/OriginalAudio.mk
+++ b/data/sounds/OriginalAudio.mk
@@ -22,6 +22,7 @@
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
 	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
 	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
 	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
 	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/data/sounds/Silence.ogg b/data/sounds/Silence.ogg
new file mode 100644
index 0000000..6d78907
--- /dev/null
+++ b/data/sounds/Silence.ogg
Binary files differ
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index a55b704..058c033 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -298,7 +298,7 @@
     const char *langNativeString = env->GetStringUTFChars(language, 0);
     const char *countryNativeString = env->GetStringUTFChars(country, 0);
     const char *variantNativeString = env->GetStringUTFChars(variant, 0);
-    // TODO check return codes
+
     if (pSynthData->mNativeSynthInterface) {
         result = pSynthData->mNativeSynthInterface->isLanguageAvailable(langNativeString,
                 countryNativeString, variantNativeString);
@@ -310,61 +310,70 @@
 }
 
 
-static void
+static int
 android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
         jstring language, jstring country, jstring variant)
 {
+    int result = TTS_LANG_NOT_SUPPORTED;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
-        return;
+        return result;
     }
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     const char *langNativeString = env->GetStringUTFChars(language, 0);
     const char *countryNativeString = env->GetStringUTFChars(country, 0);
     const char *variantNativeString = env->GetStringUTFChars(variant, 0);
-    // TODO check return codes
+
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->setLanguage(langNativeString, countryNativeString,
-                variantNativeString);
+        result = pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
+                countryNativeString, variantNativeString);
     }
     env->ReleaseStringUTFChars(language, langNativeString);
     env->ReleaseStringUTFChars(country, countryNativeString);
     env->ReleaseStringUTFChars(variant, variantNativeString);
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData,
         jstring language, jstring country, jstring variant)
 {
+    int result = TTS_LANG_NOT_SUPPORTED;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_loadLanguage(): invalid JNI data");
-        return;
+        return result;
     }
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     const char *langNativeString = env->GetStringUTFChars(language, 0);
     const char *countryNativeString = env->GetStringUTFChars(country, 0);
     const char *variantNativeString = env->GetStringUTFChars(variant, 0);
-    // TODO check return codes
+
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->loadLanguage(langNativeString, countryNativeString,
-                variantNativeString);
+        result = pSynthData->mNativeSynthInterface->loadLanguage(langNativeString,
+                countryNativeString, variantNativeString);
     }
     env->ReleaseStringUTFChars(language, langNativeString);
     env->ReleaseStringUTFChars(country, countryNativeString);
     env->ReleaseStringUTFChars(variant, variantNativeString);
+
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
         jint speechRate)
 {
+    int result = TTS_FAILURE;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data");
-        return;
+        return result;
     }
 
     int bufSize = 10;
@@ -373,20 +382,24 @@
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     LOGI("setting speech rate to %d", speechRate);
-    // TODO check return codes
+
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->setProperty("rate", buffer, bufSize);
+        result = pSynthData->mNativeSynthInterface->setProperty("rate", buffer, bufSize);
     }
+
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData,
         jint pitch)
 {
+    int result = TTS_FAILURE;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_setPitch(): invalid JNI data");
-        return;
+        return result;
     }
 
     int bufSize = 10;
@@ -395,26 +408,30 @@
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     LOGI("setting pitch to %d", pitch);
-    // TODO check return codes
+
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->setProperty("pitch", buffer, bufSize);
+        result = pSynthData->mNativeSynthInterface->setProperty("pitch", buffer, bufSize);
     }
+
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
         jstring textJavaString, jstring filenameJavaString)
 {
+    int result = TTS_FAILURE;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid JNI data");
-        return;
+        return result;
     }
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     if (!pSynthData->mNativeSynthInterface) {
         LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid engine handle");
-        return;
+        return result;
     }
 
     // Retrieve audio parameters before writing the file header
@@ -425,7 +442,7 @@
 
     if ((encoding != AudioSystem::PCM_16_BIT) && (encoding != AudioSystem::PCM_8_BIT)) {
         LOGE("android_tts_SynthProxy_synthesizeToFile(): engine uses invalid format");
-        return;
+        return result;
     }
 
     const char *filenameNativeString =
@@ -441,7 +458,7 @@
     if (pForAfter->outputFile == NULL) {
         LOGE("android_tts_SynthProxy_synthesizeToFile(): error creating output file");
         delete pForAfter;
-        return;
+        return result;
     }
 
     // Write 44 blank bytes for WAV header, then come back and fill them in
@@ -451,9 +468,8 @@
 
     unsigned int unique_identifier;
 
-    // TODO check return codes
-    pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer,
-            pSynthData->mBufferSize, (void *)pForAfter);
+    result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
+            pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
 
     long filelen = ftell(pForAfter->outputFile);
 
@@ -503,16 +519,20 @@
 
     env->ReleaseStringUTFChars(textJavaString, textNativeString);
     env->ReleaseStringUTFChars(filenameJavaString, filenameNativeString);
+
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
         jstring textJavaString)
 {
+    int result = TTS_FAILURE;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_speak(): invalid JNI data");
-        return;
+        return result;
     }
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
@@ -528,29 +548,35 @@
 
     if (pSynthData->mNativeSynthInterface) {
         const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
-        pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer,
-                pSynthData->mBufferSize, (void *)pForAfter);
+        result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
+                pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
         env->ReleaseStringUTFChars(textJavaString, textNativeString);
     }
+
+    return result;
 }
 
 
-static void
+static int
 android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
 {
+    int result = TTS_FAILURE;
+
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
-        return;
+        return result;
     }
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
 
     if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->stop();
+        result = pSynthData->mNativeSynthInterface->stop();
     }
     if (pSynthData->mAudioOut) {
         pSynthData->mAudioOut->stop();
     }
+
+    return result;
 }
 
 
@@ -642,15 +668,15 @@
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {   "native_stop",
-        "(I)V",
+        "(I)I",
         (void*)android_tts_SynthProxy_stop
     },
     {   "native_speak",
-        "(ILjava/lang/String;)V",
+        "(ILjava/lang/String;)I",
         (void*)android_tts_SynthProxy_speak
     },
     {   "native_synthesizeToFile",
-        "(ILjava/lang/String;Ljava/lang/String;)V",
+        "(ILjava/lang/String;Ljava/lang/String;)I",
         (void*)android_tts_SynthProxy_synthesizeToFile
     },
     {   "native_isLanguageAvailable",
@@ -658,19 +684,19 @@
         (void*)android_tts_SynthProxy_isLanguageAvailable
     },
     {   "native_setLanguage",
-        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
         (void*)android_tts_SynthProxy_setLanguage
     },
     {   "native_loadLanguage",
-        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
         (void*)android_tts_SynthProxy_loadLanguage
     },
     {   "native_setSpeechRate",
-        "(II)V",
+        "(II)I",
         (void*)android_tts_SynthProxy_setSpeechRate
     },
     {   "native_setPitch",
-        "(II)V",
+        "(II)I",
         (void*)android_tts_SynthProxy_setPitch
     },
     {   "native_playAudioBuffer",
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index 91fe3b7..11a4380 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -156,24 +156,24 @@
 
     private native final void native_finalize(int jniData);
 
-    private native final void native_stop(int jniData);
+    private native final int native_stop(int jniData);
 
-    private native final void native_speak(int jniData, String text);
+    private native final int native_speak(int jniData, String text);
 
-    private native final void native_synthesizeToFile(int jniData, String text, String filename);
+    private native final int native_synthesizeToFile(int jniData, String text, String filename);
 
     private native final int  native_isLanguageAvailable(int jniData, String language,
             String country, String variant);
 
-    private native final void native_setLanguage(int jniData, String language, String country,
+    private native final int native_setLanguage(int jniData, String language, String country,
             String variant);
 
-    private native final void native_loadLanguage(int jniData, String language, String country,
+    private native final int native_loadLanguage(int jniData, String language, String country,
             String variant);
 
-    private native final void native_setSpeechRate(int jniData, int speechRate);
+    private native final int native_setSpeechRate(int jniData, int speechRate);
 
-    private native final void native_setPitch(int jniData, int speechRate);
+    private native final int native_setPitch(int jniData, int speechRate);
 
     // TODO add buffer format
     private native final void native_playAudioBuffer(int jniData, int bufferPointer, int bufferSize);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 7977d1f..e47d853 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -17,9 +17,11 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.app.IBackupAgent;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -41,6 +43,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -76,8 +79,9 @@
 
     // How often we perform a backup pass.  Privileged external callers can
     // trigger an immediate pass.
-    private static final long BACKUP_INTERVAL = 60 * 60 * 1000;
+    private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
 
+    private static final String RUN_BACKUP_ACTION = "_backup_run_";
     private static final int MSG_RUN_BACKUP = 1;
     private static final int MSG_RUN_FULL_BACKUP = 2;
     private static final int MSG_RUN_RESTORE = 3;
@@ -89,8 +93,15 @@
     private Context mContext;
     private PackageManager mPackageManager;
     private IActivityManager mActivityManager;
+    private PowerManager mPowerManager;
+    private AlarmManager mAlarmManager;
+
     private boolean mEnabled;   // access to this is synchronized on 'this'
+    private PowerManager.WakeLock mWakelock;
     private final BackupHandler mBackupHandler = new BackupHandler();
+    private PendingIntent mRunBackupIntent;
+    private BroadcastReceiver mRunBackupReceiver;
+    private IntentFilter mRunBackupFilter;
     // map UIDs to the set of backup client services within that UID's app set
     private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
         = new SparseArray<HashSet<ApplicationInfo>>();
@@ -171,12 +182,26 @@
         mPackageManager = context.getPackageManager();
         mActivityManager = ActivityManagerNative.getDefault();
 
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+
         // Set up our bookkeeping
-        mEnabled = Settings.Secure.getInt(context.getContentResolver(),
+        boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
         mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
         mDataDir = Environment.getDownloadCacheDirectory();
 
+        mRunBackupReceiver = new RunBackupReceiver();
+        mRunBackupFilter = new IntentFilter();
+        mRunBackupFilter.addAction(RUN_BACKUP_ACTION);
+        context.registerReceiver(mRunBackupReceiver, mRunBackupFilter);
+
+        Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
+        // !!! TODO: restrict delivery to our receiver; the naive setClass() doesn't seem to work
+        //backupIntent.setClass(context, mRunBackupReceiver.getClass());
+        backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
+
         // Set up the backup-request journaling
         mJournalDir = new File(mBaseStateDir, "pending");
         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
@@ -224,12 +249,29 @@
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        // Schedule the first backup pass -- okay because no other threads are
-        // running yet
-        if (mEnabled) {
-            scheduleBackupPassLocked(BACKUP_INTERVAL);
+        // Power management
+        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
+
+        // Start the backup passes going
+        setBackupEnabled(areEnabled);
+    }
+
+    private class RunBackupReceiver extends BroadcastReceiver {
+        public void onReceive(Context context, Intent intent) {
+            if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
+                if (DEBUG) Log.v(TAG, "Running a backup pass");
+
+                synchronized (mQueueLock) {
+                    // acquire a wakelock and pass it to the backup thread.  it will
+                    // be released once backup concludes.
+                    mWakelock.acquire();
+
+                    Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
+                    mBackupHandler.sendMessage(msg);
+                }
+            }
         }
-}
+    }
 
     private void makeJournalLocked() {
         try {
@@ -344,6 +386,7 @@
                 IBackupTransport transport = getTransport(mCurrentTransport);
                 if (transport == null) {
                     Log.v(TAG, "Backup requested but no transport available");
+                    mWakelock.release();
                     break;
                 }
 
@@ -377,13 +420,9 @@
                         (new PerformBackupThread(transport, queue, oldJournal)).start();
                     } else {
                         Log.v(TAG, "Backup requested but nothing pending");
+                        mWakelock.release();
                     }
                 }
-
-                // Schedule the next pass.
-                synchronized (mQueueLock) {
-                    scheduleBackupPassLocked(BACKUP_INTERVAL);
-                }
                 break;
             }
 
@@ -394,7 +433,8 @@
             {
                 RestoreParams params = (RestoreParams)msg.obj;
                 Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
-                (new PerformRestoreThread(params.transport, params.observer, params.token)).start();
+                (new PerformRestoreThread(params.transport, params.observer,
+                        params.token)).start();
                 break;
             }
 
@@ -521,19 +561,6 @@
         addPackageParticipantsLockedInner(packageName, allApps);
     }
 
-    // The queue lock should be held when scheduling a backup pass
-    private void scheduleBackupPassLocked(long timeFromNowMillis) {
-        // We only schedule backups when we're actually enabled
-        synchronized (this) {
-            if (mEnabled) {
-                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
-                mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
-            } else if (DEBUG) {
-                Log.v(TAG, "Disabled, so not scheduling backup pass");
-            }
-        }
-    }
-
     // Return the given transport
     private IBackupTransport getTransport(String transportName) {
         synchronized (mTransports) {
@@ -685,6 +712,9 @@
             if (!mJournal.delete()) {
                 Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
             }
+
+            // Only once we're entirely finished do we release the wakelock
+            mWakelock.release();
         }
 
         private void doQueuedBackups(IBackupTransport transport) {
@@ -1041,6 +1071,9 @@
                         Log.d(TAG, "Restore observer died at restoreFinished");
                     }
                 }
+
+                // done; we can finally release the wakelock
+                mWakelock.release();
             }
         }
 
@@ -1125,6 +1158,9 @@
                 } catch (RemoteException e) {
                     // can't happen; the transport is local
                 }
+
+                // Last but not least, release the cpu
+                mWakelock.release();
             }
         }
     }
@@ -1237,6 +1273,7 @@
                 if (DEBUG) Log.v(TAG, "Found the app - running clear process");
                 // found it; fire off the clear request
                 synchronized (mQueueLock) {
+                    mWakelock.acquire();
                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
                             new ClearParams(getTransport(mCurrentTransport), info));
                     mBackupHandler.sendMessage(msg);
@@ -1253,13 +1290,20 @@
 
         if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
         synchronized (mQueueLock) {
-            scheduleBackupPassLocked(0);
+            try {
+                if (DEBUG) Log.v(TAG, "sending immediate backup broadcast");
+                mRunBackupIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+                // should never happen
+                Log.e(TAG, "run-backup intent cancelled!");
+            }
         }
     }
 
     // Enable/disable the backup transport
     public void setBackupEnabled(boolean enable) {
-        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "setBackupEnabled");
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+                "setBackupEnabled");
 
         boolean wasEnabled = mEnabled;
         synchronized (this) {
@@ -1271,10 +1315,12 @@
         synchronized (mQueueLock) {
             if (enable && !wasEnabled) {
                 // if we've just been enabled, start scheduling backup passes
-                scheduleBackupPassLocked(BACKUP_INTERVAL);
+                long when = System.currentTimeMillis() + BACKUP_INTERVAL;
+                mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
+                        BACKUP_INTERVAL, mRunBackupIntent);
             } else if (!enable) {
-                // No longer enabled, so stop running backups.
-                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
+                // No longer enabled, so stop running backups
+                mAlarmManager.cancel(mRunBackupIntent);
             }
         }
     }
@@ -1422,6 +1468,7 @@
             if (mRestoreSets != null) {
                 for (int i = 0; i < mRestoreSets.length; i++) {
                     if (token == mRestoreSets[i].token) {
+                        mWakelock.acquire();
                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                         msg.obj = new RestoreParams(mRestoreTransport, observer, token);
                         mBackupHandler.sendMessage(msg);
@@ -1457,14 +1504,6 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mQueueLock) {
             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
-            boolean scheduled = mBackupHandler.hasMessages(MSG_RUN_BACKUP);
-            if (scheduled != mEnabled) {
-                if (mEnabled) {
-                    pw.println("ERROR: backups enabled but none scheduled!");
-                } else {
-                    pw.println("ERROR: backups are scheduled but not enabled!");
-                }
-            }
             pw.println("Available transports:");
             for (String t : listAllTransports()) {
                 String pad = (t.equals(mCurrentTransport)) ? "  * " : "    ";