Merge "Fix JNI for warning about failure to unlink DeathRecipients"
diff --git a/api/current.txt b/api/current.txt
index dfc17ba..6daf77e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10681,6 +10681,7 @@
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setScreenOnWhilePlaying(boolean);
method public void setTexture(android.graphics.SurfaceTexture);
+ method public void setSurface(android.view.Surface);
method public void setVolume(float, float);
method public void setWakeMode(android.content.Context, int);
method public void start() throws java.lang.IllegalStateException;
@@ -16057,7 +16058,7 @@
public final class ContactsContract {
ctor public ContactsContract();
- field public static final java.lang.String ALLOW_PROFILE = "allow_profile";
+ method public static boolean isProfileId(long);
field public static final java.lang.String AUTHORITY = "com.android.contacts";
field public static final android.net.Uri AUTHORITY_URI;
field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
@@ -16584,6 +16585,16 @@
field public static final android.net.Uri CONTENT_RAW_CONTACTS_URI;
field public static final android.net.Uri CONTENT_URI;
field public static final android.net.Uri CONTENT_VCARD_URI;
+ field public static final long MIN_ID = 9223372034707292160L; // 0x7fffffff80000000L
+ }
+
+ public static final class ContactsContract.ProfileSyncState implements android.provider.SyncStateContract.Columns {
+ method public static byte[] get(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
+ method public static android.util.Pair<android.net.Uri, byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
+ method public static android.content.ContentProviderOperation newSetOperation(android.accounts.Account, byte[]);
+ method public static void set(android.content.ContentProviderClient, android.accounts.Account, byte[]) throws android.os.RemoteException;
+ field public static final java.lang.String CONTENT_DIRECTORY = "syncstate";
+ field public static final android.net.Uri CONTENT_URI;
}
public static final class ContactsContract.QuickContact {
@@ -16682,6 +16693,7 @@
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/status-update";
field public static final android.net.Uri CONTENT_URI;
+ field public static final android.net.Uri PROFILE_CONTENT_URI;
}
public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
@@ -22514,6 +22526,7 @@
}
public class Surface implements android.os.Parcelable {
+ ctor public Surface(android.graphics.SurfaceTexture);
method public int describeContents();
method public boolean isValid();
method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 5321c6a..1f2b342 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -125,19 +125,6 @@
public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
/**
- * An optional URI parameter for selection queries that instructs the
- * provider to allow the user's personal profile contact entry (if any)
- * to appear in a list of contact results. It is only useful when issuing
- * a query that may retrieve more than one contact. If present, the user's
- * profile will always be the first entry returned. The default value is
- * false.
- *
- * Specifying this parameter will result in a security error if the calling
- * application does not have android.permission.READ_PROFILE permission.
- */
- public static final String ALLOW_PROFILE = "allow_profile";
-
- /**
* Query parameter that should be used by the client to access a specific
* {@link Directory}. The parameter value should be the _ID of the corresponding
* directory, e.g.
@@ -557,7 +544,7 @@
}
/**
- * A table provided for sync adapters to use for storing private sync state data.
+ * A table provided for sync adapters to use for storing private sync state data for contacts.
*
* @see SyncStateContract
*/
@@ -608,6 +595,60 @@
}
}
+
+ /**
+ * A table provided for sync adapters to use for storing private sync state data for the
+ * user's personal profile.
+ *
+ * @see SyncStateContract
+ */
+ public static final class ProfileSyncState implements SyncStateContract.Columns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private ProfileSyncState() {}
+
+ public static final String CONTENT_DIRECTORY =
+ SyncStateContract.Constants.CONTENT_DIRECTORY;
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(Profile.CONTENT_URI, CONTENT_DIRECTORY);
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#get
+ */
+ public static byte[] get(ContentProviderClient provider, Account account)
+ throws RemoteException {
+ return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#get
+ */
+ public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account)
+ throws RemoteException {
+ return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#set
+ */
+ public static void set(ContentProviderClient provider, Account account, byte[] data)
+ throws RemoteException {
+ SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#newSetOperation
+ */
+ public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
+ return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
+ }
+ }
+
/**
* Generic columns for use by sync adapters. The specific functions of
* these columns are private to the sync adapter. Other clients of the API
@@ -1875,8 +1916,8 @@
* Constants for the user's profile data, which is represented as a single contact on
* the device that represents the user. The profile contact is not aggregated
* together automatically in the same way that normal contacts are; instead, each
- * account on the device may contribute a single raw contact representing the user's
- * personal profile data from that source.
+ * account (including data set, if applicable) on the device may contribute a single
+ * raw contact representing the user's personal profile data from that source.
* </p>
* <p>
* Access to the profile entry through these URIs (or incidental access to parts of
@@ -1950,6 +1991,31 @@
*/
public static final Uri CONTENT_RAW_CONTACTS_URI = Uri.withAppendedPath(CONTENT_URI,
"raw_contacts");
+
+ /**
+ * The minimum ID for any entity that belongs to the profile. This essentially
+ * defines an ID-space in which profile data is stored, and is used by the provider
+ * to determine whether a request via a non-profile-specific URI should be directed
+ * to the profile data rather than general contacts data, along with all the special
+ * permission checks that entails.
+ *
+ * Callers may use {@link #isProfileId} to check whether a specific ID falls into
+ * the set of data intended for the profile.
+ */
+ public static final long MIN_ID = Long.MAX_VALUE - (long) Integer.MAX_VALUE;
+ }
+
+ /**
+ * This method can be used to identify whether the given ID is associated with profile
+ * data. It does not necessarily indicate that the ID is tied to valid data, merely
+ * that accessing data using this ID will result in profile access checks and will only
+ * return data from the profile.
+ *
+ * @param id The ID to check.
+ * @return Whether the ID is associated with profile data.
+ */
+ public static boolean isProfileId(long id) {
+ return id >= Profile.MIN_ID;
}
protected interface RawContactsColumns {
@@ -4542,6 +4608,12 @@
* either.
* </p>
* <p>
+ * Inserting or updating a status update for the user's profile requires either using
+ * the {@link #DATA_ID} to identify the data row to attach the update to, or
+ * {@link StatusUpdates#PROFILE_CONTENT_URI} to ensure that the change is scoped to the
+ * profile.
+ * </p>
+ * <p>
* You cannot use {@link ContentResolver#update} to change a status, but
* {@link ContentResolver#insert} will replace the latests status if it already
* exists.
@@ -4687,6 +4759,12 @@
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "status_updates");
/**
+ * The content:// style URI for this table, specific to the user's profile.
+ */
+ public static final Uri PROFILE_CONTENT_URI =
+ Uri.withAppendedPath(Profile.CONTENT_URI, "status_updates");
+
+ /**
* Gets the resource ID for the proper presence icon.
*
* @param status the status to get the icon for
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 788711d..e8b2045 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -729,12 +729,22 @@
start - widthStart, end - start);
}
- // If ellipsize is in marquee mode, do not apply ellipsis on the first line
- if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) {
+ if (ellipsize != null) {
+ // If there is only one line, then do any type of ellipsis except when it is MARQUEE
+ // if there are multiple lines, just allow END ellipsis on the last line
+ boolean firstLine = (j == 0);
+ boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
- calculateEllipsis(start, end, widths, widthStart,
- ellipsisWidth, ellipsize, j,
- textWidth, paint, forceEllipsis);
+
+ boolean doEllipsis = (firstLine && !moreChars &&
+ ellipsize != TextUtils.TruncateAt.MARQUEE) ||
+ (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
+ ellipsize == TextUtils.TruncateAt.END);
+ if (doEllipsis) {
+ calculateEllipsis(start, end, widths, widthStart,
+ ellipsisWidth, ellipsize, j,
+ textWidth, paint, forceEllipsis);
+ }
}
mLineCount++;
@@ -797,8 +807,8 @@
ellipsisStart = i;
ellipsisCount = len - i;
- if (forceEllipsis && ellipsisCount == 0 && i > 0) {
- ellipsisStart = i - 1;
+ if (forceEllipsis && ellipsisCount == 0 && len > 0) {
+ ellipsisStart = len - 1;
ellipsisCount = 1;
}
} else {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ef3d3fa5..ae81537 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -36,10 +36,14 @@
public static final int ROTATION_270 = 3;
/**
- * Create Surface from a SurfaceTexture.
+ * Create Surface from a {@link SurfaceTexture}.
*
- * @param surfaceTexture The {@link SurfaceTexture} that is updated by this Surface.
- * @hide
+ * Images drawn to the Surface will be made available to the {@link
+ * SurfaceTexture}, which can attach them an OpenGL ES texture via {@link
+ * SurfaceTexture#updateTexImage}.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
+ * Surface.
*/
public Surface(SurfaceTexture surfaceTexture) {
if (DEBUG_RELEASE) {
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
index ef1906c..1b9a25e 100644
--- a/core/java/android/webkit/HTML5VideoInline.java
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -5,6 +5,7 @@
import android.media.MediaPlayer;
import android.webkit.HTML5VideoView;
import android.webkit.HTML5VideoViewProxy;
+import android.view.Surface;
import android.opengl.GLES20;
/**
@@ -38,7 +39,10 @@
@Override
public void decideDisplayMode() {
- mPlayer.setTexture(getSurfaceTexture(getVideoLayerId()));
+ SurfaceTexture surfaceTexture = getSurfaceTexture(getVideoLayerId());
+ Surface surface = new Surface(surfaceTexture);
+ mPlayer.setSurface(surface);
+ surface.release();
}
// Normally called immediately after setVideoURI. But for full screen,
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
index f3850d5..3a7c1e1 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
@@ -42,11 +42,8 @@
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip"
- android:layout_marginLeft="-10dip"
>
<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
index f4c99f1..c02341e 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
@@ -45,8 +45,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android_layout_marginLeft="-10dip">
+ android:layout_marginBottom="8dip">
<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
top of the other. Hence the redundant layout... -->
diff --git a/core/res/res/values-sw600dp/colors.xml b/core/res/res/values-sw600dp/colors.xml
index 6b5a55a..edd2712 100644
--- a/core/res/res/values-sw600dp/colors.xml
+++ b/core/res/res/values-sw600dp/colors.xml
@@ -21,7 +21,7 @@
<!-- keyguard clock -->
<color name="lockscreen_clock_background">#b3ffffff</color>
<color name="lockscreen_clock_foreground">#7affffff</color>
- <color name="lockscreen_clock_am_pm">#ff9a9a9a</color>
+ <color name="lockscreen_clock_am_pm">#ffffffff</color>
<color name="lockscreen_owner_info">#ff9a9a9a</color>
</resources>
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9acf99b..dd05e61 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -394,14 +394,14 @@
bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
// If the glyph is too tall, don't cache it
- if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
+ if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) {
// Default cache not large enough for large glyphs - resize cache to
// max size and try again
flushAllAndInvalidate();
initTextTexture(true);
}
- if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
+ if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
LOGE("Font size to large to fit in cache. width, height = %i, %i",
(int) glyph.fWidth, (int) glyph.fHeight);
return false;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 66bd56a..1ee9a1f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -381,7 +381,7 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>setTexture </p></td>
+ * <tr><td>setSurface </p></td>
* <td>any </p></td>
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
@@ -608,7 +608,7 @@
* portion of the media.
*
* Either a surface holder or surface must be set if a display or video sink
- * is needed. Not calling this method or {@link #setTexture(SurfaceTexture)}
+ * is needed. Not calling this method or {@link #setSurface(Surface)}
* when playing back a video will result in only the audio track being played.
* A null surface holder or surface will result in only the audio track being
* played.
@@ -629,14 +629,21 @@
/**
* Sets the {@link Surface} to be used as the sink for the video portion of
- * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but does not
- * support {@link #setScreenOnWhilePlaying(boolean)} or {@link #updateSurfaceScreenOn()}.
- * Setting a Surface will un-set any Surface or SurfaceHolder that was previously set.
+ * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but
+ * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a
+ * Surface will un-set any Surface or SurfaceHolder that was previously set.
* A null surface will result in only the audio track being played.
*
- * @param surface The {@link Surface} to be used for the video portion of the media.
+ * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
+ * returned from {@link SurfaceTexture#getTimestamp()} will have an
+ * unspecified zero point. These timestamps cannot be directly compared
+ * between different media sources, different instances of the same media
+ * source, or multiple runs of the same program. The timestamp is normally
+ * monotonically increasing and is unaffected by time-of-day adjustments,
+ * but it is reset when the position is set.
*
- * @hide Pending review by API council.
+ * @param surface The {@link Surface} to be used for the video portion of
+ * the media.
*/
public void setSurface(Surface surface) {
if (mScreenOnWhilePlaying && surface != null) {
diff --git a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java
index 809ee82..f76cf37 100644
--- a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java
+++ b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpView.java
@@ -49,6 +49,7 @@
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.MediaController;
@@ -569,7 +570,9 @@
mSurface = new SurfaceTexture(mTextureID);
mSurface.setOnFrameAvailableListener(this);
- mMediaPlayer.setTexture(mSurface);
+ Surface surface = new Surface(mSurface);
+ mMediaPlayer.setSurface(surface);
+ surface.release();
try {
mMediaPlayer.prepare();
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index e17d98d..6743da0 100755
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -36,6 +36,7 @@
import android.content.res.Resources;
+import java.util.TimeZone;
/**
@@ -231,7 +232,7 @@
public static class TimeStamp extends Time {
public TimeStamp() {
- super(Time.TIMEZONE_UTC);
+ super(TimeZone.getDefault().getID()); // 3GPP2 timestamps use the local timezone
}
public static TimeStamp fromByteArray(byte[] data) {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 3b3cbf3..49effa8 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -72,6 +72,7 @@
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.CSeqHeader;
+import javax.sip.header.ContactHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
@@ -873,16 +874,21 @@
}
private int getExpiryTime(Response response) {
- int expires = EXPIRY_TIME;
- ExpiresHeader expiresHeader = (ExpiresHeader)
- response.getHeader(ExpiresHeader.NAME);
- if (expiresHeader != null) expires = expiresHeader.getExpires();
- expiresHeader = (ExpiresHeader)
- response.getHeader(MinExpiresHeader.NAME);
- if (expiresHeader != null) {
- expires = Math.max(expires, expiresHeader.getExpires());
+ int time = -1;
+ ContactHeader contact = (ContactHeader) response.getHeader(ContactHeader.NAME);
+ if (contact != null) {
+ time = contact.getExpires();
}
- return expires;
+ ExpiresHeader expires = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME);
+ if (expires != null && (time < 0 || time > expires.getExpires())) {
+ time = expires.getExpires();
+ }
+ expires = (ExpiresHeader) response.getHeader(MinExpiresHeader.NAME);
+ if (expires != null && time < expires.getExpires()) {
+ time = expires.getExpires();
+ }
+ Log.v(TAG, "Expiry time = " + time);
+ return (time > 0) ? time : EXPIRY_TIME;
}
private boolean registeringToReady(EventObject evt)