Merge "Keep initial zoom overview for non-standard load."
diff --git a/api/current.txt b/api/current.txt
index d90dbab..1c2950a 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
@@ -5896,6 +5897,7 @@
field public long codeSize;
field public long dataSize;
field public long externalCacheSize;
+ field public long externalCodeSize;
field public long externalDataSize;
field public long externalMediaSize;
field public long externalObbSize;
@@ -21880,6 +21882,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();
@@ -21965,8 +21968,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);
@@ -22066,6 +22071,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
@@ -22389,6 +22395,7 @@
method public void requestDisallowInterceptTouchEvent(boolean);
method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
+ method protected void resetLayoutDirectionResolution();
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -26057,6 +26064,7 @@
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 resetLayoutDirectionResolution();
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 0acba8b..ccd668d 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -213,9 +213,10 @@
// create the native surface
sp<SurfaceControl> control = session()->createSurface(
0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
- session()->openTransaction();
+
+ SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
- session()->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index d45ac192..26b9113 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -288,8 +288,9 @@
}
int get_size(const char *pkgname, const char *apkpath,
- const char *fwdlock_apkpath,
- int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize)
+ const char *fwdlock_apkpath, const char *asecpath,
+ int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
+ int64_t* _asecsize)
{
DIR *d;
int dfd;
@@ -300,6 +301,7 @@
int64_t codesize = 0;
int64_t datasize = 0;
int64_t cachesize = 0;
+ int64_t asecsize = 0;
/* count the source apk as code -- but only if it's not
* on the /system partition and its not on the sdcard.
@@ -324,6 +326,14 @@
}
}
+ /* compute asec size if it is given
+ */
+ if (asecpath != NULL && asecpath[0] != '!') {
+ if (stat(asecpath, &s) == 0) {
+ asecsize += stat_size(&s);
+ }
+ }
+
if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
goto done;
}
@@ -370,6 +380,7 @@
*_codesize = codesize;
*_datasize = datasize;
*_cachesize = cachesize;
+ *_asecsize = asecsize;
return 0;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index c062d36..feb6b92 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -77,16 +77,18 @@
int64_t codesize = 0;
int64_t datasize = 0;
int64_t cachesize = 0;
+ int64_t asecsize = 0;
int res = 0;
/* pkgdir, apkpath */
- res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize);
+ res = get_size(arg[0], arg[1], arg[2], arg[3], &codesize, &datasize, &cachesize, &asecsize);
/*
* Each int64_t can take up 22 characters printed out. Make sure it
* doesn't go over REPLY_MAX in the future.
*/
- snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize);
+ snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
+ codesize, datasize, cachesize, asecsize);
return res;
}
@@ -137,7 +139,7 @@
{ "freecache", 1, do_free_cache },
{ "rmcache", 1, do_rm_cache },
{ "protect", 2, do_protect },
- { "getsize", 3, do_get_size },
+ { "getsize", 4, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 2, do_linklib },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index e5f6739..c5872b8 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -143,7 +143,8 @@
int rm_dex(const char *path);
int protect(char *pkgname, gid_t gid);
int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
- int64_t *codesize, int64_t *datasize, int64_t *cachesize);
+ const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
+ int64_t *asecsize);
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index ddd64ec..6fa66cf 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -568,10 +568,10 @@
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
surface = control->getSurface();
CHECK(surface != NULL);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 656f5fd..1a5b7f3 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -865,10 +865,10 @@
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
gSurface = control->getSurface();
CHECK(gSurface != NULL);
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 41ccd91..ee91c29 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -305,10 +305,10 @@
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> surface = control->getSurface();
CHECK(surface != NULL);
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 11068e5..1205da7 100755
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -40,6 +40,12 @@
public long cacheSize;
/**
+ * Size of the secure container on external storage holding the
+ * application's code.
+ */
+ public long externalCodeSize;
+
+ /**
* Size of the external data used by the application (e.g.,
* <sdcard>/Android/data/<app>)
*/
@@ -80,6 +86,8 @@
sb.append(dataSize);
sb.append(",cacheSize=");
sb.append(cacheSize);
+ sb.append(",externalCodeSize=");
+ sb.append(externalCodeSize);
sb.append(",externalDataSize=");
sb.append(externalDataSize);
sb.append(",externalCacheSize=");
@@ -100,6 +108,7 @@
codeSize = source.readLong();
dataSize = source.readLong();
cacheSize = source.readLong();
+ externalCodeSize = source.readLong();
externalDataSize = source.readLong();
externalCacheSize = source.readLong();
externalMediaSize = source.readLong();
@@ -111,6 +120,7 @@
codeSize = pStats.codeSize;
dataSize = pStats.dataSize;
cacheSize = pStats.cacheSize;
+ externalCodeSize = pStats.externalCodeSize;
externalDataSize = pStats.externalDataSize;
externalCacheSize = pStats.externalCacheSize;
externalMediaSize = pStats.externalMediaSize;
@@ -126,6 +136,7 @@
dest.writeLong(codeSize);
dest.writeLong(dataSize);
dest.writeLong(cacheSize);
+ dest.writeLong(externalCodeSize);
dest.writeLong(externalDataSize);
dest.writeLong(externalCacheSize);
dest.writeLong(externalMediaSize);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 21fad2c..593b2b7 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -49,6 +49,8 @@
/** Reject traffic on metered networks. */
public static final int RULE_REJECT_METERED = 0x1;
+ private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
+
/**
* {@link Intent} action launched when user selects {@link NetworkPolicy}
* warning notification.
@@ -223,25 +225,27 @@
return false;
}
- final PackageManager pm = context.getPackageManager();
- final HashSet<Signature> systemSignature;
- try {
- systemSignature = Sets.newHashSet(
- pm.getPackageInfo("android", GET_SIGNATURES).signatures);
- } catch (NameNotFoundException e) {
- throw new RuntimeException("problem finding system signature", e);
- }
-
- try {
- // reject apps signed with system cert
- for (String packageName : pm.getPackagesForUid(uid)) {
- final HashSet<Signature> packageSignature = Sets.newHashSet(
- pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
- if (packageSignature.containsAll(systemSignature)) {
- return false;
- }
+ if (!ALLOW_PLATFORM_APP_POLICY) {
+ final PackageManager pm = context.getPackageManager();
+ final HashSet<Signature> systemSignature;
+ try {
+ systemSignature = Sets.newHashSet(
+ pm.getPackageInfo("android", GET_SIGNATURES).signatures);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException("problem finding system signature", e);
}
- } catch (NameNotFoundException e) {
+
+ try {
+ // reject apps signed with platform cert
+ for (String packageName : pm.getPackagesForUid(uid)) {
+ final HashSet<Signature> packageSignature = Sets.newHashSet(
+ pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
+ if (packageSignature.containsAll(systemSignature)) {
+ return false;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ }
}
// nothing found above; we can apply policy to UID
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 5ade9eb..0eb8cd8 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -338,7 +338,15 @@
* @hide
*/
public static NdefRecord createUri(Uri uri) {
- String uriString = uri.toString();
+ return createUri(uri.toString());
+ }
+
+ /**
+ * Creates an NDEF record of well known type URI.
+ * TODO: Make a public API
+ * @hide
+ */
+ public static NdefRecord createUri(String uriString) {
byte prefix = 0x0;
for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
if (uriString.startsWith(URI_PREFIX_MAP[i])) {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1b09242..c9b6121 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -210,6 +210,21 @@
NetworkStats getNetworkStatsUidDetail(int uid);
/**
+ * Set quota for an interface.
+ */
+ void setInterfaceQuota(String iface, long quota);
+
+ /**
+ * Remove quota for an interface.
+ */
+ void removeInterfaceQuota(String iface);
+
+ /**
+ * 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/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index c2dc8ae..9302060 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -655,6 +655,26 @@
}
return _result;
}
+
+ /*
+ * Returns the filesystem path of a mounted secure container.
+ */
+ public String getSecureContainerFilesystemPath(String id) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ String _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(id);
+ mRemote.transact(Stub.TRANSACTION_getSecureContainerFilesystemPath, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readString();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "IMountService";
@@ -719,6 +739,8 @@
static final int TRANSACTION_getVolumeList = IBinder.FIRST_CALL_TRANSACTION + 29;
+ static final int TRANSACTION_getSecureContainerFilesystemPath = IBinder.FIRST_CALL_TRANSACTION + 30;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1031,6 +1053,15 @@
reply.writeParcelableArray(result, 0);
return true;
}
+ case TRANSACTION_getSecureContainerFilesystemPath: {
+ data.enforceInterface(DESCRIPTOR);
+ String id;
+ id = data.readString();
+ String path = getSecureContainerFilesystemPath(id);
+ reply.writeNoException();
+ reply.writeString(path);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1210,4 +1241,6 @@
* Returns list of all mountable volumes.
*/
public Parcelable[] getVolumeList() throws RemoteException;
+
+ public String getSecureContainerFilesystemPath(String id) throws RemoteException;
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 3971045..b492615 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -17,9 +17,6 @@
package android.provider;
-import com.android.internal.util.ArrayUtils;
-
-import android.accounts.Account;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
@@ -35,13 +32,10 @@
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Log;
-import java.util.Arrays;
-
/**
* <p>
* The contract between the calendar provider and applications. Contains
@@ -97,6 +91,8 @@
/**
* Broadcast Action: This is the intent that gets fired when an alarm
* notification needs to be posted for a reminder.
+ *
+ * @SdkConstant
*/
public static final String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
@@ -122,8 +118,7 @@
/**
* The content:// style URL for the top-level calendar authority
*/
- public static final Uri CONTENT_URI =
- Uri.parse("content://" + AUTHORITY);
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
/**
* An optional insert, update or delete URI parameter that allows the caller
@@ -572,29 +567,6 @@
* </ul>
*/
public static class Calendars implements BaseColumns, SyncColumns, CalendarColumns {
- private static final String WHERE_DELETE_FOR_ACCOUNT = Calendars.ACCOUNT_NAME + "=?"
- + " AND "
- + Calendars.ACCOUNT_TYPE + "=?";
-
- /**
- * Helper function for generating a calendars query. This is blocking
- * and should not be used on the UI thread. See
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- * for more details about using the parameters.
- *
- * @param cr The ContentResolver to query with
- * @param projection A list of columns to return
- * @param selection A formatted selection string
- * @param selectionArgs arguments to the selection string
- * @param orderBy How to order the returned rows
- * @return
- */
- public static final Cursor query(ContentResolver cr, String[] projection, String selection,
- String[] selectionArgs, String orderBy) {
- return cr.query(CONTENT_URI, projection, selection, selectionArgs,
- orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
/**
* The content:// style URL for accessing Calendars
*/
@@ -622,7 +594,9 @@
* These fields are only writable by a sync adapter. To modify them the
* caller must include {@link #CALLER_IS_SYNCADAPTER},
* {@link #ACCOUNT_NAME}, and {@link #ACCOUNT_TYPE} in the Uri's query
- * parameters.
+ * parameters. TODO move to provider
+ *
+ * @hide
*/
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
@@ -737,7 +711,7 @@
/**
* the projection used by the attendees query
*/
- private static final String[] PROJECTION = new String[] {
+ public static final String[] PROJECTION = new String[] {
_ID, ATTENDEE_NAME, ATTENDEE_EMAIL, ATTENDEE_RELATIONSHIP, ATTENDEE_STATUS,};
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
@@ -1420,37 +1394,6 @@
CalendarColumns {
/**
- * Queries all events with the given projection. This is a blocking call
- * and should not be done on the UI thread.
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @return A Cursor containing all events in the db
- */
- public static final Cursor query(ContentResolver cr, String[] projection) {
- return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
- }
-
- /**
- * Queries events using the given projection, selection filter, and
- * ordering. This is a blocking call and should not be done on the UI
- * thread. For selection and selectionArgs usage see
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @param selection Filter on the query as an SQL WHERE statement
- * @param selectionArgs Args to replace any '?'s in the selection
- * @param orderBy How to order the rows as an SQL ORDER BY statement
- * @return A Cursor containing the matching events
- */
- public static final Cursor query(ContentResolver cr, String[] projection, String selection,
- String[] selectionArgs, String orderBy) {
- return cr.query(CONTENT_URI, projection, selection, null,
- orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
- /**
* The content:// style URL for interacting with events. Appending an
* event id using {@link ContentUris#withAppendedId(Uri, long)} will
* specify a single event.
@@ -1464,7 +1407,7 @@
* appended event ID. Deletion of exceptions requires both the original event ID and
* the exception event ID (see {@link Uri.Builder#appendPath}).
*/
- public static final Uri EXCEPTION_CONTENT_URI =
+ public static final Uri CONTENT_EXCEPTION_URI =
Uri.parse("content://" + AUTHORITY + "/exception");
/**
@@ -1475,7 +1418,9 @@
/**
* These are columns that should only ever be updated by the provider,
* either because they are views mapped to another table or because they
- * are used for provider only functionality.
+ * are used for provider only functionality. TODO move to provider
+ *
+ * @hide
*/
public static String[] PROVIDER_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
@@ -1505,7 +1450,9 @@
/**
* These fields are only writable by a sync adapter. To modify them the
* caller must include CALLER_IS_SYNCADAPTER, _SYNC_ACCOUNT, and
- * _SYNC_ACCOUNT_TYPE in the query parameters.
+ * _SYNC_ACCOUNT_TYPE in the query parameters. TODO move to provider.
+ *
+ * @hide
*/
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
_SYNC_ID,
@@ -1672,11 +1619,6 @@
public static final String END_MINUTE = "endMinute";
}
- /**
- * CalendarCache stores some settings for calendar including the current
- * time zone for the instaces. These settings are stored using a key/value
- * scheme.
- */
protected interface CalendarCacheColumns {
/**
* The key for the setting. Keys are defined in {@link CalendarCache}.
@@ -1689,6 +1631,11 @@
public static final String VALUE = "value";
}
+ /**
+ * CalendarCache stores some settings for calendar including the current
+ * time zone for the instances. These settings are stored using a key/value
+ * scheme. A {@link #KEY} must be specified when updating these values.
+ */
public static class CalendarCache implements CalendarCacheColumns {
/**
* The URI to use for retrieving the properties from the Calendar db.
@@ -1697,22 +1644,11 @@
Uri.parse("content://" + AUTHORITY + "/properties");
/**
- * If updating a property, this must be provided as the selection. All
- * other selections will fail. For queries this field can be omitted to
- * retrieve all properties or used to query a single property. Valid
- * keys include {@link #TIMEZONE_KEY_TYPE},
- * {@link #TIMEZONE_KEY_INSTANCES}, and
- * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
- * only be read, not written.
- */
- public static final String WHERE = "key=?";
-
- /**
* They key for updating the use of auto/home time zones in Calendar.
* Valid values are {@link #TIMEZONE_TYPE_AUTO} or
* {@link #TIMEZONE_TYPE_HOME}.
*/
- public static final String TIMEZONE_KEY_TYPE = "timezoneType";
+ public static final String KEY_TIMEZONE_TYPE = "timezoneType";
/**
* The key for updating the time zone used by the provider when it
@@ -1720,24 +1656,24 @@
* type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
* should be written to this field.
*/
- public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";
+ public static final String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
/**
* The key for reading the last time zone set by the user. This should
* only be read by apps and it will be automatically updated whenever
- * {@link #TIMEZONE_KEY_INSTANCES} is updated with
+ * {@link #KEY_TIMEZONE_INSTANCES} is updated with
* {@link #TIMEZONE_TYPE_HOME} set.
*/
- public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+ public static final String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
/**
- * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * The value to write to {@link #KEY_TIMEZONE_TYPE} if the provider
* should stay in sync with the device's time zone.
*/
public static final String TIMEZONE_TYPE_AUTO = "auto";
/**
- * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * The value to write to {@link #KEY_TIMEZONE_TYPE} if the provider
* should use a fixed time zone set by the user.
*/
public static final String TIMEZONE_TYPE_HOME = "home";
@@ -1814,7 +1750,7 @@
/**
* The projection used by the EventDays query.
*/
- private static final String[] PROJECTION = {
+ public static final String[] PROJECTION = {
STARTDAY, ENDDAY
};
private static final String SELECTION = "selected=1";
@@ -1900,7 +1836,7 @@
/**
* The projection used by the reminders query.
*/
- private static final String[] PROJECTION = new String[] {
+ public static final String[] PROJECTION = new String[] {
_ID, MINUTES, METHOD,};
@SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/reminders");
@@ -1967,17 +1903,28 @@
public static final String NOTIFY_TIME = "notifyTime";
/**
- * The state of this alert. It starts out as {@link #SCHEDULED}, then
- * when the alarm goes off, it changes to {@link #FIRED}, and then when
- * the user dismisses the alarm it changes to {@link #DISMISSED}. Column
+ * The state of this alert. It starts out as {@link #STATE_SCHEDULED}, then
+ * when the alarm goes off, it changes to {@link #STATE_FIRED}, and then when
+ * the user dismisses the alarm it changes to {@link #STATE_DISMISSED}. Column
* name.
* <P>Type: INTEGER</P>
*/
public static final String STATE = "state";
- public static final int SCHEDULED = 0;
- public static final int FIRED = 1;
- public static final int DISMISSED = 2;
+ /**
+ * An alert begins in this state when it is first created.
+ */
+ public static final int STATE_SCHEDULED = 0;
+ /**
+ * After a notification for an alert has been created it should be
+ * updated to fired.
+ */
+ public static final int STATE_FIRED = 1;
+ /**
+ * Once the user has dismissed the notification the alert's state should
+ * be set to dismissed so it is not fired again.
+ */
+ public static final int STATE_DISMISSED = 2;
/**
* The number of minutes that this alarm precedes the start time. Column
@@ -2024,7 +1971,7 @@
private static final String WHERE_FINDNEXTALARMTIME = ALARM_TIME + ">=?";
private static final String SORT_ORDER_ALARMTIME_ASC = ALARM_TIME + " ASC";
- private static final String WHERE_RESCHEDULE_MISSED_ALARMS = STATE + "=" + SCHEDULED
+ private static final String WHERE_RESCHEDULE_MISSED_ALARMS = STATE + "=" + STATE_SCHEDULED
+ " AND " + ALARM_TIME + "<?"
+ " AND " + ALARM_TIME + ">?"
+ " AND " + END + ">=?";
@@ -2038,10 +1985,11 @@
public static final Uri CONTENT_URI_BY_INSTANCE =
Uri.parse("content://" + AUTHORITY + "/calendar_alerts/by_instance");
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
/**
- * Helper for inserting an alarm time associated with an event
+ * Helper for inserting an alarm time associated with an event TODO move
+ * to Provider
*
* @hide
*/
@@ -2056,51 +2004,32 @@
values.put(CalendarAlerts.CREATION_TIME, currentTime);
values.put(CalendarAlerts.RECEIVED_TIME, 0);
values.put(CalendarAlerts.NOTIFY_TIME, 0);
- values.put(CalendarAlerts.STATE, SCHEDULED);
+ values.put(CalendarAlerts.STATE, STATE_SCHEDULED);
values.put(CalendarAlerts.MINUTES, minutes);
return cr.insert(CONTENT_URI, values);
}
/**
- * Queries alerts info using the given projection, selection filter, and
- * ordering. This is a blocking call and should not be done on the UI
- * thread. For selection and selectionArgs usage see
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @param selection Filter on the query as an SQL WHERE statement
- * @param selectionArgs Args to replace any '?'s in the selection
- * @param sortOrder How to order the rows as an SQL ORDER BY statement
- * @return A Cursor containing the matching alerts
- */
- public static final Cursor query(ContentResolver cr, String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
- return cr.query(CONTENT_URI, projection, selection, selectionArgs,
- sortOrder);
- }
-
- /**
* Finds the next alarm after (or equal to) the given time and returns
* the time of that alarm or -1 if no such alarm exists. This is a
- * blocking call and should not be done on the UI thread.
+ * blocking call and should not be done on the UI thread. TODO move to
+ * provider
*
* @param cr the ContentResolver
* @param millis the time in UTC milliseconds
* @return the next alarm time greater than or equal to "millis", or -1
* if no such alarm exists.
+ * @hide
*/
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
String selection = ALARM_TIME + ">=" + millis;
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
- Cursor cursor = query(cr, projection,
- WHERE_FINDNEXTALARMTIME,
- new String[] {
+ Cursor cursor = cr.query(CONTENT_URI, projection, WHERE_FINDNEXTALARMTIME,
+ (new String[] {
Long.toString(millis)
- },
- SORT_ORDER_ALARMTIME_ASC);
+ }), SORT_ORDER_ALARMTIME_ASC);
long alarmTime = -1;
try {
if (cursor != null && cursor.moveToFirst()) {
@@ -2116,13 +2045,14 @@
/**
* Searches the CalendarAlerts table for alarms that should have fired
- * but have not and then reschedules them. This method can be called
- * at boot time to restore alarms that may have been lost due to a
- * phone reboot.
+ * but have not and then reschedules them. This method can be called at
+ * boot time to restore alarms that may have been lost due to a phone
+ * reboot. TODO move to provider
*
* @param cr the ContentResolver
* @param context the Context
* @param manager the AlarmManager
+ * @hide
*/
public static final void rescheduleMissedAlarms(ContentResolver cr,
Context context, AlarmManager manager) {
@@ -2136,15 +2066,10 @@
// TODO: construct an explicit SQL query so that we can add
// "GROUPBY" instead of doing a sort and de-dup
- Cursor cursor = CalendarAlerts.query(cr,
- projection,
- WHERE_RESCHEDULE_MISSED_ALARMS,
- new String[] {
- Long.toString(now),
- Long.toString(ancient),
- Long.toString(now)
- },
- SORT_ORDER_ALARMTIME_ASC);
+ Cursor cursor = cr.query(CalendarAlerts.CONTENT_URI, projection,
+ WHERE_RESCHEDULE_MISSED_ALARMS, (new String[] {
+ Long.toString(now), Long.toString(ancient), Long.toString(now)
+ }), SORT_ORDER_ALARMTIME_ASC);
if (cursor == null) {
return;
}
@@ -2177,12 +2102,13 @@
* keep scheduled reminders up to date but apps may use this to
* implement snooze functionality without modifying the reminders table.
* Scheduled alarms will generate an intent using
- * {@link #ACTION_EVENT_REMINDER}.
+ * {@link #ACTION_EVENT_REMINDER}. TODO Move to provider
*
* @param context A context for referencing system resources
* @param manager The AlarmManager to use or null
* @param alarmTime The time to fire the intent in UTC millis since
* epoch
+ * @hide
*/
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
if (DEBUG) {
@@ -2204,31 +2130,28 @@
}
/**
- * Searches for an entry in the CalendarAlerts table that matches
- * the given event id, begin time and alarm time. If one is found
- * then this alarm already exists and this method returns true.
- *
+ * Searches for an entry in the CalendarAlerts table that matches the
+ * given event id, begin time and alarm time. If one is found then this
+ * alarm already exists and this method returns true. TODO Move to
+ * provider
+ *
* @param cr the ContentResolver
* @param eventId the event id to match
* @param begin the start time of the event in UTC millis
* @param alarmTime the alarm time of the event in UTC millis
- * @return true if there is already an alarm for the given event
- * with the same start time and alarm time.
+ * @return true if there is already an alarm for the given event with
+ * the same start time and alarm time.
+ * @hide
*/
public static final boolean alarmExists(ContentResolver cr, long eventId,
long begin, long alarmTime) {
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
- Cursor cursor = query(cr,
- projection,
- WHERE_ALARM_EXISTS,
- new String[] {
- Long.toString(eventId),
- Long.toString(begin),
- Long.toString(alarmTime)
- },
- null);
+ Cursor cursor = cr.query(CONTENT_URI, projection, WHERE_ALARM_EXISTS,
+ (new String[] {
+ Long.toString(eventId), Long.toString(begin), Long.toString(alarmTime)
+ }), null);
boolean found = false;
try {
if (cursor != null && cursor.getCount() > 0) {
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/text/Layout.java b/core/java/android/text/Layout.java
index 4107c5a..aae9ccf 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -266,7 +266,7 @@
}
}
- Alignment align = mAlignment;
+ Alignment paraAlign = mAlignment;
TabStops tabStops = null;
boolean tabStopsIsInitialized = false;
@@ -310,10 +310,10 @@
ParagraphStyle.class);
spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
- align = mAlignment;
+ paraAlign = mAlignment;
for (int n = spans.length-1; n >= 0; n--) {
if (spans[n] instanceof AlignmentSpan) {
- align = ((AlignmentSpan) spans[n]).getAlignment();
+ paraAlign = ((AlignmentSpan) spans[n]).getAlignment();
break;
}
}
@@ -360,6 +360,16 @@
tabStopsIsInitialized = true;
}
+ // Determine whether the line aligns to normal, opposite, or center.
+ Alignment align = paraAlign;
+ if (align == Alignment.ALIGN_LEFT) {
+ align = (dir == DIR_LEFT_TO_RIGHT) ?
+ Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ align = (dir == DIR_LEFT_TO_RIGHT) ?
+ Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
+ }
+
int x;
if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
@@ -411,7 +421,9 @@
int dir = getParagraphDirection(line);
int x;
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ x = left;
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = left;
} else {
@@ -430,7 +442,9 @@
}
}
int max = (int)getLineExtent(line, tabStops, false);
- if (align == Alignment.ALIGN_OPPOSITE) {
+ if (align == Alignment.ALIGN_RIGHT) {
+ x = right - max;
+ } else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = right - max;
} else {
@@ -738,11 +752,15 @@
int dir = getParagraphDirection(line);
Alignment align = getParagraphAlignment(line);
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ return 0;
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_RIGHT_TO_LEFT)
return getParagraphRight(line) - getLineMax(line);
else
return 0;
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ return mWidth - getLineMax(line);
} else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_RIGHT_TO_LEFT)
return 0;
@@ -765,11 +783,15 @@
int dir = getParagraphDirection(line);
Alignment align = getParagraphAlignment(line);
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ return getParagraphLeft(line) + getLineMax(line);
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_RIGHT_TO_LEFT)
return mWidth;
else
return getParagraphLeft(line) + getLineMax(line);
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ return mWidth;
} else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_RIGHT_TO_LEFT)
return getLineMax(line);
@@ -1765,8 +1787,10 @@
ALIGN_NORMAL,
ALIGN_OPPOSITE,
ALIGN_CENTER,
- // XXX ALIGN_LEFT,
- // XXX ALIGN_RIGHT,
+ /** @hide */
+ ALIGN_LEFT,
+ /** @hide */
+ ALIGN_RIGHT,
}
private static final int TAB_INCREMENT = 20;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 411b714..bb5c954 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);
@@ -9038,9 +9121,15 @@
}
/**
- * Reset the resolved layout direction by clearing the corresponding flag
+ * Reset the resolved layout direction.
+ *
+ * Subclasses need to override this method to clear cached information that depends on the
+ * resolved layout direction, or to inform child views that inherit their layout direction.
+ * Overrides must also call the superclass implementation at the start of their implementation.
+ *
+ * @hide
*/
- void resetLayoutDirectionResolution() {
+ protected void resetLayoutDirectionResolution() {
// Reset the current View resolution
mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
}
@@ -9051,7 +9140,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 +12987,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..da88fbb 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>
@@ -1745,6 +1746,7 @@
final long now = SystemClock.uptimeMillis();
event = MotionEvent.obtain(now, now,
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
syntheticEvent = true;
}
@@ -4997,12 +4999,8 @@
viewAncestor.requestTransitionStart(transition);
}
- /**
- * This method will be called when we need to reset the layout direction resolution flag
- *
- */
@Override
- void resetLayoutDirectionResolution() {
+ protected void resetLayoutDirectionResolution() {
super.resetLayoutDirectionResolution();
// Take care of resetting the children resolution too
@@ -5016,6 +5014,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/webkit/CertTool.java b/core/java/android/webkit/CertTool.java
index 4c534f9..a2325c3 100644
--- a/core/java/android/webkit/CertTool.java
+++ b/core/java/android/webkit/CertTool.java
@@ -21,31 +21,27 @@
import com.android.org.bouncycastle.jce.netscape.NetscapeCertRequest;
import com.android.org.bouncycastle.util.encoders.Base64;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.Intent;
import android.security.Credentials;
+import android.security.KeyChain;
import android.util.Log;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.HashMap;
-class CertTool {
+final class CertTool {
private static final String LOGTAG = "CertTool";
private static final AlgorithmIdentifier MD5_WITH_RSA =
new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption);
- static final String CERT = Credentials.CERTIFICATE;
- static final String PKCS12 = Credentials.PKCS12;
-
private static HashMap<String, String> sCertificateTypeMap;
static {
sCertificateTypeMap = new HashMap<String, String>();
- sCertificateTypeMap.put("application/x-x509-ca-cert", CertTool.CERT);
- sCertificateTypeMap.put("application/x-x509-user-cert", CertTool.CERT);
- sCertificateTypeMap.put("application/x-pkcs12", CertTool.PKCS12);
+ sCertificateTypeMap.put("application/x-x509-ca-cert", KeyChain.EXTRA_CERTIFICATE);
+ sCertificateTypeMap.put("application/x-x509-user-cert", KeyChain.EXTRA_CERTIFICATE);
+ sCertificateTypeMap.put("application/x-pkcs12", KeyChain.EXTRA_PKCS12);
}
static String[] getKeyStrengthList() {
@@ -77,7 +73,7 @@
static String getCertType(String mimeType) {
return sCertificateTypeMap.get(mimeType);
- }
+ }
private CertTool() {}
}
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 4cae9d8..11ab0d7 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -104,9 +104,13 @@
public void surfaceDestroyed(SurfaceHolder holder)
{
- // after we return from this we can't use the surface any more
- mSurfaceHolder = null;
+ // After we return from this we can't use the surface any more.
// The current Video View will be destroy when we play a new video.
+ pauseAndDispatch(mProxy);
+ mSurfaceHolder = null;
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
}
};
@@ -210,7 +214,6 @@
// which happens when the video view is detached from its parent
// view. This happens in the WebChromeClient before this method
// is invoked.
- pauseAndDispatch(mProxy);
mProxy.dispatchOnStopFullScreen();
mLayout.removeView(getSurfaceView());
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index f10d7d8..7d43e94 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -1112,7 +1112,8 @@
}
reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
}
- mInitialZoomOverview = !exceedsMinScaleIncrement(scale, overviewScale);
+ mInitialZoomOverview = settings.getLoadWithOverviewMode() &&
+ !exceedsMinScaleIncrement(scale, overviewScale);
setZoomScale(scale, reflowText);
// update the zoom buttons as the scale can be changed
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 712ecca..aa23ad0 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -549,13 +549,11 @@
final ValueAnimator fadeScroller = ObjectAnimator.ofInt(this, "selectorPaintAlpha", 255, 0);
final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton,
"alpha", 0, 1);
- final ObjectAnimator showInputText = ObjectAnimator.ofFloat(mInputText,
- "alpha", 0, 1);
final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton,
"alpha", 0, 1);
mShowInputControlsAnimator = new AnimatorSet();
mShowInputControlsAnimator.playTogether(fadeScroller, showIncrementButton,
- showInputText, showDecrementButton);
+ showDecrementButton);
mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCanceled = false;
@@ -1203,16 +1201,15 @@
private void initializeScrollWheel() {
if (mInitialScrollOffset != Integer.MIN_VALUE) {
return;
-
}
int[] selectorIndices = getSelectorIndices();
int totalTextHeight = selectorIndices.length * mTextSize;
float totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
float textGapCount = selectorIndices.length - 1;
int selectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
- // Compensate if text size is odd since every time we get its middle a pixel is lost.
- mInitialScrollOffset = mCurrentScrollOffset = mTextSize - (3 * (mTextSize % 2));
mSelectorElementHeight = mTextSize + selectorTextGapHeight;
+ mInitialScrollOffset = mTextSize - 3 * (mSelectorElementHeight % 2);
+ mCurrentScrollOffset = mInitialScrollOffset;
updateInputTextView();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2f9bd69..939779f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -340,6 +340,16 @@
private WordIterator mWordIterator;
+ // The alignment to pass to Layout, or null if not resolved.
+ private Layout.Alignment mLayoutAlignment;
+
+ // The default value for mTextAlign.
+ private TextAlign mTextAlign = TextAlign.INHERIT;
+
+ private static enum TextAlign {
+ INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
+ }
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -5532,6 +5542,73 @@
physicalWidth, false);
}
+ @Override
+ protected void resetLayoutDirectionResolution() {
+ super.resetLayoutDirectionResolution();
+
+ if (mLayoutAlignment != null &&
+ (mTextAlign == TextAlign.VIEW_START ||
+ mTextAlign == TextAlign.VIEW_END)) {
+ mLayoutAlignment = null;
+ }
+ }
+
+ private Layout.Alignment getLayoutAlignment() {
+ if (mLayoutAlignment == null) {
+ Layout.Alignment alignment;
+ TextAlign textAlign = mTextAlign;
+ switch (textAlign) {
+ case INHERIT:
+ // fall through to gravity temporarily
+ // intention is to inherit value through view hierarchy.
+ case GRAVITY:
+ switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.START:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ case Gravity.END:
+ alignment = Layout.Alignment.ALIGN_OPPOSITE;
+ break;
+ case Gravity.LEFT:
+ alignment = Layout.Alignment.ALIGN_LEFT;
+ break;
+ case Gravity.RIGHT:
+ alignment = Layout.Alignment.ALIGN_RIGHT;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ alignment = Layout.Alignment.ALIGN_CENTER;
+ break;
+ default:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ }
+ break;
+ case TEXT_START:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ case TEXT_END:
+ alignment = Layout.Alignment.ALIGN_OPPOSITE;
+ break;
+ case CENTER:
+ alignment = Layout.Alignment.ALIGN_CENTER;
+ break;
+ case VIEW_START:
+ alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_RIGHT : Layout.Alignment.ALIGN_LEFT;
+ break;
+ case VIEW_END:
+ alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_LEFT : Layout.Alignment.ALIGN_RIGHT;
+ break;
+ default:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ }
+ mLayoutAlignment = alignment;
+ }
+ return mLayoutAlignment;
+ }
+
/**
* The width passed in is now the desired layout width,
* not the full view width with padding.
@@ -5552,25 +5629,7 @@
hintWidth = 0;
}
- final int layoutDirection = getResolvedLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-
- Layout.Alignment alignment;
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- alignment = Layout.Alignment.ALIGN_CENTER;
- break;
-
- case Gravity.RIGHT:
- // Note, Layout resolves ALIGN_OPPOSITE to left or
- // right based on the paragraph direction.
- alignment = Layout.Alignment.ALIGN_OPPOSITE;
- break;
-
- default:
- alignment = Layout.Alignment.ALIGN_NORMAL;
- }
-
+ Layout.Alignment alignment = getLayoutAlignment();
boolean shouldEllipsize = mEllipsize != null && mInput == null;
if (mText instanceof Spannable) {
@@ -10016,6 +10075,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/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index b57046c..ec64552 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -135,6 +135,16 @@
return null;
}
+ public static String getSdFilesystem(String cid) {
+ try {
+ return getMountService().getSecureContainerFilesystemPath(cid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get container path for " + cid +
+ " with exception " + e);
+ }
+ return null;
+ }
+
public static boolean finalizeSdDir(String cid) {
try {
int rc = getMountService().finalizeSecureContainer(cid);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 47902a8..1a32060 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1384,7 +1384,7 @@
<permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
android:label="@string/permlab_readNetworkUsageHistory"
android:description="@string/permdesc_readNetworkUsageHistory"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to manage network policies (such as warning and disable
limits) and to define application-specific rules. @hide -->
@@ -1393,6 +1393,14 @@
android:description="@string/permdesc_manageNetworkPolicy"
android:protectionLevel="signature" />
+ <!-- Allows an application to account its network traffic against other UIDs. Used
+ by system services like download manager and media server. Not for use by
+ third party apps. @hide -->
+ <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
+ android:label="@string/permlab_modifyNetworkAccounting"
+ android:description="@string/permdesc_modifyNetworkAccounting"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- C2DM permission.
@hide Used internally.
-->
diff --git a/core/res/res/drawable-hdpi/spinner_black_16.png b/core/res/res/drawable-hdpi/spinner_black_16.png
index eb34867..ef5ca35 100644
--- a/core/res/res/drawable-hdpi/spinner_black_16.png
+++ b/core/res/res/drawable-hdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_20.png b/core/res/res/drawable-hdpi/spinner_black_20.png
index dac06d7..d938931 100644
--- a/core/res/res/drawable-hdpi/spinner_black_20.png
+++ b/core/res/res/drawable-hdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_48.png b/core/res/res/drawable-hdpi/spinner_black_48.png
index 337f72a..9d1efb7 100644
--- a/core/res/res/drawable-hdpi/spinner_black_48.png
+++ b/core/res/res/drawable-hdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_76.png b/core/res/res/drawable-hdpi/spinner_black_76.png
index 2edc3e7..0d90881 100644
--- a/core/res/res/drawable-hdpi/spinner_black_76.png
+++ b/core/res/res/drawable-hdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_16.png b/core/res/res/drawable-hdpi/spinner_white_16.png
index 7914a68..32fa447 100644
--- a/core/res/res/drawable-hdpi/spinner_white_16.png
+++ b/core/res/res/drawable-hdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_48.png b/core/res/res/drawable-hdpi/spinner_white_48.png
index faee8ca..31fa267 100644
--- a/core/res/res/drawable-hdpi/spinner_white_48.png
+++ b/core/res/res/drawable-hdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_76.png b/core/res/res/drawable-hdpi/spinner_white_76.png
index cd26379..9f63292 100644
--- a/core/res/res/drawable-hdpi/spinner_white_76.png
+++ b/core/res/res/drawable-hdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default.9.png b/core/res/res/drawable-hdpi/textfield_default.9.png
old mode 100644
new mode 100755
index 4c20179..f7b6e99
--- a/core/res/res/drawable-hdpi/textfield_default.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled.9.png b/core/res/res/drawable-hdpi/textfield_disabled.9.png
old mode 100644
new mode 100755
index 81569d1..3011502
--- a/core/res/res/drawable-hdpi/textfield_disabled.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
old mode 100644
new mode 100755
index 2591490..e0f82eb
--- a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected.9.png b/core/res/res/drawable-hdpi/textfield_selected.9.png
old mode 100644
new mode 100755
index a36ed72..cf2cae3
--- a/core/res/res/drawable-hdpi/textfield_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_16.png b/core/res/res/drawable-mdpi/spinner_black_16.png
index 5ee33ce..4b7fdfe 100644
--- a/core/res/res/drawable-mdpi/spinner_black_16.png
+++ b/core/res/res/drawable-mdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_20.png b/core/res/res/drawable-mdpi/spinner_black_20.png
index e55b60d..86d7a20 100755
--- a/core/res/res/drawable-mdpi/spinner_black_20.png
+++ b/core/res/res/drawable-mdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_48.png b/core/res/res/drawable-mdpi/spinner_black_48.png
index 3a68192..f1571f9 100644
--- a/core/res/res/drawable-mdpi/spinner_black_48.png
+++ b/core/res/res/drawable-mdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_76.png b/core/res/res/drawable-mdpi/spinner_black_76.png
index ec57460..e9f6e8f 100644
--- a/core/res/res/drawable-mdpi/spinner_black_76.png
+++ b/core/res/res/drawable-mdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_16.png b/core/res/res/drawable-mdpi/spinner_white_16.png
index dd2e1fd..650e315 100644
--- a/core/res/res/drawable-mdpi/spinner_white_16.png
+++ b/core/res/res/drawable-mdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_48.png b/core/res/res/drawable-mdpi/spinner_white_48.png
index d25a33e..11eacf8 100644
--- a/core/res/res/drawable-mdpi/spinner_white_48.png
+++ b/core/res/res/drawable-mdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_76.png b/core/res/res/drawable-mdpi/spinner_white_76.png
index f53e8ff..6c31bc3 100644
--- a/core/res/res/drawable-mdpi/spinner_white_76.png
+++ b/core/res/res/drawable-mdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default.9.png b/core/res/res/drawable-mdpi/textfield_default.9.png
index cc78e6c..1a59bb2 100644
--- a/core/res/res/drawable-mdpi/textfield_default.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled.9.png b/core/res/res/drawable-mdpi/textfield_disabled.9.png
index 9c77149..800205a 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
index 6d47708..59e1536 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_selected.9.png b/core/res/res/drawable-mdpi/textfield_selected.9.png
index 0c1b446..faadace 100644
--- a/core/res/res/drawable-mdpi/textfield_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png b/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png
new file mode 100644
index 0000000..cdc0afb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png b/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png
new file mode 100644
index 0000000..36b0448
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png b/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png
new file mode 100644
index 0000000..3a7a8b3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_bright.9.png b/core/res/res/drawable-xhdpi/popup_center_bright.9.png
new file mode 100644
index 0000000..b1a8e3e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_dark.9.png b/core/res/res/drawable-xhdpi/popup_center_dark.9.png
new file mode 100644
index 0000000..87378e1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_medium.9.png b/core/res/res/drawable-xhdpi/popup_center_medium.9.png
new file mode 100644
index 0000000..ea29ed4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_full_bright.9.png b/core/res/res/drawable-xhdpi/popup_full_bright.9.png
new file mode 100644
index 0000000..114faa0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_full_dark.9.png b/core/res/res/drawable-xhdpi/popup_full_dark.9.png
new file mode 100644
index 0000000..996beaa
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_top_bright.9.png b/core/res/res/drawable-xhdpi/popup_top_bright.9.png
new file mode 100644
index 0000000..64e4139
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_top_dark.9.png b/core/res/res/drawable-xhdpi/popup_top_dark.9.png
new file mode 100644
index 0000000..902bc29
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_16.png b/core/res/res/drawable-xhdpi/spinner_black_16.png
new file mode 100644
index 0000000..5b1422c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_20.png b/core/res/res/drawable-xhdpi/spinner_black_20.png
new file mode 100644
index 0000000..5f53e38
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_48.png b/core/res/res/drawable-xhdpi/spinner_black_48.png
new file mode 100644
index 0000000..3aab620
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_76.png b/core/res/res/drawable-xhdpi/spinner_black_76.png
new file mode 100644
index 0000000..2968d8c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_16.png b/core/res/res/drawable-xhdpi/spinner_white_16.png
new file mode 100644
index 0000000..69be752
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_48.png b/core/res/res/drawable-xhdpi/spinner_white_48.png
new file mode 100644
index 0000000..7b196bc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_76.png b/core/res/res/drawable-xhdpi/spinner_white_76.png
new file mode 100644
index 0000000..ba47005
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
index 026cbfb..8627637 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -77,7 +77,8 @@
android:id="@+id/calendar_view"
android:layout_width="245dip"
android:layout_height="280dip"
- android:layout_marginLeft="22dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true"
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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cd52a5a..88ed9c6b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1443,6 +1443,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_manageNetworkPolicy">Allows an application to manage network policies and define application-specific rules.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_modifyNetworkAccounting">modify network usage accounting</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_modifyNetworkAccounting">Allows modification of how network usage is accounted against applications. Not for use by normal applications.</string>
+
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
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/data/etc/platform.xml b/data/etc/platform.xml
index b9c0d80..0b8d40f 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -84,6 +84,16 @@
<group gid="diag" />
</permission>
+ <!-- Group that can read detailed network usage statistics -->
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
+ <group gid="net_bw_stats" />
+ </permission>
+
+ <!-- Group that can modify how network statistics are accounted -->
+ <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
+ <group gid="net_bw_acct" />
+ </permission>
+
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
diff --git a/data/fonts/DroidSansHebrew-Bold.ttf b/data/fonts/DroidSansHebrew-Bold.ttf
new file mode 100644
index 0000000..c1acb38
--- /dev/null
+++ b/data/fonts/DroidSansHebrew-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSansHebrew-Regular.ttf b/data/fonts/DroidSansHebrew-Regular.ttf
new file mode 100644
index 0000000..af6a58d
--- /dev/null
+++ b/data/fonts/DroidSansHebrew-Regular.ttf
Binary files differ
diff --git a/data/fonts/DroidSansHebrew.ttf b/data/fonts/DroidSansHebrew.ttf
deleted file mode 100644
index 8d77e3e..0000000
--- a/data/fonts/DroidSansHebrew.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 692ce34..d222c0b 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -18,7 +18,8 @@
frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \
- frameworks/base/data/fonts/DroidSansHebrew.ttf:system/fonts/DroidSansHebrew.ttf \
+ frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
+ frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
frameworks/base/data/fonts/DroidSerif-Regular.ttf:system/fonts/DroidSerif-Regular.ttf \
frameworks/base/data/fonts/DroidSerif-Bold.ttf:system/fonts/DroidSerif-Bold.ttf \
diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h
index d7fe572e..d2fed41 100644
--- a/include/private/surfaceflinger/LayerState.h
+++ b/include/private/surfaceflinger/LayerState.h
@@ -29,6 +29,7 @@
namespace android {
class Parcel;
+class ISurfaceComposerClient;
struct layer_state_t {
@@ -68,6 +69,13 @@
Region transparentRegion;
};
+struct ComposerState {
+ sp<ISurfaceComposerClient> client;
+ layer_state_t state;
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
+};
+
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 03fd01b..dba98a3 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -34,6 +34,7 @@
// ----------------------------------------------------------------------------
class IMemoryHeap;
+class ComposerState;
class ISurfaceComposer : public IInterface
{
@@ -105,8 +106,7 @@
virtual sp<IMemoryHeap> getCblk() const = 0;
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
- virtual void openGlobalTransaction() = 0;
- virtual void closeGlobalTransaction() = 0;
+ virtual void setTransactionState(const Vector<ComposerState>& state) = 0;
/* [un]freeze display. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0;
@@ -149,8 +149,7 @@
CREATE_CONNECTION,
CREATE_GRAPHIC_BUFFER_ALLOC,
GET_CBLK,
- OPEN_GLOBAL_TRANSACTION,
- CLOSE_GLOBAL_TRANSACTION,
+ SET_TRANSACTION_STATE,
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 2e75a0e..6e9a654 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -37,8 +37,6 @@
// ----------------------------------------------------------------------------
-class layer_state_t;
-
class ISurfaceComposerClient : public IInterface
{
public:
@@ -69,11 +67,6 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t destroySurface(SurfaceID sid) = 0;
-
- /*
- * Requires ACCESS_SURFACE_FLINGER permission
- */
- virtual status_t setState(int32_t count, const layer_state_t* states) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 140b9f8..7fbbfb24 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -37,10 +37,12 @@
// ---------------------------------------------------------------------------
class DisplayInfo;
+class Composer;
class IMemoryHeap;
class ISurfaceComposer;
class Region;
class surface_flinger_cblk_t;
+struct layer_state_t;
// ---------------------------------------------------------------------------
@@ -59,8 +61,11 @@
// ---------------------------------------------------------------------------
+class Composer;
+
class SurfaceComposerClient : public RefBase
{
+ friend class Composer;
public:
SurfaceComposerClient();
virtual ~SurfaceComposerClient();
@@ -101,13 +106,7 @@
// All composer parameters must be changed within a transaction
// several surfaces can be updated in one transaction, all changes are
// committed at once when the transaction is closed.
- // CloseTransaction() usually requires an IPC with the server.
-
- //! Open a composer transaction
- status_t openTransaction();
-
- //! commit the transaction
- status_t closeTransaction();
+ // closeGlobalTransaction() usually requires an IPC with the server.
//! Open a composer transaction on all active SurfaceComposerClients.
static void openGlobalTransaction();
@@ -152,19 +151,12 @@
private:
virtual void onFirstRef();
- inline layer_state_t* get_state_l(SurfaceID id);
- layer_state_t* lockLayerState(SurfaceID id);
- inline void unlockLayerState();
+ Composer& getComposer();
- mutable Mutex mLock;
- SortedVector<layer_state_t> mStates;
- int32_t mTransactionOpen;
- layer_state_t* mPrebuiltLayerState;
-
- // these don't need to be protected because they never change
- // after assignment
+ mutable Mutex mLock;
status_t mStatus;
sp<ISurfaceComposerClient> mClient;
+ Composer& mComposer;
};
// ---------------------------------------------------------------------------
diff --git a/include/utils/LinearTransform.h b/include/utils/LinearTransform.h
new file mode 100644
index 0000000..04cb355
--- /dev/null
+++ b/include/utils/LinearTransform.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBS_UTILS_LINEAR_TRANSFORM_H
+#define _LIBS_UTILS_LINEAR_TRANSFORM_H
+
+#include <stdint.h>
+
+namespace android {
+
+// LinearTransform defines a structure which hold the definition of a
+// transformation from single dimensional coordinate system A into coordinate
+// system B (and back again). Values in A and in B are 64 bit, the linear
+// scale factor is expressed as a rational number using two 32 bit values.
+//
+// Specifically, let
+// f(a) = b
+// F(b) = f^-1(b) = a
+// then
+//
+// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
+//
+// and
+//
+// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
+//
+struct LinearTransform {
+ int64_t a_zero;
+ int64_t b_zero;
+ int32_t a_to_b_numer;
+ uint32_t a_to_b_denom;
+
+ // Transform from A->B
+ // Returns true on success, or false in the case of a singularity or an
+ // overflow.
+ bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
+
+ // Transform from B->A
+ // Returns true on success, or false in the case of a singularity or an
+ // overflow.
+ bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
+
+ // Helpers which will reduce the fraction N/D using Euclid's method.
+ template <class T> static void reduce(T* N, T* D);
+ static void reduce(int32_t* N, uint32_t* D);
+};
+
+
+}
+
+#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 8beec57..0e98aeb 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -32,6 +32,8 @@
template <class TYPE>
class SortedVector : private SortedVectorImpl
{
+ friend class Vector<TYPE>;
+
public:
typedef TYPE value_type;
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index f1e87e6..b908e2a 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -29,6 +29,9 @@
namespace android {
+template <typename TYPE>
+class SortedVector;
+
/*!
* The main templated vector class ensuring type safety
* while making use of VectorImpl.
@@ -47,13 +50,17 @@
Vector();
Vector(const Vector<TYPE>& rhs);
+ explicit Vector(const SortedVector<TYPE>& rhs);
virtual ~Vector();
/*! copy operator */
const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
- /*
+ const Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
+ Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
+
+ /*
* empty the vector
*/
@@ -215,6 +222,11 @@
}
template<class TYPE> inline
+Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs)
+ : VectorImpl(static_cast<const VectorImpl&>(rhs)) {
+}
+
+template<class TYPE> inline
Vector<TYPE>::~Vector() {
finish_vector();
}
@@ -227,6 +239,18 @@
template<class TYPE> inline
const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+ VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+ return *this;
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+ VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+ return *this;
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
VectorImpl::operator = (rhs);
return *this;
}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index ab4b9e0..f75208d 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -60,16 +60,10 @@
public static final String WIFI = "WIFI_";
/** Data type for public keys. */
- public static final String PUBLIC_KEY = "KEY";
+ public static final String EXTRA_PUBLIC_KEY = "KEY";
/** Data type for private keys. */
- public static final String PRIVATE_KEY = "PKEY";
-
- /** Data type for certificates. */
- public static final String CERTIFICATE = "CERT";
-
- /** Data type for PKCS12. */
- public static final String PKCS12 = "PKCS12";
+ public static final String EXTRA_PRIVATE_KEY = "PKEY";
// historically used by Android
public static final String EXTENSION_CRT = ".crt";
@@ -130,16 +124,9 @@
}
}
- private Intent createInstallIntent() {
- Intent intent = new Intent(INSTALL_ACTION);
- intent.setClassName("com.android.certinstaller",
- "com.android.certinstaller.CertInstallerMain");
- return intent;
- }
-
public void install(Context context) {
try {
- Intent intent = createInstallIntent();
+ Intent intent = KeyChain.createInstallIntent();
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
@@ -148,9 +135,9 @@
public void install(Context context, KeyPair pair) {
try {
- Intent intent = createInstallIntent();
- intent.putExtra(PRIVATE_KEY, pair.getPrivate().getEncoded());
- intent.putExtra(PUBLIC_KEY, pair.getPublic().getEncoded());
+ Intent intent = KeyChain.createInstallIntent();
+ intent.putExtra(EXTRA_PRIVATE_KEY, pair.getPrivate().getEncoded());
+ intent.putExtra(EXTRA_PUBLIC_KEY, pair.getPublic().getEncoded());
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
@@ -159,7 +146,7 @@
public void install(Context context, String type, byte[] value) {
try {
- Intent intent = createInstallIntent();
+ Intent intent = KeyChain.createInstallIntent();
intent.putExtra(type, value);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 18011e6..b567207 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -89,31 +89,117 @@
public static final String ACCOUNT_TYPE = "com.android.keychain";
/**
+ * Action to bring up the KeyChainActivity
+ */
+ private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER";
+
+ /**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_RESPONSE = "response";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_HOST = "host";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_PORT = "port";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_ALIAS = "alias";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_SENDER = "sender";
/**
+ * Action to bring up the CertInstaller
+ */
+ private static final String ACTION_INSTALL = "android.credentials.INSTALL";
+
+ /**
+ * Optional extra to specify a {@code String} credential name on
+ * the {@code Intent} returned by {@link #createInstallIntent}.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY
+ public static final String EXTRA_NAME = "name";
+
+ /**
+ * Optional extra to specify an X.509 certificate to install on
+ * the {@code Intent} returned by {@link #createInstallIntent}.
+ * The extra value should be a PEM or ASN.1 DER encoded {@code
+ * byte[]}. An {@link X509Certificate} can be converted to DER
+ * encoded bytes with {@link X509Certificate#getEncoded}.
+ *
+ * <p>{@link #EXTRA_NAME} may be used to provide a default alias
+ * name for the installed certificate.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old android.security.Credentials.CERTIFICATE
+ public static final String EXTRA_CERTIFICATE = "CERT";
+
+ /**
+ * Optional extra for use with the {@code Intent} returned by
+ * {@link #createInstallIntent} to specify a PKCS#12 key store to
+ * install. The extra value should be a {@code byte[]}. The bytes
+ * may come from an external source or be generated with {@link
+ * KeyStore#store} on a "PKCS12" instance.
+ *
+ * <p>The user will be prompted for the password to load the key store.
+ *
+ * <p>The key store will be scanned for {@link
+ * java.security.KeyStore.PrivateKeyEntry} entries and both the
+ * private key and associated certificate chain will be installed.
+ *
+ * <p>{@link #EXTRA_NAME} may be used to provide a default alias
+ * name for the installed credentials.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old android.security.Credentials.PKCS12
+ public static final String EXTRA_PKCS12 = "PKCS12";
+
+ /**
+ * Returns an {@code Intent} that can be used for credential
+ * installation. The intent may be used without any extras, in
+ * which case the user will be able to install credentials from
+ * their own source.
+ *
+ * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link
+ * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509
+ * certificate or a PKCS#12 key store for installation. These
+ * extras may be combined with {@link EXTRA_NAME} to provide a
+ * default alias name for credentials being installed.
+ *
+ * <p>When used with {@link Activity#startActivityForResult},
+ * {@link Activity#RESULT_OK} will be returned if a credential was
+ * successfully installed, otherwise {@link
+ * Activity#RESULT_CANCELED} will be returned.
+ *
+ * @hide TODO make public with createInstallIntent, EXTRA_NAME, EXTRA_CERTIFICATE, EXTRA_PKCS12
+ */
+ public static Intent createInstallIntent() {
+ Intent intent = new Intent(ACTION_INSTALL);
+ intent.setClassName("com.android.certinstaller",
+ "com.android.certinstaller.CertInstallerMain");
+ return intent;
+ }
+
+ /**
* Launches an {@code Activity} for the user to select the alias
* for a private key and certificate pair for authentication. The
* selected alias or null will be returned via the
@@ -176,7 +262,7 @@
if (response == null) {
throw new NullPointerException("response == null");
}
- Intent intent = new Intent("com.android.keychain.CHOOSER");
+ Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_RESPONSE, new AliasResponse(activity, response));
intent.putExtra(EXTRA_HOST, host);
intent.putExtra(EXTRA_PORT, port);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 40450a3..c1156d5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,6 +25,8 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <private/surfaceflinger/LayerState.h>
+
#include <surfaceflinger/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -74,18 +76,17 @@
return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
- virtual void openGlobalTransaction()
+ virtual void setTransactionState(const Vector<ComposerState>& state)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
- }
-
- virtual void closeGlobalTransaction()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+ Vector<ComposerState>::const_iterator b(state.begin());
+ Vector<ComposerState>::const_iterator e(state.end());
+ data.writeInt32(state.size());
+ for ( ; b != e ; ++b ) {
+ b->write(data);
+ }
+ remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
@@ -218,13 +219,17 @@
sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
reply->writeStrongBinder(b);
} break;
- case OPEN_GLOBAL_TRANSACTION: {
+ case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- openGlobalTransaction();
- } break;
- case CLOSE_GLOBAL_TRANSACTION: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- closeGlobalTransaction();
+ size_t count = data.readInt32();
+ ComposerState s;
+ Vector<ComposerState> state;
+ state.setCapacity(count);
+ for (size_t i=0 ; i<count ; i++) {
+ s.read(data);
+ state.add(s);
+ }
+ setTransactionState(state);
} break;
case SET_ORIENTATION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 8d83392..bc97cac 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -51,8 +51,7 @@
enum {
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE,
- SET_STATE
+ DESTROY_SURFACE
};
class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@@ -92,17 +91,6 @@
remote()->transact(DESTROY_SURFACE, data, &reply);
return reply.readInt32();
}
-
- virtual status_t setState(int32_t count, const layer_state_t* states)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeInt32(count);
- for (int i=0 ; i<count ; i++)
- states[i].write(data);
- remote()->transact(SET_STATE, data, &reply);
- return reply.readInt32();
- }
};
IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@@ -133,17 +121,6 @@
reply->writeInt32( destroySurface( data.readInt32() ) );
return NO_ERROR;
} break;
- case SET_STATE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- int32_t count = data.readInt32();
- layer_state_t* states = new layer_state_t[count];
- for (int i=0 ; i<count ; i++)
- states[i].read(data);
- status_t err = setState(count, states);
- delete [] states;
- reply->writeInt32(err);
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01c4c7e..87901e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -17,6 +17,7 @@
#include <utils/Errors.h>
#include <binder/Parcel.h>
#include <private/surfaceflinger/LayerState.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
namespace android {
@@ -58,4 +59,14 @@
return NO_ERROR;
}
+status_t ComposerState::write(Parcel& output) const {
+ output.writeStrongBinder(client->asBinder());
+ return state.write(output);
+}
+
+status_t ComposerState::read(const Parcel& input) {
+ client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
+ return state.read(input);
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1678711..8cead80 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -74,75 +74,52 @@
// ---------------------------------------------------------------------------
+// NOTE: this is NOT a member function (it's a friend defined with its
+// declaration).
+static inline
+int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
+ if (lhs.client < rhs.client) return -1;
+ if (lhs.client > rhs.client) return 1;
+ if (lhs.state.surface < rhs.state.surface) return -1;
+ if (lhs.state.surface > rhs.state.surface) return 1;
+ return 0;
+}
+
class Composer : public Singleton<Composer>
{
- Mutex mLock;
- SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
- SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
-
- Composer() : Singleton<Composer>() {
- }
-
- void addClientImpl(const sp<SurfaceComposerClient>& client) {
- Mutex::Autolock _l(mLock);
- mActiveConnections.add(client);
- }
-
- void removeClientImpl(const sp<SurfaceComposerClient>& client) {
- Mutex::Autolock _l(mLock);
- mActiveConnections.remove(client);
- }
-
- void openGlobalTransactionImpl()
- {
- Mutex::Autolock _l(mLock);
- if (mOpenTransactions.size()) {
- LOGE("openGlobalTransaction() called more than once. skipping.");
- return;
- }
- const size_t N = mActiveConnections.size();
- for (size_t i=0; i<N; i++) {
- sp<SurfaceComposerClient> client(mActiveConnections[i].promote());
- if (client != 0 && mOpenTransactions.indexOf(client) < 0) {
- if (client->openTransaction() == NO_ERROR) {
- mOpenTransactions.add(client);
- } else {
- LOGE("openTransaction on client %p failed", client.get());
- // let it go, it'll fail later when the user
- // tries to do something with the transaction
- }
- }
- }
- }
-
- void closeGlobalTransactionImpl()
- {
- mLock.lock();
- SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions);
- mOpenTransactions.clear();
- mLock.unlock();
-
- sp<ISurfaceComposer> sm(getComposerService());
- sm->openGlobalTransaction();
- const size_t N = clients.size();
- for (size_t i=0; i<N; i++) {
- clients[i]->closeTransaction();
- }
- sm->closeGlobalTransaction();
- }
-
friend class Singleton<Composer>;
+ mutable Mutex mLock;
+ SortedVector<ComposerState> mStates;
+
+ Composer() : Singleton<Composer>() { }
+
+ void closeGlobalTransactionImpl();
+
+ layer_state_t* getLayerStateLocked(
+ const sp<SurfaceComposerClient>& client, SurfaceID id);
+
public:
- static void addClient(const sp<SurfaceComposerClient>& client) {
- Composer::getInstance().addClientImpl(client);
- }
- static void removeClient(const sp<SurfaceComposerClient>& client) {
- Composer::getInstance().removeClientImpl(client);
- }
- static void openGlobalTransaction() {
- Composer::getInstance().openGlobalTransactionImpl();
- }
+
+ status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ int32_t x, int32_t y);
+ status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t w, uint32_t h);
+ status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ int32_t z);
+ status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const Region& transparentRegion);
+ status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ float alpha);
+ status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setFreezeTint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t tint);
+
static void closeGlobalTransaction() {
Composer::getInstance().closeGlobalTransactionImpl();
}
@@ -152,69 +129,306 @@
// ---------------------------------------------------------------------------
-static inline int compare_type( const layer_state_t& lhs,
- const layer_state_t& rhs) {
- if (lhs.surface < rhs.surface) return -1;
- if (lhs.surface > rhs.surface) return 1;
- return 0;
+void Composer::closeGlobalTransactionImpl() {
+ sp<ISurfaceComposer> sm(getComposerService());
+
+ Vector<ComposerState> transaction;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ transaction = mStates;
+ mStates.clear();
+ }
+
+ sm->setTransactionState(transaction);
}
+layer_state_t* Composer::getLayerStateLocked(
+ const sp<SurfaceComposerClient>& client, SurfaceID id) {
+
+ ComposerState s;
+ s.client = client->mClient;
+ s.state.surface = id;
+
+ ssize_t index = mStates.indexOf(s);
+ if (index < 0) {
+ // we don't have it, add an initialized layer_state to our list
+ index = mStates.add(s);
+ }
+
+ ComposerState* const out = mStates.editArray();
+ return &(out[index].state);
+}
+
+status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, int32_t x, int32_t y) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::ePositionChanged;
+ s->x = x;
+ s->y = y;
+ return NO_ERROR;
+}
+
+status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t w, uint32_t h) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eSizeChanged;
+ s->w = w;
+ s->h = h;
+ return NO_ERROR;
+}
+
+status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, int32_t z) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eLayerChanged;
+ s->z = z;
+ return NO_ERROR;
+}
+
+status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t flags,
+ uint32_t mask) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eVisibilityChanged;
+ s->flags &= ~mask;
+ s->flags |= (flags & mask);
+ s->mask |= mask;
+ return NO_ERROR;
+}
+
+status_t Composer::setTransparentRegionHint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const Region& transparentRegion) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eTransparentRegionChanged;
+ s->transparentRegion = transparentRegion;
+ return NO_ERROR;
+}
+
+status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, float alpha) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eAlphaChanged;
+ s->alpha = alpha;
+ return NO_ERROR;
+}
+
+status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, float dsdx, float dtdx,
+ float dsdy, float dtdy) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eMatrixChanged;
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = dsdx;
+ matrix.dtdx = dtdx;
+ matrix.dsdy = dsdy;
+ matrix.dtdy = dtdy;
+ s->matrix = matrix;
+ return NO_ERROR;
+}
+
+status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t tint) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eFreezeTintChanged;
+ s->tint = tint;
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::SurfaceComposerClient()
- : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)
+ : mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}
-void SurfaceComposerClient::onFirstRef()
-{
+void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sm(getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
- Composer::addClient(this);
- mPrebuiltLayerState = new layer_state_t;
mStatus = NO_ERROR;
}
}
}
-SurfaceComposerClient::~SurfaceComposerClient()
-{
- delete mPrebuiltLayerState;
+SurfaceComposerClient::~SurfaceComposerClient() {
dispose();
}
-status_t SurfaceComposerClient::initCheck() const
-{
+status_t SurfaceComposerClient::initCheck() const {
return mStatus;
}
-sp<IBinder> SurfaceComposerClient::connection() const
-{
+sp<IBinder> SurfaceComposerClient::connection() const {
return (mClient != 0) ? mClient->asBinder() : 0;
}
status_t SurfaceComposerClient::linkToComposerDeath(
const sp<IBinder::DeathRecipient>& recipient,
- void* cookie, uint32_t flags)
-{
+ void* cookie, uint32_t flags) {
sp<ISurfaceComposer> sm(getComposerService());
return sm->asBinder()->linkToDeath(recipient, cookie, flags);
}
-void SurfaceComposerClient::dispose()
-{
+void SurfaceComposerClient::dispose() {
// this can be called more than once.
sp<ISurfaceComposerClient> client;
Mutex::Autolock _lm(mLock);
if (mClient != 0) {
- Composer::removeClient(this);
client = mClient; // hold ref while lock is held
mClient.clear();
}
mStatus = NO_INIT;
}
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+{
+ String8 name;
+ const size_t SIZE = 128;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "<pid_%d>", getpid());
+ name.append(buffer);
+
+ return SurfaceComposerClient::createSurface(name, display,
+ w, h, format, flags);
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
+ const String8& name,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+{
+ sp<SurfaceControl> result;
+ if (mStatus == NO_ERROR) {
+ ISurfaceComposerClient::surface_data_t data;
+ sp<ISurface> surface = mClient->createSurface(&data, name,
+ display, w, h, format, flags);
+ if (surface != 0) {
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
+ }
+ }
+ return result;
+}
+
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
+ if (mStatus != NO_ERROR)
+ return mStatus;
+ status_t err = mClient->destroySurface(sid);
+ return err;
+}
+
+inline Composer& SurfaceComposerClient::getComposer() {
+ return mComposer;
+}
+
+// ----------------------------------------------------------------------------
+
+void SurfaceComposerClient::openGlobalTransaction() {
+ // Currently a no-op
+}
+
+void SurfaceComposerClient::closeGlobalTransaction() {
+ Composer::closeGlobalTransaction();
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) {
+ return getComposer().setFreezeTint(this, id, tint);
+}
+
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) {
+ return getComposer().setPosition(this, id, x, y);
+}
+
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) {
+ return getComposer().setSize(this, id, w, h);
+}
+
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) {
+ return getComposer().setLayer(this, id, z);
+}
+
+status_t SurfaceComposerClient::hide(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ ISurfaceComposer::eLayerHidden,
+ ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t) {
+ return getComposer().setFlags(this, id,
+ 0,
+ ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::freeze(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ ISurfaceComposer::eLayerFrozen,
+ ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::unfreeze(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ 0,
+ ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags,
+ uint32_t mask) {
+ return getComposer().setFlags(this, id, flags, mask);
+}
+
+status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id,
+ const Region& transparentRegion) {
+ return getComposer().setTransparentRegionHint(this, id, transparentRegion);
+}
+
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) {
+ return getComposer().setAlpha(this, id, alpha);
+}
+
+status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
+ float dsdy, float dtdy) {
+ return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
+}
+
+// ----------------------------------------------------------------------------
+
status_t SurfaceComposerClient::getDisplayInfo(
DisplayID dpy, DisplayInfo* info)
{
@@ -273,70 +487,7 @@
return n;
}
-sp<SurfaceControl> SurfaceComposerClient::createSurface(
- DisplayID display,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags)
-{
- String8 name;
- const size_t SIZE = 128;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "<pid_%d>", getpid());
- name.append(buffer);
-
- return SurfaceComposerClient::createSurface(name, display,
- w, h, format, flags);
-}
-
-sp<SurfaceControl> SurfaceComposerClient::createSurface(
- const String8& name,
- DisplayID display,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags)
-{
- sp<SurfaceControl> result;
- if (mStatus == NO_ERROR) {
- ISurfaceComposerClient::surface_data_t data;
- sp<ISurface> surface = mClient->createSurface(&data, name,
- display, w, h, format, flags);
- if (surface != 0) {
- result = new SurfaceControl(this, surface, data, w, h, format, flags);
- }
- }
- return result;
-}
-
-status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
-{
- if (mStatus != NO_ERROR)
- return mStatus;
-
- // it's okay to destroy a surface while a transaction is open,
- // (transactions really are a client-side concept)
- // however, this indicates probably a misuse of the API or a bug
- // in the client code.
- LOGW_IF(mTransactionOpen,
- "Destroying surface while a transaction is open. "
- "Client %p: destroying surface %d, mTransactionOpen=%d",
- this, sid, mTransactionOpen);
-
- status_t err = mClient->destroySurface(sid);
- return err;
-}
-
-void SurfaceComposerClient::openGlobalTransaction()
-{
- Composer::openGlobalTransaction();
-}
-
-void SurfaceComposerClient::closeGlobalTransaction()
-{
- Composer::closeGlobalTransaction();
-}
+// ----------------------------------------------------------------------------
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
{
@@ -350,199 +501,13 @@
return sm->unfreezeDisplay(dpy, flags);
}
-int SurfaceComposerClient::setOrientation(DisplayID dpy,
+int SurfaceComposerClient::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
sp<ISurfaceComposer> sm(getComposerService());
return sm->setOrientation(dpy, orientation, flags);
}
-status_t SurfaceComposerClient::openTransaction()
-{
- if (mStatus != NO_ERROR)
- return mStatus;
- Mutex::Autolock _l(mLock);
- mTransactionOpen++;
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::closeTransaction()
-{
- if (mStatus != NO_ERROR)
- return mStatus;
-
- Mutex::Autolock _l(mLock);
- if (mTransactionOpen <= 0) {
- LOGE( "closeTransaction (client %p, mTransactionOpen=%d) "
- "called more times than openTransaction()",
- this, mTransactionOpen);
- return INVALID_OPERATION;
- }
-
- if (mTransactionOpen >= 2) {
- mTransactionOpen--;
- return NO_ERROR;
- }
-
- mTransactionOpen = 0;
- const ssize_t count = mStates.size();
- if (count) {
- mClient->setState(count, mStates.array());
- mStates.clear();
- }
- return NO_ERROR;
-}
-
-layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
-{
- // API usage error, do nothing.
- if (mTransactionOpen<=0) {
- LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
- this, int(index), mTransactionOpen);
- return 0;
- }
-
- // use mPrebuiltLayerState just to find out if we already have it
- layer_state_t& dummy(*mPrebuiltLayerState);
- dummy.surface = index;
- ssize_t i = mStates.indexOf(dummy);
- if (i < 0) {
- // we don't have it, add an initialized layer_state to our list
- i = mStates.add(dummy);
- }
- return mStates.editArray() + i;
-}
-
-layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
-{
- layer_state_t* s;
- mLock.lock();
- s = get_state_l(id);
- if (!s) mLock.unlock();
- return s;
-}
-
-void SurfaceComposerClient::unlockLayerState()
-{
- mLock.unlock();
-}
-
-status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::ePositionChanged;
- s->x = x;
- s->y = y;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eSizeChanged;
- s->w = w;
- s->h = h;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eLayerChanged;
- s->z = z;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::hide(SurfaceID id)
-{
- return setFlags(id, ISurfaceComposer::eLayerHidden,
- ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
-{
- return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::freeze(SurfaceID id)
-{
- return setFlags(id, ISurfaceComposer::eLayerFrozen,
- ISurfaceComposer::eLayerFrozen);
-}
-
-status_t SurfaceComposerClient::unfreeze(SurfaceID id)
-{
- return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
-}
-
-status_t SurfaceComposerClient::setFlags(SurfaceID id,
- uint32_t flags, uint32_t mask)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eVisibilityChanged;
- s->flags &= ~mask;
- s->flags |= (flags & mask);
- s->mask |= mask;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(
- SurfaceID id, const Region& transparentRegion)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eTransparentRegionChanged;
- s->transparentRegion = transparentRegion;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eAlphaChanged;
- s->alpha = alpha;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setMatrix(
- SurfaceID id,
- float dsdx, float dtdx,
- float dsdy, float dtdy )
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eMatrixChanged;
- layer_state_t::matrix22_t matrix;
- matrix.dsdx = dsdx;
- matrix.dtdx = dtdx;
- matrix.dsdy = dsdy;
- matrix.dtdy = dtdy;
- s->matrix = matrix;
- unlockLayerState();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eFreezeTintChanged;
- s->tint = tint;
- unlockLayerState();
- return NO_ERROR;
-}
-
// ----------------------------------------------------------------------------
ScreenshotClient::ScreenshotClient()
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index dfa9211..c06400e 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -84,10 +84,10 @@
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ SurfaceComposerClient::openGlobalTransaction();
ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+ SurfaceComposerClient::closeGlobalTransaction();
sp<ANativeWindow> window = mSurfaceControl->getSurface();
mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 35c8640..450cdf1 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -36,10 +36,10 @@
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ SurfaceComposerClient::openGlobalTransaction();
ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+ SurfaceComposerClient::closeGlobalTransaction();
mSurface = mSurfaceControl->getSurface();
ASSERT_TRUE(mSurface != NULL);
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 093189c..774e8c9 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -27,6 +27,7 @@
Debug.cpp \
FileMap.cpp \
Flattenable.cpp \
+ LinearTransform.cpp \
ObbFile.cpp \
Pool.cpp \
PropertyMap.cpp \
diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp
new file mode 100644
index 0000000..d752415
--- /dev/null
+++ b/libs/utils/LinearTransform.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <utils/LinearTransform.h>
+
+namespace android {
+
+template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; }
+
+// Static math methods involving linear transformations
+static bool scale_u64_to_u64(
+ uint64_t val,
+ uint32_t N,
+ uint32_t D,
+ uint64_t* res,
+ bool round_up_not_down) {
+ uint64_t tmp1, tmp2;
+ uint32_t r;
+
+ assert(res);
+ assert(D);
+
+ // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
+ // integer X.
+ // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
+ // integer X.
+ // Let X[A, B] with A <= B denote bits A through B of the integer X.
+ // Let (A | B) denote the concatination of two 32 bit ints, A and B.
+ // IOW X = (A | B) => U32(X) == A && L32(X) == B
+ //
+ // compute M = val * N (a 96 bit int)
+ // ---------------------------------
+ // tmp2 = U32(val) * N (a 64 bit int)
+ // tmp1 = L32(val) * N (a 64 bit int)
+ // which means
+ // M = val * N = (tmp2 << 32) + tmp1
+ tmp2 = (val >> 32) * N;
+ tmp1 = (val & UINT32_MAX) * N;
+
+ // compute M[32, 95]
+ // tmp2 = tmp2 + U32(tmp1)
+ // = (U32(val) * N) + U32(L32(val) * N)
+ // = M[32, 95]
+ tmp2 += tmp1 >> 32;
+
+ // if M[64, 95] >= D, then M/D has bits > 63 set and we have
+ // an overflow.
+ if ((tmp2 >> 32) >= D) {
+ *res = UINT64_MAX;
+ return false;
+ }
+
+ // Divide. Going in we know
+ // tmp2 = M[32, 95]
+ // U32(tmp2) < D
+ r = tmp2 % D;
+ tmp2 /= D;
+
+ // At this point
+ // tmp1 = L32(val) * N
+ // tmp2 = M[32, 95] / D
+ // = (M / D)[32, 95]
+ // r = M[32, 95] % D
+ // U32(tmp2) = 0
+ //
+ // compute tmp1 = (r | M[0, 31])
+ tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
+
+ // Divide again. Keep the remainder around in order to round properly.
+ r = tmp1 % D;
+ tmp1 /= D;
+
+ // At this point
+ // tmp2 = (M / D)[32, 95]
+ // tmp1 = (M / D)[ 0, 31]
+ // r = M % D
+ // U32(tmp1) = 0
+ // U32(tmp2) = 0
+
+ // Pack the result and deal with the round-up case (As well as the
+ // remote possiblility over overflow in such a case).
+ *res = (tmp2 << 32) | tmp1;
+ if (r && round_up_not_down) {
+ ++(*res);
+ if (!(*res)) {
+ *res = UINT64_MAX;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool linear_transform_s64_to_s64(
+ int64_t val,
+ int64_t basis1,
+ int32_t N,
+ uint32_t D,
+ int64_t basis2,
+ int64_t* out) {
+ uint64_t scaled, res;
+ uint64_t abs_val;
+ bool is_neg;
+
+ if (!out)
+ return false;
+
+ // Compute abs(val - basis_64). Keep track of whether or not this delta
+ // will be negative after the scale opertaion.
+ if (val < basis1) {
+ is_neg = true;
+ abs_val = basis1 - val;
+ } else {
+ is_neg = false;
+ abs_val = val - basis1;
+ }
+
+ if (N < 0)
+ is_neg = !is_neg;
+
+ if (!scale_u64_to_u64(abs_val,
+ ABS(N),
+ D,
+ &scaled,
+ is_neg))
+ return false; // overflow/undeflow
+
+ // if scaled is >= 0x8000<etc>, then we are going to overflow or
+ // underflow unless ABS(basis2) is large enough to pull us back into the
+ // non-overflow/underflow region.
+ if (scaled & INT64_MIN) {
+ if (is_neg && (basis2 < 0))
+ return false; // certain underflow
+
+ if (!is_neg && (basis2 >= 0))
+ return false; // certain overflow
+
+ if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
+ return false; // not enough
+
+ // Looks like we are OK
+ *out = (is_neg ? (-scaled) : scaled) + basis2;
+ } else {
+ // Scaled fits within signed bounds, so we just need to check for
+ // over/underflow for two signed integers. Basically, if both scaled
+ // and basis2 have the same sign bit, and the result has a different
+ // sign bit, then we have under/overflow. An easy way to compute this
+ // is
+ // (scaled_signbit XNOR basis_signbit) &&
+ // (scaled_signbit XOR res_signbit)
+ // ==
+ // (scaled_signbit XOR basis_signbit XOR 1) &&
+ // (scaled_signbit XOR res_signbit)
+
+ if (is_neg)
+ scaled = -scaled;
+ res = scaled + basis2;
+
+ if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
+ return false;
+
+ *out = res;
+ }
+
+ return true;
+}
+
+bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
+ if (0 == a_to_b_denom)
+ return false;
+
+ return linear_transform_s64_to_s64(a_in,
+ a_zero,
+ a_to_b_numer,
+ a_to_b_denom,
+ b_zero,
+ b_out);
+}
+
+bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
+ if (0 == a_to_b_numer)
+ return false;
+
+ return linear_transform_s64_to_s64(b_in,
+ b_zero,
+ a_to_b_denom,
+ a_to_b_numer,
+ a_zero,
+ a_out);
+}
+
+template <class T> void LinearTransform::reduce(T* N, T* D) {
+ T a, b;
+ if (!N || !D || !(*D)) {
+ assert(false);
+ return;
+ }
+
+ a = *N;
+ b = *D;
+
+ if (a == 0) {
+ *D = 1;
+ return;
+ }
+
+ // This implements Euclid's method to find GCD.
+ if (a < b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ while (1) {
+ // a is now the greater of the two.
+ const T remainder = a % b;
+ if (remainder == 0) {
+ *N /= b;
+ *D /= b;
+ return;
+ }
+ // by swapping remainder and b, we are guaranteeing that a is
+ // still the greater of the two upon entrance to the loop.
+ a = b;
+ b = remainder;
+ }
+};
+
+template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
+template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
+
+void LinearTransform::reduce(int32_t* N, uint32_t* D) {
+ if (N && D && *D) {
+ if (*N < 0) {
+ *N = -(*N);
+ reduce(reinterpret_cast<uint32_t*>(N), D);
+ *N = -(*N);
+ } else {
+ reduce(reinterpret_cast<uint32_t*>(N), D);
+ }
+ }
+}
+
+} // namespace android
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index 29c4b89..0d2bcd5 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -957,12 +957,8 @@
public static final int FADE_FROM_BLACK = 8;
- public static final int CURTAIN_OPENING = 9;
-
public static final int FADE_TO_BLACK = 16;
- public static final int CURTAIN_CLOSING = 17;
-
public static final int EXTERNAL = 256;
public static final int BLACK_AND_WHITE = 257;
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index d43a562..277e16c 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -378,9 +378,7 @@
{
VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kVideoEffectType_None),
VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_FROM_BLACK", M4VSS3GPP_kVideoEffectType_FadeFromBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_OPENING", M4VSS3GPP_kVideoEffectType_CurtainOpening),
VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_TO_BLACK", M4VSS3GPP_kVideoEffectType_FadeToBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_CLOSING", M4VSS3GPP_kVideoEffectType_CurtainClosing),
VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL", M4VSS3GPP_kVideoEffectType_External),
VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_AND_WHITE", M4xVSS_kVideoEffectType_BlackAndWhite),
VIDEOEDIT_JAVA_CONSTANT_INIT("PINK", M4xVSS_kVideoEffectType_Pink),
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index 53e7de1..a8c08ac 100755
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -166,7 +166,6 @@
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INTERNAL_STATE ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_LUMA_FILTER_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_CURTAIN_FILTER_ERROR ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_TRANSITION_FILTER_ERROR ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE ),
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 513eda8..167071a3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2282,6 +2282,11 @@
if (data2 == kPortIndexInput || data2 == kPortIndexOutput) {
CHECK(!mFlushComplete[data2]);
mFlushComplete[data2] = true;
+
+ if (mFlushComplete[kPortIndexInput]
+ && mFlushComplete[kPortIndexOutput]) {
+ changeStateIfWeOwnAllBuffers();
+ }
} else {
CHECK_EQ(data2, OMX_ALL);
CHECK(mFlushComplete[kPortIndexInput]);
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/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index fd0505e..f03f7a2 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -301,9 +301,6 @@
// static
bool ASessionDescription::parseNTPRange(
const char *s, float *npt1, float *npt2) {
- *npt1 = 0.0f;
- *npt2 = 0.0f;
-
if (s[0] == '-') {
return false; // no start time available.
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index f89f8e2..d15d9c5 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -995,12 +995,10 @@
AString val;
CHECK(GetAttribute(range.c_str(), "npt", &val));
- bool seekable = true;
-
float npt1, npt2;
if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
// This is a live stream and therefore not seekable.
- seekable = false;
+ return;
}
i = response->mHeaders.indexOfKey("rtp-info");
@@ -1046,7 +1044,7 @@
++n;
}
- mSeekable = seekable;
+ mSeekable = true;
}
sp<APacketSource> getPacketSource(size_t index) {
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index bc2f7ee..51e7d97 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -25,14 +25,13 @@
android:layout_width="match_parent"
>
- <FrameLayout
- android:id="@+id/background"
+ <FrameLayout android:id="@+id/rot0"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#FF000000"
>
- <LinearLayout android:id="@+id/rot0"
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
@@ -40,12 +39,12 @@
<!-- navigation controls -->
<View
- android:layout_width="32dp"
+ android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_weight="0"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_back_default"
systemui:keyCode="4"
@@ -57,7 +56,7 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_home_default"
systemui:keyCode="3"
@@ -69,13 +68,13 @@
android:layout_weight="1"
/>
<ImageView android:id="@+id/recent_apps"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_recent_default"
android:layout_weight="0"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="32dp"
+ android:layout_width="40dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_menu_default"
systemui:keyCode="82"
@@ -84,17 +83,31 @@
/>
</LinearLayout>
- <LinearLayout android:id="@+id/rot90"
+ <View android:id="@+id/deadzone"
+ android:layout_height="@dimen/navigation_bar_deadzone_size"
+ android:layout_width="match_parent"
+ android:layout_gravity="top"
+ android:clickable="true"
+ />
+ </FrameLayout>
+
+ <FrameLayout android:id="@+id/rot90"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:visibility="gone"
+ android:paddingTop="24dp"
+ >
+
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
- android:visibility="gone"
- android:paddingTop="24dp"
>
<!-- navigation controls -->
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_menu_default_land"
systemui:keyCode="82"
@@ -102,7 +115,7 @@
android:visibility="invisible"
/>
<ImageView android:id="@+id/recent_apps"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_recent_default_land"
android:layout_weight="0"
@@ -113,7 +126,7 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_home_default_land"
systemui:keyCode="3"
@@ -125,28 +138,32 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_back_default_land"
systemui:keyCode="4"
android:layout_weight="0"
/>
<View
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:layout_width="match_parent"
android:layout_weight="0"
/>
</LinearLayout>
- <LinearLayout android:id="@+id/rot270"
+ <View android:id="@+id/deadzone"
+ android:layout_width="@dimen/navigation_bar_deadzone_size"
android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:visibility="gone"
- >
-
- <!-- not used -->
- </LinearLayout>
-
+ android:layout_gravity="left"
+ android:clickable="true"
+ />
</FrameLayout>
+
+ <!-- not used -->
+ <View android:id="@+id/rot270"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:visibility="gone"
+ />
+
</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3944c203..da28e1e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -40,7 +40,11 @@
<dimen name="peek_window_y_offset">-12dp</dimen>
<!-- thickness (height) of the navigation bar on phones that require it -->
- <dimen name="navigation_bar_size">32dp</dimen>
+ <dimen name="navigation_bar_size">48dp</dimen>
+
+ <!-- thickness (height) of the dead zone at the top of the navigation bar,
+ reducing false presses on navbar buttons; approx 2mm -->
+ <dimen name="navigation_bar_deadzone_size">12dp</dimen>
<!-- thickness (height) of each notification row, including any separators or padding -->
<dimen name="notification_height">65dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 22181b8..550fc57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,13 +36,14 @@
import com.android.systemui.R;
public class NavigationBarView extends LinearLayout {
+ final static boolean DEBUG_DEADZONE = false;
+
final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
protected IStatusBarService mBarService;
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
- View mBackground;
Animator mLastAnimator = null;
public View getRecentsButton() {
@@ -74,13 +75,13 @@
}
private void setLights(final boolean on) {
- float oldAlpha = mBackground.getAlpha();
+ float oldAlpha = mCurrentView.getAlpha();
android.util.Log.d("NavigationBarView", "animating alpha: " + oldAlpha + " -> "
+ (on ? 1f : 0f));
if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel();
- mLastAnimator = ObjectAnimator.ofFloat(mBackground, "alpha", oldAlpha, on ? 1f : 0f)
+ mLastAnimator = ObjectAnimator.ofFloat(mCurrentView, "alpha", oldAlpha, on ? 1f : 0f)
.setDuration(on ? 250 : 1500);
mLastAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -92,8 +93,6 @@
}
public void onFinishInflate() {
- mBackground = findViewById(R.id.background);
-
mRotatedViews[Surface.ROTATION_0] =
mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
@@ -121,6 +120,10 @@
mCurrentView = mRotatedViews[rot];
mCurrentView.setVisibility(View.VISIBLE);
+ if (DEBUG_DEADZONE) {
+ mCurrentView.findViewById(R.id.deadzone).setBackgroundColor(0x808080FF);
+ }
+
android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
}
}
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index b9029a7..85ce38a 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -4279,6 +4279,12 @@
memento.setPointers(entry);
return true;
}
+ if (actionMasked == AMOTION_EVENT_ACTION_MOVE
+ && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK
+ | AINPUT_SOURCE_CLASS_NAVIGATION))) {
+ // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
+ return true;
+ }
#if DEBUG_OUTBOUND_EVENT_DETAILS
LOGD("Dropping inconsistent motion pointer up/down or move event: "
"deviceId=%d, source=%08x, actionMasked=%d",
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 014f962..82c3af3 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -922,7 +922,7 @@
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
LOGD("Input event: device=%d type=0x%04x scancode=0x%04x "
- "keycode=0x%04x value=0x%04x flags=0x%08x",
+ "keycode=0x%04x value=0x%08x flags=0x%08x",
rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode,
rawEvent->value, rawEvent->flags);
#endif
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
index 08cc75e..0ae2ab8 100644
--- a/services/input/SpriteController.cpp
+++ b/services/input/SpriteController.cpp
@@ -252,11 +252,7 @@
| DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
status_t status;
if (!haveTransaction) {
- status = mSurfaceComposerClient->openTransaction();
- if (status) {
- LOGE("Error %d opening transation to update sprite surface.", status);
- break;
- }
+ SurfaceComposerClient::openGlobalTransaction();
haveTransaction = true;
}
@@ -322,10 +318,7 @@
}
if (haveTransaction) {
- status_t status = mSurfaceComposerClient->closeTransaction();
- if (status) {
- LOGE("Error %d closing transaction to update sprite surface.", status);
- }
+ SurfaceComposerClient::closeGlobalTransaction();
}
// If any surfaces were changed, write back the new surface properties to the sprites.
diff --git a/services/java/com/android/server/DnsPinger.java b/services/java/com/android/server/DnsPinger.java
index a7324d9..4e33938 100644
--- a/services/java/com/android/server/DnsPinger.java
+++ b/services/java/com/android/server/DnsPinger.java
@@ -16,7 +16,6 @@
package com.android.server;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
@@ -28,6 +27,7 @@
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.Random;
@@ -49,7 +49,7 @@
private static final boolean V = true;
/** Number of bytes for the query */
- private static final int DNS_QUERY_BASE_SIZE = 33;
+ private static final int DNS_QUERY_BASE_SIZE = 32;
/** The DNS port */
private static final int DNS_PORT = 53;
@@ -84,12 +84,7 @@
* dns set. Should not be null.
*/
public InetAddress getDns() {
- if (mConnectivityManager == null) {
- mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
-
- LinkProperties curLinkProps = mConnectivityManager.getLinkProperties(mConnectionType);
+ LinkProperties curLinkProps = getCurrentLinkProperties();
if (curLinkProps == null) {
Slog.e(TAG, "getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
return mDefaultDns;
@@ -104,6 +99,15 @@
return dnses.iterator().next();
}
+ private LinkProperties getCurrentLinkProperties() {
+ if (mConnectivityManager == null) {
+ mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ }
+
+ return mConnectivityManager.getLinkProperties(mConnectionType);
+ }
+
private InetAddress getDefaultDns() {
String dns = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_DNS_SERVER);
@@ -130,8 +134,15 @@
// Set some socket properties
socket.setSoTimeout(timeout);
- byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
- fillQuery(buf);
+ // Try to bind but continue ping if bind fails
+ try {
+ socket.setNetworkInterface(NetworkInterface.getByName(
+ getCurrentLinkProperties().getInterfaceName()));
+ } catch (Exception e) {
+ Slog.d(TAG,"pingDns::Error binding to socket", e);
+ }
+
+ byte[] buf = constructQuery();
// Send the DNS query
@@ -164,48 +175,47 @@
}
- private static void fillQuery(byte[] buf) {
-
- /*
- * See RFC2929 (though the bit tables in there are misleading for us.
- * For example, the recursion desired bit is the 0th bit for us, but
- * looking there it would appear as the 7th bit of the byte
- */
-
- // Make sure it's all zeroed out
- for (int i = 0; i < buf.length; i++)
- buf[i] = 0;
-
- // Form a query for www.android.com
+ /**
+ * @return google.com DNS query packet
+ */
+ private static byte[] constructQuery() {
+ byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
// [0-1] bytes are an ID, generate random ID for this query
buf[0] = (byte) sRandom.nextInt(256);
buf[1] = (byte) sRandom.nextInt(256);
// [2-3] bytes are for flags.
- buf[2] = 1; // Recursion desired
+ buf[2] = 0x01; // Recursion desired
- // [4-5] bytes are for the query count
- buf[5] = 1; // One query
+ // [4-5] bytes are for number of queries (QCOUNT)
+ buf[5] = 0x01;
// [6-7] [8-9] [10-11] are all counts of other fields we don't use
// [12-15] for www
writeString(buf, 12, "www");
- // [16-23] for android
- writeString(buf, 16, "android");
+ // [16-22] for google
+ writeString(buf, 16, "google");
- // [24-27] for com
- writeString(buf, 24, "com");
+ // [23-26] for com
+ writeString(buf, 23, "com");
- // [29-30] bytes are for QTYPE, set to 1
- buf[30] = 1;
+ // [27] is a null byte terminator byte for the url
- // [31-32] bytes are for QCLASS, set to 1
- buf[32] = 1;
+ // [28-29] bytes are for QTYPE, set to 1 = A (host address)
+ buf[29] = 0x01;
+
+ // [30-31] bytes are for QCLASS, set to 1 = IN (internet)
+ buf[31] = 0x01;
+
+ return buf;
}
+ /**
+ * Writes the string's length and its contents to the buffer
+ */
private static void writeString(byte[] buf, int startPos, String string) {
int pos = startPos;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d3244ec..54e5432 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1626,6 +1626,30 @@
}
}
+ public String getSecureContainerFilesystemPath(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
+
+ try {
+ ArrayList<String> rsp = mConnector.doCommand(String.format("asec fspath %s", id));
+ String []tok = rsp.get(0).split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code != VoldResponseCode.AsecPathResult) {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ return tok[1];
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageNotFound) {
+ Slog.i(TAG, String.format("Container '%s' not found", id));
+ return null;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ }
+
public void finishMediaUpdate() {
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index b31d128..adc6570 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -37,9 +37,11 @@
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
import java.io.BufferedReader;
import java.io.DataInputStream;
@@ -52,6 +54,7 @@
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
@@ -115,6 +118,11 @@
private ArrayList<INetworkManagementEventObserver> mObservers;
+ /** Set of interfaces with active quotas. */
+ private HashSet<String> mInterfaceQuota = Sets.newHashSet();
+ /** Set of UIDs with active reject rules. */
+ private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+
/**
* Constructs a new NetworkManagementService instance
*
@@ -919,6 +927,84 @@
}
@Override
+ public void setInterfaceQuota(String iface, long quota) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ synchronized (mInterfaceQuota) {
+ if (mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth setiquota ").append(iface).append(" ").append(quota);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.add(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeInterfaceQuota(String iface) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ synchronized (mInterfaceQuota) {
+ if (!mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth removeiquota ").append(iface);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.remove(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ synchronized (mUidRejectOnQuota) {
+ final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
+ if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth");
+ if (rejectOnQuotaInterfaces) {
+ command.append(" addnaughtyapps");
+ } else {
+ command.append(" removenaughtyapps");
+ }
+ command.append(" ").append(uid);
+
+ try {
+ mConnector.doCommand(command.toString());
+ if (rejectOnQuotaInterfaces) {
+ mUidRejectOnQuota.put(uid, true);
+ } else {
+ mUidRejectOnQuota.delete(uid);
+ }
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
public NetworkStats getNetworkStatsUidDetail(int uid) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(
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/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index db3b61e..54bddb2 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -27,15 +27,23 @@
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.INetworkManagementEventObserver;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
import com.android.server.ConnectivityService.VpnCallback;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charsets;
+
/**
* @hide
*/
@@ -49,7 +57,8 @@
private String mPackageName;
private String mInterfaceName;
- private String mDnsPropertyPrefix;
+
+ private LegacyVpnRunner mLegacyVpnRunner;
public Vpn(Context context, VpnCallback callback) {
mContext = context;
@@ -81,7 +90,7 @@
// Reset the interface and hide the notification.
if (mInterfaceName != null) {
- nativeReset(mInterfaceName);
+ jniResetInterface(mInterfaceName);
mCallback.restore();
hideNotification();
mInterfaceName = null;
@@ -110,7 +119,7 @@
public void protect(ParcelFileDescriptor socket, String name) {
try {
mContext.enforceCallingPermission(VPN, "protect");
- nativeProtect(socket.getFd(), name);
+ jniProtectSocket(socket.getFd(), name);
} finally {
try {
socket.close();
@@ -143,17 +152,22 @@
}
// Create and configure the interface.
- ParcelFileDescriptor descriptor = ParcelFileDescriptor.adoptFd(
- nativeEstablish(config.mtu, config.addresses, config.routes));
+ ParcelFileDescriptor descriptor =
+ ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu));
- // Replace the interface and abort if it fails.
+ // Abort if any of the following steps fails.
try {
- String interfaceName = nativeGetName(descriptor.getFd());
-
- if (mInterfaceName != null && !mInterfaceName.equals(interfaceName)) {
- nativeReset(mInterfaceName);
+ String name = jniGetInterfaceName(descriptor.getFd());
+ if (jniSetAddresses(name, config.addresses) < 1) {
+ throw new IllegalArgumentException("At least one address must be specified");
}
- mInterfaceName = interfaceName;
+ if (config.routes != null) {
+ jniSetRoutes(name, config.routes);
+ }
+ if (mInterfaceName != null && !mInterfaceName.equals(name)) {
+ jniResetInterface(mInterfaceName);
+ }
+ mInterfaceName = name;
} catch (RuntimeException e) {
try {
descriptor.close();
@@ -186,7 +200,7 @@
// INetworkManagementEventObserver.Stub
public synchronized void interfaceRemoved(String name) {
- if (name.equals(mInterfaceName) && nativeCheck(name) == 0) {
+ if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) {
hideNotification();
mInterfaceName = null;
mCallback.restore();
@@ -244,9 +258,202 @@
}
}
- private native int nativeEstablish(int mtu, String addresses, String routes);
- private native String nativeGetName(int fd);
- private native void nativeReset(String name);
- private native int nativeCheck(String name);
- private native void nativeProtect(int fd, String name);
+ private native int jniCreateInterface(int mtu);
+ private native String jniGetInterfaceName(int fd);
+ private native int jniSetAddresses(String name, String addresses);
+ private native int jniSetRoutes(String name, String routes);
+ private native void jniResetInterface(String name);
+ private native int jniCheckInterface(String name);
+ private native void jniProtectSocket(int fd, String name);
+
+ /**
+ * Handle legacy VPN requests. This method stops the services and restart
+ * them if their arguments are not null. Heavy things are offloaded to
+ * another thread, so callers will not be blocked too long.
+ *
+ * @param raoocn The arguments to be passed to racoon.
+ * @param mtpd The arguments to be passed to mtpd.
+ */
+ public synchronized void doLegacyVpn(String[] racoon, String[] mtpd) {
+ // Currently only system user is allowed.
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Unauthorized Caller");
+ }
+
+ // If the previous runner is still alive, interrupt it.
+ if (mLegacyVpnRunner != null && mLegacyVpnRunner.isAlive()) {
+ mLegacyVpnRunner.interrupt();
+ }
+
+ // Start a new runner and we are done!
+ mLegacyVpnRunner = new LegacyVpnRunner(
+ new String[] {"racoon", "mtpd"}, racoon, mtpd);
+ mLegacyVpnRunner.start();
+ }
+
+ /**
+ * Bringing up a VPN connection takes time, and that is all this thread
+ * does. Here we have plenty of time. The only thing we need to take
+ * care of is responding to interruptions as soon as possible. Otherwise
+ * requests will be piled up. This can be done in a Handler as a state
+ * machine, but it is much easier to read in the current form.
+ */
+ private class LegacyVpnRunner extends Thread {
+ private static final String TAG = "LegacyVpnRunner";
+
+ private static final String NONE = "--";
+
+ private final String[] mServices;
+ private final String[][] mArguments;
+ private long mTimer = -1;
+
+ public LegacyVpnRunner(String[] services, String[]... arguments) {
+ super(TAG);
+ mServices = services;
+ mArguments = arguments;
+ }
+
+ @Override
+ public void run() {
+ // Wait for the previous thread since it has been interrupted.
+ Log.v(TAG, "wait");
+ synchronized (TAG) {
+ Log.v(TAG, "run");
+ execute();
+ Log.v(TAG, "exit");
+ }
+ }
+
+ private void checkpoint(boolean yield) throws InterruptedException {
+ long now = SystemClock.elapsedRealtime();
+ if (mTimer == -1) {
+ mTimer = now;
+ Thread.sleep(1);
+ } else if (now - mTimer <= 30000) {
+ Thread.sleep(yield ? 200 : 1);
+ } else {
+ throw new InterruptedException("timeout");
+ }
+ }
+
+ private void execute() {
+ // Catch all exceptions so we can clean up few things.
+ try {
+ // Initialize the timer.
+ checkpoint(false);
+
+ // First stop the services.
+ for (String service : mServices) {
+ SystemProperties.set("ctl.stop", service);
+ }
+
+ // Wait for the services to stop.
+ for (String service : mServices) {
+ String key = "init.svc." + service;
+ while (!"stopped".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+ }
+
+ // Reset the properties.
+ SystemProperties.set("vpn.dns", NONE);
+ SystemProperties.set("vpn.via", NONE);
+ while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
+ !NONE.equals(SystemProperties.get("vpn.via"))) {
+ checkpoint(true);
+ }
+
+ // Check if we need to restart some services.
+ boolean restart = false;
+ for (String[] arguments : mArguments) {
+ restart = restart || (arguments != null);
+ }
+ if (!restart) {
+ return;
+ }
+
+ // Start the service with arguments.
+ for (int i = 0; i < mServices.length; ++i) {
+ String[] arguments = mArguments[i];
+ if (arguments == null) {
+ continue;
+ }
+
+ // Start the service.
+ String service = mServices[i];
+ SystemProperties.set("ctl.start", service);
+
+ // Wait for the service to start.
+ String key = "init.svc." + service;
+ while (!"running".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+
+ // Create the control socket.
+ LocalSocket socket = new LocalSocket();
+ LocalSocketAddress address = new LocalSocketAddress(
+ service, LocalSocketAddress.Namespace.RESERVED);
+
+ // Wait for the socket to connect.
+ while (true) {
+ try {
+ socket.connect(address);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ checkpoint(true);
+ }
+ socket.setSoTimeout(500);
+
+ // Send over the arguments.
+ OutputStream output = socket.getOutputStream();
+ for (String argument : arguments) {
+ byte[] bytes = argument.getBytes(Charsets.UTF_8);
+ if (bytes.length >= 0xFFFF) {
+ throw new IllegalArgumentException("argument too large");
+ }
+ output.write(bytes.length >> 8);
+ output.write(bytes.length);
+ output.write(bytes);
+ checkpoint(false);
+ }
+
+ // Send End-Of-Arguments.
+ output.write(0xFF);
+ output.write(0xFF);
+ output.flush();
+ socket.close();
+ }
+
+ // Now here is the beast from the old days. We check few
+ // properties to figure out the current status. Ideally we
+ // can read things back from the sockets and get rid of the
+ // properties, but we have no time...
+ while (NONE.equals(SystemProperties.get("vpn.dns")) ||
+ NONE.equals(SystemProperties.get("vpn.via"))) {
+
+ // Check if a running service is dead.
+ for (int i = 0; i < mServices.length; ++i) {
+ String service = mServices[i];
+ if (mArguments[i] != null && !"running".equals(
+ SystemProperties.get("init.svc." + service))) {
+ throw new IllegalArgumentException(service + " is dead");
+ }
+ }
+ checkpoint(true);
+ }
+
+ // Great! Now we are connected!
+ Log.i(TAG, "connected!");
+ // TODO:
+
+ } catch (Exception e) {
+ Log.i(TAG, e.getMessage());
+ for (String service : mServices) {
+ SystemProperties.set("ctl.stop", service);
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 67e73f5f..4fa3bda 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -132,7 +132,7 @@
private static final int GPS_CAPABILITY_MSB = 0x0000002;
private static final int GPS_CAPABILITY_MSA = 0x0000004;
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
-
+ private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
// these need to match AGpsType enum in gps.h
private static final int AGPS_TYPE_SUPL = 1;
@@ -200,6 +200,9 @@
private boolean mInjectNtpTimePending = true;
private boolean mDownloadXtraDataPending = true;
+ // set to true if the GPS engine does not do on-demand NTP time requests
+ private boolean mPeriodicTimeInjection;
+
// true if GPS is navigating
private boolean mNavigating;
@@ -549,10 +552,12 @@
delay = RETRY_INTERVAL;
}
- // send delayed message for next NTP injection
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.removeMessages(INJECT_NTP_TIME);
- mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ if (mPeriodicTimeInjection) {
+ // send delayed message for next NTP injection
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ }
}
private void handleDownloadXtraData() {
@@ -1305,6 +1310,11 @@
*/
private void setEngineCapabilities(int capabilities) {
mEngineCapabilities = capabilities;
+
+ if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
+ mPeriodicTimeInjection = true;
+ requestUtcTime();
+ }
}
/**
@@ -1438,6 +1448,14 @@
}
/**
+ * Called from native code to request utc time info
+ */
+
+ private void requestUtcTime() {
+ sendMessage(INJECT_NTP_TIME, 0, null);
+ }
+
+ /**
* Called from native code to request reference location info
*/
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 12d3ed8..1f2ec2c 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -25,6 +25,7 @@
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.*;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -57,6 +58,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -71,6 +74,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;
@@ -109,6 +113,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import libcore.io.IoUtils;
@@ -156,6 +161,7 @@
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
private final INetworkStatsService mNetworkStats;
+ private final INetworkManagementService mNetworkManagement;
private final TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -164,6 +170,7 @@
private final Object mRulesLock = new Object();
private boolean mScreenOn;
+ private boolean mBackgroundData;
/** Current policy for network templates. */
private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
@@ -192,11 +199,14 @@
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
+ // TODO: watch for package added broadcast to catch new 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(),
- getSystemDir());
+ this(context, activityManager, powerManager, networkStats, networkManagement,
+ new NtpTrustedTime(), getSystemDir());
}
private static File getSystemDir() {
@@ -204,12 +214,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 networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
mHandlerThread = new HandlerThread(TAG);
@@ -235,6 +247,7 @@
}
updateScreenOn();
+ updateBackgroundData(true);
try {
mActivityManager.registerProcessObserver(mProcessObserver);
@@ -260,11 +273,15 @@
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
- // listen for warning polling events; currently dispatched by
+ // listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
mContext.registerReceiver(
mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
+ // listen for changes to background data flag
+ final IntentFilter bgFilter = new IntentFilter(ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.registerReceiver(mBgReceiver, bgFilter, CONNECTIVITY_INTERNAL, mHandler);
+
}
private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -347,6 +364,22 @@
};
/**
+ * Receiver that watches for
+ * {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
+ */
+ private BroadcastReceiver mBgReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // permission above.
+
+ synchronized (mRulesLock) {
+ updateBackgroundData(false);
+ }
+ }
+ };
+
+ /**
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
*/
@@ -559,7 +592,7 @@
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- mMeteredIfaces.clear();
+ final HashSet<String> newMeteredIfaces = Sets.newHashSet();
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
@@ -589,14 +622,28 @@
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 (ifaces.length > 1) {
+ // TODO: switch to shared quota once NMS supports
+ Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
+ }
for (String iface : ifaces) {
- mMeteredIfaces.add(iface);
+ removeInterfaceQuota(iface);
+ setInterfaceQuota(iface, quota);
+ newMeteredIfaces.add(iface);
}
}
}
+ // remove quota on any trailing interfaces
+ for (String iface : mMeteredIfaces) {
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuota(iface);
+ }
+ }
+ mMeteredIfaces = newMeteredIfaces;
+
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
}
@@ -924,6 +971,21 @@
}
}
+ private void updateBackgroundData(boolean systemReady) {
+ synchronized (mRulesLock) {
+ try {
+ mBackgroundData = mConnManager.getBackgroundDataSetting();
+ } catch (RemoteException e) {
+ }
+ if (systemReady && mBackgroundData) {
+ // typical behavior of background enabled during systemReady;
+ // no need to clear rules for all UIDs.
+ } else {
+ updateRulesForBackgroundDataLocked();
+ }
+ }
+ }
+
/**
* Update rules that might be changed by {@link #mScreenOn} value.
*/
@@ -938,6 +1000,33 @@
}
}
+ /**
+ * Update rules that might be changed by {@link #mBackgroundData} value.
+ */
+ private void updateRulesForBackgroundDataLocked() {
+ // update rules for all installed applications
+ final PackageManager pm = mContext.getPackageManager();
+ final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
+ for (ApplicationInfo app : apps) {
+ updateRulesForUidLocked(app.uid);
+ }
+
+ // and catch system UIDs
+ // TODO: keep in sync with android_filesystem_config.h
+ for (int uid = 1000; uid <= 1025; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 2000; uid <= 2002; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 3000; uid <= 3007; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 9998; uid <= 9999; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ }
+
private void updateRulesForUidLocked(int uid) {
final int uidPolicy = getUidPolicy(uid);
final boolean uidForeground = isUidForeground(uid);
@@ -948,6 +1037,10 @@
// uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED;
}
+ if (!uidForeground && !mBackgroundData) {
+ // uid in background, and global background disabled
+ uidRules = RULE_REJECT_METERED;
+ }
// TODO: only dispatch when rules actually change
@@ -955,7 +1048,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();
@@ -1003,6 +1096,36 @@
}
};
+ private void setInterfaceQuota(String iface, long quota) {
+ try {
+ mNetworkManagement.setInterfaceQuota(iface, quota);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ }
+ }
+
+ private void removeInterfaceQuota(String iface) {
+ try {
+ mNetworkManagement.removeInterfaceQuota(iface);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ }
+ }
+
+ private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ try {
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ }
+ }
+
private String getActiveSubscriberId() {
final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index d10aa97..11ccd60 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -307,7 +307,7 @@
}
public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
- PackageStats pStats) {
+ String asecPath, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -315,17 +315,20 @@
builder.append(apkPath);
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
+ builder.append(' ');
+ builder.append(asecPath != null ? asecPath : "!");
String s = transaction(builder.toString());
String res[] = s.split(" ");
- if ((res == null) || (res.length != 4)) {
+ if ((res == null) || (res.length != 5)) {
return -1;
}
try {
pStats.codeSize = Long.parseLong(res[1]);
pStats.dataSize = Long.parseLong(res[2]);
pStats.cacheSize = Long.parseLong(res[3]);
+ pStats.externalCodeSize = Long.parseLong(res[4]);
return Integer.parseInt(res[0]);
} catch (NumberFormatException e) {
return -1;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5a9dae9..22e2dde 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -75,6 +75,7 @@
import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
+import android.os.FileUtils.FileStatus;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -4887,8 +4888,7 @@
private final IPackageStatsObserver mObserver;
- public MeasureParams(PackageStats stats, boolean success,
- IPackageStatsObserver observer) {
+ public MeasureParams(PackageStats stats, boolean success, IPackageStatsObserver observer) {
mObserver = observer;
mStats = stats;
mSuccess = success;
@@ -5480,6 +5480,17 @@
}
}
+ /**
+ * Extract the MountService "container ID" from the full code path of an
+ * .apk.
+ */
+ static String cidFromCodePath(String fullCodePath) {
+ int eidx = fullCodePath.lastIndexOf("/");
+ String subStr1 = fullCodePath.substring(0, eidx);
+ int sidx = subStr1.lastIndexOf("/");
+ return subStr1.substring(sidx+1, eidx);
+ }
+
class SdInstallArgs extends InstallArgs {
static final String RES_FILE_NAME = "pkg.apk";
@@ -6831,6 +6842,7 @@
}
PackageParser.Package p;
boolean dataOnly = false;
+ String asecPath = null;
synchronized (mPackages) {
p = mPackages.get(packageName);
if(p == null) {
@@ -6842,6 +6854,12 @@
}
p = ps.pkg;
}
+ if (p != null && isExternal(p)) {
+ String secureContainerId = cidFromCodePath(p.applicationInfo.sourceDir);
+ if (secureContainerId != null) {
+ asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+ }
+ }
}
String publicSrcDir = null;
if(!dataOnly) {
@@ -6850,10 +6868,13 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
+ if (isForwardLocked(p)) {
+ publicSrcDir = applicationInfo.publicSourceDir;
+ }
}
if (mInstaller != null) {
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir, pStats);
+ int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ asecPath, pStats);
if (res < 0) {
return false;
} else {
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index ae7fbfe..a0ea92b 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -42,6 +42,9 @@
namespace android
{
+static int inet4 = -1;
+static int inet6 = -1;
+
static inline in_addr_t *as_in_addr(sockaddr *sa) {
return &((sockaddr_in *)sa)->sin_addr.s_addr;
}
@@ -51,11 +54,9 @@
#define SYSTEM_ERROR -1
#define BAD_ARGUMENT -2
-static int create_interface(int mtu, char *name, int *index)
+static int create_interface(int mtu)
{
- int tun = open("/dev/tun", O_RDWR);
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int flags;
+ int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
@@ -81,38 +82,45 @@
goto error;
}
- // Get interface index.
- if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
- LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- // Make it non-blocking.
- flags = fcntl(tun, F_GETFL, 0);
- if (flags == -1 || fcntl(tun, F_SETFL, flags | O_NONBLOCK)) {
- LOGE("Cannot set non-blocking on %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- strcpy(name, ifr4.ifr_name);
- *index = ifr4.ifr_ifindex;
- close(inet4);
return tun;
error:
close(tun);
- close(inet4);
return SYSTEM_ERROR;
}
-static int set_addresses(const char *name, int index, const char *addresses)
+static int get_interface_name(char *name, int tun)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ LOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ LOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
- strcpy(ifr4.ifr_name, name);
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_addr.sa_family = AF_INET;
in6_ifreq ifr6;
@@ -121,7 +129,6 @@
char address[65];
int prefix;
-
int chars;
int count = 0;
@@ -164,7 +171,7 @@
break;
}
}
- LOGV("Address added on %s: %s/%d", name, address, prefix);
+ LOGD("Address added on %s: %s/%d", name, address, prefix);
++count;
}
@@ -177,15 +184,15 @@
count = BAD_ARGUMENT;
}
- close(inet4);
- close(inet6);
return count;
}
-static int set_routes(const char *name, int index, const char *routes)
+static int set_routes(const char *name, const char *routes)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
rtentry rt4;
memset(&rt4, 0, sizeof(rt4));
@@ -201,7 +208,6 @@
char address[65];
int prefix;
-
int chars;
int count = 0;
@@ -211,32 +217,50 @@
if (strchr(address, ':')) {
// Add an IPv6 route.
if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
- prefix < 1 || prefix > 128) {
+ prefix < 0 || prefix > 128) {
count = BAD_ARGUMENT;
break;
}
- rt6.rtmsg_dst_len = prefix;
+ rt6.rtmsg_dst_len = prefix ? prefix : 1;
if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
+ if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
} else {
// Add an IPv4 route.
if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
- prefix < 1 || prefix > 32) {
+ prefix < 0 || prefix > 32) {
count = BAD_ARGUMENT;
break;
}
- in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
+ in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 1;
*as_in_addr(&rt4.rt_genmask) = htonl(mask);
if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
+ if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
}
- LOGV("Route added on %s: %s/%d", name, address, prefix);
+ LOGD("Route added on %s: %s/%d", name, address, prefix);
++count;
}
@@ -250,43 +274,24 @@
count = BAD_ARGUMENT;
}
- close(inet4);
- close(inet6);
return count;
}
-static int get_interface_name(char *name, int tun)
-{
- ifreq ifr4;
- if (ioctl(tun, TUNGETIFF, &ifr4)) {
- LOGE("Cannot get interface name: %s", strerror(errno));
- return SYSTEM_ERROR;
- }
- strcpy(name, ifr4.ifr_name);
- return 0;
-}
-
static int reset_interface(const char *name)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
-
ifreq ifr4;
- ifr4.ifr_flags = 0;
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
LOGE("Cannot reset %s: %s", name, strerror(errno));
- close(inet4);
return SYSTEM_ERROR;
}
- close(inet4);
return 0;
}
static int check_interface(const char *name)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
-
ifreq ifr4;
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_flags = 0;
@@ -294,7 +299,6 @@
if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
LOGE("Cannot check %s: %s", name, strerror(errno));
}
- close(inet4);
return ifr4.ifr_flags;
}
@@ -318,86 +322,108 @@
}
}
-static jint establish(JNIEnv *env, jobject thiz,
- jint mtu, jstring jAddresses, jstring jRoutes)
+static jint createInterface(JNIEnv *env, jobject thiz, jint mtu)
{
- char name[IFNAMSIZ];
- int index;
- int tun = create_interface(mtu, name, &index);
+ int tun = create_interface(mtu);
if (tun < 0) {
throwException(env, tun, "Cannot create interface");
return -1;
}
- LOGD("%s is created", name);
-
- const char *addresses;
- const char *routes;
- int count;
-
- // Addresses are required.
- addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
- if (!addresses) {
- jniThrowNullPointerException(env, "address");
- goto error;
- }
- count = set_addresses(name, index, addresses);
- env->ReleaseStringUTFChars(jAddresses, addresses);
- if (count <= 0) {
- throwException(env, count, "Cannot set address");
- goto error;
- }
- LOGD("Configured %d address(es) on %s", count, name);
-
- // Routes are optional.
- routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
- if (routes) {
- count = set_routes(name, index, routes);
- env->ReleaseStringUTFChars(jRoutes, routes);
- if (count < 0) {
- throwException(env, count, "Cannot set route");
- goto error;
- }
- LOGD("Configured %d route(s) on %s", count, name);
- }
-
return tun;
-
-error:
- close(tun);
- LOGD("%s is destroyed", name);
- return -1;
}
-static jstring getName(JNIEnv *env, jobject thiz, jint fd)
+static jstring getInterfaceName(JNIEnv *env, jobject thiz, jint tun)
{
char name[IFNAMSIZ];
- if (get_interface_name(name, fd) < 0) {
+ if (get_interface_name(name, tun) < 0) {
throwException(env, SYSTEM_ERROR, "Cannot get interface name");
return NULL;
}
return env->NewStringUTF(name);
}
-static void reset(JNIEnv *env, jobject thiz, jstring jName)
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jAddresses)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+ if (!addresses) {
+ jniThrowNullPointerException(env, "addresses");
+ goto error;
+ }
+ count = set_addresses(name, addresses);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
+}
+
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jRoutes)
+{
+ const char *name = NULL;
+ const char *routes = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+ if (!routes) {
+ jniThrowNullPointerException(env, "routes");
+ goto error;
+ }
+ count = set_routes(name, routes);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (routes) {
+ env->ReleaseStringUTFChars(jRoutes, routes);
+ }
+ return count;
+}
+
+static void resetInterface(JNIEnv *env, jobject thiz, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return;
}
if (reset_interface(name) < 0) {
throwException(env, SYSTEM_ERROR, "Cannot reset interface");
- } else {
- LOGD("%s is deactivated", name);
}
env->ReleaseStringUTFChars(jName, name);
}
-static jint check(JNIEnv *env, jobject thiz, jstring jName)
+static jint checkInterface(JNIEnv *env, jobject thiz, jstring jName)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return 0;
@@ -407,10 +433,9 @@
return flags;
}
-static void protect(JNIEnv *env, jobject thiz, jint fd, jstring jName)
+static void protectSocket(JNIEnv *env, jobject thiz, jint fd, jstring jName)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return;
@@ -424,15 +449,23 @@
//------------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"nativeEstablish", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)establish},
- {"nativeGetName", "(I)Ljava/lang/String;", (void *)getName},
- {"nativeReset", "(Ljava/lang/String;)V", (void *)reset},
- {"nativeCheck", "(Ljava/lang/String;)I", (void *)check},
- {"nativeProtect", "(ILjava/lang/String;)V", (void *)protect},
+ {"jniCreateInterface", "(I)I", (void *)createInterface},
+ {"jniGetInterfaceName", "(I)Ljava/lang/String;", (void *)getInterfaceName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
+ {"jniResetInterface", "(Ljava/lang/String;)V", (void *)resetInterface},
+ {"jniCheckInterface", "(Ljava/lang/String;)I", (void *)checkInterface},
+ {"jniProtectSocket", "(ILjava/lang/String;)V", (void *)protectSocket},
};
int register_android_server_connectivity_Vpn(JNIEnv *env)
{
+ if (inet4 == -1) {
+ inet4 = socket(AF_INET, SOCK_DGRAM, 0);
+ }
+ if (inet6 == -1) {
+ inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ }
return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
gMethods, NELEM(gMethods));
}
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 6d4ad9a..87ffcba 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -42,6 +42,7 @@
static jmethodID method_reportNiNotification;
static jmethodID method_requestRefLocation;
static jmethodID method_requestSetID;
+static jmethodID method_requestUtcTime;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -122,6 +123,13 @@
release_wake_lock(WAKE_LOCK_NAME);
}
+static void request_utc_time_callback()
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
@@ -137,6 +145,7 @@
acquire_wakelock_callback,
release_wakelock_callback,
create_thread_callback,
+ request_utc_time_callback,
};
static void xtra_download_request_callback()
@@ -232,6 +241,7 @@
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+ method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f0b19f2..1c57bc1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -78,7 +78,6 @@
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
- mTransactionCount(0),
mResizeTransationPending(false),
mLayersRemoved(false),
mBootTime(systemTime()),
@@ -385,13 +384,11 @@
handleConsoleEvents();
}
- if (LIKELY(mTransactionCount == 0)) {
- // if we're in a global transaction, don't do anything.
- const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = peekTransactionFlags(mask);
- if (LIKELY(transactionFlags)) {
- handleTransaction(transactionFlags);
- }
+ // if we're in a global transaction, don't do anything.
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ uint32_t transactionFlags = peekTransactionFlags(mask);
+ if (UNLIKELY(transactionFlags)) {
+ handleTransaction(transactionFlags);
}
// post surfaces (if needed)
@@ -1176,28 +1173,33 @@
return old;
}
-void SurfaceFlinger::openGlobalTransaction()
-{
- android_atomic_inc(&mTransactionCount);
-}
-void SurfaceFlinger::closeGlobalTransaction()
-{
- if (android_atomic_dec(&mTransactionCount) == 1) {
- signalEvent();
+void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state) {
+ Mutex::Autolock _l(mStateLock);
- // if there is a transaction with a resize, wait for it to
- // take effect before returning.
- Mutex::Autolock _l(mStateLock);
- while (mResizeTransationPending) {
- status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- // just in case something goes wrong in SF, return to the
- // called after a few seconds.
- LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
- mResizeTransationPending = false;
- break;
- }
+ uint32_t flags = 0;
+ const size_t count = state.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const ComposerState& s(state[i]);
+ sp<Client> client( static_cast<Client *>(s.client.get()) );
+ flags |= setClientStateLocked(client, s.state);
+ }
+ if (flags) {
+ setTransactionFlags(flags);
+ }
+
+ signalEvent();
+
+ // if there is a transaction with a resize, wait for it to
+ // take effect before returning.
+ while (mResizeTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mResizeTransationPending = false;
+ break;
}
}
}
@@ -1393,60 +1395,52 @@
return err;
}
-status_t SurfaceFlinger::setClientState(
+uint32_t SurfaceFlinger::setClientStateLocked(
const sp<Client>& client,
- int32_t count,
- const layer_state_t* states)
+ const layer_state_t& s)
{
- Mutex::Autolock _l(mStateLock);
uint32_t flags = 0;
- for (int i=0 ; i<count ; i++) {
- const layer_state_t& s(states[i]);
- sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
- if (layer != 0) {
- const uint32_t what = s.what;
- if (what & ePositionChanged) {
- if (layer->setPosition(s.x, s.y))
- flags |= eTraversalNeeded;
- }
- if (what & eLayerChanged) {
- ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayer(s.z)) {
- mCurrentState.layersSortedByZ.removeAt(idx);
- mCurrentState.layersSortedByZ.add(layer);
- // we need traversal (state changed)
- // AND transaction (list changed)
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
- if (what & eSizeChanged) {
- if (layer->setSize(s.w, s.h)) {
- flags |= eTraversalNeeded;
- mResizeTransationPending = true;
- }
- }
- if (what & eAlphaChanged) {
- if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
- flags |= eTraversalNeeded;
- }
- if (what & eMatrixChanged) {
- if (layer->setMatrix(s.matrix))
- flags |= eTraversalNeeded;
- }
- if (what & eTransparentRegionChanged) {
- if (layer->setTransparentRegionHint(s.transparentRegion))
- flags |= eTraversalNeeded;
- }
- if (what & eVisibilityChanged) {
- if (layer->setFlags(s.flags, s.mask))
- flags |= eTraversalNeeded;
+ sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
+ if (layer != 0) {
+ const uint32_t what = s.what;
+ if (what & ePositionChanged) {
+ if (layer->setPosition(s.x, s.y))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eLayerChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setLayer(s.z)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
}
+ if (what & eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
+ mResizeTransationPending = true;
+ }
+ }
+ if (what & eAlphaChanged) {
+ if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eVisibilityChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
}
- if (flags) {
- setTransactionFlags(flags);
- }
- return NO_ERROR;
+ return flags;
}
void SurfaceFlinger::screenReleased(int dpy)
@@ -1588,8 +1582,7 @@
{
switch (code) {
case CREATE_CONNECTION:
- case OPEN_GLOBAL_TRANSACTION:
- case CLOSE_GLOBAL_TRANSACTION:
+ case SET_TRANSACTION_STATE:
case SET_ORIENTATION:
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
@@ -2469,9 +2462,6 @@
status_t Client::destroySurface(SurfaceID sid) {
return mFlinger->removeSurface(this, sid);
}
-status_t Client::setState(int32_t count, const layer_state_t* states) {
- return mFlinger->setClientState(this, count, states);
-}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 45f80ae..b49fa36 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -70,14 +70,12 @@
sp<LayerBaseClient> getLayerUser(int32_t i) const;
private:
-
// ISurfaceComposerClient interface
virtual sp<ISurface> createSurface(
surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
- virtual status_t setState(int32_t count, const layer_state_t* states);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
@@ -168,8 +166,7 @@
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
- virtual void openGlobalTransaction();
- virtual void closeGlobalTransaction();
+ virtual void setTransactionState(const Vector<ComposerState>& state);
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
@@ -220,8 +217,7 @@
status_t removeSurface(const sp<Client>& client, SurfaceID sid);
status_t destroySurface(const wp<LayerBaseClient>& layer);
- status_t setClientState(const sp<Client>& client,
- int32_t count, const layer_state_t* states);
+ uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
class LayerVector : public SortedVector< sp<LayerBase> > {
public:
@@ -337,7 +333,6 @@
mutable Mutex mStateLock;
State mCurrentState;
volatile int32_t mTransactionFlags;
- volatile int32_t mTransactionCount;
Condition mTransactionCV;
SortedVector< sp<LayerBase> > mLayerPurgatory;
bool mResizeTransationPending;
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 18c54b3..56b2a8f 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -43,9 +43,9 @@
PIXEL_FORMAT_RGB_565);
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surface->setLayer(100000);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
Surface::SurfaceInfo info;
surface->lock(&info);
@@ -57,9 +57,9 @@
android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
surface->unlockAndPost();
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surface->setSize(320, 240);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
IPCThreadState::self()->joinThreadPool();
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 5265f91..8e1c3fe 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -39,9 +39,9 @@
sp<SurfaceControl> surfaceControl = client->createSurface(
getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565);
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
// pretend it went cross-process
Parcel parcel;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 324e896..b4ac987 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);
@@ -175,6 +179,9 @@
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
expectTime(System.currentTimeMillis());
+ // default behavior is background data enabled
+ expect(mConnManager.getBackgroundDataSetting()).andReturn(true);
+
replay();
mService.systemReady();
verifyAndReset();
@@ -253,6 +260,7 @@
public void testScreenChangesRules() throws Exception {
Future<Void> future;
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -260,6 +268,7 @@
verifyAndReset();
// push strict policy for foreground uid, verify ALLOW rule
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -268,6 +277,7 @@
// now turn screen off and verify REJECT rule
expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
@@ -276,6 +286,7 @@
// and turn screen back on, verify ALLOW rule restored
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
@@ -286,6 +297,7 @@
public void testPolicyNone() throws Exception {
Future<Void> future;
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -293,6 +305,7 @@
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in foreground
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
@@ -300,6 +313,7 @@
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -311,6 +325,7 @@
Future<Void> future;
// POLICY_REJECT should RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -318,6 +333,7 @@
verifyAndReset();
// POLICY_REJECT should RULE_ALLOW in foreground
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -325,6 +341,7 @@
verifyAndReset();
// POLICY_REJECT should RULE_REJECT in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -336,6 +353,7 @@
Future<Void> future;
// POLICY_NONE should have RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -344,6 +362,7 @@
verifyAndReset();
// adding POLICY_REJECT should cause RULE_REJECT
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -351,6 +370,7 @@
verifyAndReset();
// removing POLICY_REJECT should return us to RULE_ALLOW
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
@@ -431,8 +451,9 @@
expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
.andReturn(stats).atLeastOnce();
- // expect that quota remaining should be 1536 bytes
- // TODO: write up NetworkManagementService mock
+ // TODO: consider making strongly ordered mock
+ expectRemoveInterfaceQuota(TEST_IFACE);
+ expectSetInterfaceQuota(TEST_IFACE, 1536L);
expectClearNotifications();
future = expectMeteredIfacesChanged(TEST_IFACE);
@@ -447,6 +468,7 @@
Future<Void> future;
// POLICY_REJECT should RULE_REJECT in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -454,6 +476,7 @@
verifyAndReset();
// uninstall should clear RULE_REJECT
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
final Intent intent = new Intent(ACTION_UID_REMOVED);
@@ -494,6 +517,22 @@
expectLastCall().anyTimes();
}
+ private void expectSetInterfaceQuota(String iface, long quota) throws Exception {
+ mNetworkManagement.setInterfaceQuota(iface, quota);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectRemoveInterfaceQuota(String iface) throws Exception {
+ mNetworkManagement.removeInterfaceQuota(iface);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+ throws Exception {
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ expectLastCall().atLeastOnce();
+ }
+
private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
final FutureAnswer future = new FutureAnswer();
mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
@@ -526,14 +565,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/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 184d665..66120a1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -191,10 +191,6 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
- if (!isVoiceCapable()) {
- return null;
- }
-
try {
return getSubscriberInfo().getDeviceId();
} catch (RemoteException ex) {
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);
+ }
+}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7aa0617..8734143 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,15 @@
android:hardwareAccelerated="true">
<activity
+ android:name="TimeDialogActivity"
+ android:label="_TimeDialog">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="OpaqueActivity"
android:label="_Opaque">
<intent-filter>
@@ -494,8 +503,7 @@
<activity
android:name="Animated3dActivity"
- android:label="_Animated 3d"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ android:label="_Animated 3d">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
new file mode 100644
index 0000000..9e3e950
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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.test.hwui;
+
+import android.app.Activity;
+import android.app.TimePickerDialog;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TimeDialogActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout layout = new FrameLayout(this);
+ Button b = new Button(this);
+ b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+ b.setText("Show dialog");
+ b.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new TimePickerDialog(TimeDialogActivity.this, null, 12, 12, true).show();
+ }
+ });
+ layout.addView(b);
+
+ setContentView(layout);
+ }
+}
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index 3b0f5460..47863bd 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -756,21 +756,20 @@
}
}
- private class IntervalMeasurementProcess implements
+ private class IntervalMeasurementProcess implements Runnable,
SipSessionGroup.KeepAliveProcessCallback {
private static final String TAG = "SipKeepAliveInterval";
private static final int MAX_INTERVAL = 120; // in seconds
- private static final int MIN_INTERVAL = 10; // in seconds
+ private static final int MIN_INTERVAL = 5; // in seconds
private static final int PASS_THRESHOLD = 10;
private static final int MAX_RETRY_COUNT = 5;
+ private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
private SipSessionGroupExt mGroup;
private SipSessionGroup.SipSessionImpl mSession;
- private boolean mRunning;
- private int mMinInterval = 10; // in seconds
+ private int mMinInterval = DEFAULT_KEEPALIVE_INTERVAL; // in seconds
private int mMaxInterval;
private int mInterval;
private int mPassCount = 0;
- private int mErrorCount = 0;
public IntervalMeasurementProcess(SipProfile localProfile, int maxInterval) {
mMaxInterval = (maxInterval < 0) ? MAX_INTERVAL : maxInterval;
@@ -788,8 +787,6 @@
// TODO: remove this line once SipWakeupTimer can better handle
// variety of timeout values
mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
- mSession = (SipSessionGroup.SipSessionImpl)
- mGroup.createSession(null);
} catch (Exception e) {
Log.w(TAG, "start interval measurement error: " + e);
}
@@ -797,6 +794,11 @@
public void start() {
synchronized (SipService.this) {
+ Log.d(TAG, "start measurement w interval=" + mInterval);
+ if (mSession == null) {
+ mSession = (SipSessionGroup.SipSessionImpl)
+ mGroup.createSession(null);
+ }
try {
mSession.startKeepAliveProcess(mInterval, this);
} catch (SipException e) {
@@ -807,14 +809,23 @@
public void stop() {
synchronized (SipService.this) {
- mSession.stopKeepAliveProcess();
+ if (mSession != null) {
+ mSession.stopKeepAliveProcess();
+ mSession = null;
+ }
+ mTimer.cancel(this);
}
}
private void restart() {
synchronized (SipService.this) {
+ // Return immediately if the measurement process is stopped
+ if (mSession == null) return;
+
+ Log.d(TAG, "restart measurement w interval=" + mInterval);
try {
mSession.stopKeepAliveProcess();
+ mPassCount = 0;
mSession.startKeepAliveProcess(mInterval, this);
} catch (SipException e) {
Log.e(TAG, "restart()", e);
@@ -826,8 +837,6 @@
@Override
public void onResponse(boolean portChanged) {
synchronized (SipService.this) {
- mErrorCount = 0;
-
if (!portChanged) {
if (++mPassCount != PASS_THRESHOLD) return;
// update the interval, since the current interval is good to
@@ -853,7 +862,6 @@
} else {
// calculate the new interval and continue.
mInterval = (mMaxInterval + mMinInterval) / 2;
- mPassCount = 0;
if (DEBUG) {
Log.d(TAG, "current interval: " + mKeepAliveInterval
+ ", test new interval: " + mInterval);
@@ -866,22 +874,32 @@
// SipSessionGroup.KeepAliveProcessCallback
@Override
public void onError(int errorCode, String description) {
+ Log.w(TAG, "interval measurement error: " + description);
+ restartLater();
+ }
+
+ // timeout handler
+ @Override
+ public void run() {
+ mTimer.cancel(this);
+ restart();
+ }
+
+ private void restartLater() {
synchronized (SipService.this) {
- Log.w(TAG, "interval measurement error: " + description);
- if (++mErrorCount < MAX_RETRY_COUNT) {
- Log.w(TAG, " retry count = " + mErrorCount);
- mPassCount = 0;
- restart();
- } else {
- Log.w(TAG, " max retry count reached; measurement aborted");
- }
+ int interval = NAT_MEASUREMENT_RETRY_INTERVAL;
+ Log.d(TAG, "Retry measurement " + interval + "s later.");
+ mTimer.cancel(this);
+ mTimer.set(interval * 1000, this);
}
}
}
private class AutoRegistrationProcess extends SipSessionAdapter
implements Runnable, SipSessionGroup.KeepAliveProcessCallback {
+ private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10;
private String TAG = "SipAudoReg";
+
private SipSessionGroup.SipSessionImpl mSession;
private SipSessionGroup.SipSessionImpl mKeepAliveSession;
private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
@@ -892,6 +910,8 @@
private String mErrorMessage;
private boolean mRunning = false;
+ private int mKeepAliveSuccessCount = 0;
+
private String getAction() {
return toString();
}
@@ -915,18 +935,56 @@
}
}
+ private void startKeepAliveProcess(int interval) {
+ Log.d(TAG, "start keepalive w interval=" + interval);
+ if (mKeepAliveSession == null) {
+ mKeepAliveSession = mSession.duplicate();
+ } else {
+ mKeepAliveSession.stopKeepAliveProcess();
+ }
+ try {
+ mKeepAliveSession.startKeepAliveProcess(interval, this);
+ } catch (SipException e) {
+ Log.e(TAG, "failed to start keepalive w interval=" + interval,
+ e);
+ }
+ }
+
+ private void stopKeepAliveProcess() {
+ if (mKeepAliveSession != null) {
+ mKeepAliveSession.stopKeepAliveProcess();
+ mKeepAliveSession = null;
+ }
+ mKeepAliveSuccessCount = 0;
+ }
+
// SipSessionGroup.KeepAliveProcessCallback
@Override
public void onResponse(boolean portChanged) {
synchronized (SipService.this) {
if (portChanged) {
- restartPortMappingLifetimeMeasurement(
- mSession.getLocalProfile(), getKeepAliveInterval());
+ int interval = getKeepAliveInterval();
+ if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) {
+ Log.i(TAG, "keepalive doesn't work with interval "
+ + interval + ", past success count="
+ + mKeepAliveSuccessCount);
+ if (interval > DEFAULT_KEEPALIVE_INTERVAL) {
+ restartPortMappingLifetimeMeasurement(
+ mSession.getLocalProfile(), interval);
+ mKeepAliveSuccessCount = 0;
+ }
+ } else {
+ Log.i(TAG, "keep keepalive going with interval "
+ + interval + ", past success count="
+ + mKeepAliveSuccessCount);
+ mKeepAliveSuccessCount /= 2;
+ }
} else {
// Start keep-alive interval measurement on the first
// successfully kept-alive SipSessionGroup
startPortMappingLifetimeMeasurement(
mSession.getLocalProfile());
+ mKeepAliveSuccessCount++;
}
if (!mRunning || !portChanged) return;
@@ -960,10 +1018,7 @@
}
mTimer.cancel(this);
- if (mKeepAliveSession != null) {
- mKeepAliveSession.stopKeepAliveProcess();
- mKeepAliveSession = null;
- }
+ stopKeepAliveProcess();
mRegistered = false;
setListener(mProxy.getListener());
@@ -975,12 +1030,8 @@
if (DEBUGV) {
Log.v(TAG, "restart keepalive w interval=" + newInterval);
}
- mKeepAliveSession.stopKeepAliveProcess();
- try {
- mKeepAliveSession.startKeepAliveProcess(newInterval, this);
- } catch (SipException e) {
- Log.e(TAG, "onKeepAliveIntervalChanged()", e);
- }
+ mKeepAliveSuccessCount = 0;
+ startKeepAliveProcess(newInterval);
}
}
@@ -1105,14 +1156,7 @@
SipProfile localProfile = mSession.getLocalProfile();
if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp)
|| localProfile.getSendKeepAlive())) {
- mKeepAliveSession = mSession.duplicate();
- Log.d(TAG, "start keepalive");
- try {
- mKeepAliveSession.startKeepAliveProcess(
- getKeepAliveInterval(), this);
- } catch (SipException e) {
- Log.e(TAG, "AutoRegistrationProcess", e);
- }
+ startKeepAliveProcess(getKeepAliveInterval());
}
}
mMyWakeLock.release(session);