Merge "Minor tweak of NumberPicker to draw the scroll wheel at the right locaion"
diff --git a/api/current.txt b/api/current.txt
index 6693647..a49fa9f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -975,6 +975,7 @@
field public static final int textColorTertiary = 16843282; // 0x1010212
field public static final int textColorTertiaryInverse = 16843283; // 0x1010213
field public static final int textCursorDrawable = 16843618; // 0x1010362
+ field public static final int textDirection = 16843677; // 0x101039d
field public static final int textEditNoPasteWindowLayout = 16843541; // 0x1010315
field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
@@ -9397,6 +9398,7 @@
method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo);
method public void onUpdateSelection(int, int, int, int, int, int);
+ method public void onViewClicked(boolean);
method public void onWindowHidden();
method public void onWindowShown();
method public void requestHideSelf(int);
@@ -9440,6 +9442,7 @@
method public void updateCursor(android.graphics.Rect);
method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
method public void updateSelection(int, int, int, int, int, int);
+ method public void viewClicked(boolean);
}
public static final class InputMethodService.Insets {
@@ -21878,6 +21881,7 @@
method public boolean isHovered();
method public boolean isInEditMode();
method public boolean isInTouchMode();
+ method protected static boolean isLayoutDirectionRtl(java.util.Locale);
method public boolean isLayoutRequested();
method public boolean isLongClickable();
method public boolean isOpaque();
@@ -21963,8 +21967,10 @@
method public void requestLayout();
method public boolean requestRectangleOnScreen(android.graphics.Rect);
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
+ method protected void resetResolvedTextDirection();
method public static int resolveSize(int, int);
method public static int resolveSizeAndState(int, int, int);
+ method protected void resolveTextDirection();
method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -22064,6 +22070,7 @@
method public boolean willNotCacheDrawing();
method public boolean willNotDraw();
field public static android.util.Property ALPHA;
+ field protected static int DEFAULT_TEXT_DIRECTION;
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -23511,6 +23518,7 @@
method public void updateCursor(android.view.View, int, int, int, int);
method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
method public void updateSelection(android.view.View, int, int, int, int);
+ method public void viewClicked(android.view.View);
field public static final int HIDE_IMPLICIT_ONLY = 1; // 0x1
field public static final int HIDE_NOT_ALWAYS = 2; // 0x2
field public static final int RESULT_HIDDEN = 3; // 0x3
@@ -23531,6 +23539,7 @@
method public abstract void updateCursor(android.graphics.Rect);
method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText);
method public abstract void updateSelection(int, int, int, int, int, int);
+ method public abstract void viewClicked(boolean);
}
public static abstract interface InputMethodSession.EventCallback {
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index f780afb..41ccd91 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -20,6 +20,11 @@
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
@@ -31,7 +36,7 @@
using namespace android;
struct MyStreamSource : public BnStreamSource {
- // Caller retains ownership of fd.
+ // Object assumes ownership of fd.
MyStreamSource(int fd);
virtual void setListener(const sp<IStreamListener> &listener);
@@ -64,6 +69,8 @@
}
MyStreamSource::~MyStreamSource() {
+ close(mFd);
+ mFd = -1;
}
void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
@@ -99,6 +106,143 @@
mListener->queueBuffer(index, n);
}
}
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyConvertingStreamSource : public BnStreamSource {
+ MyConvertingStreamSource(const char *filename);
+
+ virtual void setListener(const sp<IStreamListener> &listener);
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+ virtual void onBufferAvailable(size_t index);
+
+protected:
+ virtual ~MyConvertingStreamSource();
+
+private:
+ Mutex mLock;
+ Condition mCondition;
+
+ sp<IStreamListener> mListener;
+ Vector<sp<IMemory> > mBuffers;
+
+ sp<MPEG2TSWriter> mWriter;
+
+ ssize_t mCurrentBufferIndex;
+ size_t mCurrentBufferOffset;
+
+ List<size_t> mBufferQueue;
+
+ static ssize_t WriteDataWrapper(void *me, const void *data, size_t size);
+ ssize_t writeData(const void *data, size_t size);
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
+ : mCurrentBufferIndex(-1),
+ mCurrentBufferOffset(0) {
+ sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+ CHECK(dataSource != NULL);
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ CHECK(extractor != NULL);
+
+ mWriter = new MPEG2TSWriter(
+ this, &MyConvertingStreamSource::WriteDataWrapper);
+
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ const sp<MetaData> &meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) {
+ continue;
+ }
+
+ CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
+ }
+
+ CHECK_EQ(mWriter->start(), (status_t)OK);
+}
+
+MyConvertingStreamSource::~MyConvertingStreamSource() {
+}
+
+void MyConvertingStreamSource::setListener(
+ const sp<IStreamListener> &listener) {
+ mListener = listener;
+}
+
+void MyConvertingStreamSource::setBuffers(
+ const Vector<sp<IMemory> > &buffers) {
+ mBuffers = buffers;
+}
+
+ssize_t MyConvertingStreamSource::WriteDataWrapper(
+ void *me, const void *data, size_t size) {
+ return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size);
+}
+
+ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) {
+ size_t totalWritten = 0;
+
+ while (size > 0) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mCurrentBufferIndex < 0) {
+ while (mBufferQueue.empty()) {
+ mCondition.wait(mLock);
+ }
+
+ mCurrentBufferIndex = *mBufferQueue.begin();
+ mCurrentBufferOffset = 0;
+
+ mBufferQueue.erase(mBufferQueue.begin());
+ }
+
+ sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex);
+
+ size_t copy = size;
+ if (copy + mCurrentBufferOffset > mem->size()) {
+ copy = mem->size() - mCurrentBufferOffset;
+ }
+
+ memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
+ mCurrentBufferOffset += copy;
+
+ if (mCurrentBufferOffset == mem->size()) {
+ mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+ mCurrentBufferIndex = -1;
+ }
+
+ data = (const uint8_t *)data + copy;
+ size -= copy;
+
+ totalWritten += copy;
+ }
+
+ return (ssize_t)totalWritten;
+}
+
+void MyConvertingStreamSource::onBufferAvailable(size_t index) {
+ Mutex::Autolock autoLock(mLock);
+
+ mBufferQueue.push_back(index);
+ mCondition.signal();
+
+ if (mWriter->reachedEOS()) {
+ if (mCurrentBufferIndex >= 0) {
+ mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+ mCurrentBufferIndex = -1;
+ }
+
+ mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
+ }
+}
////////////////////////////////////////////////////////////////////////////////
@@ -139,6 +283,8 @@
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
+ DataSource::RegisterDefaultSniffers();
+
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return 1;
@@ -173,17 +319,28 @@
CHECK(service.get() != NULL);
- int fd = open(argv[1], O_RDONLY);
-
- if (fd < 0) {
- fprintf(stderr, "Failed to open file '%s'.", argv[1]);
- return 1;
- }
-
sp<MyClient> client = new MyClient;
+ sp<IStreamSource> source;
+
+ size_t len = strlen(argv[1]);
+ if (len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) {
+ int fd = open(argv[1], O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+ return 1;
+ }
+
+ source = new MyStreamSource(fd);
+ } else {
+ printf("Converting file to transport stream for streaming...\n");
+
+ source = new MyConvertingStreamSource(argv[1]);
+ }
+
sp<IMediaPlayer> player =
- service->create(getpid(), client, new MyStreamSource(fd), 0);
+ service->create(getpid(), client, source, 0);
if (player != NULL) {
player->setVideoSurface(surface);
@@ -196,9 +353,6 @@
fprintf(stderr, "failed to instantiate player.\n");
}
- close(fd);
- fd = -1;
-
composerClient->dispose();
return 0;
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index df8cf9a..e10f218 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -47,6 +47,7 @@
private static final int DO_APP_PRIVATE_COMMAND = 100;
private static final int DO_TOGGLE_SOFT_INPUT = 105;
private static final int DO_FINISH_SESSION = 110;
+ private static final int DO_VIEW_CLICKED = 115;
HandlerCaller mCaller;
InputMethodSession mInputMethodSession;
@@ -133,6 +134,10 @@
mInputMethodSession = null;
return;
}
+ case DO_VIEW_CLICKED: {
+ mInputMethodSession.viewClicked(msg.arg1 == 1);
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -167,7 +172,11 @@
oldSelStart, oldSelEnd, newSelStart, newSelEnd,
candidatesStart, candidatesEnd));
}
-
+
+ public void viewClicked(boolean focusChanged) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
+ }
+
public void updateCursor(Rect newCursor) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR,
newCursor));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index feb246e..9481a88 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -488,7 +488,15 @@
InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
newSelStart, newSelEnd, candidatesStart, candidatesEnd);
}
-
+
+ @Override
+ public void viewClicked(boolean focusChanged) {
+ if (!isEnabled()) {
+ return;
+ }
+ InputMethodService.this.onViewClicked(focusChanged);
+ }
+
/**
* Call {@link InputMethodService#onUpdateCursor
* InputMethodService.onUpdateCursor()}.
@@ -1609,6 +1617,16 @@
}
/**
+ * Called when the user tapped or clicked a text view.
+ * IMEs can't rely on this method being called because this was not part of the original IME
+ * protocol, so applications with custom text editing written before this method appeared will
+ * not call to inform the IME of this interaction.
+ * @param focusChanged true if the user changed the focused view by this click.
+ */
+ public void onViewClicked(boolean focusChanged) {
+ }
+
+ /**
* Called when the application has reported a new location of its text
* cursor. This is only called if explicitly requested by the input method.
* The default implementation does nothing.
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 040489e..2b59dba 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -25,8 +25,9 @@
import android.os.RemoteException;
import android.os.ServiceManager;
-import dalvik.system.BlockGuard;
+import com.android.server.NetworkManagementSocketTagger;
+import dalvik.system.SocketTagger;
import java.net.Socket;
import java.net.SocketException;
@@ -92,7 +93,7 @@
* {@link #tagSocket(Socket)}.
*/
public static void setThreadStatsTag(int tag) {
- BlockGuard.setThreadSocketStatsTag(tag);
+ NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
}
/**
@@ -104,7 +105,7 @@
}
public static void clearThreadStatsTag() {
- BlockGuard.setThreadSocketStatsTag(-1);
+ NetworkManagementSocketTagger.setThreadSocketStatsTag(-1);
}
/**
@@ -121,12 +122,12 @@
* {@hide}
*/
public static void setThreadStatsUid(int uid) {
- BlockGuard.setThreadSocketStatsUid(uid);
+ NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
/** {@hide} */
public static void clearThreadStatsUid() {
- BlockGuard.setThreadSocketStatsUid(-1);
+ NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
/**
@@ -139,14 +140,14 @@
* @see #setThreadStatsUid(int)
*/
public static void tagSocket(Socket socket) throws SocketException {
- BlockGuard.tagSocketFd(socket.getFileDescriptor$());
+ SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link Socket}.
*/
public static void untagSocket(Socket socket) throws SocketException {
- BlockGuard.untagSocketFd(socket.getFileDescriptor$());
+ SocketTagger.get().untag(socket);
}
/**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1b09242..047a265 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -210,6 +210,16 @@
NetworkStats getNetworkStatsUidDetail(int uid);
/**
+ * Set an overall quota for a group of interfaces.
+ */
+ void setInterfaceQuota(in String[] iface, long quota);
+
+ /**
+ * Control network activity of a UID over interfaces with a quota limit.
+ */
+ void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
+
+ /**
* Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 0933193..39c6f57 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -57,6 +57,29 @@
Uri.parse("content://call_log/calls/filter");
/**
+ * An optional URI parameter which instructs the provider to allow the operation to be
+ * applied to voicemail records as well.
+ * <p>
+ * TYPE: Boolean
+ * <p>
+ * Using this parameter with a value of {@code true} will result in a security error if the
+ * calling package does not have appropriate permissions to access voicemails.
+ *
+ * @hide
+ */
+ public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails";
+
+ /**
+ * Content uri with {@link #ALLOW_VOICEMAILS_PARAM_KEY} set. This can directly be used to
+ * access call log entries that includes voicemail records.
+ *
+ * @hide
+ */
+ public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
+ .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
+ .build();
+
+ /**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "date DESC";
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
old mode 100755
new mode 100644
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 411b714..bf7f359 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2493,6 +2493,84 @@
private boolean mSendingHoverAccessibilityEvents;
/**
+ * Undefined text direction (used by resolution algorithm).
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_UNDEFINED = -1;
+
+ /**
+ * Text direction is inherited thru {@link ViewGroup}
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_INHERIT = 0;
+
+ /**
+ * Text direction is using "first strong algorithm". The first strong directional character
+ * determines the paragraph direction. If there is no strong directional character, the
+ * paragraph direction is the view’s resolved ayout direction.
+ *
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
+
+ /**
+ * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
+ * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
+ * If there are neither, the paragraph direction is the view’s resolved layout direction.
+ *
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_ANY_RTL = 2;
+
+ /**
+ * Text direction is forced to LTR.
+ *
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_LTR = 3;
+
+ /**
+ * Text direction is forced to RTL.
+ *
+ * @hide
+ */
+ public static final int TEXT_DIRECTION_RTL = 4;
+
+ /**
+ * Default text direction is inherited
+ */
+ protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
+
+ /**
+ * The text direction that has been defined by {@link #setTextDirection(int)}.
+ *
+ * {@hide}
+ */
+ @ViewDebug.ExportedProperty(category = "text", mapping = {
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
+ })
+ protected int mTextDirection = DEFAULT_TEXT_DIRECTION;
+
+ /**
+ * The resolved text direction. If resolution has not yet been done or has been reset, it will
+ * be equal to {@link #TEXT_DIRECTION_UNDEFINED}. Otherwise it will be either {@link #TEXT_DIRECTION_LTR}
+ * or {@link #TEXT_DIRECTION_RTL}.
+ *
+ * {@hide}
+ */
+ @ViewDebug.ExportedProperty(category = "text", mapping = {
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
+ })
+ protected int mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+
+ /**
* Consistency verifier for debugging purposes.
* @hide
*/
@@ -2865,6 +2943,9 @@
case R.styleable.View_layerType:
setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
break;
+ case R.styleable.View_textDirection:
+ mTextDirection = a.getInt(attr, DEFAULT_TEXT_DIRECTION);
+ break;
}
}
@@ -8951,6 +9032,8 @@
resetLayoutDirectionResolution();
resolveLayoutDirectionIfNeeded();
resolvePadding();
+ resetResolvedTextDirection();
+ resolveTextDirection();
if (isFocused()) {
InputMethodManager imm = InputMethodManager.peekInstance();
imm.focusIn(this);
@@ -9051,7 +9134,7 @@
* @param locale Locale to check
* @return true if a Locale is corresponding to a RTL script.
*/
- private static boolean isLayoutDirectionRtl(Locale locale) {
+ protected static boolean isLayoutDirectionRtl(Locale locale) {
return (LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE ==
LocaleUtil.getLayoutDirectionFromLocale(locale));
}
@@ -12898,6 +12981,89 @@
return getVerticalScrollFactor();
}
+ /**
+ * Return the value specifying the text direction or policy that was set with
+ * {@link #setTextDirection(int)}.
+ *
+ * @return the defined text direction. It can be one of:
+ *
+ * {@link #TEXT_DIRECTION_INHERIT},
+ * {@link #TEXT_DIRECTION_FIRST_STRONG}
+ * {@link #TEXT_DIRECTION_ANY_RTL},
+ * {@link #TEXT_DIRECTION_LTR},
+ * {@link #TEXT_DIRECTION_RTL},
+ *
+ * @hide
+ */
+ public int getTextDirection() {
+ return mTextDirection;
+ }
+
+ /**
+ * Set the text direction.
+ *
+ * @param textDirection the direction to set. Should be one of:
+ *
+ * {@link #TEXT_DIRECTION_INHERIT},
+ * {@link #TEXT_DIRECTION_FIRST_STRONG}
+ * {@link #TEXT_DIRECTION_ANY_RTL},
+ * {@link #TEXT_DIRECTION_LTR},
+ * {@link #TEXT_DIRECTION_RTL},
+ *
+ * @hide
+ */
+ public void setTextDirection(int textDirection) {
+ if (textDirection != mTextDirection) {
+ mTextDirection = textDirection;
+ resetResolvedTextDirection();
+ requestLayout();
+ }
+ }
+
+ /**
+ * Return the resolved text direction.
+ *
+ * @return the resolved text direction. Return one of:
+ *
+ * {@link #TEXT_DIRECTION_LTR},
+ * {@link #TEXT_DIRECTION_RTL},
+ *
+ * @hide
+ */
+ public int getResolvedTextDirection() {
+ if (!isResolvedTextDirection()) {
+ resolveTextDirection();
+ }
+ return mResolvedTextDirection;
+ }
+
+ /**
+ * Resolve the text direction. Classes that extend View and want to do a specific text direction
+ * resolution will need to implement this method and set the mResolvedTextDirection to
+ * either TEXT_DIRECTION_LTR if direction is LTR or TEXT_DIRECTION_RTL if
+ * direction is RTL.
+ */
+ protected void resolveTextDirection() {
+ }
+
+ /**
+ * Return if the text direction has been resolved or not.
+ *
+ * @return true, if resolved and false if not resolved
+ *
+ * @hide
+ */
+ public boolean isResolvedTextDirection() {
+ return (mResolvedTextDirection != TEXT_DIRECTION_UNDEFINED);
+ }
+
+ /**
+ * Reset resolved text direction. Will be resolved during a call to getResolvedLayoutDirection().
+ */
+ protected void resetResolvedTextDirection() {
+ mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ }
+
//
// Properties
//
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6405398..2a90dde 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -46,6 +46,7 @@
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Locale;
/**
* <p>
@@ -5016,6 +5017,51 @@
}
/**
+ * This method will be called during text direction resolution (text direction resolution
+ * inheritance)
+ */
+ @Override
+ protected void resolveTextDirection() {
+ int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ switch(mTextDirection) {
+ default:
+ case TEXT_DIRECTION_INHERIT:
+ // Try to the text direction from the parent layout
+ if (mParent != null && mParent instanceof ViewGroup) {
+ resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
+ } else {
+ // We reached the top of the View hierarchy, so get the direction from
+ // the Locale
+ resolvedTextDirection = isLayoutDirectionRtl(Locale.getDefault()) ?
+ TEXT_DIRECTION_RTL : TEXT_DIRECTION_LTR;
+ }
+ break;
+ // Pass down the hierarchy the following text direction values
+ case TEXT_DIRECTION_FIRST_STRONG:
+ case TEXT_DIRECTION_ANY_RTL:
+ case TEXT_DIRECTION_LTR:
+ case TEXT_DIRECTION_RTL:
+ resolvedTextDirection = mTextDirection;
+ break;
+ }
+ mResolvedTextDirection = resolvedTextDirection;
+ }
+
+ @Override
+ protected void resetResolvedTextDirection() {
+ super.resetResolvedTextDirection();
+
+ // Take care of resetting the children resolution too
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getTextDirection() == TEXT_DIRECTION_INHERIT) {
+ child.resetResolvedTextDirection();
+ }
+ }
+ }
+
+ /**
* Return true if the pressed state should be delayed for children or descendants of this
* ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
* This prevents the pressed state from appearing when the user is actually trying to scroll
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 47f5e4c..a1a7281 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1126,7 +1126,7 @@
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
return;
}
-
+
InputConnection ic = null;
synchronized (mH) {
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
@@ -1242,6 +1242,27 @@
}
/**
+ * Notify the event when the user tapped or clicked the text view.
+ */
+ public void viewClicked(View view) {
+ final boolean focusChanged = mServedView != mNextServedView;
+ checkFocus();
+ synchronized (mH) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
+ return;
+ }
+ try {
+ if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
+ mCurMethod.viewClicked(focusChanged);
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ }
+ }
+ }
+
+ /**
* Returns true if the current input method wants to watch the location
* of the input editor's cursor in its window.
*/
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index bb03afa..ea6f5ee 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -63,6 +63,15 @@
int candidatesStart, int candidatesEnd);
/**
+ * This method is called when the user tapped a text view.
+ * IMEs can't rely on this method being called because this was not part of the original IME
+ * protocol, so applications with custom text editing written before this method appeared will
+ * not call to inform the IME of this interaction.
+ * @param focusChanged true if the user changed the focused view by this click.
+ */
+ public void viewClicked(boolean focusChanged);
+
+ /**
* This method is called when cursor location of the target input field
* has changed within its window. This is not normally called, but will
* only be reported if requested by the input method.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 85e7eec..2a70ac8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4948,7 +4948,10 @@
if (mMovement != null && mText instanceof Editable
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) imm.showSoftInput(this, 0);
+ if (imm != null) {
+ imm.viewClicked(this);
+ imm.showSoftInput(this, 0);
+ }
}
}
}
@@ -7398,8 +7401,11 @@
if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) {
// Show the IME, except when selecting in read-only text.
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.viewClicked(this);
+ }
if (!mTextIsSelectable) {
- final InputMethodManager imm = InputMethodManager.peekInstance();
handled |= imm != null && imm.showSoftInput(this, 0);
}
@@ -10010,6 +10016,127 @@
return mInBatchEditControllers;
}
+ /**
+ * Resolve the text direction.
+ *
+ * Text direction of paragraphs in a TextView is determined using a heuristic. If the correct
+ * text direction cannot be determined by the heuristic, the view’s resolved layout direction
+ * determines the direction.
+ *
+ * This heuristic and result is applied individually to each paragraph in a TextView, based on
+ * the text and style content of that paragraph. Paragraph text styles can also be used to force
+ * a particular direction.
+ */
+ @Override
+ protected void resolveTextDirection() {
+ int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ switch(mTextDirection) {
+ default:
+ case TEXT_DIRECTION_INHERIT:
+ // Try to the text direction from the parent layout. If not possible, then we will
+ // use the default layout direction to decide later
+ if (mParent != null && mParent instanceof ViewGroup) {
+ resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
+ }
+ break;
+ case TEXT_DIRECTION_FIRST_STRONG:
+ resolvedTextDirection = getTextDirectionFromFirstStrong(mText);
+ break;
+ case TEXT_DIRECTION_ANY_RTL:
+ resolvedTextDirection = getTextDirectionFromAnyRtl(mText);
+ break;
+ case TEXT_DIRECTION_LTR:
+ resolvedTextDirection = TEXT_DIRECTION_LTR;
+ break;
+ case TEXT_DIRECTION_RTL:
+ resolvedTextDirection = TEXT_DIRECTION_RTL;
+ break;
+ }
+ // if we have been so far unable to get the text direction from the heuristics, then we are
+ // falling back using the layout direction
+ if (resolvedTextDirection == TEXT_DIRECTION_UNDEFINED) {
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ resolvedTextDirection = TEXT_DIRECTION_LTR;
+ break;
+ case LAYOUT_DIRECTION_RTL:
+ resolvedTextDirection = TEXT_DIRECTION_RTL;
+ break;
+ }
+ }
+ mResolvedTextDirection = resolvedTextDirection;
+ }
+
+ /**
+ * Get text direction following the "first strong" heuristic.
+ *
+ * @param cs the CharSequence used to get the text direction.
+ *
+ * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
+ * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
+ */
+ private static int getTextDirectionFromFirstStrong(final CharSequence cs) {
+ final int length = cs.length();
+ for(int i = 0; i < length; i++) {
+ final char c = cs.charAt(i);
+ final byte dir = Character.getDirectionality(c);
+ if (isStrongLtrChar(dir)) {
+ return TEXT_DIRECTION_LTR;
+ } else if (isStrongRtlChar(dir)) {
+ return TEXT_DIRECTION_RTL;
+ }
+ }
+ return TEXT_DIRECTION_UNDEFINED;
+ }
+
+ /**
+ * Get text direction following the "any RTL" heuristic.
+ *
+ * @param cs the CharSequence used to get the text direction.
+ *
+ * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
+ * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
+ */
+ private static int getTextDirectionFromAnyRtl(final CharSequence cs) {
+ final int length = cs.length();
+ boolean foundStrongLtr = false;
+ boolean foundStrongRtl = false;
+ for(int i = 0; i < length; i++) {
+ final char c = cs.charAt(i);
+ final byte dir = Character.getDirectionality(c);
+ if (isStrongLtrChar(dir)) {
+ foundStrongLtr = true;
+ } else if (isStrongRtlChar(dir)) {
+ foundStrongRtl = true;
+ }
+ }
+ if (foundStrongRtl) {
+ return TEXT_DIRECTION_RTL;
+ }
+ if (foundStrongLtr) {
+ return TEXT_DIRECTION_LTR;
+ }
+ return TEXT_DIRECTION_UNDEFINED;
+ }
+
+ /**
+ * Return true if the char direction is corresponding to a "strong RTL char" following the
+ * Unicode Bidirectional Algorithm (UBA).
+ */
+ private static boolean isStrongRtlChar(final byte dir) {
+ return (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
+ dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC);
+ }
+
+ /**
+ * Return true if the char direction is corresponding to a "strong LTR char" following the
+ * Unicode Bidirectional Algorithm (UBA).
+ */
+ private static boolean isStrongLtrChar(final byte dir) {
+ return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 5e9cd23..f13e770 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -25,16 +25,13 @@
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-
import com.android.internal.logging.AndroidConfig;
-
+import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.VMRuntime;
-
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.logging.LogManager;
import java.util.TimeZone;
-
+import java.util.logging.LogManager;
import org.apache.harmony.luni.internal.util.TimezoneGetter;
/**
@@ -129,6 +126,11 @@
System.setProperty("http.agent", userAgent);
/*
+ * Wire socket tagging to traffic stats.
+ */
+ NetworkManagementSocketTagger.install();
+
+ /*
* If we're running in an emulator launched with "-trace", put the
* VM into emulator trace profiling mode so that the user can hit
* F9/F10 at any time to capture traces. This has performance
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 338dcaa..f875cbd 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -36,7 +36,9 @@
void updateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd);
-
+
+ void viewClicked(boolean focusChanged);
+
void updateCursor(in Rect newCursor);
void displayCompletions(in CompletionInfo[] completions);
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
new file mode 100644
index 0000000..306d223
--- /dev/null
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -0,0 +1,165 @@
+/*
+ * 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.server;
+
+import dalvik.system.SocketTagger;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.SocketException;
+import java.nio.charset.Charsets;
+
+/**
+ * Assigns tags to sockets for traffic stats.
+ */
+public final class NetworkManagementSocketTagger extends SocketTagger {
+
+ private static final boolean LOGI = false;
+
+ private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
+ @Override protected SocketTags initialValue() {
+ return new SocketTags();
+ }
+ };
+
+ public static void install() {
+ SocketTagger.set(new NetworkManagementSocketTagger());
+ }
+
+ public static void setThreadSocketStatsTag(int tag) {
+ threadSocketTags.get().statsTag = tag;
+ }
+
+ public static void setThreadSocketStatsUid(int uid) {
+ threadSocketTags.get().statsUid = uid;
+ }
+
+ @Override public void tag(FileDescriptor fd) throws SocketException {
+ final SocketTags options = threadSocketTags.get();
+ if (LOGI) {
+ System.logI("tagSocket(" + fd.getInt$() + ") with statsTag="
+ + options.statsTag + ", statsUid=" + options.statsUid);
+ }
+ try {
+ // TODO: skip tagging when options would be no-op
+ tagSocketFd(fd, options.statsTag, options.statsUid);
+ } catch (IOException e) {
+ throw new SocketException("Problem tagging socket", e);
+ }
+ }
+
+ private void tagSocketFd(FileDescriptor fd, int tag, int uid) throws IOException {
+ final int fdNum = fd.getInt$();
+ if (fdNum == -1 || (tag == -1 && uid == -1)) return;
+
+ String cmd = "t " + fdNum;
+ if (tag == -1) {
+ // Case where just the uid needs adjusting. But probably the caller
+ // will want to track his own name here, just in case.
+ cmd += " 0";
+ } else {
+ cmd += " " + tagToKernel(tag);
+ }
+ if (uid != -1) {
+ cmd += " " + uid;
+ }
+ internalModuleCtrl(cmd);
+ }
+
+ @Override public void untag(FileDescriptor fd) throws SocketException {
+ if (LOGI) {
+ System.logI("untagSocket(" + fd.getInt$() + ")");
+ }
+ try {
+ unTagSocketFd(fd);
+ } catch (IOException e) {
+ throw new SocketException("Problem untagging socket", e);
+ }
+ }
+
+ private void unTagSocketFd(FileDescriptor fd) throws IOException {
+ int fdNum = fd.getInt$();
+ if (fdNum == -1) return;
+ String cmd = "u " + fdNum;
+ internalModuleCtrl(cmd);
+ }
+
+ public static class SocketTags {
+ public int statsTag = -1;
+ public int statsUid = -1;
+ }
+
+ /**
+ * Sends commands to the kernel netfilter module.
+ *
+ * @param cmd command string for the qtaguid netfilter module. May not be null.
+ * <p>Supports:
+ * <ul><li>tag a socket:<br>
+ * <code>t <i>sock_fd</i> <i>acct_tag</i> [<i>uid_in_case_caller_is_acting_on_behalf_of</i>]</code><br>
+ * <code>*_tag</code> defaults to default_policy_tag_from_uid(uid_of_caller)<br>
+ * <code>acct_tag</code> is either 0 or greater that 2^32.<br>
+ * <code>uid_*</code> is only settable by privileged UIDs (DownloadManager,...)
+ * </li>
+ * <li>untag a socket, preserving counters:<br>
+ * <code>u <i>sock_fd</i></code>
+ * </li></ul>
+ * <p>Notes:<br>
+ * <ul><li><i>sock_fd</i> is withing the callers process space.</li>
+ * <li><i>*_tag</i> are 64bit values</li></ul>
+ *
+ */
+ private void internalModuleCtrl(String cmd) throws IOException {
+ final FileOutputStream procOut;
+ // TODO: Use something like
+ // android.os.SystemProperties.getInt("persist.bandwidth.enable", 0)
+ // to see if tagging should happen or not.
+ try {
+ procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
+ } catch (FileNotFoundException e) {
+ if (LOGI) {
+ System.logI("Can't talk to kernel module:" + e);
+ }
+ return;
+ }
+ try {
+ procOut.write(cmd.getBytes(Charsets.US_ASCII));
+ } finally {
+ procOut.close();
+ }
+ }
+
+ /**
+ * Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
+ * base-10 format like {@code 2147483647}. Currently strips signed bit to
+ * avoid using {@link java.math.BigInteger}.
+ */
+ public static String tagToKernel(int tag) {
+ // TODO: eventually write in hex, since that's what proc exports
+ // TODO: migrate to direct integer instead of odd shifting
+ return Long.toString((((long) tag) << 32) & 0x7FFFFFFF00000000L);
+ }
+
+ /**
+ * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
+ * format like {@code 0x7fffffff00000000}.
+ */
+ public static int kernelToTag(String string) {
+ // TODO: migrate to direct integer instead of odd shifting
+ return (int) (Long.decode(string) >> 32);
+ }
+}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 37e6027..fd61cfd 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1972,6 +1972,24 @@
<!-- Locale -->
<enum name="locale" value="3" />
</attr>
+ <!-- Direction of the text. A heuristic is used to determine the resolved text direction
+ of paragraphs. -->
+ <attr name="textDirection" format="integer">
+ <!-- Default -->
+ <enum name="inherit" value="0" />
+ <!-- Default for the root view. The first strong directional character determines the
+ paragraph direction. If there is o strong directional character, the paragraph
+ direction is the view’s resolved layout direction. -->
+ <enum name="firstStrong" value="1" />
+ <!-- The paragraph direction is RTL if it contains any strong RTL character, otherwise
+ it is LTR if it contains any strong LTR characters. If there are neither, the
+ paragraph direction is the view’s resolved layout direction. -->
+ <enum name="anyRtl" value="2" />
+ <!-- The text direction is left to right. -->
+ <enum name="ltr" value="3" />
+ <!-- The text direction is right to left. -->
+ <enum name="rtl" value="4" />
+ </attr>
</declare-styleable>
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bbfa9c..db6f98f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1782,4 +1782,5 @@
<public type="integer" name="status_bar_notification_info_maxnum" />
<public type="string" name="status_bar_notification_info_overflow" />
+ <public type="attr" name="textDirection"/>
</resources>
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index d8d145c..a37f1a3 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -22,6 +22,7 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.GetChars;
+import android.view.View;
import android.widget.TextView;
/**
@@ -58,4 +59,122 @@
assertEquals('o', c2[4]);
assertEquals('\0', c2[5]);
}
+
+ @SmallTest
+ public void testTextDirectionDefault() {
+ TextView tv = new TextView(mContext);
+ assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getTextDirection());
+ }
+
+ @SmallTest
+ public void testSetGetTextDirection() {
+ TextView tv = new TextView(mContext);
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
+ }
+
+ @SmallTest
+ public void testGetResolvedTextDirectionLtr() {
+ TextView tv = new TextView(mContext);
+ tv.setText("this is a test");
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+ }
+
+ @SmallTest
+ public void testGetResolvedTextDirectionLtrWithInheritance() {
+ LinearLayout ll = new LinearLayout(mContext);
+ ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+
+ TextView tv = new TextView(mContext);
+ tv.setText("this is a test");
+ ll.addView(tv);
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+ }
+
+ @SmallTest
+ public void testGetResolvedTextDirectionRtl() {
+ TextView tv = new TextView(mContext);
+ tv.setText("\u05DD\u05DE"); // hebrew
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+ }
+
+ @SmallTest
+ public void testGetResolvedTextDirectionRtlWithInheritance() {
+ LinearLayout ll = new LinearLayout(mContext);
+ ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+
+ TextView tv = new TextView(mContext);
+ tv.setText("\u05DD\u05DE"); // hebrew
+ ll.addView(tv);
+
+ tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_LTR);
+ assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection());
+
+ tv.setTextDirection(View.TEXT_DIRECTION_RTL);
+ assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
+ }
}
diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java
index 3c05403..939bd4a 100755
--- a/location/java/android/location/Country.java
+++ b/location/java/android/location/Country.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Locale;
+
/**
* This class wraps the country information.
*
@@ -74,7 +76,7 @@
|| source > COUNTRY_SOURCE_LOCALE) {
throw new IllegalArgumentException();
}
- mCountryIso = countryIso.toLowerCase();
+ mCountryIso = countryIso.toUpperCase(Locale.US);
mSource = source;
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 6f42596..e3cbd57 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -720,8 +720,9 @@
*
* <p>Since API level 13, if applications set a camera via
* {@link #setCamera(Camera)}, the apps can use the camera after this method
- * call. The apps do not need to lock the camera again. The apps should not
- * start another recording session during recording.
+ * call. The apps do not need to lock the camera again. However, if this
+ * method fails, the apps should still lock the camera back. The apps should
+ * not start another recording session during recording.
*
* @throws IllegalStateException if it is called before
* prepare().
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index bdffce9..ed8149a 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -158,9 +158,12 @@
mVideoSize.width = -1;
mVideoSize.height = -1;
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
mInitCheck = init(camera, proxy, cameraId,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
+ if (mInitCheck != OK) releaseCamera();
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
status_t CameraSource::initCheck() const {
@@ -295,7 +298,6 @@
if (width != -1 && height != -1) {
if (!isVideoSizeSupported(width, height, sizes)) {
LOGE("Video dimension (%dx%d) is unsupported", width, height);
- releaseCamera();
return BAD_VALUE;
}
if (isSetVideoSizeSupportedByCamera) {
@@ -309,7 +311,6 @@
// If one and only one of the width and height is -1
// we reject such a request.
LOGE("Requested video size (%dx%d) is not supported", width, height);
- releaseCamera();
return BAD_VALUE;
} else { // width == -1 && height == -1
// Do not configure the camera.
@@ -327,7 +328,6 @@
if (strstr(supportedFrameRates, buf) == NULL) {
LOGE("Requested frame rate (%d) is not supported: %s",
frameRate, supportedFrameRates);
- releaseCamera();
return BAD_VALUE;
}
@@ -463,7 +463,6 @@
bool storeMetaDataInVideoBuffers) {
status_t err = OK;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
LOGE("Camera connection could not be established.");
@@ -505,8 +504,6 @@
}
}
- IPCThreadState::self()->restoreCallingIdentity(token);
-
int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
if (glitchDurationUs > mGlitchDurationThresholdUs) {
mGlitchDurationThresholdUs = glitchDurationUs;
@@ -573,13 +570,21 @@
void CameraSource::releaseCamera() {
LOGV("releaseCamera");
- if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
- LOGV("Camera was cold when we started, stopping preview");
- mCamera->stopPreview();
+ if (mCamera != 0) {
+ if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
+ LOGV("Camera was cold when we started, stopping preview");
+ mCamera->stopPreview();
+ mCamera->disconnect();
+ } else {
+ // Unlock the camera so the application can lock it back.
+ mCamera->unlock();
+ }
+ mCamera.clear();
}
- mCamera.clear();
- mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
- mCameraRecordingProxy.clear();
+ if (mCameraRecordingProxy != 0) {
+ mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+ mCameraRecordingProxy.clear();
+ }
mCameraFlags = 0;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index cd97302..e36b01f 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1838,7 +1838,7 @@
}
}
- LOGV("native_window_set_usage usage=0x%x", usage);
+ LOGV("native_window_set_usage usage=0x%lx", usage);
err = native_window_set_usage(
mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index ed6846c..967f126 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -41,6 +41,7 @@
static Mutex gNetworkThreadLock;
static base::Thread *gNetworkThread = NULL;
static scoped_refptr<net::URLRequestContext> gReqContext;
+static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier;
static void InitializeNetworkThreadIfNecessary() {
Mutex::Autolock autoLock(gNetworkThreadLock);
@@ -52,6 +53,8 @@
gReqContext = new SfRequestContext;
+ gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create());
+
net::AndroidNetworkLibrary::RegisterSharedInstance(
new SfNetworkLibrary);
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index b03bd4d..14abf80 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1641,7 +1641,7 @@
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
if (imi == null) return false;
final int N = subtypes.length;
- mFileManager.addInputMethodSubtypes(mCurMethodId, subtypes);
+ mFileManager.addInputMethodSubtypes(imi, subtypes);
buildInputMethodListLocked(mMethodList, mMethodMap);
return true;
}
@@ -2023,25 +2023,26 @@
final CharSequence label = imi.loadLabel(pm);
if (showSubtypes && enabledSubtypeSet.size() > 0) {
final int subtypeCount = imi.getSubtypeCount();
+ if (DEBUG) {
+ Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+ }
for (int j = 0; j < subtypeCount; ++j) {
- InputMethodSubtype subtype = imi.getSubtypeAt(j);
- if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))
- && !subtype.isAuxiliary()) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+ final String subtypeHashCode = String.valueOf(subtype.hashCode());
+ // We show all enabled IMEs and subtypes when an IME is shown.
+ if (enabledSubtypeSet.contains(subtypeHashCode)
+ && (mInputShown || !subtype.isAuxiliary())) {
final CharSequence title;
- int nameResId = subtype.getNameResId();
- String mode = subtype.getMode();
- if (nameResId != 0) {
- title = TextUtils.concat(subtype.getDisplayName(context,
- imi.getPackageName(), imi.getServiceInfo().applicationInfo),
- (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
- } else {
- CharSequence language = subtype.getLocale();
- // TODO: Use more friendly Title and UI
- title = label + "," + (mode == null ? "" : mode) + ","
- + (language == null ? "" : language);
- }
+ final String mode = subtype.getMode();
+ title = TextUtils.concat(subtype.getDisplayName(context,
+ imi.getPackageName(), imi.getServiceInfo().applicationInfo),
+ (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
title, new Pair<InputMethodInfo, Integer>(imi, j)));
+ // Removing this subtype from enabledSubtypeSet because we no longer
+ // need to add an entry of this subtype to imList to avoid duplicated
+ // entries.
+ enabledSubtypeSet.remove(subtypeHashCode);
}
}
} else {
@@ -2338,7 +2339,7 @@
}
}
}
- ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
+ final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
applicableModeAndSubtypesMap.values());
if (!containsKeyboardSubtype) {
InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
@@ -3016,17 +3017,23 @@
}
public void addInputMethodSubtypes(
- String imiId, InputMethodSubtype[] additionalSubtypes) {
+ InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
synchronized (mMethodMap) {
+ final HashSet<InputMethodSubtype> existingSubtypes =
+ new HashSet<InputMethodSubtype>();
+ for (int i = 0; i < imi.getSubtypeCount(); ++i) {
+ existingSubtypes.add(imi.getSubtypeAt(i));
+ }
+
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
final int N = additionalSubtypes.length;
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = additionalSubtypes[i];
- if (!subtypes.contains(subtype)) {
+ if (!subtypes.contains(subtype) && !existingSubtypes.contains(subtype)) {
subtypes.add(subtype);
}
}
- mSubtypesMap.put(imiId, subtypes);
+ mSubtypesMap.put(imi.getId(), subtypes);
writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
mMethodMap);
}
@@ -3133,8 +3140,8 @@
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
final String imeSubtypeExtraValue =
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
- final boolean isAuxiliary =
- Boolean.valueOf(parser.getAttributeValue(null, ATTR_IS_AUXILIARY));
+ final boolean isAuxiliary = "1".equals(String.valueOf(
+ parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
final InputMethodSubtype subtype =
new InputMethodSubtype(label, icon, imeSubtypeLocale,
imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 630aaf9..8d92a39 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -41,8 +41,6 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import dalvik.system.BlockGuard;
-
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
@@ -921,6 +919,38 @@
}
@Override
+ public void setInterfaceQuota(String[] iface, long quota)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_NETWORK_POLICY, "NetworkManagementService");
+ try {
+ // TODO: Add support for clubbing together multiple interfaces under
+ // one quota. Will need support from the kernel and
+ // BandwidthController to do this.
+ mConnector.doCommand(
+ String.format("bandwidth setquota %s %d", iface[0], quota));
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating to native daemon to set Interface quota",
+ e);
+ }
+ }
+
+ @Override
+ public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_NETWORK_POLICY, "NetworkManagementService");
+ try {
+ // TODO: Connect with BandwidthController
+ // mConnector.doCommand("");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating to native daemon to set Interface quota",
+ e);
+ }
+ }
+
public NetworkStats getNetworkStatsUidDetail(int uid) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(
@@ -958,7 +988,8 @@
try {
final String iface = parsed.get(KEY_IFACE);
- final int tag = BlockGuard.kernelToTag(parsed.get(KEY_TAG_HEX));
+ final int tag = NetworkManagementSocketTagger.kernelToTag(
+ parsed.get(KEY_TAG_HEX));
final int uid = Integer.parseInt(parsed.get(KEY_UID));
final long rx = Long.parseLong(parsed.get(KEY_RX));
final long tx = Long.parseLong(parsed.get(KEY_TX));
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd68c68..dbfd145 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -283,7 +283,8 @@
try {
Slog.i(TAG, "NetworkPolicy Service");
networkPolicy = new NetworkPolicyManagerService(
- context, ActivityManagerService.self(), power, networkStats);
+ context, ActivityManagerService.self(), power,
+ networkStats, networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 12d3ed8..8a93f43 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -71,6 +71,7 @@
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.os.Message;
import android.os.RemoteCallbackList;
@@ -156,6 +157,7 @@
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
private final INetworkStatsService mNetworkStats;
+ private final INetworkManagementService mNetworkManagement;
private final TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -193,9 +195,11 @@
// rules enforced, such as system, phone, and radio UIDs.
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats) {
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement) {
// TODO: move to using cached NtpTrustedTime
- this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
+ this(context, activityManager, powerManager, networkStats,
+ networkManagement, new NtpTrustedTime(),
getSystemDir());
}
@@ -204,12 +208,14 @@
}
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
- File systemDir) {
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement,
+ TrustedTime time, File systemDir) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
+ mNetworkManagement = checkNotNull(networkManagement, "missing networkManagementService");
mTime = checkNotNull(time, "missing TrustedTime");
mHandlerThread = new HandlerThread(TAG);
@@ -589,7 +595,13 @@
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
// remaining "quota" is based on usage in current cycle
final long quota = Math.max(0, policy.limitBytes - total);
- //kernelSetIfacesQuota(ifaces, quota);
+ if (LOGD) {
+ Slog.d(TAG, "Applying quota rules for ifaces=" + Arrays.toString(ifaces)
+ + " LIMIT=" + policy.limitBytes + " TOTAL="
+ + total + " QUOTA=" + quota);
+ }
+
+ setQuotaOnIfaceList(ifaces, quota);
for (String iface : ifaces) {
mMeteredIfaces.add(iface);
@@ -601,6 +613,32 @@
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
}
+ private void setQuotaOnIfaceList(String[] ifaces, long quota) {
+ try {
+ mNetworkManagement.setInterfaceQuota(ifaces, quota);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "IllegalStateException in setQuotaOnIfaceList " + e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote Exception in setQuotaOnIfaceList " + e);
+ }
+ }
+
+ private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ // TODO: connect over to NMS
+ // ndc bandwidth app <uid> naughty
+ try {
+ if (LOGD) {
+ Slog.d(TAG, "setUidNetworkRules() with uid=" + uid
+ + ", rejectOnQuotaInterfaces=" + rejectOnQuotaInterfaces);
+ }
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "IllegalStateException in setUidNetworkRules " + e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote Exception in setUidNetworkRules " + e);
+ }
+ }
+
/**
* Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
* have at least a default mobile policy defined.
@@ -955,7 +993,7 @@
mUidRules.put(uid, uidRules);
final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
- //kernelSetUidRejectPaid(uid, rejectPaid);
+ setUidNetworkRules(uid, rejectMetered);
// dispatch changed rule to existing listeners
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index 8b752ee..ac7cb5a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -16,8 +16,8 @@
package com.android.server;
-import static dalvik.system.BlockGuard.kernelToTag;
-import static dalvik.system.BlockGuard.tagToKernel;
+import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+import static com.android.server.NetworkManagementSocketTagger.tagToKernel;
import android.content.res.Resources;
import android.net.NetworkStats;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 324e896..af2e01c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -56,6 +56,7 @@
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.os.Binder;
+import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.test.AndroidTestCase;
import android.test.mock.MockPackageManager;
@@ -95,6 +96,7 @@
private IActivityManager mActivityManager;
private IPowerManager mPowerManager;
private INetworkStatsService mStatsService;
+ private INetworkManagementService mNetworkManagement;
private INetworkPolicyListener mPolicyListener;
private TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -150,13 +152,15 @@
mActivityManager = createMock(IActivityManager.class);
mPowerManager = createMock(IPowerManager.class);
mStatsService = createMock(INetworkStatsService.class);
+ mNetworkManagement = createMock(INetworkManagementService.class);
mPolicyListener = createMock(INetworkPolicyListener.class);
mTime = createMock(TrustedTime.class);
mConnManager = createMock(IConnectivityManager.class);
mNotifManager = createMock(INotificationManager.class);
mService = new NetworkPolicyManagerService(
- mServiceContext, mActivityManager, mPowerManager, mStatsService, mTime, mPolicyDir);
+ mServiceContext, mActivityManager, mPowerManager, mStatsService,
+ mNetworkManagement, mTime, mPolicyDir);
mService.bindConnectivityManager(mConnManager);
mService.bindNotificationManager(mNotifManager);
@@ -526,14 +530,14 @@
}
private void replay() {
- EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
+ EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
}
private void verifyAndReset() {
- EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
- EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
+ EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
+ EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
}
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index c4a6f53..6e9d0f9d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -502,16 +502,17 @@
@SmallTest
public void testFormatNumberToE164() {
- assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "us"));
- assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "us"));
- assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "us"));
+ // Note: ISO 3166-1 only allows upper case country codes.
+ assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "US"));
+ assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "US"));
+ assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "US"));
}
@SmallTest
public void testFormatNumber() {
- assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "us"));
- assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "us"));
- assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "us"));
+ assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
+ assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "US"));
+ assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
}
diff --git a/tests/BiDiTests/res/layout/textview_direction_ltr.xml b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
new file mode 100644
index 0000000..f7b7b8e
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
@@ -0,0 +1,112 @@
+<?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_direction_ltr"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="ltr">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textDirection="ltr">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="inherit"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="firstStrong"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="anyRtl"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="ltr"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="rtl"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="inherit"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="firstStrong"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="anyRtl"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="ltr"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="rtl"
+ />
+ </LinearLayout>
+
+ </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/textview_direction_rtl.xml b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
new file mode 100644
index 0000000..81c5411
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
@@ -0,0 +1,112 @@
+<?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_direction_rtl"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="rtl">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textDirection="rtl">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="inherit"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="firstStrong"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="anyRtl"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="ltr"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:textDirection="rtl"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="inherit"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="firstStrong"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="anyRtl"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="ltr"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="rtl"
+ />
+ </LinearLayout>
+
+ </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index b1e494a..c033879 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -122,9 +122,6 @@
addItem(result, "Table RTL", BiDiTestTableLayoutRtl.class, R.id.table_layout_rtl);
addItem(result, "Table LOC", BiDiTestTableLayoutLocale.class, R.id.table_layout_locale);
- addItem(result, "ViewPadding", BiDiTestViewPadding.class, R.id.view_padding);
- addItem(result, "ViewPadding MIXED", BiDiTestViewPaddingMixed.class, R.id.view_padding_mixed);
-
addItem(result, "Padding", BiDiTestViewPadding.class, R.id.view_padding);
addItem(result, "Padding MIXED", BiDiTestViewPaddingMixed.class, R.id.view_padding_mixed);
@@ -134,6 +131,9 @@
addItem(result, "TextView RTL", BiDiTestTextViewRtl.class, R.id.textview_rtl);
addItem(result, "TextView LOC", BiDiTestTextViewLocale.class, R.id.textview_locale);
+ addItem(result, "TextDirection LTR", BiDiTestTextViewDirectionLtr.class, R.id.textview_direction_ltr);
+ addItem(result, "TextDirection RTL", BiDiTestTextViewDirectionRtl.class, R.id.textview_direction_rtl);
+
return result;
}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionLtr.java
new file mode 100644
index 0000000..882ed1f
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionLtr.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+public class BiDiTestTextViewDirectionLtr extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.textview_direction_ltr, container, false);
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionRtl.java
new file mode 100644
index 0000000..e63ee35
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDirectionRtl.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+public class BiDiTestTextViewDirectionRtl extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.textview_direction_rtl, container, false);
+ }
+}