summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--core/java/android/net/NetworkStatsHistory.java51
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java2
-rw-r--r--core/java/android/speech/tts/AudioPlaybackHandler.java31
-rw-r--r--core/java/android/speech/tts/SynthesisMessageParams.java5
-rw-r--r--core/java/android/widget/TextView.java524
-rwxr-xr-xcore/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java102
-rw-r--r--include/media/IStreamSource.h11
-rw-r--r--libs/rs/driver/rsdBcc.cpp1
-rw-r--r--libs/rs/driver/rsdBcc.h1
-rw-r--r--libs/rs/rsElement.cpp12
-rw-r--r--libs/rs/rsScriptC.cpp2
-rw-r--r--libs/rs/rs_hal.h1
-rw-r--r--media/java/android/mtp/MtpServer.java30
-rw-r--r--media/jni/android_mtp_MtpServer.cpp226
-rw-r--r--media/libmedia/IStreamSource.cpp3
-rw-r--r--media/libmediaplayerservice/nuplayer/StreamingSource.cpp13
-rwxr-xr-x[-rw-r--r--]media/libstagefright/CameraSource.cpp4
-rwxr-xr-x[-rw-r--r--]media/libstagefright/MPEG4Writer.cpp7
-rwxr-xr-x[-rw-r--r--]media/libstagefright/OMXCodec.cpp28
-rw-r--r--media/mtp/MtpServer.cpp2
-rw-r--r--services/input/InputDispatcher.cpp7
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java23
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java10
-rw-r--r--services/surfaceflinger/Layer.cpp25
-rw-r--r--services/surfaceflinger/Transform.cpp1
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java38
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyProperties.java7
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java7
-rw-r--r--tests/BiDiTests/res/layout/textview_drawables_ltr.xml104
-rw-r--r--tests/BiDiTests/res/layout/textview_drawables_rtl.xml104
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java3
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java45
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java45
36 files changed, 1104 insertions, 382 deletions
diff --git a/api/current.txt b/api/current.txt
index 24c7d76ef0df..d3333f025f34 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -377,9 +377,11 @@ package android {
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
+ field public static final int drawableEnd = 16843687; // 0x10103a7
field public static final int drawableLeft = 16843119; // 0x101016f
field public static final int drawablePadding = 16843121; // 0x1010171
field public static final int drawableRight = 16843120; // 0x1010170
+ field public static final int drawableStart = 16843686; // 0x10103a6
field public static final int drawableTop = 16843117; // 0x101016d
field public static final int drawingCacheQuality = 16842984; // 0x10100e8
field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -26421,7 +26423,9 @@ package android.widget {
method protected void onTextChanged(java.lang.CharSequence, int, int, int);
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
+ method protected void resetResolvedDrawables();
method protected void resetResolvedLayoutDirection();
+ method protected void resolveDrawables();
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index b0930b2ae287..8bd173893794 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -124,6 +124,22 @@ public class NetworkStatsHistory implements Parcelable {
return bucketDuration;
}
+ public long getStart() {
+ if (bucketCount > 0) {
+ return bucketStart[0];
+ } else {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ public long getEnd() {
+ if (bucketCount > 0) {
+ return bucketStart[bucketCount - 1] + bucketDuration;
+ } else {
+ return Long.MIN_VALUE;
+ }
+ }
+
/**
* Return specific stats entry.
*/
@@ -253,9 +269,20 @@ public class NetworkStatsHistory implements Parcelable {
* Return interpolated data usage across the requested range. Interpolates
* across buckets, so values may be rounded slightly.
*/
- public long[] getTotalData(long start, long end, long[] outTotal) {
- long rx = 0;
- long tx = 0;
+ public Entry getValues(long start, long end, Entry recycle) {
+ return getValues(start, end, Long.MAX_VALUE, recycle);
+ }
+
+ /**
+ * Return interpolated data usage across the requested range. Interpolates
+ * across buckets, so values may be rounded slightly.
+ */
+ public Entry getValues(long start, long end, long now, Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+ entry.bucketStart = start;
+ entry.bucketDuration = end - start;
+ entry.rxBytes = 0;
+ entry.txBytes = 0;
for (int i = bucketCount - 1; i >= 0; i--) {
final long curStart = bucketStart[i];
@@ -266,19 +293,19 @@ public class NetworkStatsHistory implements Parcelable {
// bucket is newer than record; keep looking
if (curStart > end) continue;
+ // include full value for active buckets, otherwise only fractional
+ final boolean activeBucket = curStart < now && curEnd > now;
final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
- if (overlap > 0) {
- rx += this.rxBytes[i] * overlap / bucketDuration;
- tx += this.txBytes[i] * overlap / bucketDuration;
+ if (activeBucket || overlap == bucketDuration) {
+ entry.rxBytes += rxBytes[i];
+ entry.txBytes += txBytes[i];
+ } else if (overlap > 0) {
+ entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
+ entry.txBytes += txBytes[i] * overlap / bucketDuration;
}
}
- if (outTotal == null || outTotal.length != 2) {
- outTotal = new long[2];
- }
- outTotal[0] = rx;
- outTotal[1] = tx;
- return outTotal;
+ return entry;
}
/**
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 641a576edd45..c534e58f37e1 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -65,7 +65,7 @@ import android.util.Base64;
import android.util.Log;
/**
- * Subclass of the Apache {@link DefaultHttpClient} that is configured with
+ * Implementation of the Apache {@link DefaultHttpClient} that is configured with
* reasonable default settings and registered schemes for Android, and
* also lets the user add {@link HttpRequestInterceptor} classes.
* Don't create this directly, use the {@link #newInstance} factory method.
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index 8ef4295de33a..12109417b2d5 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -384,7 +384,7 @@ class AudioPlaybackHandler {
}
count += written;
}
-
+ param.mBytesWritten += count;
param.mLogger.onPlaybackStart();
}
@@ -396,14 +396,16 @@ class AudioPlaybackHandler {
params.mLogger.onWriteData();
}
- // Flush all remaining data to the audio track, stop it and release
- // all it's resources.
+ // Wait for the audio track to stop playing, and then release it's resources.
private void handleSynthesisDone(SynthesisMessageParams params) {
if (DBG) Log.d(TAG, "handleSynthesisDone()");
final AudioTrack audioTrack = params.getAudioTrack();
try {
if (audioTrack != null) {
+ if (DBG) Log.d(TAG, "Waiting for audio track to complete : " +
+ audioTrack.hashCode());
+ blockUntilDone(params);
if (DBG) Log.d(TAG, "Releasing audio track [" + audioTrack.hashCode() + "]");
// The last call to AudioTrack.write( ) will return only after
// all data from the audioTrack has been sent to the mixer, so
@@ -417,6 +419,18 @@ class AudioPlaybackHandler {
}
}
+ private static void blockUntilDone(SynthesisMessageParams params) {
+ if (params.mAudioTrack == null || params.mBytesWritten <= 0) {
+ return;
+ }
+
+ final AudioTrack track = params.mAudioTrack;
+ final int bytesPerFrame = getBytesPerFrame(params.mAudioFormat);
+ final int lengthInBytes = params.mBytesWritten;
+
+ blockUntilDone(track, bytesPerFrame, lengthInBytes);
+ }
+
private void handleSynthesisCompleteDataAvailable(MessageParams msg) {
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
@@ -455,13 +469,18 @@ class AudioPlaybackHandler {
}
- private static void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame, int length) {
- int lengthInFrames = length / bytesPerFrame;
+ private static void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame,
+ int lengthInBytes) {
+ int lengthInFrames = lengthInBytes / bytesPerFrame;
int currentPosition = 0;
while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
+ if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
+ break;
+ }
+
long estimatedTimeMs = ((lengthInFrames - currentPosition) * 1000) /
audioTrack.getSampleRate();
- audioTrack.getPlayState();
+
if (DBG) Log.d(TAG, "About to sleep for : " + estimatedTimeMs + " ms," +
" Playback position : " + currentPosition);
try {
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index caf02ef3eb56..ffe70e27378e 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -32,7 +32,9 @@ final class SynthesisMessageParams extends MessageParams {
final float mPan;
final EventLogger mLogger;
- public volatile AudioTrack mAudioTrack;
+ volatile AudioTrack mAudioTrack;
+ // Not volatile, accessed only from the synthesis thread.
+ int mBytesWritten;
private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
@@ -52,6 +54,7 @@ final class SynthesisMessageParams extends MessageParams {
// initially null.
mAudioTrack = null;
+ mBytesWritten = 0;
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 766b520f2b40..6b4e4542cd5e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,11 +16,6 @@
package android.widget;
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import android.R;
import android.content.ClipData;
import android.content.ClipData.Item;
@@ -132,6 +127,11 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
@@ -260,9 +260,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
class Drawables {
final Rect mCompoundRect = new Rect();
- Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
- int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
- int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
+ Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
+ mDrawableStart, mDrawableEnd;
+ int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
+ mDrawableSizeStart, mDrawableSizeEnd;
+ int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
+ mDrawableHeightStart, mDrawableHeightEnd;
int mDrawablePadding;
}
private Drawables mDrawables;
@@ -352,6 +355,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
}
+ private boolean bResolvedDrawables = false;
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -494,7 +499,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int buffertype = 0;
boolean selectallonfocus = false;
Drawable drawableLeft = null, drawableTop = null, drawableRight = null,
- drawableBottom = null;
+ drawableBottom = null, drawableStart = null, drawableEnd = null;
int drawablePadding = 0;
int ellipsize = -1;
boolean singleLine = false;
@@ -571,6 +576,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
drawableBottom = a.getDrawable(attr);
break;
+ case com.android.internal.R.styleable.TextView_drawableStart:
+ drawableStart = a.getDrawable(attr);
+ break;
+
+ case com.android.internal.R.styleable.TextView_drawableEnd:
+ drawableEnd = a.getDrawable(attr);
+ break;
+
case com.android.internal.R.styleable.TextView_drawablePadding:
drawablePadding = a.getDimensionPixelSize(attr, drawablePadding);
break;
@@ -980,6 +993,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setCompoundDrawablesWithIntrinsicBounds(
drawableLeft, drawableTop, drawableRight, drawableBottom);
+ setRelativeDrawablesIfNeeded(drawableStart, drawableEnd);
setCompoundDrawablePadding(drawablePadding);
// Same as setSingleLine(), but make sure the transformation method and the maximum number
@@ -1105,6 +1119,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setTypeface(tf, styleIndex);
}
+ private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) {
+ boolean hasRelativeDrawables = (start != null) || (end != null);
+ if (hasRelativeDrawables) {
+ Drawables dr = mDrawables;
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state = getDrawableState();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+
+ dr.mDrawableStart = start;
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+
+ dr.mDrawableEnd = end;
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+ }
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (enabled == isEnabled()) {
@@ -1119,6 +1169,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
super.setEnabled(enabled);
+ prepareCursorControllers();
}
/**
@@ -1410,6 +1461,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns the start padding of the view, plus space for the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingStart() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingLeft();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingRight();
+ }
+ }
+
+ /**
+ * Returns the end padding of the view, plus space for the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingEnd() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingRight();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingLeft();
+ }
+ }
+
+ /**
* Returns the extended top padding of the view, including both the
* top Drawable if any and any extra space to keep more than maxLines
* of text from showing. It is only valid to call this after measuring.
@@ -1492,6 +1577,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns the total start padding of the view, including the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingStart() {
+ return getCompoundPaddingStart();
+ }
+
+ /**
+ * Returns the total end padding of the view, including the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingEnd() {
+ return getCompoundPaddingEnd();
+ }
+
+ /**
* Returns the total top padding of the view, including the top
* Drawable if any, the extra space to keep more than maxLines
* from showing, and the vertical offset for gravity, if any.
@@ -1678,6 +1783,185 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables must already have had
+ * {@link Drawable#setBounds} called.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelative(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+ Drawables dr = mDrawables;
+
+ final boolean drawables = start != null || top != null
+ || end != null || bottom != null;
+
+ if (!drawables) {
+ // Clearing drawables... can we free the data structure?
+ if (dr != null) {
+ if (dr.mDrawablePadding == 0) {
+ mDrawables = null;
+ } else {
+ // We need to retain the last set padding, so just clear
+ // out all of the fields in the existing structure.
+ if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
+ dr.mDrawableStart = null;
+ if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
+ dr.mDrawableTop = null;
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+ dr.mDrawableEnd = null;
+ if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
+ dr.mDrawableBottom = null;
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+ } else {
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+
+ if (dr.mDrawableStart != start && dr.mDrawableStart != null) {
+ dr.mDrawableStart.setCallback(null);
+ }
+ dr.mDrawableStart = start;
+
+ if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
+ dr.mDrawableTop.setCallback(null);
+ }
+ dr.mDrawableTop = top;
+
+ if (dr.mDrawableEnd != end && dr.mDrawableEnd != null) {
+ dr.mDrawableEnd.setCallback(null);
+ }
+ dr.mDrawableEnd = end;
+
+ if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
+ dr.mDrawableBottom.setCallback(null);
+ }
+ dr.mDrawableBottom = bottom;
+
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state;
+
+ state = getDrawableState();
+
+ if (start != null) {
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+
+ if (end != null) {
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+
+ if (top != null) {
+ top.setState(state);
+ top.copyBounds(compoundRect);
+ top.setCallback(this);
+ dr.mDrawableSizeTop = compoundRect.height();
+ dr.mDrawableWidthTop = compoundRect.width();
+ } else {
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ }
+
+ if (bottom != null) {
+ bottom.setState(state);
+ bottom.copyBounds(compoundRect);
+ bottom.setCallback(this);
+ dr.mDrawableSizeBottom = compoundRect.height();
+ dr.mDrawableWidthBottom = compoundRect.width();
+ } else {
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+
+ resolveDrawables();
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use 0 if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @param start Resource identifier of the start Drawable.
+ * @param top Resource identifier of the top Drawable.
+ * @param end Resource identifier of the end Drawable.
+ * @param bottom Resource identifier of the bottom Drawable.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
+ int bottom) {
+ resetResolvedDrawables();
+ final Resources resources = getContext().getResources();
+ setCompoundDrawablesRelativeWithIntrinsicBounds(
+ start != 0 ? resources.getDrawable(start) : null,
+ top != 0 ? resources.getDrawable(top) : null,
+ end != 0 ? resources.getDrawable(end) : null,
+ bottom != 0 ? resources.getDrawable(bottom) : null);
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+
+ resetResolvedDrawables();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ }
+ if (top != null) {
+ top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight());
+ }
+ if (bottom != null) {
+ bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
+ }
+ setCompoundDrawablesRelative(start, top, end, bottom);
+ }
+
+ /**
* Returns drawables for the left, top, right, and bottom borders.
*/
public Drawable[] getCompoundDrawables() {
@@ -1692,6 +1976,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Returns drawables for the start, top, end, and bottom borders.
+ *
+ * @hide
+ */
+ public Drawable[] getCompoundDrawablesRelative() {
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ return new Drawable[] {
+ dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom
+ };
+ } else {
+ return new Drawable[] { null, null, null, null };
+ }
+ }
+
+ /**
* Sets the size of the padding between the compound drawables and
* the text.
*
@@ -2494,6 +2794,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
dr.mDrawableRight.setState(state);
}
+ if (dr.mDrawableStart != null && dr.mDrawableStart.isStateful()) {
+ dr.mDrawableStart.setState(state);
+ }
+ if (dr.mDrawableEnd != null && dr.mDrawableEnd.isStateful()) {
+ dr.mDrawableEnd.setState(state);
+ }
}
}
@@ -2841,8 +3147,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Do not change the movement method for text that support text selection as it
// would prevent an arbitrary cursor displacement.
- final boolean hasTextSelection = this instanceof EditText || mTextIsSelectable;
- if (mLinksClickable && !hasTextSelection) {
+ if (mLinksClickable && !textCanBeSelected()) {
setMovementMethod(LinkMovementMethod.getInstance());
}
}
@@ -3546,7 +3851,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mErrorWasChanged = true;
final Drawables dr = mDrawables;
if (dr != null) {
- setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, dr.mDrawableBottom);
+ switch (getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
+ dr.mDrawableBottom);
+ break;
+ case LAYOUT_DIRECTION_RTL:
+ setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight,
+ dr.mDrawableBottom);
+ break;
+ }
} else {
setCompoundDrawables(null, null, icon, null);
}
@@ -4048,6 +4363,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mSelectionModifierCursorController != null) {
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
+
+ // Resolve drawables as the layout direction has been resolved
+ resolveDrawables();
}
@Override
@@ -4077,6 +4395,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
hideControllers();
+
+ resetResolvedDrawables();
}
@Override
@@ -4111,7 +4431,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final boolean verified = super.verifyDrawable(who);
if (!verified && mDrawables != null) {
return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
- who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom;
+ who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom ||
+ who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd;
}
return verified;
}
@@ -4132,6 +4453,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mDrawables.mDrawableBottom != null) {
mDrawables.mDrawableBottom.jumpToCurrentState();
}
+ if (mDrawables.mDrawableStart != null) {
+ mDrawables.mDrawableStart.jumpToCurrentState();
+ }
+ if (mDrawables.mDrawableEnd != null) {
+ mDrawables.mDrawableEnd.jumpToCurrentState();
+ }
}
}
@@ -4192,7 +4519,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mDrawables != null) {
final Drawables drawables = mDrawables;
if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight ||
- who == drawables.mDrawableTop || who == drawables.mDrawableBottom) {
+ who == drawables.mDrawableTop || who == drawables.mDrawableBottom ||
+ who == drawables.mDrawableStart || who == drawables.mDrawableEnd) {
return getResolvedLayoutDirection();
}
}
@@ -4211,6 +4539,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
+ if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
}
return true;
}
@@ -4228,7 +4558,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* {@link android.R.styleable#TextView_textIsSelectable} XML attribute to make this TextView
* selectable (text is not selectable by default).
*
- * Note that the content of an EditText is always selectable.
+ * Note that this method simply returns the state of this flag. Although this flag has to be set
+ * in order to select text in non-editable TextView, the content of an {@link EditText} can
+ * always be selected, independently of the value of this flag.
*
* @return True if the text displayed in this TextView can be selected by the user.
*
@@ -4465,12 +4797,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
selStart = getSelectionStart();
selEnd = getSelectionEnd();
- if ((isCursorVisible() || mTextIsSelectable) && selStart >= 0 && isEnabled()) {
+ if (selStart >= 0) {
if (mHighlightPath == null)
mHighlightPath = new Path();
if (selStart == selEnd) {
- if (!mTextIsSelectable &&
+ if (isCursorVisible() &&
(SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK) < BLINK) {
if (mHighlightPathBogus) {
mHighlightPath.reset();
@@ -4489,7 +4821,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
highlight = mHighlightPath;
drawCursor = mCursorCount > 0;
}
- } else {
+ } else if (textCanBeSelected()) {
if (mHighlightPathBogus) {
mHighlightPath.reset();
mLayout.getSelectionPath(selStart, selEnd, mHighlightPath);
@@ -7450,9 +7782,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
- if (hasInsertionController()) {
- getInsertionController().onTouchEvent(event);
- }
if (hasSelectionController()) {
getSelectionController().onTouchEvent(event);
}
@@ -7880,7 +8209,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// prepareCursorController() relies on this method.
// If you change this condition, make sure prepareCursorController is called anywhere
// the value of this condition might be changed.
- return mText instanceof Spannable && mMovement != null && mMovement.canSelectArbitrarily();
+ if (mMovement == null || !mMovement.canSelectArbitrarily()) return false;
+ return isTextEditable() || (mTextIsSelectable && mText instanceof Spannable && isEnabled());
}
private boolean canCut() {
@@ -7968,6 +8298,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int minOffset = extractRangeStartFromLong(lastTouchOffsets);
final int maxOffset = extractRangeEndFromLong(lastTouchOffsets);
+ // Safety check in case standard touch event handling has been bypassed
+ if (minOffset < 0 || minOffset >= mText.length()) return false;
+ if (maxOffset < 0 || maxOffset >= mText.length()) return false;
+
int selectionStart, selectionEnd;
// If a URLSpan (web address, email, phone...) is found at that position, select it.
@@ -9723,13 +10057,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void hide();
/**
- * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
- * a chance to become active and/or visible.
- * @param event The touch event
- */
- public boolean onTouchEvent(MotionEvent event);
-
- /**
* Called when the view is detached from window. Perform house keeping task, such as
* stopping Runnable thread that would otherwise keep a reference on the context, thus
* preventing the activity from being recycled.
@@ -9756,10 +10083,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- public boolean onTouchEvent(MotionEvent ev) {
- return false;
- }
-
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
@@ -9818,52 +10141,49 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mEndHandle != null) mEndHandle.hide();
}
- public boolean onTouchEvent(MotionEvent event) {
+ public void onTouchEvent(MotionEvent event) {
// This is done even when the View does not have focus, so that long presses can start
// selection and tap can move cursor from this tap position.
- if (isTextEditable() || mTextIsSelectable) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- final float x = event.getX();
- final float y = event.getY();
-
- // Remember finger down position, to be able to start selection from there
- mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
-
- // Double tap detection
- long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
- if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
- isPositionOnText(x, y)) {
- final float deltaX = x - mPreviousTapPositionX;
- final float deltaY = y - mPreviousTapPositionY;
- final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
- if (distanceSquared < mSquaredTouchSlopDistance) {
- showSuggestions();
- mDiscardNextActionUp = true;
- }
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ final float x = event.getX();
+ final float y = event.getY();
+
+ // Remember finger down position, to be able to start selection from there
+ mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
+
+ // Double tap detection
+ long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
+ if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
+ isPositionOnText(x, y)) {
+ final float deltaX = x - mPreviousTapPositionX;
+ final float deltaY = y - mPreviousTapPositionY;
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ if (distanceSquared < mSquaredTouchSlopDistance) {
+ showSuggestions();
+ mDiscardNextActionUp = true;
}
+ }
- mPreviousTapPositionX = x;
- mPreviousTapPositionY = y;
+ mPreviousTapPositionX = x;
+ mPreviousTapPositionY = y;
- break;
+ break;
- case MotionEvent.ACTION_POINTER_DOWN:
- case MotionEvent.ACTION_POINTER_UP:
- // Handle multi-point gestures. Keep min and max offset positions.
- // Only activated for devices that correctly handle multi-touch.
- if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
- updateMinAndMaxOffsets(event);
- }
- break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_POINTER_UP:
+ // Handle multi-point gestures. Keep min and max offset positions.
+ // Only activated for devices that correctly handle multi-touch.
+ if (mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
+ updateMinAndMaxOffsets(event);
+ }
+ break;
- case MotionEvent.ACTION_UP:
- mPreviousTapUpTime = SystemClock.uptimeMillis();
- break;
- }
+ case MotionEvent.ACTION_UP:
+ mPreviousTapUpTime = SystemClock.uptimeMillis();
+ break;
}
- return false;
}
/**
@@ -10285,6 +10605,68 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
}
+ /**
+ * Subclasses will need to override this method to implement their own way of resolving
+ * drawables depending on the layout direction.
+ *
+ * A call to the super method will be required from the subclasses implementation.
+ *
+ */
+ protected void resolveDrawables() {
+ // No need to resolve twice
+ if (bResolvedDrawables) {
+ return;
+ }
+ // No drawable to resolve
+ if (mDrawables == null) {
+ return;
+ }
+ // No relative drawable to resolve
+ if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
+ bResolvedDrawables = true;
+ return;
+ }
+
+ Drawables dr = mDrawables;
+ switch(getResolvedLayoutDirection()) {
+ case LAYOUT_DIRECTION_RTL:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableRight = dr.mDrawableStart;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeStart;
+ dr.mDrawableHeightRight = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableLeft = dr.mDrawableEnd;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightEnd;
+ }
+ break;
+
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableLeft = dr.mDrawableStart;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeStart;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableRight = dr.mDrawableEnd;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightRight = dr.mDrawableHeightEnd;
+ }
+ break;
+ }
+ bResolvedDrawables = true;
+ }
+
+ protected void resetResolvedDrawables() {
+ bResolvedDrawables = false;
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9c2133f0fd68..cfc5041cddbc 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3015,6 +3015,10 @@
<attr name="drawableLeft" format="reference|color" />
<!-- The drawable to be drawn to the right of the text. -->
<attr name="drawableRight" format="reference|color" />
+ <!-- The drawable to be drawn to the start of the text. -->
+ <attr name="drawableStart" format="reference|color" />
+ <!-- The drawable to be drawn to the end of the text. -->
+ <attr name="drawableEnd" format="reference|color" />
<!-- The padding between the drawables and the text. -->
<attr name="drawablePadding" format="dimension" />
<!-- Extra spacing between lines of text. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f7701f287213..6dedc83eb087 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1826,4 +1826,7 @@
<public type="color" name="holo_purple" />
<public type="color" name="holo_blue_bright" />
+ <public type="attr" name="drawableStart" />
+ <public type="attr" name="drawableEnd" />
+
</resources>
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index 16bb00060eef..9403d95700d4 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -55,7 +55,7 @@ public class NetworkStatsHistoryTest extends TestCase {
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
assertEquals(1, stats.size());
- assertEntry(stats, 0, 1024L, 2048L);
+ assertValues(stats, 0, 1024L, 2048L);
}
public void testRecordEqualBuckets() throws Exception {
@@ -67,8 +67,8 @@ public class NetworkStatsHistoryTest extends TestCase {
stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
assertEquals(2, stats.size());
- assertEntry(stats, 0, 512L, 64L);
- assertEntry(stats, 1, 512L, 64L);
+ assertValues(stats, 0, 512L, 64L);
+ assertValues(stats, 1, 512L, 64L);
}
public void testRecordTouchingBuckets() throws Exception {
@@ -83,11 +83,11 @@ public class NetworkStatsHistoryTest extends TestCase {
assertEquals(3, stats.size());
// first bucket should have (1/20 of value)
- assertEntry(stats, 0, 50L, 250L);
+ assertValues(stats, 0, 50L, 250L);
// second bucket should have (15/20 of value)
- assertEntry(stats, 1, 750L, 3750L);
+ assertValues(stats, 1, 750L, 3750L);
// final bucket should have (4/20 of value)
- assertEntry(stats, 2, 200L, 1000L);
+ assertValues(stats, 2, 200L, 1000L);
}
public void testRecordGapBuckets() throws Exception {
@@ -102,8 +102,8 @@ public class NetworkStatsHistoryTest extends TestCase {
// we should have two buckets, far apart from each other
assertEquals(2, stats.size());
- assertEntry(stats, 0, 128L, 256L);
- assertEntry(stats, 1, 64L, 512L);
+ assertValues(stats, 0, 128L, 256L);
+ assertValues(stats, 1, 64L, 512L);
// now record something in middle, spread across two buckets
final long middleStart = TEST_START + DAY_IN_MILLIS;
@@ -112,10 +112,10 @@ public class NetworkStatsHistoryTest extends TestCase {
// now should have four buckets, with new record in middle two buckets
assertEquals(4, stats.size());
- assertEntry(stats, 0, 128L, 256L);
- assertEntry(stats, 1, 1024L, 1024L);
- assertEntry(stats, 2, 1024L, 1024L);
- assertEntry(stats, 3, 64L, 512L);
+ assertValues(stats, 0, 128L, 256L);
+ assertValues(stats, 1, 1024L, 1024L);
+ assertValues(stats, 2, 1024L, 1024L);
+ assertValues(stats, 3, 64L, 512L);
}
public void testRecordOverlapBuckets() throws Exception {
@@ -129,13 +129,11 @@ public class NetworkStatsHistoryTest extends TestCase {
// should have two buckets, with some data mixed together
assertEquals(2, stats.size());
- assertEntry(stats, 0, 768L, 768L);
- assertEntry(stats, 1, 512L, 512L);
+ assertValues(stats, 0, 768L, 768L);
+ assertValues(stats, 1, 512L, 512L);
}
public void testRecordEntireGapIdentical() throws Exception {
- final long[] total = new long[2];
-
// first, create two separate histories far apart
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
@@ -150,19 +148,16 @@ public class NetworkStatsHistoryTest extends TestCase {
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 3000L, 1500L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
// now inspect internal buckets
- assertEntry(stats, 0, 1000L, 500L);
- assertEntry(stats, 1, 1000L, 500L);
- assertEntry(stats, 2, 500L, 250L);
- assertEntry(stats, 3, 500L, 250L);
+ assertValues(stats, 0, 1000L, 500L);
+ assertValues(stats, 1, 1000L, 500L);
+ assertValues(stats, 2, 500L, 250L);
+ assertValues(stats, 3, 500L, 250L);
}
public void testRecordEntireOverlapVaryingBuckets() throws Exception {
- final long[] total = new long[2];
-
// create history just over hour bucket boundary
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
@@ -177,17 +172,16 @@ public class NetworkStatsHistoryTest extends TestCase {
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 650L, 650L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// now inspect internal buckets
- assertEntry(stats, 0, 10L, 10L);
- assertEntry(stats, 1, 20L, 20L);
- assertEntry(stats, 2, 20L, 20L);
- assertEntry(stats, 3, 20L, 20L);
- assertEntry(stats, 4, 20L, 20L);
- assertEntry(stats, 5, 20L, 20L);
- assertEntry(stats, 6, 10L, 10L);
+ assertValues(stats, 0, 10L, 10L);
+ assertValues(stats, 1, 20L, 20L);
+ assertValues(stats, 2, 20L, 20L);
+ assertValues(stats, 3, 20L, 20L);
+ assertValues(stats, 4, 20L, 20L);
+ assertValues(stats, 5, 20L, 20L);
+ assertValues(stats, 6, 10L, 10L);
// now combine using 15min buckets
stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
@@ -195,14 +189,13 @@ public class NetworkStatsHistoryTest extends TestCase {
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 650L, 650L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// and inspect buckets
- assertEntry(stats, 0, 200L, 200L);
- assertEntry(stats, 1, 150L, 150L);
- assertEntry(stats, 2, 150L, 150L);
- assertEntry(stats, 3, 150L, 150L);
+ assertValues(stats, 0, 200L, 200L);
+ assertValues(stats, 1, 150L, 150L);
+ assertValues(stats, 2, 150L, 150L);
+ assertValues(stats, 3, 150L, 150L);
}
public void testRemove() throws Exception {
@@ -241,27 +234,20 @@ public class NetworkStatsHistoryTest extends TestCase {
// record uniform data across day
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
- final long[] total = new long[2];
-
// verify that total outside range is 0
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total);
- assertTotalEquals(total, 0, 0);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
// verify total in first hour
- stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total);
- assertTotalEquals(total, 100, 200);
+ assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
// verify total across 1.5 hours
- stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total);
- assertTotalEquals(total, 150, 300);
+ assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
// verify total beyond end
- stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 100, 200);
+ assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
// verify everything total
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 2400, 4800);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
}
@@ -302,16 +288,18 @@ public class NetworkStatsHistoryTest extends TestCase {
}
}
- private static void assertTotalEquals(long[] total, long rxBytes, long txBytes) {
- assertEquals("unexpected rxBytes", rxBytes, total[0]);
- assertEquals("unexpected txBytes", txBytes, total[1]);
- }
-
- private static void assertEntry(
+ private static void assertValues(
NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
+ private static void assertValues(
+ NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ }
+
}
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index d310cee3096d..cc63356803df 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -51,6 +51,17 @@ struct IStreamListener : public IInterface {
// will be suppressed until media time reaches this timestamp.
static const char *const kKeyResumeAtPTS;
+ // When signalling a discontinuity you can optionally
+ // signal that this is a "hard" discontinuity, i.e. the format
+ // or configuration of subsequent stream data differs from that
+ // currently active. To do so, include a non-zero int32_t value
+ // under the key "kKeyFormatChange" when issuing the DISCONTINUITY
+ // command.
+ // The new logical stream must start with proper codec initialization
+ // information for playback to continue, i.e. SPS and PPS in the case
+ // of AVC video etc.
+ static const char *const kKeyFormatChange;
+
virtual void issueCommand(
Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0;
};
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 62eb24ef7c8f..bbf283668386 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -269,6 +269,7 @@ static void wc_x(void *usr, uint32_t idx) {
void rsdScriptInvokeForEach(const Context *rsc,
Script *s,
+ uint32_t slot,
const Allocation * ain,
Allocation * aout,
const void * usr,
diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h
index 62b50f47348f..67929bc55a60 100644
--- a/libs/rs/driver/rsdBcc.h
+++ b/libs/rs/driver/rsdBcc.h
@@ -32,6 +32,7 @@ void rsdScriptInvokeFunction(const android::renderscript::Context *dc,
void rsdScriptInvokeForEach(const android::renderscript::Context *rsc,
android::renderscript::Script *s,
+ uint32_t slot,
const android::renderscript::Allocation * ain,
android::renderscript::Allocation * aout,
const void * usr,
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 2b58e9eb0e03..b77b18a0b686 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -263,10 +263,10 @@ void Element::incRefs(const void *ptr) const {
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- p = &p[mFields[i].offsetBits >> 3];
+ const uint8_t *p2 = &p[mFields[i].offsetBits >> 3];
for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
- mFields[i].e->incRefs(p);
- p += mFields[i].e->getSizeBytes();
+ mFields[i].e->incRefs(p2);
+ p2 += mFields[i].e->getSizeBytes();
}
}
}
@@ -285,10 +285,10 @@ void Element::decRefs(const void *ptr) const {
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- p = &p[mFields[i].offsetBits >> 3];
+ const uint8_t *p2 = &p[mFields[i].offsetBits >> 3];
for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
- mFields[i].e->decRefs(p);
- p += mFields[i].e->getSizeBytes();
+ mFields[i].e->decRefs(p2);
+ p2 += mFields[i].e->getSizeBytes();
}
}
}
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b230bb5b3a73..e8b1014f53dd 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -121,7 +121,7 @@ void ScriptC::runForEach(Context *rsc,
setupGLState(rsc);
setupScript(rsc);
- rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, usrBytes, sc);
+ rsc->mHal.funcs.script.invokeForEach(rsc, this, 0, ain, aout, usr, usrBytes, sc);
}
void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 928dca5376ed..6a4537b392a2 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -70,6 +70,7 @@ typedef struct {
int (*invokeRoot)(const Context *rsc, Script *s);
void (*invokeForEach)(const Context *rsc,
Script *s,
+ uint32_t slot,
const Allocation * ain,
Allocation * aout,
const void * usr,
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 0133cf601463..f561cc0bbbad 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -16,18 +16,13 @@
package android.mtp;
-import android.util.Log;
-
/**
* Java wrapper for MTP/PTP support as USB responder.
* {@hide}
*/
-public class MtpServer {
-
- private final Object mLock = new Object();
- private boolean mStarted;
+public class MtpServer implements Runnable {
- private static final String TAG = "MtpServer";
+ private int mNativeContext; // accessed by native methods
static {
System.loadLibrary("media_jni");
@@ -38,19 +33,14 @@ public class MtpServer {
}
public void start() {
- synchronized (mLock) {
- native_start();
- mStarted = true;
- }
+ Thread thread = new Thread(this, "MtpServer");
+ thread.start();
}
- public void stop() {
- synchronized (mLock) {
- if (mStarted) {
- native_stop();
- mStarted = false;
- }
- }
+ @Override
+ public void run() {
+ native_run();
+ native_cleanup();
}
public void sendObjectAdded(int handle) {
@@ -70,8 +60,8 @@ public class MtpServer {
}
private native final void native_setup(MtpDatabase database, boolean usePtp);
- private native final void native_start();
- private native final void native_stop();
+ private native final void native_run();
+ private native final void native_cleanup();
private native final void native_send_object_added(int handle);
private native final void native_send_object_removed(int handle);
private native final void native_add_storage(MtpStorage storage);
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 446b6303da25..107db08d516f 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -22,13 +22,8 @@
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
-#include <sys/ioctl.h>
#include <utils/threads.h>
-#ifdef HAVE_ANDROID_OS
-#include <linux/usb/f_mtp.h>
-#endif
-
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
@@ -39,8 +34,8 @@
using namespace android;
-// MtpStorage class
-jclass clazz_MtpStorage;
+// MtpServer fields
+static jfieldID field_MtpServer_nativeContext;
// MtpStorage fields
static jfieldID field_MtpStorage_storageId;
@@ -57,173 +52,78 @@ static Mutex sMutex;
// in android_mtp_MtpDatabase.cpp
extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
-// ----------------------------------------------------------------------------
-
-#ifdef HAVE_ANDROID_OS
-
-static bool ExceptionCheck(void* env)
-{
- return ((JNIEnv *)env)->ExceptionCheck();
+static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
+ return (MtpServer*)env->GetIntField(thiz, field_MtpServer_nativeContext);
}
-class MtpThread : public Thread {
-private:
- MtpDatabase* mDatabase;
- bool mPtp;
- MtpServer* mServer;
- MtpStorageList mStorageList;
- int mFd;
-
-public:
- MtpThread(MtpDatabase* database, bool usePtp)
- : mDatabase(database),
- mPtp(usePtp),
- mServer(NULL),
- mFd(-1)
- {
- }
-
- virtual ~MtpThread() {
- }
-
- void addStorage(MtpStorage *storage) {
- mStorageList.push(storage);
- if (mServer)
- mServer->addStorage(storage);
- }
-
- void removeStorage(MtpStorageID id) {
- MtpStorage* storage = mServer->getStorage(id);
- if (storage) {
- for (size_t i = 0; i < mStorageList.size(); i++) {
- if (mStorageList[i] == storage) {
- mStorageList.removeAt(i);
- break;
- }
- }
- if (mServer)
- mServer->removeStorage(storage);
- delete storage;
- }
- }
-
- void start() {
- run("MtpThread");
- }
-
- virtual bool threadLoop() {
- sMutex.lock();
-
- mFd = open("/dev/mtp_usb", O_RDWR);
- if (mFd >= 0) {
- mServer = new MtpServer(mFd, mDatabase, mPtp, AID_MEDIA_RW, 0664, 0775);
- for (size_t i = 0; i < mStorageList.size(); i++) {
- mServer->addStorage(mStorageList[i]);
- }
- } else {
- LOGE("could not open MTP driver, errno: %d", errno);
- }
-
- sMutex.unlock();
- mServer->run();
- sMutex.lock();
-
- close(mFd);
- mFd = -1;
- delete mServer;
- mServer = NULL;
-
- sMutex.unlock();
- // delay a bit before retrying to avoid excessive spin
- if (!exitPending()) {
- sleep(1);
- }
-
- return true;
- }
-
- void sendObjectAdded(MtpObjectHandle handle) {
- if (mServer)
- mServer->sendObjectAdded(handle);
- }
-
- void sendObjectRemoved(MtpObjectHandle handle) {
- if (mServer)
- mServer->sendObjectRemoved(handle);
- }
-};
-
-// This smart pointer is necessary for preventing MtpThread from exiting too early
-static sp<MtpThread> sThread;
-
-#endif // HAVE_ANDROID_OS
-
static void
android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
{
-#ifdef HAVE_ANDROID_OS
- // create the thread and assign it to the smart pointer
- sThread = new MtpThread(getMtpDatabase(env, javaDatabase), usePtp);
-#endif
+ int fd = open("/dev/mtp_usb", O_RDWR);
+ if (fd >= 0) {
+ MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),
+ usePtp, AID_MEDIA_RW, 0664, 0775);
+ env->SetIntField(thiz, field_MtpServer_nativeContext, (int)server);
+ } else {
+ LOGE("could not open MTP driver, errno: %d", errno);
+ }
}
static void
-android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
+android_mtp_MtpServer_run(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->start();
- sMutex.unlock();
-#endif // HAVE_ANDROID_OS
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->run();
+ else
+ LOGE("server is null in run");
}
static void
-android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
+android_mtp_MtpServer_cleanup(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread) {
- thread->requestExitAndWait();
- sThread = NULL;
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
+ delete server;
+ env->SetIntField(thiz, field_MtpServer_nativeContext, 0);
+ } else {
+ LOGE("server is null in cleanup");
}
- sMutex.unlock();
-#endif
}
static void
android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->sendObjectAdded(handle);
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectAdded(handle);
+ else
+ LOGE("server is null in send_object_added");
}
static void
android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->sendObjectRemoved(handle);
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectRemoved(handle);
+ else
+ LOGE("server is null in send_object_removed");
}
static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread) {
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
@@ -237,7 +137,7 @@ android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
if (descriptionStr != NULL) {
MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
reserveSpace, removable, maxFileSize);
- thread->addStorage(storage);
+ server->addStorage(storage);
env->ReleaseStringUTFChars(path, pathStr);
env->ReleaseStringUTFChars(description, descriptionStr);
} else {
@@ -245,24 +145,24 @@ android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
}
}
} else {
- LOGE("MtpThread is null in add_storage");
+ LOGE("server is null in add_storage");
}
- sMutex.unlock();
-#endif
}
static void
android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->removeStorage(storageId);
- else
- LOGE("MtpThread is null in remove_storage");
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
+ MtpStorage* storage = server->getStorage(storageId);
+ if (storage) {
+ server->removeStorage(storage);
+ delete storage;
+ }
+ } else
+ LOGE("server is null in remove_storage");
}
// ----------------------------------------------------------------------------
@@ -270,8 +170,8 @@ android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
static JNINativeMethod gMethods[] = {
{"native_setup", "(Landroid/mtp/MtpDatabase;Z)V",
(void *)android_mtp_MtpServer_setup},
- {"native_start", "()V", (void *)android_mtp_MtpServer_start},
- {"native_stop", "()V", (void *)android_mtp_MtpServer_stop},
+ {"native_run", "()V", (void *)android_mtp_MtpServer_run},
+ {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup},
{"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added},
{"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
{"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
@@ -320,13 +220,17 @@ int register_android_mtp_MtpServer(JNIEnv *env)
LOGE("Can't find MtpStorage.mMaxFileSize");
return -1;
}
- clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);
clazz = env->FindClass("android/mtp/MtpServer");
if (clazz == NULL) {
LOGE("Can't find android/mtp/MtpServer");
return -1;
}
+ field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_MtpServer_nativeContext == NULL) {
+ LOGE("Can't find MtpServer.mNativeContext");
+ return -1;
+ }
return AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpServer", gMethods, NELEM(gMethods));
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index c14ee828c50a..b311f3522518 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -29,6 +29,9 @@ namespace android {
// static
const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS";
+// static
+const char *const IStreamListener::kKeyFormatChange = "format-change";
+
enum {
// IStreamSource
SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index bbc8a6edcbb3..a6a3a1888179 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -63,8 +63,17 @@ bool NuPlayer::StreamingSource::feedMoreTSData() {
mEOS = true;
break;
} else if (n == INFO_DISCONTINUITY) {
- mTSParser->signalDiscontinuity(
- ATSParser::DISCONTINUITY_SEEK, extra);
+ ATSParser::DiscontinuityType type = ATSParser::DISCONTINUITY_SEEK;
+
+ int32_t formatChange;
+ if (extra != NULL
+ && extra->findInt32(
+ IStreamListener::kKeyFormatChange, &formatChange)
+ && formatChange != 0) {
+ type = ATSParser::DISCONTINUITY_FORMATCHANGE;
+ }
+
+ mTSParser->signalDiscontinuity(type, extra);
} else if (n < 0) {
CHECK_EQ(n, -EWOULDBLOCK);
break;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index c7e7ced50bb9..1bc2fb9eecd7 100644..100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -103,6 +103,10 @@ static int32_t getColorFormat(const char* colorFormat) {
return OMX_COLOR_Format16bitRGB565;
}
+ if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
+ return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
+ }
+
LOGE("Uknown color format (%s), please add it to "
"CameraSource::getColorFormat", colorFormat);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index eaad2c32a876..8c9ff878e040 100644..100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1715,7 +1715,10 @@ status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
return ERROR_MALFORMED;
}
}
-
+// FIXME:
+// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
+// and remove #if 0
+#if 0
{
// Check on the profiles
// These profiles requires additional parameter set extensions
@@ -1725,7 +1728,7 @@ status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
return BAD_VALUE;
}
}
-
+#endif
return OK;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 06363eebd557..3b0575248efc 100644..100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -218,18 +218,21 @@ static const CodecInfo kEncoderInfo[] = {
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
+ { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
+ { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.H264E" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
@@ -393,7 +396,17 @@ uint32_t OMXCodec::getComponentQuirks(
if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.DECODER")) {
quirks |= kRequiresAllocateBufferOnInputPorts;
quirks |= kRequiresAllocateBufferOnOutputPorts;
- } else if (!strncmp(componentName, "OMX.TI.", 7)) {
+ }
+
+ // FIXME:
+ // Remove the quirks after the work is done.
+ else if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.MPEG4E") ||
+ !strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.H264E")) {
+
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ else if (!strncmp(componentName, "OMX.TI.", 7)) {
// Apparently I must not use OMX_UseBuffer on either input or
// output ports on any of the TI components or quote:
// "(I) may have unexpected problem (sic) which can be timing related
@@ -887,6 +900,7 @@ static size_t getFrameSize(
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
+ case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
return (width * height * 3) / 2;
default:
@@ -910,6 +924,7 @@ status_t OMXCodec::findTargetColorFormat(
}
}
+
// Check whether the target color format is supported.
return isColorFormatSupported(*colorFormat, kPortIndexInput);
}
@@ -1032,6 +1047,11 @@ void OMXCodec::setVideoInputFormat(
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->xFramerate = 0; // No need for output port
+ // FIXME:
+ // Revmoe this workaround after work is done.
+ if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
+ video_def->xFramerate = (frameRate << 16);
+ }
video_def->nBitrate = bitRate; // Q16 format
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
@@ -1304,6 +1324,12 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) {
h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
+ // FIXME:
+ // Remove the workaround after the work in done.
+ if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
+ h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
+ }
+
if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
h264type.nSliceHeaderSpacing = 0;
h264type.bUseHadamard = OMX_TRUE;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 9085f10e8afb..4047e2e8777e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -237,6 +237,8 @@ void MtpServer::run() {
if (mSessionOpen)
mDatabase->sessionEnded();
+ close(fd);
+ mFD = -1;
}
void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index da9b55ccd2a3..10b9083549f2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -3154,9 +3154,11 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
mLastHoverWindow = NULL;
}
+ mWindows.clear();
+
// Loop over new windows and rebuild the necessary window pointers for
// tracking focus and touch.
- mWindows = inputWindows;
+ mWindows.appendVector(inputWindows);
size_t numWindows = mWindows.size();
for (size_t i = 0; i < numWindows; i++) {
@@ -4558,7 +4560,8 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
split = other.split;
deviceId = other.deviceId;
source = other.source;
- windows = other.windows;
+ windows.clear();
+ windows.appendVector(other.windows);
}
void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 872438c5e504..54e94db07389 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -313,21 +313,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
+ // use system clock to be externally consistent
+ final long now = System.currentTimeMillis();
+
final NetworkStats stats = new NetworkStats(end - start, 1);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- long[] total = new long[2];
+ NetworkStatsHistory.Entry historyEntry = null;
// combine total from all interfaces that match template
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
- total = history.getTotalData(start, end, total);
+ historyEntry = history.getValues(start, end, now, historyEntry);
entry.iface = IFACE_ALL;
entry.uid = UID_ALL;
entry.tag = TAG_NONE;
- entry.rxBytes = total[0];
- entry.txBytes = total[1];
+ entry.rxBytes = historyEntry.rxBytes;
+ entry.txBytes = historyEntry.txBytes;
stats.combineValues(entry);
}
@@ -345,9 +348,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
synchronized (mStatsLock) {
ensureUidStatsLoadedLocked();
+ // use system clock to be externally consistent
+ final long now = System.currentTimeMillis();
+
final NetworkStats stats = new NetworkStats(end - start, 24);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- long[] total = new long[2];
+ NetworkStatsHistory.Entry historyEntry = null;
for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) {
@@ -361,13 +367,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// other tags when requested.
if (tag == TAG_NONE || includeTags) {
final NetworkStatsHistory history = uidStats.valueAt(i);
- total = history.getTotalData(start, end, total);
+ historyEntry = history.getValues(start, end, now, historyEntry);
entry.iface = IFACE_ALL;
entry.uid = uid;
entry.tag = tag;
- entry.rxBytes = total[0];
- entry.txBytes = total[1];
+ entry.rxBytes = historyEntry.rxBytes;
+ entry.txBytes = historyEntry.txBytes;
if (entry.rxBytes > 0 || entry.txBytes > 0) {
stats.combineValues(entry);
@@ -425,6 +431,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// broadcast.
final int uid = intent.getIntExtra(EXTRA_UID, 0);
synchronized (mStatsLock) {
+ // TODO: perform one last stats poll for UID
removeUidLocked(uid);
}
}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 86b3d364ab02..313979808ced 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -138,12 +138,9 @@ public class UsbDeviceManager {
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
- Process.THREAD_PRIORITY_BACKGROUND) {
- protected void onLooperPrepared() {
- mHandler = new UsbHandler();
- }
- };
+ Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
+ mHandler = new UsbHandler(thread.getLooper());
}
public void systemReady() {
@@ -249,7 +246,8 @@ public class UsbDeviceManager {
private static final int NOTIFICATION_INSTALLER = 3;
private static final int NOTIFICATION_ADB = 4;
- public UsbHandler() {
+ public UsbHandler(Looper looper) {
+ super(looper);
try {
// persist.sys.usb.config should never be unset. But if it is, set it to "adb"
// so we have a chance of debugging what happened.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 35e29a6315a8..f3b6c4dd23b3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -188,22 +188,37 @@ void Layer::setGeometry(hwc_layer_t* hwcl)
return;
}
+ /*
+ * Transformations are applied in this order:
+ * 1) buffer orientation/flip/mirror
+ * 2) state transformation (window manager)
+ * 3) layer orientation (screen orientation)
+ * (NOTE: the matrices are multiplied in reverse order)
+ */
+
+ const Transform bufferOrientation(mCurrentTransform);
+ const Transform& stateTransform(s.transform);
+ const Transform layerOrientation(mOrientation);
+
+ const Transform tr(layerOrientation * stateTransform * bufferOrientation);
+
+ // this gives us only the "orientation" component of the transform
+ const uint32_t finalTransform = tr.getOrientation();
+
// we can only handle simple transformation
- if (mOrientation & Transform::ROT_INVALID) {
+ if (finalTransform & Transform::ROT_INVALID) {
hwcl->flags = HWC_SKIP_LAYER;
return;
}
- // FIXME: shouldn't we take the state's transform into account here?
-
- Transform tr(Transform(mOrientation) * Transform(mCurrentTransform));
- hwcl->transform = tr.getOrientation();
+ hwcl->transform = finalTransform;
if (!isOpaque()) {
hwcl->blending = mPremultipliedAlpha ?
HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
}
+ // scaling is already applied in mTransformedBounds
hwcl->displayFrame.left = mTransformedBounds.left;
hwcl->displayFrame.top = mTransformedBounds.top;
hwcl->displayFrame.right = mTransformedBounds.right;
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 0467a14604c9..4cedcbf86cc6 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -308,6 +308,7 @@ uint32_t Transform::type() const
scale = true;
}
} else {
+ // there is a skew component and/or a non 90 degrees rotation
flags = ROT_INVALID;
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 36b3b82a4111..ac740636138e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -264,7 +264,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
public void testStatsBucketResize() throws Exception {
long elapsedRealtime = 0;
NetworkStatsHistory history = null;
- long[] total = null;
assertStatsFilesExist(false);
@@ -292,9 +291,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
// verify service recorded history
history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
- total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(512L, total[0]);
- assertEquals(512L, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
assertEquals(2, history.size());
verifyAndReset();
@@ -311,9 +308,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
// verify identical stats, but spread across 4 buckets now
history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
- total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(512L, total[0]);
- assertEquals(512L, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
assertEquals(4, history.size());
verifyAndReset();
@@ -575,32 +570,28 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
NetworkStats stats = mService.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(3, stats.size());
- assertEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L);
- assertEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L);
- assertEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L);
+ assertValues(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L);
+ assertValues(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L);
+ assertValues(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L);
// now verify that recent history only contains one uid
final long currentTime = TEST_START + elapsedRealtime;
stats = mService.getSummaryForAllUid(
sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
assertEquals(1, stats.size());
- assertEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L);
+ assertValues(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L);
verifyAndReset();
}
- private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) {
+ private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long txBytes) {
final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
- final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(rx, total[0]);
- assertEquals(tx, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes);
}
- private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) {
+ private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long txBytes) {
final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
- final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(rx, total[0]);
- assertEquals(tx, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes);
}
private void expectSystemReady() throws Exception {
@@ -660,7 +651,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
}
}
- private static void assertEntry(NetworkStats stats, int i, String iface, int uid, int tag,
+ private static void assertValues(NetworkStats stats, int i, String iface, int uid, int tag,
long rxBytes, long rxPackets, long txBytes, long txPackets) {
final NetworkStats.Entry entry = stats.getValues(i, null);
assertEquals(iface, entry.iface);
@@ -673,6 +664,13 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
// assertEquals(txPackets, entry.txPackets);
}
+ private static void assertValues(
+ NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ }
+
private static NetworkState buildWifiState() {
final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 430930965c9a..60cf9b7f362b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -166,4 +166,11 @@ public interface TelephonyProperties
* the value of config_sms_capable
*/
static final String PROPERTY_SMS_SEND = "telephony.sms.send";
+
+ /**
+ * Set to true to indicate a test CSIM card is used in the device.
+ * This property is for testing purpose only. This should not be defined
+ * in commercial configuration.
+ */
+ static final String PROPERTY_TEST_CSIM = "persist.radio.test-csim";
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index 10515f71cfc5..fc6abad48c10 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony.cdma;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.IccCardApplication.AppType;
import com.android.internal.telephony.IccFileHandler;
@@ -447,6 +448,12 @@ public final class CdmaLteUiccRecords extends SIMRecords {
// to determine if the SIM is provisioned. Otherwise,
// consider the SIM is provisioned. (for case of ordinal
// USIM only UICC.)
+ // If PROPERTY_TEST_CSIM is defined, bypess provision check
+ // and consider the SIM is provisioned.
+ if (SystemProperties.getBoolean(PROPERTY_TEST_CSIM, false)) {
+ return true;
+ }
+
if (phone.mIccCard.isApplicationOnIcc(AppType.APPTYPE_CSIM) &&
((mMdn == null) || (mMin == null))) {
return false;
diff --git a/tests/BiDiTests/res/layout/textview_drawables_ltr.xml b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
new file mode 100644
index 000000000000..88b13b7c565a
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/textview_drawables_ltr"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="ltr">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableRight="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableRight="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:id="@+id/textview_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawablePadding="3dip"
+ />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_drawables_rtl.xml b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
new file mode 100644
index 000000000000..7f47d5de6460
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/textview_drawables_rtl"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="rtl">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableRight="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:id="@+id/textview_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawablePadding="3dip"
+ />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index c0338796400e..7002c4148786 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -134,6 +134,9 @@ public class BiDiTestActivity extends Activity {
addItem(result, "TextDirection LTR", BiDiTestTextViewDirectionLtr.class, R.id.textview_direction_ltr);
addItem(result, "TextDirection RTL", BiDiTestTextViewDirectionRtl.class, R.id.textview_direction_rtl);
+ addItem(result, "TextView Drawables LTR", BiDiTestTextViewDrawablesLtr.class, R.id.textview_drawables_ltr);
+ addItem(result, "TextView Drawables RTL", BiDiTestTextViewDrawablesRtl.class, R.id.textview_drawables_rtl);
+
return result;
}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
new file mode 100644
index 000000000000..a65d92dbd4ee
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesLtr extends Fragment {
+
+ private View currentView;
+ private TextView textViewError;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = inflater.inflate(R.layout.textview_drawables_ltr, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+ textViewError.setError("Error!!");
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
new file mode 100644
index 000000000000..7b7e8124b146
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesRtl extends Fragment {
+
+ private View currentView;
+ private TextView textViewError;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = inflater.inflate(R.layout.textview_drawables_rtl, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+ textViewError.setError("Error!!");
+ }
+}