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)) ? " * " : " ";