Merge "Settings: Remove unused USE_PTP_INTERFACE setting"
diff --git a/api/14.txt b/api/14.txt
index 5c4732e..050540b 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -22239,7 +22239,6 @@
}
public class AccessibilityRecord {
- ctor protected AccessibilityRecord();
method public int getAddedCount();
method public java.lang.CharSequence getBeforeText();
method public java.lang.CharSequence getClassName();
@@ -22269,17 +22268,6 @@
method public void setParcelableData(android.os.Parcelable);
method public void setPassword(boolean);
method public void setRemovedCount(int);
- field protected int mAddedCount;
- field protected java.lang.CharSequence mBeforeText;
- field protected int mBooleanProperties;
- field protected java.lang.CharSequence mClassName;
- field protected java.lang.CharSequence mContentDescription;
- field protected int mCurrentItemIndex;
- field protected int mFromIndex;
- field protected int mItemCount;
- field protected android.os.Parcelable mParcelableData;
- field protected int mRemovedCount;
- field protected final java.util.List mText;
}
}
diff --git a/api/current.txt b/api/current.txt
index f06df4b..acea3e7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11180,6 +11180,8 @@
method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
method public java.lang.String[] getSupportedCipherSuites();
+ method public void setKeyManagers(javax.net.ssl.KeyManager[]);
+ method public void setTrustManagers(javax.net.ssl.TrustManager[]);
}
public final class SSLSessionCache {
@@ -21606,6 +21608,8 @@
method public void buildDrawingCache();
method public void buildDrawingCache(boolean);
method public void buildLayer();
+ method public boolean canScrollHorizontally(int);
+ method public boolean canScrollVertically(int);
method public void cancelLongPress();
method public boolean checkInputConnectionProxy(android.view.View);
method public void clearAnimation();
@@ -22719,13 +22723,11 @@
method public void appendRecord(android.view.accessibility.AccessibilityRecord);
method public int describeContents();
method public static java.lang.String eventTypeToString(int);
- method public int getAccessibilityWindowId();
method public long getEventTime();
method public int getEventType();
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityRecord getRecord(int);
method public int getRecordCount();
- method public android.view.accessibility.AccessibilityNodeInfo getSource();
method public void initFromParcel(android.os.Parcel);
method public static android.view.accessibility.AccessibilityEvent obtain(int);
method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
@@ -22733,7 +22735,6 @@
method public void setEventTime(long);
method public void setEventType(int);
method public void setPackageName(java.lang.CharSequence);
- method public void setSource(android.view.View);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
@@ -22749,6 +22750,7 @@
field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2
field public static final int TYPE_VIEW_SELECTED = 4; // 0x4
field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
+ field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
field public static final int TYPE_WINDOW_STATE_CHANGED = 32; // 0x20
}
@@ -22776,9 +22778,10 @@
method public void addAction(int);
method public void addChild(android.view.View);
method public int describeContents();
- method public int getAccessibilityWindowId();
+ method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String);
method public int getActions();
- method public void getBounds(android.graphics.Rect);
+ method public void getBoundsInParent(android.graphics.Rect);
+ method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
method public int getChildCount();
method public java.lang.CharSequence getClassName();
@@ -22786,6 +22789,7 @@
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityNodeInfo getParent();
method public java.lang.CharSequence getText();
+ method public int getWindowId();
method public boolean isCheckable();
method public boolean isChecked();
method public boolean isClickable();
@@ -22799,7 +22803,8 @@
method public static android.view.accessibility.AccessibilityNodeInfo obtain();
method public boolean performAction(int);
method public void recycle();
- method public void setBounds(android.graphics.Rect);
+ method public void setBoundsInParent(android.graphics.Rect);
+ method public void setBoundsInScreen(android.graphics.Rect);
method public void setCheckable(boolean);
method public void setChecked(boolean);
method public void setClassName(java.lang.CharSequence);
@@ -22824,7 +22829,6 @@
}
public class AccessibilityRecord {
- ctor protected AccessibilityRecord();
method public int getAddedCount();
method public java.lang.CharSequence getBeforeText();
method public java.lang.CharSequence getClassName();
@@ -22834,7 +22838,9 @@
method public int getItemCount();
method public android.os.Parcelable getParcelableData();
method public int getRemovedCount();
+ method public android.view.accessibility.AccessibilityNodeInfo getSource();
method public java.util.List<java.lang.CharSequence> getText();
+ method public int getWindowId();
method public boolean isChecked();
method public boolean isEnabled();
method public boolean isFullScreen();
@@ -22855,17 +22861,7 @@
method public void setParcelableData(android.os.Parcelable);
method public void setPassword(boolean);
method public void setRemovedCount(int);
- field protected int mAddedCount;
- field protected java.lang.CharSequence mBeforeText;
- field protected int mBooleanProperties;
- field protected java.lang.CharSequence mClassName;
- field protected java.lang.CharSequence mContentDescription;
- field protected int mCurrentItemIndex;
- field protected int mFromIndex;
- field protected int mItemCount;
- field protected android.os.Parcelable mParcelableData;
- field protected int mRemovedCount;
- field protected final java.util.List mText;
+ method public void setSource(android.view.View);
}
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 69c4597..0acba8b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -313,9 +313,6 @@
const GLint yc = (mHeight - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
- // draw and update only what we need
- mFlingerSurface->setSwapRectangle(updateRect);
-
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 01262fa..ca77185 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -66,6 +66,7 @@
static long gMaxNumFrames; // 0 means decode all available.
static long gReproduceBug; // if not -1.
static bool gPreferSoftwareCodec;
+static bool gForceToUseHardwareCodec;
static bool gPlaybackAudio;
static bool gWriteMP4;
static bool gDisplayHistogram;
@@ -144,10 +145,18 @@
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
rawSource = source;
} else {
+ int flags = 0;
+ if (gPreferSoftwareCodec) {
+ flags |= OMXCodec::kPreferSoftwareCodecs;
+ }
+ if (gForceToUseHardwareCodec) {
+ CHECK(!gPreferSoftwareCodec);
+ flags |= OMXCodec::kHardwareCodecsOnly;
+ }
rawSource = OMXCodec::Create(
client->interface(), meta, false /* createEncoder */, source,
NULL /* matchComponentName */,
- gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0,
+ flags,
gSurface);
if (rawSource == NULL) {
@@ -545,6 +554,7 @@
fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n");
fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n");
fprintf(stderr, " -s(oftware) prefer software codec\n");
+ fprintf(stderr, " -r(hardware) force to use hardware codec\n");
fprintf(stderr, " -o playback audio\n");
fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n");
fprintf(stderr, " -k seek test\n");
@@ -566,6 +576,7 @@
gMaxNumFrames = 0;
gReproduceBug = -1;
gPreferSoftwareCodec = false;
+ gForceToUseHardwareCodec = false;
gPlaybackAudio = false;
gWriteMP4 = false;
gDisplayHistogram = false;
@@ -575,7 +586,7 @@
sp<LiveSession> liveSession;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:ptsow:kxS")) >= 0) {
+ while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxS")) >= 0) {
switch (res) {
case 'a':
{
@@ -636,6 +647,12 @@
break;
}
+ case 'r':
+ {
+ gForceToUseHardwareCodec = true;
+ break;
+ }
+
case 'o':
{
gPlaybackAudio = true;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bb305d..164acbc 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -190,9 +190,9 @@
* <li>
* Register for all event types with no notification timeout and keep track
* for the active window by calling
- * {@link AccessibilityEvent#getAccessibilityWindowId()} of the last received
+ * {@link AccessibilityEvent#getWindowId()} of the last received
* event and compare this with the
- * {@link AccessibilityNodeInfo#getAccessibilityWindowId()} before calling
+ * {@link AccessibilityNodeInfo#getWindowId()} before calling
* retrieval methods on the latter.
* </li>
* <li>
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 19f0bf0..8b4e7aee 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -47,7 +47,9 @@
/**
* Finds {@link AccessibilityNodeInfo}s by View text. The match is case
- * insensitive containment.
+ * insensitive containment. The search is performed in the window whose
+ * id is specified and starts from the View whose accessibility id is
+ * specified.
* <p>
* <strong>
* It is a client responsibility to recycle the received infos by
@@ -57,12 +59,35 @@
* </p>
*
* @param text The searched text.
+ * @param accessibilityId The id of the view from which to start searching.
+ * Use {@link android.view.View#NO_ID} to start from the root.
* @return A list of node info.
*/
- List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text);
+ List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
+ int accessibilityWindowId, int accessibilityViewId);
/**
- * Finds an {@link AccessibilityNodeInfo} by View id.
+ * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+ * insensitive containment. The search is performed in the currently
+ * active window and start from the root View in the window.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received infos by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ *
+ * @param text The searched text.
+ * @param accessibilityId The id of the view from which to start searching.
+ * Use {@link android.view.View#NO_ID} to start from the root.
+ * @return A list of node info.
+ */
+ List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(String text);
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
+ * in the currently active window and start from the root View in the window.
* <p>
* <strong>
* It is a client responsibility to recycle the received info by
@@ -74,7 +99,7 @@
* @param id The id of the node.
* @return The node info.
*/
- AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId);
+ AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId);
/**
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 906a564..9bd45d3 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -277,24 +277,24 @@
public int compatSmallestScreenWidthDp;
/**
- * @hide
+ * @hide Do not use. Implementation not finished.
*/
- public static final int LAYOUT_DIRECTION_UNDEFINED = -1;
+ public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;
/**
- * @hide
+ * @hide Do not use. Implementation not finished.
*/
- public static final int LAYOUT_DIRECTION_LTR = 0;
+ public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;
/**
- * @hide
+ * @hide Do not use. Implementation not finished.
*/
- public static final int LAYOUT_DIRECTION_RTL = 1;
+ public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;
/**
- * @hide The layout direction associated to the current Locale
+ * @hide The text layout direction associated to the current Locale
*/
- public int layoutDirection;
+ public int textLayoutDirection;
/**
* @hide Internal book-keeping.
@@ -322,7 +322,7 @@
mnc = o.mnc;
if (o.locale != null) {
locale = (Locale) o.locale.clone();
- layoutDirection = o.layoutDirection;
+ textLayoutDirection = o.textLayoutDirection;
}
userSetLocale = o.userSetLocale;
touchscreen = o.touchscreen;
@@ -358,6 +358,11 @@
} else {
sb.append(" (no locale)");
}
+ switch (textLayoutDirection) {
+ case TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
+ case TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
+ default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
+ }
if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
} else {
@@ -450,11 +455,6 @@
case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
default: sb.append("/"); sb.append(navigationHidden); break;
}
- switch (layoutDirection) {
- case LAYOUT_DIRECTION_UNDEFINED: sb.append(" ?layoutdir"); break;
- case LAYOUT_DIRECTION_LTR: sb.append(" ltr"); break;
- case LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break;
- }
if (seq != 0) {
sb.append(" s.");
sb.append(seq);
@@ -483,8 +483,8 @@
screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+ textLayoutDirection = TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
seq = 0;
- layoutDirection = LAYOUT_DIRECTION_LTR;
}
/** {@hide} */
@@ -519,7 +519,7 @@
changed |= ActivityInfo.CONFIG_LOCALE;
locale = delta.locale != null
? (Locale) delta.locale.clone() : null;
- layoutDirection = getLayoutDirectionFromLocale(locale);
+ textLayoutDirection = getLayoutDirectionFromLocale(locale);
}
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
@@ -611,23 +611,25 @@
/**
* Return the layout direction for a given Locale
* @param locale the Locale for which we want the layout direction. Can be null.
- * @return the layout direction. This may be one of {@link #LAYOUT_DIRECTION_UNDEFINED},
- * {@link #LAYOUT_DIRECTION_LTR} or {@link #LAYOUT_DIRECTION_RTL}.
+ * @return the layout direction. This may be one of:
+ * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
+ * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
+ * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
*
* @hide
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
- if (locale == null || locale.equals(Locale.ROOT)) return LAYOUT_DIRECTION_UNDEFINED;
+ if (locale == null || locale.equals(Locale.ROOT)) return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
// Be careful: this code will need to be changed when vertical scripts will be supported
// OR if ICU4C is updated to have the "likelySubtags" file
switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- return LAYOUT_DIRECTION_LTR;
+ return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return LAYOUT_DIRECTION_RTL;
+ return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
default:
- return LAYOUT_DIRECTION_UNDEFINED;
+ return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
}
}
@@ -810,7 +812,7 @@
dest.writeInt(compatScreenWidthDp);
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
- dest.writeInt(layoutDirection);
+ dest.writeInt(textLayoutDirection);
dest.writeInt(seq);
}
@@ -838,7 +840,7 @@
compatScreenWidthDp = source.readInt();
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
- layoutDirection = source.readInt();
+ textLayoutDirection = source.readInt();
seq = source.readInt();
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index c9238eb..82495e3 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -34,7 +34,7 @@
void registerListener(INetworkPolicyListener listener);
void unregisterListener(INetworkPolicyListener listener);
- void setNetworkPolicy(int networkType, String subscriberId, in NetworkPolicy policy);
- NetworkPolicy getNetworkPolicy(int networkType, String subscriberId);
+ void setNetworkPolicies(in NetworkPolicy[] policies);
+ NetworkPolicy[] getNetworkPolicies();
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index b9909c3..1899281 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -26,17 +26,27 @@
* @hide
*/
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
- public final int cycleDay;
- public final long warningBytes;
- public final long limitBytes;
+ public final int networkTemplate;
+ public final String subscriberId;
+ public int cycleDay;
+ public long warningBytes;
+ public long limitBytes;
- public NetworkPolicy(int cycleDay, long warningBytes, long limitBytes) {
+ public static final long WARNING_DISABLED = -1;
+ public static final long LIMIT_DISABLED = -1;
+
+ public NetworkPolicy(int networkTemplate, String subscriberId, int cycleDay, long warningBytes,
+ long limitBytes) {
+ this.networkTemplate = networkTemplate;
+ this.subscriberId = subscriberId;
this.cycleDay = cycleDay;
this.warningBytes = warningBytes;
this.limitBytes = limitBytes;
}
public NetworkPolicy(Parcel in) {
+ networkTemplate = in.readInt();
+ subscriberId = in.readString();
cycleDay = in.readInt();
warningBytes = in.readLong();
limitBytes = in.readLong();
@@ -44,6 +54,8 @@
/** {@inheritDoc} */
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(networkTemplate);
+ dest.writeString(subscriberId);
dest.writeInt(cycleDay);
dest.writeLong(warningBytes);
dest.writeLong(limitBytes);
@@ -56,17 +68,21 @@
/** {@inheritDoc} */
public int compareTo(NetworkPolicy another) {
- if (another == null || limitBytes < another.limitBytes) {
+ if (another == null || another.limitBytes == LIMIT_DISABLED) {
+ // other value is missing or disabled; we win
return -1;
- } else {
+ }
+ if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) {
+ // we're disabled or other limit is smaller; they win
return 1;
}
+ return 0;
}
@Override
public String toString() {
- return "NetworkPolicy: cycleDay=" + cycleDay + ", warningBytes=" + warningBytes
- + ", limitBytes=" + limitBytes;
+ return "NetworkPolicy: networkTemplate=" + networkTemplate + ", cycleDay=" + cycleDay
+ + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes;
}
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 08b1a81..13ece40 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -55,17 +55,17 @@
}
/** {@hide} */
- public void setNetworkPolicy(int networkType, String subscriberId, NetworkPolicy policy) {
+ public void setNetworkPolicies(NetworkPolicy[] policies) {
try {
- mService.setNetworkPolicy(networkType, subscriberId, policy);
+ mService.setNetworkPolicies(policies);
} catch (RemoteException e) {
}
}
/** {@hide} */
- public NetworkPolicy getNetworkPolicy(int networkType, String subscriberId) {
+ public NetworkPolicy[] getNetworkPolicies() {
try {
- return mService.getNetworkPolicy(networkType, subscriberId);
+ return mService.getNetworkPolicies();
} catch (RemoteException e) {
return null;
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 8e50cd5..5c4b258 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -240,7 +240,6 @@
/**
* Sets the {@link TrustManager}s to be used for connections made by this factory.
- * @hide
*/
public void setTrustManagers(TrustManager[] trustManager) {
mTrustManagers = trustManager;
@@ -253,7 +252,6 @@
/**
* Sets the {@link KeyManager}s to be used for connections made by this factory.
- * @hide
*/
public void setKeyManagers(KeyManager[] keyManagers) {
mKeyManagers = keyManagers;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 8a688d5..3725fa6 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -41,11 +41,9 @@
*/
public final static int UNSUPPORTED = -1;
- // TODO: find better home for these template constants
-
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
- * networks together. Only uses statistics for currently active IMSI.
+ * networks together. Only uses statistics for requested IMSI.
*
* @hide
*/
@@ -54,7 +52,7 @@
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
* networks together that roughly meet a "3G" definition, or lower. Only
- * uses statistics for currently active IMSI.
+ * uses statistics for requested IMSI.
*
* @hide
*/
@@ -63,7 +61,7 @@
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
* networks together that meet a "4G" definition. Only uses statistics for
- * currently active IMSI.
+ * requested IMSI.
*
* @hide
*/
@@ -184,6 +182,17 @@
}
}
+ /** {@hide} */
+ public static boolean isNetworkTemplateMobile(int networkTemplate) {
+ switch (networkTemplate) {
+ case TEMPLATE_MOBILE_3G_LOWER:
+ case TEMPLATE_MOBILE_4G:
+ case TEMPLATE_MOBILE_ALL:
+ return true;
+ }
+ return false;
+ }
+
/**
* Get the total number of packets transmitted through the mobile interface.
*
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index b66035f..aa5937e 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -43,7 +43,6 @@
int formatNdef(int nativeHandle, in byte[] key);
Tag rediscover(int nativehandle);
- void setIsoDepTimeout(int timeout);
- void setFelicaTimeout(int timeout);
+ int setTimeout(int technology, int timeout);
void resetTimeouts();
}
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java
index 38b2bbd..d02086f 100644
--- a/core/java/android/nfc/tech/IsoDep.java
+++ b/core/java/android/nfc/tech/IsoDep.java
@@ -16,6 +16,7 @@
package android.nfc.tech;
+import android.nfc.ErrorCodes;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
@@ -90,7 +91,10 @@
*/
public void setTimeout(int timeout) {
try {
- mTag.getTagService().setIsoDepTimeout(timeout);
+ int err = mTag.getTagService().setTimeout(TagTechnology.ISO_DEP, timeout);
+ if (err != ErrorCodes.SUCCESS) {
+ throw new IllegalArgumentException("The supplied timeout is not valid");
+ }
} catch (RemoteException e) {
Log.e(TAG, "NFC service dead", e);
}
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index c4b7718..5cafe5b 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -16,9 +16,11 @@
package android.nfc.tech;
+import android.nfc.ErrorCodes;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.RemoteException;
+import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -69,6 +71,8 @@
* require the {@link android.Manifest.permission#NFC} permission.
*/
public final class MifareClassic extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
/**
* The default factory key.
*/
@@ -568,6 +572,31 @@
return transceive(data, true);
}
+ /**
+ * Set the timeout of {@link #transceive} in milliseconds.
+ * <p>The timeout only applies to MifareUltralight {@link #transceive},
+ * and is reset to a default value when {@link #close} is called.
+ * <p>Setting a longer timeout may be useful when performing
+ * transactions that require a long processing time on the tag
+ * such as key generation.
+ *
+ * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param timeout timeout value in milliseconds
+ * @hide
+ */
+ // TODO Unhide for ICS
+ public void setTimeout(int timeout) {
+ try {
+ int err = mTag.getTagService().setTimeout(TagTechnology.MIFARE_CLASSIC, timeout);
+ if (err != ErrorCodes.SUCCESS) {
+ throw new IllegalArgumentException("The supplied timeout is not valid");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ }
+ }
+
private static void validateSector(int sector) {
// Do not be too strict on upper bounds checking, since some cards
// have more addressable memory than they report. For example,
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
index 6c2754b..3d4cdd1 100644
--- a/core/java/android/nfc/tech/MifareUltralight.java
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -16,10 +16,12 @@
package android.nfc.tech;
+import android.nfc.ErrorCodes;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.Bundle;
import android.os.RemoteException;
+import android.util.Log;
import java.io.IOException;
@@ -57,6 +59,8 @@
* require the {@link android.Manifest.permission#NFC} permission.
*/
public final class MifareUltralight extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
/** A MIFARE Ultralight compatible tag of unknown type */
public static final int TYPE_UNKNOWN = -1;
/** A MIFARE Ultralight tag */
@@ -208,6 +212,32 @@
return transceive(data, true);
}
+ /**
+ * Set the timeout of {@link #transceive} in milliseconds.
+ * <p>The timeout only applies to MifareUltralight {@link #transceive},
+ * and is reset to a default value when {@link #close} is called.
+ * <p>Setting a longer timeout may be useful when performing
+ * transactions that require a long processing time on the tag
+ * such as key generation.
+ *
+ * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param timeout timeout value in milliseconds
+ * @hide
+ */
+ // TODO Unhide for ICS
+ public void setTimeout(int timeout) {
+ try {
+ int err = mTag.getTagService().setTimeout(
+ TagTechnology.MIFARE_ULTRALIGHT, timeout);
+ if (err != ErrorCodes.SUCCESS) {
+ throw new IllegalArgumentException("The supplied timeout is not valid");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ }
+ }
+
private static void validatePageIndex(int pageIndex) {
// Do not be too strict on upper bounds checking, since some cards
// may have more addressable memory than they report.
diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index 1843eae..08095e6 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -16,9 +16,11 @@
package android.nfc.tech;
+import android.nfc.ErrorCodes;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import android.util.Log;
import java.io.IOException;
@@ -33,6 +35,8 @@
* require the {@link android.Manifest.permission#NFC} permission.
*/
public final class NfcA extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
/** @hide */
public static final String EXTRA_SAK = "sak";
/** @hide */
@@ -112,4 +116,29 @@
public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true);
}
+
+ /**
+ * Set the timeout of {@link #transceive} in milliseconds.
+ * <p>The timeout only applies to NfcA {@link #transceive}, and is
+ * reset to a default value when {@link #close} is called.
+ * <p>Setting a longer timeout may be useful when performing
+ * transactions that require a long processing time on the tag
+ * such as key generation.
+ *
+ * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param timeout timeout value in milliseconds
+ * @hide
+ */
+ // TODO Unhide for ICS
+ public void setTimeout(int timeout) {
+ try {
+ int err = mTag.getTagService().setTimeout(TagTechnology.NFC_A, timeout);
+ if (err != ErrorCodes.SUCCESS) {
+ throw new IllegalArgumentException("The supplied timeout is not valid");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ }
+ }
}
diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java
index 250c9b3..85abf89 100644
--- a/core/java/android/nfc/tech/NfcF.java
+++ b/core/java/android/nfc/tech/NfcF.java
@@ -16,6 +16,7 @@
package android.nfc.tech;
+import android.nfc.ErrorCodes;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
@@ -131,7 +132,10 @@
// TODO Unhide for ICS
public void setTimeout(int timeout) {
try {
- mTag.getTagService().setFelicaTimeout(timeout);
+ int err = mTag.getTagService().setTimeout(TagTechnology.NFC_F, timeout);
+ if (err != ErrorCodes.SUCCESS) {
+ throw new IllegalArgumentException("The supplied timeout is not valid");
+ }
} catch (RemoteException e) {
Log.e(TAG, "NFC service dead", e);
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index bb6ed9c..3b2e6b6 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -178,9 +178,8 @@
* have specific uses which are expected to be consistent by the app and
* sync adapter.
*
- * @hide
*/
- public interface SyncColumns extends CalendarSyncColumns {
+ protected interface SyncColumns extends CalendarSyncColumns {
/**
* The account that was used to sync the entry to the device. If the
* account_type is not {@link #ACCOUNT_TYPE_LOCAL} then the name and
@@ -223,7 +222,7 @@
/**
* If set to 1 this causes events on this calendar to be duplicated with
- * {@link EventsColumns#LAST_SYNCED} set to 1 whenever the event
+ * {@link Events#LAST_SYNCED} set to 1 whenever the event
* transitions from non-dirty to dirty. The duplicated event will not be
* expanded in the instances table and will only show up in sync adapter
* queries of the events table. It will also be deleted when the
@@ -236,7 +235,7 @@
/**
* Columns specific to the Calendars Uri that other Uris can query.
*/
- private interface CalendarsColumns {
+ protected interface CalendarsColumns {
/**
* The color of the calendar
* <P>Type: INTEGER (color value)</P>
@@ -549,7 +548,7 @@
/**
* Columns from the Attendees table that other tables join into themselves.
*/
- private interface AttendeesColumns {
+ protected interface AttendeesColumns {
/**
* The id of the event. Column name.
@@ -639,7 +638,7 @@
/**
* Columns from the Events table that other tables join into themselves.
*/
- private interface EventsColumns {
+ protected interface EventsColumns {
/**
* The {@link Calendars#_ID} of the calendar the event belongs to.
@@ -1525,7 +1524,7 @@
* time zone for the instaces. These settings are stored using a key/value
* scheme.
*/
- private interface CalendarCacheColumns {
+ protected interface CalendarCacheColumns {
/**
* The key for the setting. Keys are defined in {@link CalendarCache}.
*/
@@ -1597,7 +1596,7 @@
* the Instances table and these are all stored in the first (and only)
* row of the CalendarMetaData table.
*/
- private interface CalendarMetaDataColumns {
+ protected interface CalendarMetaDataColumns {
/**
* The local timezone that was used for precomputing the fields
* in the Instances table.
@@ -1637,7 +1636,7 @@
public static final class CalendarMetaData implements CalendarMetaDataColumns, BaseColumns {
}
- private interface EventDaysColumns {
+ protected interface EventDaysColumns {
/**
* The Julian starting day number. Column name.
* <P>Type: INTEGER (int)</P>
@@ -1655,7 +1654,7 @@
* Fields and helpers for querying for a list of days that contain events.
*/
public static final class EventDays implements EventDaysColumns {
- private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/instances/groupbyday");
/**
@@ -1690,7 +1689,7 @@
}
}
- private interface RemindersColumns {
+ protected interface RemindersColumns {
/**
* The event the reminder belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -1755,7 +1754,7 @@
}
}
- private interface CalendarAlertsColumns {
+ protected interface CalendarAlertsColumns {
/**
* The event that the alert belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -2069,7 +2068,7 @@
}
}
- private interface ExtendedPropertiesColumns {
+ protected interface ExtendedPropertiesColumns {
/**
* The event the extended property belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -2128,7 +2127,7 @@
/**
* Columns from the EventsRawTimes table
*/
- private interface EventsRawTimesColumns {
+ protected interface EventsRawTimesColumns {
/**
* The corresponding event id. Column name.
* <P>Type: INTEGER (long)</P>
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index c397af9..376e0bb 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,6 +19,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.CallLog.Calls;
+
/**
* The contract between the voicemail provider and applications. Contains
* definitions for the supported URIs and columns.
@@ -45,13 +46,17 @@
*/
// TODO: unhide when the API is approved by android-api-council
public class VoicemailContract {
+ /** Not instantiable. */
+ private VoicemailContract() {
+ }
+
/** The authority used by the voicemail provider. */
public static final String AUTHORITY = "com.android.voicemail";
/** URI to insert/retrieve all voicemails. */
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/voicemail");
- /** URI to insert/retrieve voicemails by a given voicemai source. */
+ /** URI to insert/retrieve voicemails by a given voicemail source. */
public static final Uri CONTENT_URI_SOURCE =
Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
@@ -72,6 +77,10 @@
"vnd.android.cursor.dir/voicemails";
public static final class Voicemails implements BaseColumns {
+ /** Not instantiable. */
+ private Voicemails() {
+ }
+
/**
* Phone number of the voicemail sender.
* <P>Type: TEXT</P>
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 441cdc1..071905c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3704,7 +3704,8 @@
* The base implementation sets:
* <ul>
* <li>{@link AccessibilityNodeInfo#setParent(View)},</li>
- * <li>{@link AccessibilityNodeInfo#setBounds(Rect)},</li>
+ * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li>
+ * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li>
* <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li>
* <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li>
* <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li>
@@ -3724,7 +3725,12 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
Rect bounds = mAttachInfo.mTmpInvalRect;
getDrawingRect(bounds);
- info.setBounds(bounds);
+ info.setBoundsInParent(bounds);
+
+ int[] locationOnScreen = mAttachInfo.mInvalidateChildLocation;
+ getLocationOnScreen(locationOnScreen);
+ bounds.offset(locationOnScreen[0], locationOnScreen[1]);
+ info.setBoundsInScreen(bounds);
ViewParent parent = getParent();
if (parent instanceof View) {
@@ -8451,6 +8457,40 @@
}
/**
+ * Check if this view can be scrolled horizontally in a certain direction.
+ *
+ * @param direction Negative to check scrolling left, positive to check scrolling right.
+ * @return true if this view can be scrolled in the specified direction, false otherwise.
+ */
+ public boolean canScrollHorizontally(int direction) {
+ final int offset = computeHorizontalScrollOffset();
+ final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent();
+ if (range == 0) return false;
+ if (direction < 0) {
+ return offset > 0;
+ } else {
+ return offset < range - 1;
+ }
+ }
+
+ /**
+ * Check if this view can be scrolled vertically in a certain direction.
+ *
+ * @param direction Negative to check scrolling up, positive to check scrolling down.
+ * @return true if this view can be scrolled in the specified direction, false otherwise.
+ */
+ public boolean canScrollVertically(int direction) {
+ final int offset = computeVerticalScrollOffset();
+ final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
+ if (range == 0) return false;
+ if (direction < 0) {
+ return offset > 0;
+ } else {
+ return offset < range - 1;
+ }
+ }
+
+ /**
* <p>Request the drawing of the horizontal and the vertical scrollbar. The
* scrollbars are painted only if they have been awakened first.</p>
*
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 17d7454..914973e 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -136,6 +136,13 @@
static final ArrayList<ComponentCallbacks> sConfigCallbacks
= new ArrayList<ComponentCallbacks>();
+ /**
+ * Delay before dispatching an accessibility event that the window
+ * content has changed. The window content is considered changed
+ * after a layout pass.
+ */
+ private static final long SEND_WINDOW_CONTENT_CHANGED_DELAY_MILLIS = 500;
+
long mLastTrackballTime = 0;
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -277,6 +284,8 @@
AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
+ SendWindowContentChanged mSendWindowContentChanged;
+
private final int mDensity;
/**
@@ -1427,6 +1436,10 @@
if (triggerGlobalLayoutListener) {
attachInfo.mRecomputeGlobalAttributes = false;
attachInfo.mTreeObserver.dispatchOnGlobalLayout();
+
+ if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
+ postSendWindowContentChangedCallback();
+ }
}
if (computesInternalInsets) {
@@ -2086,6 +2099,7 @@
mAccessibilityInteractionConnectionManager.ensureNoConnection();
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
+ removeSendWindowContentChangedCallback();
mView = null;
mAttachInfo.mRootView = null;
@@ -3671,6 +3685,29 @@
}
}
+ /**
+ * Post a callback to send a
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
+ */
+ private void postSendWindowContentChangedCallback() {
+ if (mSendWindowContentChanged == null) {
+ mSendWindowContentChanged = new SendWindowContentChanged();
+ } else {
+ removeCallbacks(mSendWindowContentChanged);
+ }
+ postDelayed(mSendWindowContentChanged, SEND_WINDOW_CONTENT_CHANGED_DELAY_MILLIS);
+ }
+
+ /**
+ * Remove a posted callback to send a
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
+ */
+ private void removeSendWindowContentChangedCallback() {
+ if (mSendWindowContentChanged != null) {
+ removeCallbacks(mSendWindowContentChanged);
+ }
+ }
+
public boolean showContextMenuForChild(View originalView) {
return false;
}
@@ -4268,12 +4305,12 @@
}
}
- public void findAccessibilityNodeInfosByViewText(String text, int interactionId,
- IAccessibilityInteractionConnectionCallback callback) {
+ public void findAccessibilityNodeInfosByViewText(String text, int accessibilityId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
if (mViewAncestor.get() != null) {
getAccessibilityInteractionController()
- .findAccessibilityNodeInfosByViewTextClientThread(text, interactionId,
- callback);
+ .findAccessibilityNodeInfosByViewTextClientThread(text, accessibilityId,
+ interactionId, callback);
}
}
}
@@ -4414,13 +4451,15 @@
}
}
- public void findAccessibilityNodeInfosByViewTextClientThread(String text, int interactionId,
+ public void findAccessibilityNodeInfosByViewTextClientThread(String text,
+ int accessibilityViewId, int interactionId,
IAccessibilityInteractionConnectionCallback callback) {
Message message = Message.obtain();
message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT;
SomeArgs args = mPool.acquire();
args.arg1 = text;
- args.argi1 = interactionId;
+ args.argi1 = accessibilityViewId;
+ args.argi2 = interactionId;
args.arg2 = callback;
message.obj = args;
sendMessage(message);
@@ -4429,18 +4468,28 @@
public void findAccessibilityNodeInfosByViewTextUiThread(Message message) {
SomeArgs args = (SomeArgs) message.obj;
final String text = (String) args.arg1;
- final int interactionId = args.argi1;
+ final int accessibilityViewId = args.argi1;
+ final int interactionId = args.argi2;
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg2;
mPool.release(args);
List<AccessibilityNodeInfo> infos = null;
try {
- View root = ViewAncestor.this.mView;
-
ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
foundViews.clear();
+ View root = null;
+ if (accessibilityViewId != View.NO_ID) {
+ root = findViewByAccessibilityId(accessibilityViewId);
+ } else {
+ root = ViewAncestor.this.mView;
+ }
+
+ if (root == null) {
+ return;
+ }
+
root.findViewsWithText(foundViews, text);
if (foundViews.isEmpty()) {
return;
@@ -4577,4 +4626,12 @@
}
}
}
+
+ private class SendWindowContentChanged implements Runnable {
+ public void run() {
+ if (mView != null) {
+ mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ }
+ }
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 06e4827..5ef7763 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -19,11 +19,10 @@
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import android.text.TextUtils;
-import android.view.View;
import java.util.ArrayList;
+import java.util.List;
/**
* This class represents accessibility events that are sent by the system when
@@ -130,7 +129,7 @@
* <p>
* <b>TRANSITION TYPES</b> <br>
* <p>
- * <b>Window state changed</b> - represents the event of opening/closing a
+ * <b>Window state changed</b> - represents the event of opening a
* {@link android.widget.PopupWindow}, {@link android.view.Menu},
* {@link android.app.Dialog}, etc. <br>
* Type: {@link #TYPE_WINDOW_STATE_CHANGED} <br>
@@ -140,6 +139,16 @@
* {@link #getEventTime()},
* {@link #getText()}
* <p>
+ * <b>Window content changed</b> - represents the event of change in the
+ * content of a window. This change can be adding/removing view, changing
+ * a view size, etc.<br>
+ * Type: {@link #TYPE_WINDOW_CONTENT_CHANGED} <br>
+ * Properties:
+ * {@link #getClassName()},
+ * {@link #getPackageName()},
+ * {@link #getEventTime()},
+ * {@link #getText()}
+ * <p>
* <b>NOTIFICATION TYPES</b> <br>
* <p>
* <b>Notification state changed</b> - represents the event showing/hiding
@@ -244,6 +253,11 @@
public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
/**
+ * Represents the event of changing the content of a window.
+ */
+ public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
+
+ /**
* Mask for {@link AccessibilityEvent} all types.
*
* @see #TYPE_VIEW_CLICKED
@@ -264,15 +278,11 @@
private boolean mIsInPool;
private int mEventType;
- private int mSourceAccessibilityViewId = View.NO_ID;
- private int mSourceAccessibilityWindowId = View.NO_ID;
private CharSequence mPackageName;
private long mEventTime;
private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
- private IAccessibilityServiceConnection mConnection;
-
/*
* Hide constructor from clients.
*/
@@ -288,10 +298,43 @@
super.init(event);
mEventType = event.mEventType;
mEventTime = event.mEventTime;
- mSourceAccessibilityWindowId = event.mSourceAccessibilityWindowId;
- mSourceAccessibilityViewId = event.mSourceAccessibilityViewId;
mPackageName = event.mPackageName;
- mConnection = event.mConnection;
+ }
+
+ /**
+ * Sets the connection for interacting with the AccessibilityManagerService.
+ *
+ * @param connection The connection.
+ *
+ * @hide
+ */
+ @Override
+ public void setConnection(IAccessibilityServiceConnection connection) {
+ super.setConnection(connection);
+ List<AccessibilityRecord> records = mRecords;
+ final int recordCount = records.size();
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = records.get(i);
+ record.setConnection(connection);
+ }
+ }
+
+ /**
+ * Sets if this instance is sealed.
+ *
+ * @param sealed Whether is sealed.
+ *
+ * @hide
+ */
+ @Override
+ public void setSealed(boolean sealed) {
+ super.setSealed(sealed);
+ List<AccessibilityRecord> records = mRecords;
+ final int recordCount = records.size();
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = records.get(i);
+ record.setSealed(sealed);
+ }
}
/**
@@ -335,81 +378,6 @@
}
/**
- * Sets the event source.
- *
- * @param source The source.
- *
- * @throws IllegalStateException If called from an AccessibilityService.
- */
- public void setSource(View source) {
- enforceNotSealed();
- if (source != null) {
- mSourceAccessibilityWindowId = source.getAccessibilityWindowId();
- mSourceAccessibilityViewId = source.getAccessibilityViewId();
- } else {
- mSourceAccessibilityWindowId = View.NO_ID;
- mSourceAccessibilityViewId = View.NO_ID;
- }
- }
-
- /**
- * Gets the {@link AccessibilityNodeInfo} of the event source.
- * <p>
- * <strong>
- * It is a client responsibility to recycle the received info by
- * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
- * of multiple instances.
- * </strong>
- * </p>
- * @return The info.
- */
- public AccessibilityNodeInfo getSource() {
- enforceSealed();
- if (mSourceAccessibilityWindowId == View.NO_ID
- || mSourceAccessibilityViewId == View.NO_ID) {
- return null;
- }
- try {
- return mConnection.findAccessibilityNodeInfoByAccessibilityId(
- mSourceAccessibilityWindowId, mSourceAccessibilityViewId);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Gets the id of the window from which the event comes from.
- *
- * @return The window id.
- */
- public int getAccessibilityWindowId() {
- return mSourceAccessibilityWindowId;
- }
-
- /**
- * Sets the client token for the accessibility service that
- * provided this node info.
- *
- * @param connection The connection.
- *
- * @hide
- */
- public final void setConnection(IAccessibilityServiceConnection connection) {
- mConnection = connection;
- }
-
- /**
- * Gets the accessibility window id of the source window.
- *
- * @return The id.
- *
- * @hide
- */
- public int getSourceAccessibilityWindowId() {
- return mSourceAccessibilityWindowId;
- }
-
- /**
* Sets the event type.
*
* @param eventType The event type.
@@ -548,10 +516,7 @@
@Override
protected void clear() {
super.clear();
- mConnection = null;
mEventType = 0;
- mSourceAccessibilityViewId = View.NO_ID;
- mSourceAccessibilityWindowId = View.NO_ID;
mPackageName = null;
mEventTime = 0;
while (!mRecords.isEmpty()) {
@@ -572,8 +537,6 @@
}
setSealed(parcel.readInt() == 1);
mEventType = parcel.readInt();
- mSourceAccessibilityWindowId = parcel.readInt();
- mSourceAccessibilityViewId = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
readAccessibilityRecordFromParcel(this, parcel);
@@ -583,6 +546,8 @@
for (int i = 0; i < recordCount; i++) {
AccessibilityRecord record = AccessibilityRecord.obtain();
readAccessibilityRecordFromParcel(record, parcel);
+ // Do this to write the connection only once.
+ record.setConnection(mConnection);
mRecords.add(record);
}
}
@@ -606,6 +571,9 @@
record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
record.mParcelableData = parcel.readParcelable(null);
parcel.readList(record.mText, null);
+ record.mSourceWindowId = parcel.readInt();
+ record.mSourceViewId = parcel.readInt();
+ record.mSealed = (parcel.readInt() == 1);
}
/**
@@ -620,8 +588,6 @@
}
parcel.writeInt(isSealed() ? 1 : 0);
parcel.writeInt(mEventType);
- parcel.writeInt(mSourceAccessibilityWindowId);
- parcel.writeInt(mSourceAccessibilityViewId);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
writeAccessibilityRecordToParcel(this, parcel, flags);
@@ -654,6 +620,9 @@
TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
parcel.writeParcelable(record.mParcelableData, flags);
parcel.writeList(record.mText);
+ parcel.writeInt(record.mSourceWindowId);
+ parcel.writeInt(record.mSourceViewId);
+ parcel.writeInt(record.mSealed ? 1 : 0);
}
/**
@@ -672,8 +641,8 @@
builder.append(super.toString());
if (DEBUG) {
builder.append("\n");
- builder.append("; sourceAccessibilityWindowId: ").append(mSourceAccessibilityWindowId);
- builder.append("; sourceAccessibilityViewId: ").append(mSourceAccessibilityViewId);
+ builder.append("; sourceWindowId: ").append(mSourceWindowId);
+ builder.append("; sourceViewId: ").append(mSourceViewId);
for (int i = 0; i < mRecords.size(); i++) {
AccessibilityRecord record = mRecords.get(i);
builder.append(" Record ");
@@ -733,6 +702,8 @@
return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
case TYPE_TOUCH_EXPLORATION_GESTURE_END:
return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
+ case TYPE_WINDOW_CONTENT_CHANGED:
+ return "TYPE_WINDOW_CONTENT_CHANGED";
default:
return null;
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5fa65b4..18ef38a 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -26,6 +26,9 @@
import android.util.SparseIntArray;
import android.view.View;
+import java.util.Collections;
+import java.util.List;
+
/**
* This class represents a node of the screen content. From the point of
* view of an accessibility service the screen content is presented as tree
@@ -97,7 +100,8 @@
private int mAccessibilityWindowId = View.NO_ID;
private int mParentAccessibilityViewId = View.NO_ID;
private int mBooleanProperties;
- private final Rect mBounds = new Rect();
+ private final Rect mBoundsInParent = new Rect();
+ private final Rect mBoundsInScreen = new Rect();
private CharSequence mPackageName;
private CharSequence mClassName;
@@ -132,7 +136,7 @@
*
* @return The window id.
*/
- public int getAccessibilityWindowId() {
+ public int getWindowId() {
return mAccessibilityWindowId;
}
@@ -163,12 +167,16 @@
public AccessibilityNodeInfo getChild(int index) {
enforceSealed();
final int childAccessibilityViewId = mChildAccessibilityIds.get(index);
+ if (!canPerformRequestOverConnection(childAccessibilityViewId)) {
+ return null;
+ }
try {
return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
childAccessibilityViewId);
- } catch (RemoteException e) {
- return null;
+ } catch (RemoteException re) {
+ /* ignore*/
}
+ return null;
}
/**
@@ -230,12 +238,37 @@
*/
public boolean performAction(int action) {
enforceSealed();
+ if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
+ return false;
+ }
try {
return mConnection.performAccessibilityAction(mAccessibilityWindowId,
mAccessibilityViewId, action);
} catch (RemoteException e) {
- return false;
+ /* ignore */
}
+ return false;
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by text. The match is case
+ * insensitive containment.
+ *
+ * @param text The searched text.
+ * @return A list of node info.
+ */
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
+ enforceSealed();
+ if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
+ return null;
+ }
+ try {
+ return mConnection.findAccessibilityNodeInfosByViewText(text, mAccessibilityWindowId,
+ mAccessibilityViewId);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ return Collections.emptyList();
}
/**
@@ -251,12 +284,16 @@
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
- try {
- return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
- mParentAccessibilityViewId);
- } catch (RemoteException e) {
+ if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
return null;
}
+ try {
+ return mConnection.findAccessibilityNodeInfoByAccessibilityId(
+ mAccessibilityWindowId, mParentAccessibilityViewId);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ return null;
}
/**
@@ -279,8 +316,9 @@
*
* @param outBounds The output node bounds.
*/
- public void getBounds(Rect outBounds) {
- outBounds.set(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
+ public void getBoundsInParent(Rect outBounds) {
+ outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
+ mBoundsInParent.right, mBoundsInParent.bottom);
}
/**
@@ -293,9 +331,34 @@
*
* @throws IllegalStateException If called from an AccessibilityService.
*/
- public void setBounds(Rect bounds) {
+ public void setBoundsInParent(Rect bounds) {
enforceNotSealed();
- mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ }
+
+ /**
+ * Gets the node bounds in screen coordinates.
+ *
+ * @param outBounds The output node bounds.
+ */
+ public void getBoundsInScreen(Rect outBounds) {
+ outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
+ mBoundsInScreen.right, mBoundsInScreen.bottom);
+ }
+
+ /**
+ * Sets the node bounds in screen coordinates.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param bounds The node bounds.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setBoundsInScreen(Rect bounds) {
+ enforceNotSealed();
+ mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
/**
@@ -636,6 +699,7 @@
* @hide
*/
public final void setConnection(IAccessibilityServiceConnection connection) {
+ enforceNotSealed();
mConnection = connection;
}
@@ -777,10 +841,15 @@
parcel.writeInt(childIds.valueAt(i));
}
- parcel.writeInt(mBounds.top);
- parcel.writeInt(mBounds.bottom);
- parcel.writeInt(mBounds.left);
- parcel.writeInt(mBounds.right);
+ parcel.writeInt(mBoundsInParent.top);
+ parcel.writeInt(mBoundsInParent.bottom);
+ parcel.writeInt(mBoundsInParent.left);
+ parcel.writeInt(mBoundsInParent.right);
+
+ parcel.writeInt(mBoundsInScreen.top);
+ parcel.writeInt(mBoundsInScreen.bottom);
+ parcel.writeInt(mBoundsInScreen.left);
+ parcel.writeInt(mBoundsInScreen.right);
parcel.writeInt(mActions);
@@ -818,10 +887,15 @@
childIds.put(i, childId);
}
- mBounds.top = parcel.readInt();
- mBounds.bottom = parcel.readInt();
- mBounds.left = parcel.readInt();
- mBounds.right = parcel.readInt();
+ mBoundsInParent.top = parcel.readInt();
+ mBoundsInParent.bottom = parcel.readInt();
+ mBoundsInParent.left = parcel.readInt();
+ mBoundsInParent.right = parcel.readInt();
+
+ mBoundsInScreen.top = parcel.readInt();
+ mBoundsInScreen.bottom = parcel.readInt();
+ mBoundsInScreen.left = parcel.readInt();
+ mBoundsInScreen.right = parcel.readInt();
mActions = parcel.readInt();
@@ -842,7 +916,8 @@
mAccessibilityViewId = View.NO_ID;
mParentAccessibilityViewId = View.NO_ID;
mChildAccessibilityIds.clear();
- mBounds.set(0, 0, 0, 0);
+ mBoundsInParent.set(0, 0, 0, 0);
+ mBoundsInScreen.set(0, 0, 0, 0);
mBooleanProperties = 0;
mPackageName = null;
mClassName = null;
@@ -869,6 +944,12 @@
return actionSymbolicNames.get(action);
}
+ private boolean canPerformRequestOverConnection(int accessibilityViewId) {
+ return (mAccessibilityWindowId != View.NO_ID
+ && accessibilityViewId != View.NO_ID
+ && mConnection != null);
+ }
+
@Override
public boolean equals(Object object) {
if (this == object) {
@@ -918,7 +999,8 @@
builder.append("]");
}
- builder.append("; bounds: " + mBounds);
+ builder.append("; boundsInParent: " + mBoundsInParent);
+ builder.append("; boundsInScreen: " + mBoundsInScreen);
builder.append("; packageName: ").append(mPackageName);
builder.append("; className: ").append(mClassName);
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 4bf03a7..9c495e21 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -16,7 +16,10 @@
package android.view.accessibility;
+import android.accessibilityservice.IAccessibilityServiceConnection;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.view.View;
import java.util.ArrayList;
import java.util.List;
@@ -45,26 +48,29 @@
private static int sPoolSize;
private AccessibilityRecord mNext;
private boolean mIsInPool;
- private boolean mSealed;
- protected int mBooleanProperties;
- protected int mCurrentItemIndex;
- protected int mItemCount;
- protected int mFromIndex;
- protected int mAddedCount;
- protected int mRemovedCount;
+ boolean mSealed;
+ int mBooleanProperties;
+ int mCurrentItemIndex;
+ int mItemCount;
+ int mFromIndex;
+ int mAddedCount;
+ int mRemovedCount;
+ int mSourceViewId = View.NO_ID;
+ int mSourceWindowId = View.NO_ID;
- protected CharSequence mClassName;
- protected CharSequence mContentDescription;
- protected CharSequence mBeforeText;
- protected Parcelable mParcelableData;
+ CharSequence mClassName;
+ CharSequence mContentDescription;
+ CharSequence mBeforeText;
+ Parcelable mParcelableData;
- protected final List<CharSequence> mText = new ArrayList<CharSequence>();
+ final List<CharSequence> mText = new ArrayList<CharSequence>();
+ IAccessibilityServiceConnection mConnection;
/*
* Hide constructor.
*/
- protected AccessibilityRecord() {
+ AccessibilityRecord() {
}
@@ -74,7 +80,7 @@
* @param record The to initialize from.
*/
void init(AccessibilityRecord record) {
- mSealed = record.isSealed();
+ mSealed = record.mSealed;
mBooleanProperties = record.mBooleanProperties;
mCurrentItemIndex = record.mCurrentItemIndex;
mItemCount = record.mItemCount;
@@ -86,6 +92,73 @@
mBeforeText = record.mBeforeText;
mParcelableData = record.mParcelableData;
mText.addAll(record.mText);
+ mSourceWindowId = record.mSourceWindowId;
+ mSourceViewId = record.mSourceViewId;
+ mConnection = record.mConnection;
+ }
+
+ /**
+ * Sets the event source.
+ *
+ * @param source The source.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setSource(View source) {
+ enforceNotSealed();
+ if (source != null) {
+ mSourceWindowId = source.getAccessibilityWindowId();
+ mSourceViewId = source.getAccessibilityViewId();
+ } else {
+ mSourceWindowId = View.NO_ID;
+ mSourceViewId = View.NO_ID;
+ }
+ }
+
+ /**
+ * Gets the {@link AccessibilityNodeInfo} of the event source.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ * @return The info.
+ */
+ public AccessibilityNodeInfo getSource() {
+ enforceSealed();
+ if (mSourceWindowId == View.NO_ID || mSourceViewId == View.NO_ID || mConnection == null) {
+ return null;
+ }
+ try {
+ return mConnection.findAccessibilityNodeInfoByAccessibilityId(mSourceWindowId,
+ mSourceViewId);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ return null;
+ }
+
+ /**
+ * Sets the connection for interacting with the AccessibilityManagerService.
+ *
+ * @param connection The connection.
+ *
+ * @hide
+ */
+ public void setConnection(IAccessibilityServiceConnection connection) {
+ enforceNotSealed();
+ mConnection = connection;
+ }
+
+ /**
+ * Gets the id of the window from which the event comes from.
+ *
+ * @return The window id.
+ */
+ public int getWindowId() {
+ return mSourceWindowId;
}
/**
@@ -386,10 +459,8 @@
* Gets if this instance is sealed.
*
* @return Whether is sealed.
- *
- * @hide
*/
- public boolean isSealed() {
+ boolean isSealed() {
return mSealed;
}
@@ -397,10 +468,8 @@
* Enforces that this instance is sealed.
*
* @throws IllegalStateException If this instance is not sealed.
- *
- * @hide
*/
- protected void enforceSealed() {
+ void enforceSealed() {
if (!isSealed()) {
throw new IllegalStateException("Cannot perform this "
+ "action on a not sealed instance.");
@@ -411,10 +480,8 @@
* Enforces that this instance is not sealed.
*
* @throws IllegalStateException If this instance is sealed.
- *
- * @hide
*/
- protected void enforceNotSealed() {
+ void enforceNotSealed() {
if (isSealed()) {
throw new IllegalStateException("Cannot perform this "
+ "action on an sealed instance.");
@@ -502,10 +569,8 @@
/**
* Clears the state of this instance.
- *
- * @hide
*/
- protected void clear() {
+ void clear() {
mSealed = false;
mBooleanProperties = 0;
mCurrentItemIndex = INVALID_POSITION;
@@ -518,6 +583,8 @@
mBeforeText = null;
mParcelableData = null;
mText.clear();
+ mSourceViewId = View.NO_ID;
+ mSourceWindowId = View.NO_ID;
}
@Override
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 77dcd07..d35186b 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -33,8 +33,8 @@
void findAccessibilityNodeInfoByViewId(int id, int interactionId,
IAccessibilityInteractionConnectionCallback callback);
- void findAccessibilityNodeInfosByViewText(String text, int interactionId,
- IAccessibilityInteractionConnectionCallback callback);
+ void findAccessibilityNodeInfosByViewText(String text, int accessibilityViewId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback);
void performAccessibilityAction(int accessibilityId, int action, int interactionId,
IAccessibilityInteractionConnectionCallback callback);
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 44229a4..4cae9d8 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -253,18 +253,19 @@
mLayout.setVisibility(View.VISIBLE);
WebChromeClient client = webView.getWebChromeClient();
- client.onShowCustomView(mLayout, mCallback);
- // Plugins like Flash will draw over the video so hide
- // them while we're playing.
- if (webView.getViewManager() != null)
- webView.getViewManager().hideAll();
+ if (client != null) {
+ client.onShowCustomView(mLayout, mCallback);
+ // Plugins like Flash will draw over the video so hide
+ // them while we're playing.
+ if (webView.getViewManager() != null)
+ webView.getViewManager().hideAll();
- mProgressView = client.getVideoLoadingProgressView();
- if (mProgressView != null) {
- mLayout.addView(mProgressView, layoutParams);
- mProgressView.setVisibility(View.VISIBLE);
+ mProgressView = client.getVideoLoadingProgressView();
+ if (mProgressView != null) {
+ mLayout.addView(mProgressView, layoutParams);
+ mProgressView.setVisibility(View.VISIBLE);
+ }
}
-
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 95e4880..bfab8a9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1395,6 +1395,10 @@
*/
public int getVisibleTitleHeight() {
checkThread();
+ return getVisibleTitleHeightImpl();
+ }
+
+ private int getVisibleTitleHeightImpl() {
// need to restrict mScrollY due to over scroll
return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
}
@@ -1405,7 +1409,7 @@
* Note: this can be called from WebCoreThread.
*/
/* package */ int getViewHeight() {
- return getViewHeightWithTitle() - getVisibleTitleHeight();
+ return getViewHeightWithTitle() - getVisibleTitleHeightImpl();
}
int getViewHeightWithTitle() {
@@ -2768,7 +2772,7 @@
// the visible height back in to account for the fact that if the title
// bar is partially visible, the part of the visible rect which is
// displaying our content is displaced by that amount.
- r.top = viewToContentY(r.top + getVisibleTitleHeight());
+ r.top = viewToContentY(r.top + getVisibleTitleHeightImpl());
r.right = viewToContentX(r.right);
r.bottom = viewToContentY(r.bottom);
}
@@ -2785,7 +2789,7 @@
// the visible height back in to account for the fact that if the title
// bar is partially visible, the part of the visible rect which is
// displaying our content is displaced by that amount.
- r.top = viewToContentYf(ri.top + getVisibleTitleHeight());
+ r.top = viewToContentYf(ri.top + getVisibleTitleHeightImpl());
r.right = viewToContentXf(ri.right);
r.bottom = viewToContentYf(ri.bottom);
}
@@ -2934,7 +2938,7 @@
if (mScrollY < 0) {
t -= mScrollY;
}
- scrollBar.setBounds(l, t + getVisibleTitleHeight(), r, b);
+ scrollBar.setBounds(l, t + getVisibleTitleHeightImpl(), r, b);
scrollBar.draw(canvas);
}
@@ -5179,7 +5183,7 @@
Rect rect = nativeCursorNodeBounds();
mSelectX = contentToViewX(rect.left);
mSelectY = contentToViewY(rect.top);
- } else if (mLastTouchY > getVisibleTitleHeight()) {
+ } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
mSelectX = mScrollX + mLastTouchX;
mSelectY = mScrollY + mLastTouchY;
} else {
@@ -5497,7 +5501,7 @@
int rootViewHeight = rootView.getHeight();
mViewRectViewport.set(mGLRectViewport);
int savedWebViewBottom = mGLRectViewport.bottom;
- mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
+ mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeightImpl();
mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
mGLViewportEmpty = false;
} else {
@@ -5554,7 +5558,7 @@
if (!mInOverScrollMode) {
sendOurVisibleRect();
// update WebKit if visible title bar height changed. The logic is same
- // as getVisibleTitleHeight.
+ // as getVisibleTitleHeightImpl.
int titleHeight = getTitleHeight();
if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
sendViewSizeZoom(false);
@@ -5605,8 +5609,8 @@
* Adjustable parameters. Angle is the radians on a unit circle, limited
* to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical)
*/
- private static final float HSLOPE_TO_START_SNAP = .1f;
- private static final float HSLOPE_TO_BREAK_SNAP = .2f;
+ private static final float HSLOPE_TO_START_SNAP = .25f;
+ private static final float HSLOPE_TO_BREAK_SNAP = .4f;
private static final float VSLOPE_TO_START_SNAP = 1.25f;
private static final float VSLOPE_TO_BREAK_SNAP = .95f;
/*
@@ -5617,6 +5621,11 @@
*/
private static final float ANGLE_VERT = 2f;
private static final float ANGLE_HORIZ = 0f;
+ /*
+ * The modified moving average weight.
+ * Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n
+ */
+ private static final float MMA_WEIGHT_N = 5;
private boolean hitFocusedPlugin(int contentX, int contentY) {
if (DebugFlags.WEB_VIEW) {
@@ -6003,8 +6012,9 @@
if (deltaX == 0 && deltaY == 0) {
keepScrollBarsVisible = done = true;
} else {
- mAverageAngle = (mAverageAngle +
- calculateDragAngle(deltaX, deltaY)) / 2;
+ mAverageAngle +=
+ (calculateDragAngle(deltaX, deltaY) - mAverageAngle)
+ / MMA_WEIGHT_N;
if (mSnapScrollMode != SNAP_NONE) {
if (mSnapScrollMode == SNAP_Y) {
// radical change means getting out of snap mode
@@ -8318,7 +8328,7 @@
(Math.min(maxHeight, y + viewHeight) - viewHeight));
// We need to take into account the visible title height
// when scrolling since y is an absolute view position.
- y = Math.max(0, y - getVisibleTitleHeight());
+ y = Math.max(0, y - getVisibleTitleHeightImpl());
scrollTo(x, y);
}
break;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 82dd5db..3fe8149 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -55,7 +55,6 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c4d05e9..755d4e0 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -904,8 +904,10 @@
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Add a record for ourselves as well.
AccessibilityEvent record = AccessibilityEvent.obtain();
+ record.setSource(this);
// Set the class since it is not populated in #dispatchPopulateAccessibilityEvent
record.setClassName(getClass().getName());
+ child.onInitializeAccessibilityEvent(record);
child.dispatchPopulateAccessibilityEvent(record);
event.appendRecord(record);
return true;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index bda82a3..092c2f7 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -494,6 +494,14 @@
requestLayout();
}
+ private static int max2(int[] a, int valueIfEmpty) {
+ int result = valueIfEmpty;
+ for (int i = 0, N = a.length; i < N; i++) {
+ result = Math.max(result, a[i]);
+ }
+ return result;
+ }
+
private static int sum(float[] a) {
int result = 0;
for (int i = 0, length = a.length; i < length; i++) {
@@ -1409,7 +1417,7 @@
// External entry points
private int size(int[] locations) {
- return locations[locations.length - 1] - locations[0];
+ return max2(locations, 0) - locations[0];
}
private int getMin() {
@@ -1878,21 +1886,13 @@
return result;
}
- private static int max(int[] a, int valueIfEmpty) {
- int result = valueIfEmpty;
- for (int i = 0, length = a.length; i < length; i++) {
- result = Math.max(result, a[i]);
- }
- return result;
- }
-
/*
Create a compact array of keys or values using the supplied index.
*/
private static <K> K[] compact(K[] a, int[] index) {
int size = a.length;
Class<?> componentType = a.getClass().getComponentType();
- K[] result = (K[]) Array.newInstance(componentType, max(index, -1) + 1);
+ K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
// this overwrite duplicates, retaining the last equivalent entry
for (int i = 0; i < size; i++) {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 40b0a9c..4c47d37 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -711,6 +711,17 @@
requestBindService();
}
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mWorkerThread != null) {
+ mWorkerThread.quit();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
private void loadNextIndexInBackground() {
mWorkerQueue.post(new Runnable() {
@Override
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 5c6a26f..b7565f3 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -387,7 +387,7 @@
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
- if (hitThumb(x, y)) {
+ if (isEnabled() && hitThumb(x, y)) {
mTouchMode = TOUCH_MODE_DOWN;
mTouchX = x;
mTouchY = y;
@@ -460,7 +460,8 @@
*/
private void stopDrag(MotionEvent ev) {
mTouchMode = TOUCH_MODE_IDLE;
- boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP;
+ // Up and not canceled, also checks the switch has not been disabled during the drag
+ boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
cancelSuperTouch(ev);
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 18d6caa..860a08c 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -54,6 +54,8 @@
*/
public static void main(String[] args) {
try {
+ // Tell the Zygote what our actual PID is (since it only knows about the
+ // wrapper that it directly forked).
int fdNum = Integer.parseInt(args[0], 10);
if (fdNum != 0) {
try {
@@ -67,6 +69,10 @@
}
}
+ // Mimic Zygote preloading.
+ ZygoteInit.preload();
+
+ // Launch the application.
String[] runtimeArgs = new String[args.length - 1];
System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length);
RuntimeInit.wrapperInit(runtimeArgs);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 157c0bf..b4a7e52 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -228,6 +228,11 @@
}
}
+ static void preload() {
+ preloadClasses();
+ preloadResources();
+ }
+
/**
* Performs Zygote process initialization. Loads and initializes
* commonly used classes.
@@ -509,8 +514,7 @@
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
- preloadClasses();
- preloadResources();
+ preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 246c0e5..0c5101f 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -31,7 +31,7 @@
#include <media/AudioTrack.h>
#include <system/audio.h>
-#include <hardware/audio_policy.h>
+#include <system/audio_policy.h>
// ----------------------------------------------------------------------------
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 3260616..99d534c 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -29,6 +29,7 @@
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -49,6 +50,9 @@
*/
public class InterrogationActivityTest
extends ActivityInstrumentationTestCase2<InterrogationActivity> {
+ private static final boolean DEBUG = true;
+
+ private static String LOG_TAG = "InterrogationActivityTest";
// Timeout before give up wait for the system to process an accessibility setting change.
private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
@@ -62,7 +66,7 @@
private static IAccessibilityServiceConnection sConnection;
// The last received accessibility event
- private static volatile AccessibilityEvent sLastAccessibilityEvent;
+ private static volatile AccessibilityEvent sLastFocusAccessibilityEvent;
public InterrogationActivityTest() {
super(InterrogationActivity.class);
@@ -72,18 +76,19 @@
@LargeTest
public void testFindAccessibilityNodeInfoByViewId() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertNotNull(button);
assertEquals(0, button.getChildCount());
// bounds
Rect bounds = new Rect();
- button.getBounds(bounds);
+ button.getBoundsInParent(bounds);
assertEquals(0, bounds.left);
assertEquals(0, bounds.top);
assertEquals(73, bounds.right);
@@ -111,28 +116,40 @@
button.getActions());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewId: "
+ + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testFindAccessibilityNodeInfoByViewText() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view by text
List<AccessibilityNodeInfo> buttons =
- getConnection().findAccessibilityNodeInfosByViewText("butto");
+ getConnection().findAccessibilityNodeInfosByViewTextInActiveWindow("butto");
assertEquals(9, buttons.size());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewText: "
+ + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testTraverseAllViews() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
@@ -153,8 +170,8 @@
classNameAndTextList.add("android.widget.ButtonButton8");
classNameAndTextList.add("android.widget.ButtonButton9");
- AccessibilityNodeInfo root = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.root);
+ AccessibilityNodeInfo root =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
assertNotNull("We must find the existing root.", root);
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -181,125 +198,152 @@
}
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testPerformAccessibilityActionFocus() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testPerformAccessibilityActionFocus: " + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testPerformAccessibilityActionClearFocus() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
// unfocus the view
assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
// find the view again and make sure it is not focused
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testPerformAccessibilityActionClearFocus: "
+ + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testPerformAccessibilityActionSelect() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testPerformAccessibilityActionSelect: " + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testPerformAccessibilityActionClearSelection() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
// unselect the view
assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
// find the view again and make sure it is not selected
- button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testPerformAccessibilityActionClearSelection: "
+ + elapsedTimeMillis + "ms");
+ }
}
}
@LargeTest
public void testAccessibilityEventGetSource() throws Exception {
beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
try {
// bring up the activity
getActivity();
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
- R.id.button5);
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// focus the view
@@ -314,14 +358,14 @@
}
// check that last event source
- AccessibilityNodeInfo source = sLastAccessibilityEvent.getSource();
+ AccessibilityNodeInfo source = sLastFocusAccessibilityEvent.getSource();
assertNotNull(source);
// bounds
Rect buttonBounds = new Rect();
- button.getBounds(buttonBounds);
+ button.getBoundsInParent(buttonBounds);
Rect sourceBounds = new Rect();
- source.getBounds(sourceBounds);
+ source.getBoundsInParent(sourceBounds);
assertEquals(buttonBounds.left, sourceBounds.left);
assertEquals(buttonBounds.right, sourceBounds.right);
@@ -346,6 +390,42 @@
assertSame(button.isChecked(), source.isChecked());
} finally {
afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testAccessibilityEventGetSource: " + elapsedTimeMillis + "ms");
+ }
+ }
+ }
+
+ @LargeTest
+ public void testObjectContract() throws Exception {
+ beforeClassIfNeeded();
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not focused
+ AccessibilityNodeInfo button =
+ getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+ AccessibilityNodeInfo parent = button.getParent();
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ AccessibilityNodeInfo child = parent.getChild(i);
+ assertNotNull(child);
+ if (child.equals(button)) {
+ assertEquals("Equal objects must have same hasCode.", button.hashCode(),
+ child.hashCode());
+ return;
+ }
+ }
+ fail("Parent's children do not have the info whose parent is the parent.");
+ } finally {
+ afterClassIfNeeded();
+ if (DEBUG) {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ Log.i(LOG_TAG, "testObjectContract: " + elapsedTimeMillis + "ms");
+ }
}
}
@@ -442,7 +522,9 @@
public void onInterrupt() {}
public void onAccessibilityEvent(AccessibilityEvent event) {
- sLastAccessibilityEvent = AccessibilityEvent.obtain(event);
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
+ sLastFocusAccessibilityEvent = AccessibilityEvent.obtain(event);
+ }
synchronized (sConnection) {
sConnection.notifyAll();
}
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index f1f745e..54a5e4e 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -30,169 +30,169 @@
args = {Locale.class}
)
public void testGetLayoutDirectionFromLocale() {
- assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(null));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.ENGLISH));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.CANADA));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.FRANCE));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.FRENCH));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.GERMAN));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.GERMANY));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.ITALIAN));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.ITALY));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.UK));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.US));
- assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.ROOT));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.CHINA));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.CHINESE));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.JAPAN));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.JAPANESE));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.KOREA));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.KOREAN));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.PRC));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.TAIWAN));
- assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE));
Locale locale = new Locale("ar");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "AE");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "BH");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "DZ");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "EG");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "IQ");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "JO");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "KW");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "LB");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "LY");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "MA");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "OM");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "QA");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "SA");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "SD");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "SY");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "TN");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ar", "YE");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("fa");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("fa", "AF");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("fa", "IR");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("iw");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("iw", "IL");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("he");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("he", "IL");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
// The following test will not pass until we are able to take care about the scrip subtag
// thru having the "likelySubTags" file into ICU4C
// locale = new Locale("pa_Arab");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
// locale = new Locale("pa_Arab", "PK");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ps");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
locale = new Locale("ps", "AF");
- assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+ assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
Configuration.getLayoutDirectionFromLocale(locale));
// The following test will not work as the localized display name would be "Urdu" with ICU 4.4
// We will need ICU 4.6 to get the correct localized display name
// locale = new Locale("ur");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
// locale = new Locale("ur", "IN");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
// locale = new Locale("ur", "PK");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
// The following test will not pass until we are able to take care about the scrip subtag
// thru having the "likelySubTags" file into ICU4C
// locale = new Locale("uz_Arab");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
// locale = new Locale("uz_Arab", "AF");
-// assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+// assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
// Configuration.getLayoutDirectionFromLocale(locale));
}
}
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2b31462..9294df6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -188,6 +188,11 @@
status_t setBufferCountServerLocked(int bufferCount);
+ // computeCurrentTransformMatrix computes the transform matrix for the
+ // current texture. It uses mCurrentTransform and the current GraphicBuffer
+ // to compute this matrix and stores it in mCurrentTransformMatrix.
+ void computeCurrentTransformMatrix();
+
enum { INVALID_BUFFER_SLOT = -1 };
struct BufferSlot {
@@ -288,9 +293,9 @@
// by calling setBufferCount or setBufferCountServer
int mBufferCount;
- // mRequestedBufferCount is the number of buffer slots requested by the
- // client. The default is zero, which means the client doesn't care how
- // many buffers there is.
+ // mClientBufferCount is the number of buffer slots requested by the client.
+ // The default is zero, which means the client doesn't care how many buffers
+ // there is.
int mClientBufferCount;
// mServerBufferCount buffer count requested by the server-side
@@ -322,6 +327,11 @@
// gets set to mLastQueuedTransform each time updateTexImage is called.
uint32_t mCurrentTransform;
+ // mCurrentTransformMatrix is the transform matrix for the current texture.
+ // It gets computed by computeTransformMatrix each time updateTexImage is
+ // called.
+ float mCurrentTransformMatrix[16];
+
// mCurrentTimestamp is the timestamp for the current texture. It
// gets set to mLastQueuedTimestamp each time updateTexImage is called.
int64_t mCurrentTimestamp;
@@ -362,6 +372,7 @@
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
+
};
// ----------------------------------------------------------------------------
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 68cd188..89213b7 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -22,7 +22,7 @@
#include <media/IAudioFlinger.h>
#include <system/audio.h>
-#include <hardware/audio_policy.h>
+#include <system/audio_policy.h>
/* XXX: Should be include by all the users instead */
#include <media/AudioParameter.h>
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 09b2bfe..0fc8dbf 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -26,7 +26,7 @@
#include <binder/IInterface.h>
#include <media/AudioSystem.h>
-#include <hardware/audio_policy.h>
+#include <system/audio_policy.h>
namespace android {
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 4044c5d..deade5e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -55,6 +55,7 @@
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
kKeyTime = 'time', // int64_t (usecs)
+ kKeyDecodingTime = 'decT', // int64_t (decoding timestamp in usecs)
kKeyNTPTime = 'ntpT', // uint64_t (ntp-timestamp)
kKeyTargetTime = 'tarT', // int64_t (usecs)
kKeyDriftTime = 'dftT', // int64_t (usecs)
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 70daafa..589cefd 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -202,6 +202,10 @@
bool mOnlySubmitOneBufferAtOneTime;
bool mEnableGrallocUsageProtected;
+ // Used to record the decoding time for an output picture from
+ // a video encoder.
+ List<int64_t> mDecodingTimeList;
+
OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
bool isEncoder, const char *mime, const char *componentName,
const sp<MediaSource> &source,
@@ -317,6 +321,8 @@
status_t applyRotation();
+ int64_t retrieveDecodingTimeUs(bool isCodecSpecific);
+
OMXCodec(const OMXCodec &);
OMXCodec &operator=(const OMXCodec &);
};
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 717f837..0da03d1 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -20,355 +20,12 @@
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/compiler.h>
-
#include <utils/Debug.h>
-#include <utils/threads.h>
-#include <utils/String8.h>
-
-#include <ui/Rect.h>
namespace android {
// ---------------------------------------------------------------------------
-/*
- * These classes manage a stack of buffers in shared memory.
- *
- * SharedClient: represents a client with several stacks
- * SharedBufferStack: represents a stack of buffers
- * SharedBufferClient: manipulates the SharedBufferStack from the client side
- * SharedBufferServer: manipulates the SharedBufferStack from the server side
- *
- * Buffers can be dequeued until there are none available, they can be locked
- * unless they are in use by the server, which is only the case for the last
- * dequeue-able buffer. When these various conditions are not met, the caller
- * waits until the condition is met.
- *
- */
-
-// ----------------------------------------------------------------------------
-
-class Region;
-class SharedBufferStack;
-class SharedClient;
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferStack
-{
- friend class SharedClient;
- friend class SharedBufferBase;
- friend class SharedBufferClient;
- friend class SharedBufferServer;
-
-public:
- // When changing these values, the COMPILE_TIME_ASSERT at the end of this
- // file need to be updated.
- static const unsigned int NUM_LAYERS_MAX = 31;
- static const unsigned int NUM_BUFFER_MAX = 32;
- static const unsigned int NUM_BUFFER_MIN = 2;
- static const unsigned int NUM_DISPLAY_MAX = 4;
-
- struct Statistics { // 4 longs
- typedef int32_t usecs_t;
- usecs_t totalTime;
- usecs_t reserved[3];
- };
-
- struct SmallRect {
- uint16_t l, t, r, b;
- };
-
- struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
- static const unsigned int NUM_RECT_MAX = 5;
- uint32_t count;
- SmallRect rects[NUM_RECT_MAX];
- };
-
- struct BufferData {
- FlatRegion dirtyRegion;
- SmallRect crop;
- uint8_t transform;
- uint8_t reserved[3];
- };
-
- SharedBufferStack();
- void init(int32_t identity);
- status_t setDirtyRegion(int buffer, const Region& reg);
- status_t setCrop(int buffer, const Rect& reg);
- status_t setTransform(int buffer, uint8_t transform);
- Region getDirtyRegion(int buffer) const;
- Rect getCrop(int buffer) const;
- uint32_t getTransform(int buffer) const;
-
- // these attributes are part of the conditions/updates
- volatile int32_t head; // server's current front buffer
- volatile int32_t available; // number of dequeue-able buffers
- volatile int32_t queued; // number of buffers waiting for post
- volatile int32_t reserved1;
- volatile status_t status; // surface's status code
-
- // not part of the conditions
- volatile int32_t reallocMask;
- volatile int8_t index[NUM_BUFFER_MAX];
-
- int32_t identity; // surface's identity (const)
- int32_t token; // surface's token (for debugging)
- Statistics stats;
- int8_t headBuf; // last retired buffer
- uint8_t reservedBytes[3];
- int32_t reserved;
- BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes
-};
-
-// ----------------------------------------------------------------------------
-
-// 64 KB max
-class SharedClient
-{
-public:
- SharedClient();
- ~SharedClient();
- status_t validate(size_t token) const;
-
-private:
- friend class SharedBufferBase;
- friend class SharedBufferClient;
- friend class SharedBufferServer;
-
- // FIXME: this should be replaced by a lock-less primitive
- Mutex lock;
- Condition cv;
- SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
-};
-
-// ============================================================================
-
-class SharedBufferBase
-{
-public:
- SharedBufferBase(SharedClient* sharedClient, int surface,
- int32_t identity);
- ~SharedBufferBase();
- status_t getStatus() const;
- int32_t getIdentity() const;
- String8 dump(char const* prefix) const;
-
-protected:
- SharedClient* const mSharedClient;
- SharedBufferStack* const mSharedStack;
- const int mIdentity;
-
- friend struct Update;
- friend struct QueueUpdate;
-
- struct ConditionBase {
- SharedBufferStack& stack;
- inline ConditionBase(SharedBufferBase* sbc)
- : stack(*sbc->mSharedStack) { }
- virtual ~ConditionBase() { };
- virtual bool operator()() const = 0;
- virtual const char* name() const = 0;
- };
- status_t waitForCondition(const ConditionBase& condition);
-
- struct UpdateBase {
- SharedBufferStack& stack;
- inline UpdateBase(SharedBufferBase* sbb)
- : stack(*sbb->mSharedStack) { }
- };
- template <typename T>
- status_t updateCondition(T update);
-};
-
-template <typename T>
-status_t SharedBufferBase::updateCondition(T update) {
- SharedClient& client( *mSharedClient );
- Mutex::Autolock _l(client.lock);
- ssize_t result = update();
- client.cv.broadcast();
- return result;
-}
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferClient : public SharedBufferBase
-{
-public:
- SharedBufferClient(SharedClient* sharedClient, int surface, int num,
- int32_t identity);
-
- ssize_t dequeue();
- status_t undoDequeue(int buf);
-
- status_t lock(int buf);
- status_t cancel(int buf);
- status_t queue(int buf);
- bool needNewBuffer(int buffer) const;
- status_t setDirtyRegion(int buffer, const Region& reg);
- status_t setCrop(int buffer, const Rect& reg);
- status_t setTransform(int buffer, uint32_t transform);
-
- class SetBufferCountCallback {
- friend class SharedBufferClient;
- virtual status_t operator()(int bufferCount) const = 0;
- protected:
- virtual ~SetBufferCountCallback() { }
- };
- status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
-
-private:
- friend struct Condition;
- friend struct DequeueCondition;
- friend struct LockCondition;
-
- struct QueueUpdate : public UpdateBase {
- inline QueueUpdate(SharedBufferBase* sbb);
- inline ssize_t operator()();
- };
-
- struct DequeueUpdate : public UpdateBase {
- inline DequeueUpdate(SharedBufferBase* sbb);
- inline ssize_t operator()();
- };
-
- struct CancelUpdate : public UpdateBase {
- int tail, buf;
- inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf);
- inline ssize_t operator()();
- };
-
- // --
-
- struct DequeueCondition : public ConditionBase {
- inline DequeueCondition(SharedBufferClient* sbc);
- inline bool operator()() const;
- inline const char* name() const { return "DequeueCondition"; }
- };
-
- struct LockCondition : public ConditionBase {
- int buf;
- inline LockCondition(SharedBufferClient* sbc, int buf);
- inline bool operator()() const;
- inline const char* name() const { return "LockCondition"; }
- };
-
- int32_t computeTail() const;
-
- mutable RWLock mLock;
- int mNumBuffers;
-
- int32_t tail;
- int32_t queued_head;
- // statistics...
- nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
-};
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferServer
- : public SharedBufferBase,
- public LightRefBase<SharedBufferServer>
-{
-public:
- SharedBufferServer(SharedClient* sharedClient, int surface, int num,
- int32_t identity);
-
- ssize_t retireAndLock();
- void setStatus(status_t status);
- status_t reallocateAll();
- status_t reallocateAllExcept(int buffer);
- int32_t getQueuedCount() const;
- Region getDirtyRegion(int buffer) const;
- Rect getCrop(int buffer) const;
- uint32_t getTransform(int buffer) const;
-
- status_t resize(int newNumBuffers);
- status_t grow(int newNumBuffers);
- status_t shrink(int newNumBuffers);
-
- SharedBufferStack::Statistics getStats() const;
-
-
-private:
- friend class LightRefBase<SharedBufferServer>;
- ~SharedBufferServer();
-
- /*
- * BufferList is basically a fixed-capacity sorted-vector of
- * unsigned 5-bits ints using a 32-bits int as storage.
- * it has efficient iterators to find items in the list and not in the list.
- */
- class BufferList {
- size_t mCapacity;
- uint32_t mList;
- public:
- BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
- : mCapacity(c), mList(0) { }
- status_t add(int value);
- status_t remove(int value);
- uint32_t getMask() const { return mList; }
-
- class const_iterator {
- friend class BufferList;
- uint32_t mask, curr;
- const_iterator(uint32_t mask) :
- mask(mask), curr(__builtin_clz(mask)) {
- }
- public:
- inline bool operator == (const const_iterator& rhs) const {
- return mask == rhs.mask;
- }
- inline bool operator != (const const_iterator& rhs) const {
- return mask != rhs.mask;
- }
- inline int operator *() const { return curr; }
- inline const const_iterator& operator ++() {
- mask &= ~(1<<(31-curr));
- curr = __builtin_clz(mask);
- return *this;
- }
- };
-
- inline const_iterator begin() const {
- return const_iterator(mList);
- }
- inline const_iterator end() const {
- return const_iterator(0);
- }
- inline const_iterator free_begin() const {
- uint32_t mask = (1 << (32-mCapacity)) - 1;
- return const_iterator( ~(mList | mask) );
- }
- };
-
- // this protects mNumBuffers and mBufferList
- mutable RWLock mLock;
- int mNumBuffers;
- BufferList mBufferList;
-
- struct BuffersAvailableCondition : public ConditionBase {
- int mNumBuffers;
- inline BuffersAvailableCondition(SharedBufferServer* sbs,
- int numBuffers);
- inline bool operator()() const;
- inline const char* name() const { return "BuffersAvailableCondition"; }
- };
-
- struct RetireUpdate : public UpdateBase {
- const int numBuffers;
- inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
- inline ssize_t operator()();
- };
-
- struct StatusUpdate : public UpdateBase {
- const status_t status;
- inline StatusUpdate(SharedBufferBase* sbb, status_t status);
- inline ssize_t operator()();
- };
-};
-
-// ===========================================================================
+#define NUM_DISPLAY_MAX 4
struct display_cblk_t
{
@@ -389,12 +46,11 @@
uint8_t connected;
uint8_t reserved[3];
uint32_t pad[7];
- display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX];
+ display_cblk_t displays[NUM_DISPLAY_MAX];
};
// ---------------------------------------------------------------------------
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 65536)
COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
// ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
index 01e4bd9..e1b6b57 100644
--- a/include/surfaceflinger/IGraphicBufferAlloc.h
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -27,6 +27,8 @@
namespace android {
// ----------------------------------------------------------------------------
+class GraphicBuffer;
+
class IGraphicBufferAlloc : public IInterface
{
public:
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index cd0ee40..5fdf234 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -27,42 +27,23 @@
#include <ui/PixelFormat.h>
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-
namespace android {
typedef int32_t SurfaceID;
-class GraphicBuffer;
+class ISurfaceTexture;
class ISurface : public IInterface
{
protected:
enum {
- RESERVED0 = IBinder::FIRST_CALL_TRANSACTION,
- RESERVED1,
- RESERVED2,
- REQUEST_BUFFER,
- SET_BUFFER_COUNT,
+ GET_SURFACE_TEXTURE = IBinder::FIRST_CALL_TRANSACTION,
};
public:
DECLARE_META_INTERFACE(Surface);
- /*
- * requests a new buffer for the given index. If w, h, or format are
- * null the buffer is created with the parameters assigned to the
- * surface it is bound to. Otherwise the buffer's parameters are
- * set to those specified.
- */
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
-
- /*
- * sets the number of buffers dequeuable for this surface.
- */
- virtual status_t setBufferCount(int bufferCount) = 0;
+ virtual sp<ISurfaceTexture> getSurfaceTexture() const = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index dea1b10..03fd01b 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -33,6 +33,8 @@
namespace android {
// ----------------------------------------------------------------------------
+class IMemoryHeap;
+
class ISurfaceComposer : public IInterface
{
public:
@@ -95,10 +97,6 @@
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;
- /* create a client connection with surface flinger
- */
- virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
-
/* create a graphic buffer allocator
*/
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
@@ -134,11 +132,6 @@
virtual status_t turnElectronBeamOff(int32_t mode) = 0;
virtual status_t turnElectronBeamOn(int32_t mode) = 0;
- /* Signal surfaceflinger that there might be some work to do
- * This is an ASYNCHRONOUS call.
- */
- virtual void signal() const = 0;
-
/* verify that an ISurface was created by SurfaceFlinger.
*/
virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
@@ -154,7 +147,6 @@
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- CREATE_CLIENT_CONNECTION,
CREATE_GRAPHIC_BUFFER_ALLOC,
GET_CBLK,
OPEN_GLOBAL_TRANSACTION,
@@ -162,7 +154,6 @@
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
- SIGNAL,
CAPTURE_SCREEN,
TURN_ELECTRON_BEAM_OFF,
TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 46b1bb7..2e75a0e 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -33,9 +33,6 @@
// ----------------------------------------------------------------------------
-class IMemoryHeap;
-
-typedef int32_t ClientID;
typedef int32_t DisplayID;
// ----------------------------------------------------------------------------
@@ -57,9 +54,6 @@
status_t writeToParcel(Parcel* parcel) const;
};
- virtual sp<IMemoryHeap> getControlBlock() const = 0;
- virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0;
-
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index ab30f45..8845dc9 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -43,9 +43,7 @@
class Rect;
class Surface;
class SurfaceComposerClient;
-class SharedClient;
-class SharedBufferClient;
-class SurfaceClient;
+class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@@ -162,9 +160,6 @@
status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
status_t unlockAndPost();
- // setSwapRectangle() is intended to be used by GL ES clients
- void setSwapRectangle(const Rect& r);
-
sp<IBinder> asBinder() const;
private:
@@ -209,6 +204,7 @@
static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
+ int setSwapInterval(int interval);
int dequeueBuffer(ANativeWindowBuffer** buffer);
int lockBuffer(ANativeWindowBuffer* buffer);
int queueBuffer(ANativeWindowBuffer* buffer);
@@ -216,83 +212,23 @@
int query(int what, int* value) const;
int perform(int operation, va_list args);
- void dispatch_setUsage(va_list args);
- int dispatch_connect(va_list args);
- int dispatch_disconnect(va_list args);
- int dispatch_crop(va_list args);
- int dispatch_set_buffer_count(va_list args);
- int dispatch_set_buffers_geometry(va_list args);
- int dispatch_set_buffers_transform(va_list args);
- int dispatch_set_buffers_timestamp(va_list args);
-
- void setUsage(uint32_t reqUsage);
- int connect(int api);
- int disconnect(int api);
- int crop(Rect const* rect);
- int setBufferCount(int bufferCount);
- int setBuffersGeometry(int w, int h, int format);
- int setBuffersTransform(int transform);
- int setBuffersTimestamp(int64_t timestamp);
-
/*
* private stuff...
*/
void init();
status_t validate(bool inCancelBuffer = false) const;
- // When the buffer pool is a fixed size we want to make sure SurfaceFlinger
- // won't stall clients, so we require an extra buffer.
- enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-
- inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
- inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-
- status_t getBufferLocked(int index,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
- int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
-
int getConnectedApi() const;
- bool needNewBuffer(int bufIdx,
- uint32_t *pWidth, uint32_t *pHeight,
- uint32_t *pFormat, uint32_t *pUsage) const;
-
static void cleanCachedSurfacesLocked();
- class BufferInfo {
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
- uint32_t mUsage;
- mutable uint32_t mDirty;
- enum {
- GEOMETRY = 0x01
- };
- public:
- BufferInfo();
- void set(uint32_t w, uint32_t h, uint32_t format);
- void set(uint32_t usage);
- void get(uint32_t *pWidth, uint32_t *pHeight,
- uint32_t *pFormat, uint32_t *pUsage) const;
- bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
- };
-
// constants
- GraphicBufferMapper& mBufferMapper;
- SurfaceClient& mClient;
- SharedBufferClient* mSharedBufferClient;
status_t mInitCheck;
sp<ISurface> mSurface;
+ sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
-
- // protected by mSurfaceLock
- Rect mSwapRectangle;
- int mConnected;
- Rect mNextBufferCrop;
- uint32_t mNextBufferTransform;
- BufferInfo mBufferInfo;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
@@ -304,9 +240,6 @@
mutable Region mOldDirtyRegion;
bool mReserved;
- // only used from dequeueBuffer()
- Vector< sp<GraphicBuffer> > mBuffers;
-
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index c61a5bf..140b9f8 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -36,10 +36,10 @@
// ---------------------------------------------------------------------------
-class Region;
-class SharedClient;
-class ISurfaceComposer;
class DisplayInfo;
+class IMemoryHeap;
+class ISurfaceComposer;
+class Region;
class surface_flinger_cblk_t;
// ---------------------------------------------------------------------------
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
new file mode 100644
index 0000000..8f76d72
--- /dev/null
+++ b/include/utils/BlobCache.h
@@ -0,0 +1,181 @@
+/*
+ ** Copyright 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 ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs. All the public
+// methods are thread-safe.
+//
+// The cache contents can be serialized to a file and reloaded in a subsequent
+// execution of the program. This serialization is non-portable and should only
+// be loaded by the device that generated it.
+class BlobCache : public RefBase {
+public:
+
+ // Create an empty blob cache. The blob cache will cache key/value pairs
+ // with key and value sizes less than or equal to maxKeySize and
+ // maxValueSize, respectively. The total combined size of ALL cache entries
+ // (key sizes plus value sizes) will not exceed maxTotalSize.
+ BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+ // set inserts a new binary value into the cache and associates it with the
+ // given binary key. If the key or value are too large for the cache then
+ // the cache remains unchanged. This includes the case where a different
+ // value was previously associated with the given key - the old value will
+ // remain in the cache. If the given key and value are small enough to be
+ // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+ // values specified to the BlobCache constructor), then the key/value pair
+ // will be in the cache after set returns. Note, however, that a subsequent
+ // call to set may evict old key/value pairs from the cache.
+ //
+ // Preconditions:
+ // key != NULL
+ // 0 < keySize
+ // value != NULL
+ // 0 < valueSize
+ void set(const void* key, size_t keySize, const void* value,
+ size_t valueSize);
+
+ // The get function retrieves from the cache the binary value associated
+ // with a given binary key. If the key is present in the cache then the
+ // length of the binary value associated with that key is returned. If the
+ // value argument is non-NULL and the size of the cached value is less than
+ // valueSize bytes then the cached value is copied into the buffer pointed
+ // to by the value argument. If the key is not present in the cache then 0
+ // is returned and the buffer pointed to by the value argument is not
+ // modified.
+ //
+ // Note that when calling get multiple times with the same key, the later
+ // calls may fail, returning 0, even if earlier calls succeeded. The return
+ // value must be checked for each call.
+ //
+ // Preconditions:
+ // key != NULL
+ // 0 < keySize
+ // 0 <= valueSize
+ size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+private:
+ // Copying is disallowed.
+ BlobCache(const BlobCache&);
+ void operator=(const BlobCache&);
+
+ // clean evicts a randomly chosen set of entries from the cache such that
+ // the total size of all remaining entries is less than mMaxTotalSize/2.
+ void clean();
+
+ // isCleanable returns true if the cache is full enough for the clean method
+ // to have some effect, and false otherwise.
+ bool isCleanable() const;
+
+ // A Blob is an immutable sized unstructured data blob.
+ class Blob : public RefBase {
+ public:
+ Blob(const void* data, size_t size, bool copyData);
+ ~Blob();
+
+ bool operator<(const Blob& rhs) const;
+
+ const void* getData() const;
+ size_t getSize() const;
+
+ private:
+ // Copying is not allowed.
+ Blob(const Blob&);
+ void operator=(const Blob&);
+
+ // mData points to the buffer containing the blob data.
+ const void* mData;
+
+ // mSize is the size of the blob data in bytes.
+ size_t mSize;
+
+ // mOwnsData indicates whether or not this Blob object should free the
+ // memory pointed to by mData when the Blob gets destructed.
+ bool mOwnsData;
+ };
+
+ // A CacheEntry is a single key/value pair in the cache.
+ class CacheEntry {
+ public:
+ CacheEntry();
+ CacheEntry(const sp<Blob>& key, const sp<Blob>& value);
+ CacheEntry(const CacheEntry& ce);
+
+ bool operator<(const CacheEntry& rhs) const;
+ const CacheEntry& operator=(const CacheEntry&);
+
+ sp<Blob> getKey() const;
+ sp<Blob> getValue() const;
+
+ void setValue(const sp<Blob>& value);
+
+ private:
+
+ // mKey is the key that identifies the cache entry.
+ sp<Blob> mKey;
+
+ // mValue is the cached data associated with the key.
+ sp<Blob> mValue;
+ };
+
+ // mMaxKeySize is the maximum key size that will be cached. Calls to
+ // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+ // simply not add the key/value pair to the cache.
+ const size_t mMaxKeySize;
+
+ // mMaxValueSize is the maximum value size that will be cached. Calls to
+ // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+ // simply not add the key/value pair to the cache.
+ const size_t mMaxValueSize;
+
+ // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+ // includes space for both keys and values. When a call to BlobCache::set
+ // would otherwise cause this limit to be exceeded, either the key/value
+ // pair passed to BlobCache::set will not be cached or other cache entries
+ // will be evicted from the cache to make room for the new entry.
+ const size_t mMaxTotalSize;
+
+ // mTotalSize is the total combined size of all keys and values currently in
+ // the cache.
+ size_t mTotalSize;
+
+ // mRandState is the pseudo-random number generator state. It is passed to
+ // nrand48 to generate random numbers when needed. It must be protected by
+ // mMutex.
+ unsigned short mRandState[3];
+
+ // mCacheEntries stores all the cache entries that are resident in memory.
+ // Cache entries are added to it by the 'set' method.
+ SortedVector<CacheEntry> mCacheEntries;
+
+ // mMutex is used to synchronize access to all member variables. It must be
+ // locked any time the member variables are written or read.
+ Mutex mMutex;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 4126225..f8c3216 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -116,17 +116,23 @@
typedef RefBase basetype;
+ // used to override the RefBase destruction.
+ class Destroyer {
+ friend class RefBase;
+ public:
+ virtual ~Destroyer();
+ private:
+ virtual void destroy(RefBase const* base) = 0;
+ };
+
+ // Make sure to never acquire a strong reference from this function. The
+ // same restrictions than for destructors apply.
+ void setDestroyer(Destroyer* destroyer);
+
protected:
RefBase();
virtual ~RefBase();
- // called when the last reference goes away. this is responsible for
- // calling the destructor. The default implementation just does
- // "delete this;".
- // Make sure to never acquire a strong reference from this function. The
- // same restrictions than for destructors apply.
- virtual void destroy() const;
-
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_WEAK = 0x0001,
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 41e5766..0bd69cf 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,7 @@
Thread& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
+ // always hold mLock when reading or writing
thread_id_t mThread;
mutable Mutex mLock;
Condition mThreadExitedCondition;
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b5737ff..4070eba 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -16,7 +16,6 @@
ISurfaceComposerClient.cpp \
IGraphicBufferAlloc.cpp \
LayerState.cpp \
- SharedBufferStack.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
index 23b90af..96155d7 100644
--- a/libs/gui/ISurface.cpp
+++ b/libs/gui/ISurface.cpp
@@ -22,9 +22,7 @@
#include <binder/Parcel.h>
-#include <ui/GraphicBuffer.h>
-
-#include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
#include <surfaceflinger/ISurface.h>
namespace android {
@@ -39,30 +37,11 @@
{
}
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
- {
+ virtual sp<ISurfaceTexture> getSurfaceTexture() const {
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(bufferIdx);
- data.writeInt32(w);
- data.writeInt32(h);
- data.writeInt32(format);
- data.writeInt32(usage);
- remote()->transact(REQUEST_BUFFER, data, &reply);
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- reply.read(*buffer);
- return buffer;
- }
-
- virtual status_t setBufferCount(int bufferCount)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(bufferCount);
- remote()->transact(SET_BUFFER_COUNT, data, &reply);
- status_t err = reply.readInt32();
- return err;
+ remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
+ return interface_cast<ISurfaceTexture>(reply.readStrongBinder());
}
};
@@ -74,23 +53,9 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
- case REQUEST_BUFFER: {
+ case GET_SURFACE_TEXTURE: {
CHECK_INTERFACE(ISurface, data, reply);
- int bufferIdx = data.readInt32();
- uint32_t w = data.readInt32();
- uint32_t h = data.readInt32();
- uint32_t format = data.readInt32();
- uint32_t usage = data.readInt32();
- sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
- if (buffer == NULL)
- return BAD_VALUE;
- return reply->write(*buffer);
- }
- case SET_BUFFER_COUNT: {
- CHECK_INTERFACE(ISurface, data, reply);
- int bufferCount = data.readInt32();
- status_t err = setBufferCount(bufferCount);
- reply->writeInt32(err);
+ reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
return NO_ERROR;
}
default:
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8951c3f..40450a3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -57,15 +57,6 @@
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
- virtual sp<ISurfaceComposerClient> createClientConnection()
- {
- uint32_t n;
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
- return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
- }
-
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
{
uint32_t n;
@@ -174,13 +165,6 @@
return reply.readInt32();
}
- virtual void signal() const
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
virtual bool authenticateSurface(const sp<ISurface>& surface) const
{
Parcel data, reply;
@@ -229,11 +213,6 @@
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
- case CREATE_CLIENT_CONNECTION: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> b = createClientConnection()->asBinder();
- reply->writeStrongBinder(b);
- } break;
case CREATE_GRAPHIC_BUFFER_ALLOC: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
@@ -270,10 +249,6 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case SIGNAL: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- signal();
- } break;
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index ea38e08..8d83392 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -50,9 +50,7 @@
namespace android {
enum {
- GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
- GET_TOKEN,
- CREATE_SURFACE,
+ CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
DESTROY_SURFACE,
SET_STATE
};
@@ -65,23 +63,6 @@
{
}
- virtual sp<IMemoryHeap> getControlBlock() const
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- remote()->transact(GET_CBLK, data, &reply);
- return interface_cast<IMemoryHeap>(reply.readStrongBinder());
- }
-
- virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(sur->asBinder());
- remote()->transact(GET_TOKEN, data, &reply);
- return reply.readInt32();
- }
-
virtual sp<ISurface> createSurface( surface_data_t* params,
const String8& name,
DisplayID display,
@@ -131,41 +112,6 @@
status_t BnSurfaceComposerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- // codes that don't require permission check
-
- switch(code) {
- case GET_CBLK: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IMemoryHeap> ctl(getControlBlock());
- reply->writeStrongBinder(ctl->asBinder());
- return NO_ERROR;
- } break;
- case GET_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
- ssize_t token = getTokenForSurface(sur);
- reply->writeInt32(token);
- return NO_ERROR;
- } break;
- }
-
- // these must be checked
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- LOGE("Permission Denial: "
- "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
-
switch(code) {
case CREATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
diff --git a/libs/gui/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp
deleted file mode 100644
index 7505d53..0000000
--- a/libs/gui/SharedBufferStack.cpp
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Copyright (C) 2007 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 LOG_TAG "SharedBufferStack"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-
-#include <private/surfaceflinger/SharedBufferStack.h>
-
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-#define DEBUG_ATOMICS 0
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-SharedClient::SharedClient()
- : lock(Mutex::SHARED), cv(Condition::SHARED)
-{
-}
-
-SharedClient::~SharedClient() {
-}
-
-
-// these functions are used by the clients
-status_t SharedClient::validate(size_t i) const {
- if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
- return BAD_INDEX;
- return surfaces[i].status;
-}
-
-// ----------------------------------------------------------------------------
-
-
-SharedBufferStack::SharedBufferStack()
-{
-}
-
-void SharedBufferStack::init(int32_t i)
-{
- status = NO_ERROR;
- identity = i;
-}
-
-status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
-{
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return BAD_INDEX;
-
- buffers[buffer].crop.l = uint16_t(crop.left);
- buffers[buffer].crop.t = uint16_t(crop.top);
- buffers[buffer].crop.r = uint16_t(crop.right);
- buffers[buffer].crop.b = uint16_t(crop.bottom);
- return NO_ERROR;
-}
-
-status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
-{
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return BAD_INDEX;
- buffers[buffer].transform = transform;
- return NO_ERROR;
-}
-
-status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
-{
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return BAD_INDEX;
-
- FlatRegion& reg(buffers[buffer].dirtyRegion);
- if (dirty.isEmpty()) {
- reg.count = 0;
- return NO_ERROR;
- }
-
- size_t count;
- Rect const* r = dirty.getArray(&count);
- if (count > FlatRegion::NUM_RECT_MAX) {
- const Rect bounds(dirty.getBounds());
- reg.count = 1;
- reg.rects[0].l = uint16_t(bounds.left);
- reg.rects[0].t = uint16_t(bounds.top);
- reg.rects[0].r = uint16_t(bounds.right);
- reg.rects[0].b = uint16_t(bounds.bottom);
- } else {
- reg.count = count;
- for (size_t i=0 ; i<count ; i++) {
- reg.rects[i].l = uint16_t(r[i].left);
- reg.rects[i].t = uint16_t(r[i].top);
- reg.rects[i].r = uint16_t(r[i].right);
- reg.rects[i].b = uint16_t(r[i].bottom);
- }
- }
- return NO_ERROR;
-}
-
-Region SharedBufferStack::getDirtyRegion(int buffer) const
-{
- Region res;
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return res;
-
- const FlatRegion& reg(buffers[buffer].dirtyRegion);
- if (reg.count > FlatRegion::NUM_RECT_MAX)
- return res;
-
- if (reg.count == 1) {
- const Rect r(
- reg.rects[0].l,
- reg.rects[0].t,
- reg.rects[0].r,
- reg.rects[0].b);
- res.set(r);
- } else {
- for (size_t i=0 ; i<reg.count ; i++) {
- const Rect r(
- reg.rects[i].l,
- reg.rects[i].t,
- reg.rects[i].r,
- reg.rects[i].b);
- res.orSelf(r);
- }
- }
- return res;
-}
-
-Rect SharedBufferStack::getCrop(int buffer) const
-{
- Rect res(-1, -1);
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return res;
- res.left = buffers[buffer].crop.l;
- res.top = buffers[buffer].crop.t;
- res.right = buffers[buffer].crop.r;
- res.bottom = buffers[buffer].crop.b;
- return res;
-}
-
-uint32_t SharedBufferStack::getTransform(int buffer) const
-{
- if (uint32_t(buffer) >= NUM_BUFFER_MAX)
- return 0;
- return buffers[buffer].transform;
-}
-
-
-// ----------------------------------------------------------------------------
-
-SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
- int surface, int32_t identity)
- : mSharedClient(sharedClient),
- mSharedStack(sharedClient->surfaces + surface),
- mIdentity(identity)
-{
-}
-
-SharedBufferBase::~SharedBufferBase()
-{
-}
-
-status_t SharedBufferBase::getStatus() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.status;
-}
-
-int32_t SharedBufferBase::getIdentity() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.identity;
-}
-
-String8 SharedBufferBase::dump(char const* prefix) const
-{
- const size_t SIZE = 1024;
- char buffer[SIZE];
- String8 result;
- SharedBufferStack& stack( *mSharedStack );
- snprintf(buffer, SIZE,
- "%s[ head=%2d, available=%2d, queued=%2d ] "
- "reallocMask=%08x, identity=%d, status=%d",
- prefix, stack.head, stack.available, stack.queued,
- stack.reallocMask, stack.identity, stack.status);
- result.append(buffer);
- result.append("\n");
- return result;
-}
-
-status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
-{
- const SharedBufferStack& stack( *mSharedStack );
- SharedClient& client( *mSharedClient );
- const nsecs_t TIMEOUT = s2ns(1);
- const int identity = mIdentity;
-
- Mutex::Autolock _l(client.lock);
- while ((condition()==false) &&
- (stack.identity == identity) &&
- (stack.status == NO_ERROR))
- {
- status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
- // handle errors and timeouts
- if (CC_UNLIKELY(err != NO_ERROR)) {
- if (err == TIMED_OUT) {
- if (condition()) {
- LOGE("waitForCondition(%s) timed out (identity=%d), "
- "but condition is true! We recovered but it "
- "shouldn't happen." , condition.name(), stack.identity);
- break;
- } else {
- LOGW("waitForCondition(%s) timed out "
- "(identity=%d, status=%d). "
- "CPU may be pegged. trying again.", condition.name(),
- stack.identity, stack.status);
- }
- } else {
- LOGE("waitForCondition(%s) error (%s) ",
- condition.name(), strerror(-err));
- return err;
- }
- }
- }
- return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
-}
-// ============================================================================
-// conditions and updates
-// ============================================================================
-
-SharedBufferClient::DequeueCondition::DequeueCondition(
- SharedBufferClient* sbc) : ConditionBase(sbc) {
-}
-bool SharedBufferClient::DequeueCondition::operator()() const {
- return stack.available > 0;
-}
-
-SharedBufferClient::LockCondition::LockCondition(
- SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
-}
-bool SharedBufferClient::LockCondition::operator()() const {
- // NOTE: if stack.head is messed up, we could crash the client
- // or cause some drawing artifacts. This is okay, as long as it is
- // limited to the client.
- return (buf != stack.index[stack.head]);
-}
-
-SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
- SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
- mNumBuffers(numBuffers) {
-}
-bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
- return stack.available == mNumBuffers;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
- : UpdateBase(sbb) {
-}
-ssize_t SharedBufferClient::QueueUpdate::operator()() {
- android_atomic_inc(&stack.queued);
- return NO_ERROR;
-}
-
-SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
- : UpdateBase(sbb) {
-}
-ssize_t SharedBufferClient::DequeueUpdate::operator()() {
- if (android_atomic_dec(&stack.available) == 0) {
- LOGW("dequeue probably called from multiple threads!");
- }
- return NO_ERROR;
-}
-
-SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb,
- int tail, int buf)
- : UpdateBase(sbb), tail(tail), buf(buf) {
-}
-ssize_t SharedBufferClient::CancelUpdate::operator()() {
- stack.index[tail] = buf;
- android_atomic_inc(&stack.available);
- return NO_ERROR;
-}
-
-SharedBufferServer::RetireUpdate::RetireUpdate(
- SharedBufferBase* sbb, int numBuffers)
- : UpdateBase(sbb), numBuffers(numBuffers) {
-}
-ssize_t SharedBufferServer::RetireUpdate::operator()() {
- int32_t head = stack.head;
- if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
- return BAD_VALUE;
-
- // Decrement the number of queued buffers
- int32_t queued;
- do {
- queued = stack.queued;
- if (queued == 0) {
- return NOT_ENOUGH_DATA;
- }
- } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
-
- // lock the buffer before advancing head, which automatically unlocks
- // the buffer we preventively locked upon entering this function
-
- head = (head + 1) % numBuffers;
- const int8_t headBuf = stack.index[head];
- stack.headBuf = headBuf;
-
- // head is only modified here, so we don't need to use cmpxchg
- android_atomic_write(head, &stack.head);
-
- // now that head has moved, we can increment the number of available buffers
- android_atomic_inc(&stack.available);
- return head;
-}
-
-SharedBufferServer::StatusUpdate::StatusUpdate(
- SharedBufferBase* sbb, status_t status)
- : UpdateBase(sbb), status(status) {
-}
-
-ssize_t SharedBufferServer::StatusUpdate::operator()() {
- android_atomic_write(status, &stack.status);
- return NO_ERROR;
-}
-
-// ============================================================================
-
-SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
- int surface, int num, int32_t identity)
- : SharedBufferBase(sharedClient, surface, identity),
- mNumBuffers(num), tail(0)
-{
- SharedBufferStack& stack( *mSharedStack );
- tail = computeTail();
- queued_head = stack.head;
-}
-
-int32_t SharedBufferClient::computeTail() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
-}
-
-ssize_t SharedBufferClient::dequeue()
-{
- SharedBufferStack& stack( *mSharedStack );
-
- RWLock::AutoRLock _rd(mLock);
-
- const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
-
- //LOGD("[%d] about to dequeue a buffer",
- // mSharedStack->identity);
- DequeueCondition condition(this);
- status_t err = waitForCondition(condition);
- if (err != NO_ERROR)
- return ssize_t(err);
-
- DequeueUpdate update(this);
- updateCondition( update );
-
- int dequeued = stack.index[tail];
- tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
- LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
- dequeued, tail, dump("").string());
-
- mDequeueTime[dequeued] = dequeueTime;
-
- return dequeued;
-}
-
-status_t SharedBufferClient::undoDequeue(int buf)
-{
- return cancel(buf);
-}
-
-status_t SharedBufferClient::cancel(int buf)
-{
- RWLock::AutoRLock _rd(mLock);
-
- // calculate the new position of the tail index (essentially tail--)
- int localTail = (tail + mNumBuffers - 1) % mNumBuffers;
- CancelUpdate update(this, localTail, buf);
- status_t err = updateCondition( update );
- if (err == NO_ERROR) {
- tail = localTail;
- }
- return err;
-}
-
-status_t SharedBufferClient::lock(int buf)
-{
- RWLock::AutoRLock _rd(mLock);
-
- SharedBufferStack& stack( *mSharedStack );
- LockCondition condition(this, buf);
- status_t err = waitForCondition(condition);
- return err;
-}
-
-status_t SharedBufferClient::queue(int buf)
-{
- RWLock::AutoRLock _rd(mLock);
-
- SharedBufferStack& stack( *mSharedStack );
-
- queued_head = (queued_head + 1) % mNumBuffers;
- stack.index[queued_head] = buf;
-
- QueueUpdate update(this);
- status_t err = updateCondition( update );
- LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
-
- const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
- stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
-
- return err;
-}
-
-bool SharedBufferClient::needNewBuffer(int buf) const
-{
- SharedBufferStack& stack( *mSharedStack );
- const uint32_t mask = 1<<(31-buf);
- return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
-}
-
-status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.setCrop(buf, crop);
-}
-
-status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.setTransform(buf, uint8_t(transform));
-}
-
-status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.setDirtyRegion(buf, reg);
-}
-
-status_t SharedBufferClient::setBufferCount(
- int bufferCount, const SetBufferCountCallback& ipc)
-{
- SharedBufferStack& stack( *mSharedStack );
- if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
- return BAD_VALUE;
-
- if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
- return BAD_VALUE;
-
- RWLock::AutoWLock _wr(mLock);
-
- status_t err = ipc(bufferCount);
- if (err == NO_ERROR) {
- mNumBuffers = bufferCount;
- queued_head = (stack.head + stack.queued) % mNumBuffers;
- tail = computeTail();
- }
- return err;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
- int surface, int num, int32_t identity)
- : SharedBufferBase(sharedClient, surface, identity),
- mNumBuffers(num)
-{
- mSharedStack->init(identity);
- mSharedStack->token = surface;
- mSharedStack->head = num-1;
- mSharedStack->available = num;
- mSharedStack->queued = 0;
- mSharedStack->reallocMask = 0;
- memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
- for (int i=0 ; i<num ; i++) {
- mBufferList.add(i);
- mSharedStack->index[i] = i;
- }
-}
-
-SharedBufferServer::~SharedBufferServer()
-{
-}
-
-ssize_t SharedBufferServer::retireAndLock()
-{
- RWLock::AutoRLock _l(mLock);
-
- RetireUpdate update(this, mNumBuffers);
- ssize_t buf = updateCondition( update );
- if (buf >= 0) {
- if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
- return BAD_VALUE;
- SharedBufferStack& stack( *mSharedStack );
- buf = stack.index[buf];
- LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
- int(buf), dump("").string());
- }
- return buf;
-}
-
-void SharedBufferServer::setStatus(status_t status)
-{
- if (status < NO_ERROR) {
- StatusUpdate update(this, status);
- updateCondition( update );
- }
-}
-
-status_t SharedBufferServer::reallocateAll()
-{
- RWLock::AutoRLock _l(mLock);
-
- SharedBufferStack& stack( *mSharedStack );
- uint32_t mask = mBufferList.getMask();
- android_atomic_or(mask, &stack.reallocMask);
- return NO_ERROR;
-}
-
-status_t SharedBufferServer::reallocateAllExcept(int buffer)
-{
- RWLock::AutoRLock _l(mLock);
-
- SharedBufferStack& stack( *mSharedStack );
- BufferList temp(mBufferList);
- temp.remove(buffer);
- uint32_t mask = temp.getMask();
- android_atomic_or(mask, &stack.reallocMask);
- return NO_ERROR;
-}
-
-int32_t SharedBufferServer::getQueuedCount() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.queued;
-}
-
-Region SharedBufferServer::getDirtyRegion(int buf) const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.getDirtyRegion(buf);
-}
-
-Rect SharedBufferServer::getCrop(int buf) const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.getCrop(buf);
-}
-
-uint32_t SharedBufferServer::getTransform(int buf) const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.getTransform(buf);
-}
-
-/*
- * NOTE: this is not thread-safe on the server-side, meaning
- * 'head' cannot move during this operation. The client-side
- * can safely operate an usual.
- *
- */
-status_t SharedBufferServer::resize(int newNumBuffers)
-{
- if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
- (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
- return BAD_VALUE;
- }
-
- RWLock::AutoWLock _l(mLock);
-
- if (newNumBuffers < mNumBuffers) {
- return shrink(newNumBuffers);
- } else {
- return grow(newNumBuffers);
- }
-}
-
-status_t SharedBufferServer::grow(int newNumBuffers)
-{
- SharedBufferStack& stack( *mSharedStack );
- const int numBuffers = mNumBuffers;
- const int extra = newNumBuffers - numBuffers;
-
- // read the head, make sure it's valid
- int32_t head = stack.head;
- if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
- return BAD_VALUE;
-
- int base = numBuffers;
- int32_t avail = stack.available;
- int tail = head - avail + 1;
-
- if (tail >= 0) {
- int8_t* const index = const_cast<int8_t*>(stack.index);
- const int nb = numBuffers - head;
- memmove(&index[head + extra], &index[head], nb);
- base = head;
- // move head 'extra' ahead, this doesn't impact stack.index[head];
- stack.head = head + extra;
- }
- stack.available += extra;
-
- // fill the new free space with unused buffers
- BufferList::const_iterator curr(mBufferList.free_begin());
- for (int i=0 ; i<extra ; i++) {
- stack.index[base+i] = *curr;
- mBufferList.add(*curr);
- ++curr;
- }
-
- mNumBuffers = newNumBuffers;
- return NO_ERROR;
-}
-
-status_t SharedBufferServer::shrink(int newNumBuffers)
-{
- SharedBufferStack& stack( *mSharedStack );
-
- // Shrinking is only supported if there are no buffers currently dequeued.
- int32_t avail = stack.available;
- int32_t queued = stack.queued;
- if (avail + queued != mNumBuffers) {
- return INVALID_OPERATION;
- }
-
- // Wait for any queued buffers to be displayed.
- BuffersAvailableCondition condition(this, mNumBuffers);
- status_t err = waitForCondition(condition);
- if (err < 0) {
- return err;
- }
-
- // Reset head to index 0 and make it refer to buffer 0. The same renaming
- // (head -> 0) is done in the BufferManager.
- int32_t head = stack.head;
- int8_t* index = const_cast<int8_t*>(stack.index);
- for (int8_t i = 0; i < newNumBuffers; i++) {
- index[i] = i;
- }
- stack.head = 0;
- stack.headBuf = 0;
-
- // Free the buffers from the end of the list that are no longer needed.
- for (int i = newNumBuffers; i < mNumBuffers; i++) {
- mBufferList.remove(i);
- }
-
- // Tell the client to reallocate all the buffers.
- reallocateAll();
-
- mNumBuffers = newNumBuffers;
- stack.available = newNumBuffers;
-
- return NO_ERROR;
-}
-
-SharedBufferStack::Statistics SharedBufferServer::getStats() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return stack.stats;
-}
-
-// ---------------------------------------------------------------------------
-status_t SharedBufferServer::BufferList::add(int value)
-{
- if (uint32_t(value) >= mCapacity)
- return BAD_VALUE;
- uint32_t mask = 1<<(31-value);
- if (mList & mask)
- return ALREADY_EXISTS;
- mList |= mask;
- return NO_ERROR;
-}
-
-status_t SharedBufferServer::BufferList::remove(int value)
-{
- if (uint32_t(value) >= mCapacity)
- return BAD_VALUE;
- uint32_t mask = 1<<(31-value);
- if (!(mList & mask))
- return NAME_NOT_FOUND;
- mList &= ~mask;
- return NO_ERROR;
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0c5767b..4d1d923 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -21,13 +21,15 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/Errors.h>
-#include <utils/threads.h>
#include <utils/CallStack.h>
+#include <utils/Errors.h>
#include <utils/Log.h>
+#include <utils/threads.h>
-#include <binder/IPCThreadState.h>
#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+
+#include <gui/SurfaceTextureClient.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicBuffer.h>
@@ -35,12 +37,11 @@
#include <ui/GraphicLog.h>
#include <ui/Rect.h>
-#include <surfaceflinger/Surface.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
-#include <private/surfaceflinger/SharedBufferStack.h>
#include <private/surfaceflinger/LayerState.h>
namespace android {
@@ -273,58 +274,10 @@
// Surface
// ============================================================================
-class SurfaceClient : public Singleton<SurfaceClient>
-{
- // all these attributes are constants
- sp<ISurfaceComposer> mComposerService;
- sp<ISurfaceComposerClient> mClient;
- status_t mStatus;
- SharedClient* mControl;
- sp<IMemoryHeap> mControlMemory;
-
- SurfaceClient()
- : Singleton<SurfaceClient>(), mStatus(NO_INIT)
- {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- mComposerService = sf;
- mClient = sf->createClientConnection();
- if (mClient != NULL) {
- mControlMemory = mClient->getControlBlock();
- if (mControlMemory != NULL) {
- mControl = static_cast<SharedClient *>(
- mControlMemory->getBase());
- if (mControl) {
- mStatus = NO_ERROR;
- }
- }
- }
- }
- friend class Singleton<SurfaceClient>;
-public:
- status_t initCheck() const {
- return mStatus;
- }
- SharedClient* getSharedClient() const {
- return mControl;
- }
- ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
- // TODO: we could cache a few tokens here to avoid an IPC
- return mClient->getTokenForSurface(sur);
- }
- void signalServer() const {
- mComposerService->signal();
- }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
-
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
- : mBufferMapper(GraphicBufferMapper::get()),
- mClient(SurfaceClient::getInstance()),
- mSharedBufferClient(NULL),
- mInitCheck(NO_INIT),
+ : mInitCheck(NO_INIT),
mSurface(surface->mSurface),
mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -334,10 +287,7 @@
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : mBufferMapper(GraphicBufferMapper::get()),
- mClient(SurfaceClient::getInstance()),
- mSharedBufferClient(NULL),
- mInitCheck(NO_INIT)
+ : mInitCheck(NO_INIT)
{
mSurface = interface_cast<ISurface>(ref);
mIdentity = parcel.readInt32();
@@ -382,7 +332,6 @@
}
-
Mutex Surface::sCachedSurfacesLock;
DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
@@ -422,32 +371,29 @@
ANativeWindow::query = query;
ANativeWindow::perform = perform;
- DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
- const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
- const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
- // FIXME: set real values here
- const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
- const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
- const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+ if (mSurface != NULL) {
+ sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+ LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
+ if (surfaceTexture != NULL) {
+ mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+ mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+ }
- mNextBufferTransform = 0;
- mConnected = 0;
- mSwapRectangle.makeInvalid();
- mNextBufferCrop = Rect(0,0);
- // two buffers by default
- mBuffers.setCapacity(2);
- mBuffers.insertAt(0, 2);
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
+ const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
- if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
- int32_t token = mClient.getTokenForSurface(mSurface);
- if (token >= 0) {
- mSharedBufferClient = new SharedBufferClient(
- mClient.getSharedClient(), token, 2, mIdentity);
- mInitCheck = mClient.getSharedClient()->validate(token);
- } else {
- LOGW("Not initializing the shared buffer client because token = %d",
- token);
+ const_cast<int&>(ANativeWindow::minSwapInterval) =
+ mSurfaceTextureClient->minSwapInterval;
+
+ const_cast<int&>(ANativeWindow::maxSwapInterval) =
+ mSurfaceTextureClient->maxSwapInterval;
+
+ const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+
+ if (mSurfaceTextureClient != 0) {
+ mInitCheck = NO_ERROR;
}
}
}
@@ -456,9 +402,8 @@
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
- mBuffers.clear();
+ mSurfaceTextureClient.clear();
mSurface.clear();
- delete mSharedBufferClient;
IPCThreadState::self()->flushCommands();
}
@@ -473,32 +418,6 @@
LOGE("invalid token (identity=%u)", mIdentity);
return mInitCheck;
}
-
- // verify the identity of this surface
- uint32_t identity = mSharedBufferClient->getIdentity();
- if (mIdentity != identity) {
- LOGE("[Surface] using an invalid surface, "
- "identity=%u should be %d",
- mIdentity, identity);
- CallStack stack;
- stack.update();
- stack.dump("Surface");
- return BAD_INDEX;
- }
-
- // check the surface didn't become invalid
- status_t err = mSharedBufferClient->getStatus();
- if (err != NO_ERROR) {
- if (!inCancelBuffer) {
- LOGE("surface (identity=%u) is invalid, err=%d (%s)",
- mIdentity, err, strerror(-err));
- CallStack stack;
- stack.update();
- stack.dump("Surface");
- }
- return err;
- }
-
return NO_ERROR;
}
@@ -509,7 +428,8 @@
// ----------------------------------------------------------------------------
int Surface::setSwapInterval(ANativeWindow* window, int interval) {
- return 0;
+ Surface* self = getSelf(window);
+ return self->setSwapInterval(interval);
}
int Surface::dequeueBuffer(ANativeWindow* window,
@@ -554,383 +474,52 @@
// ----------------------------------------------------------------------------
-bool Surface::needNewBuffer(int bufIdx,
- uint32_t *pWidth, uint32_t *pHeight,
- uint32_t *pFormat, uint32_t *pUsage) const
-{
- Mutex::Autolock _l(mSurfaceLock);
-
- // Always call needNewBuffer(), since it clears the needed buffers flags
- bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
- bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
- bool newNeewBuffer = needNewBuffer || !validBuffer;
- if (newNeewBuffer) {
- mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
- }
- return newNeewBuffer;
+int Surface::setSwapInterval(int interval) {
+ return mSurfaceTextureClient->setSwapInterval(interval);
}
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
-{
- status_t err = validate();
- if (err != NO_ERROR)
- return err;
-
- GraphicLog& logger(GraphicLog::getInstance());
- logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
-
- ssize_t bufIdx = mSharedBufferClient->dequeue();
-
- logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
-
- if (bufIdx < 0) {
- LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
- return bufIdx;
- }
-
- // grow the buffer array if needed
- const size_t size = mBuffers.size();
- const size_t needed = bufIdx+1;
- if (size < needed) {
- mBuffers.insertAt(size, needed-size);
- }
-
- uint32_t w, h, format, usage;
- if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
- err = getBufferLocked(bufIdx, w, h, format, usage);
- LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
- bufIdx, w, h, format, usage, strerror(-err));
- if (err == NO_ERROR) {
- // reset the width/height with the what we get from the buffer
- const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
- mWidth = uint32_t(backBuffer->width);
- mHeight = uint32_t(backBuffer->height);
- }
- }
-
- // if we still don't have a buffer here, we probably ran out of memory
- const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
- if (!err && backBuffer==0) {
- err = NO_MEMORY;
- }
-
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
+ status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
if (err == NO_ERROR) {
- mDirtyRegion.set(backBuffer->width, backBuffer->height);
- *buffer = backBuffer.get();
- } else {
- mSharedBufferClient->undoDequeue(bufIdx);
- }
-
- return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
-{
- status_t err = validate(true);
- switch (err) {
- case NO_ERROR:
- // no error, common case
- break;
- case BAD_INDEX:
- // legitimate errors here
- return err;
- default:
- // other errors happen because the surface is now invalid,
- // for instance because it has been destroyed. In this case,
- // we just fail silently (canceling a buffer is not technically
- // an error at this point)
- return NO_ERROR;
- }
-
- int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
- err = mSharedBufferClient->cancel(bufIdx);
-
- LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err));
- return err;
-}
-
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer)
-{
- status_t err = validate();
- if (err != NO_ERROR)
- return err;
-
- int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
- GraphicLog& logger(GraphicLog::getInstance());
- logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
-
- err = mSharedBufferClient->lock(bufIdx);
-
- logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
-
- LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
- return err;
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer)
-{
- status_t err = validate();
- if (err != NO_ERROR)
- return err;
-
- if (mSwapRectangle.isValid()) {
- mDirtyRegion.set(mSwapRectangle);
- }
-
- int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
- GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
-
- mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
- mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
- mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
- err = mSharedBufferClient->queue(bufIdx);
- LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
-
- if (err == NO_ERROR) {
- // TODO: can we avoid this IPC if we know there is one pending?
- mClient.signalServer();
+ mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
}
return err;
}
-int Surface::query(int what, int* value) const
-{
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
+ return mSurfaceTextureClient->cancelBuffer(buffer);
+}
+
+int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
+ return mSurfaceTextureClient->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
+ return mSurfaceTextureClient->queueBuffer(buffer);
+}
+
+int Surface::query(int what, int* value) const {
switch (what) {
- case NATIVE_WINDOW_WIDTH:
- *value = int(mWidth);
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ // TODO: this is not needed anymore
+ *value = 1;
return NO_ERROR;
- case NATIVE_WINDOW_HEIGHT:
- *value = int(mHeight);
- return NO_ERROR;
- case NATIVE_WINDOW_FORMAT:
- *value = int(mFormat);
- return NO_ERROR;
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- *value = MIN_UNDEQUEUED_BUFFERS;
- return NO_ERROR;
- case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- *value = sf->authenticateSurface(mSurface) ? 1 : 0;
- return NO_ERROR;
- }
case NATIVE_WINDOW_CONCRETE_TYPE:
+ // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
- return BAD_VALUE;
+ return mSurfaceTextureClient->query(what, value);
}
-int Surface::perform(int operation, va_list args)
-{
- status_t err = validate();
- if (err != NO_ERROR)
- return err;
-
- int res = NO_ERROR;
- switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- dispatch_setUsage( args );
- break;
- case NATIVE_WINDOW_CONNECT:
- res = dispatch_connect( args );
- break;
- case NATIVE_WINDOW_DISCONNECT:
- res = dispatch_disconnect( args );
- break;
- case NATIVE_WINDOW_SET_CROP:
- res = dispatch_crop( args );
- break;
- case NATIVE_WINDOW_SET_BUFFER_COUNT:
- res = dispatch_set_buffer_count( args );
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- res = dispatch_set_buffers_geometry( args );
- break;
- case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
- res = dispatch_set_buffers_transform( args );
- break;
- case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
- res = dispatch_set_buffers_timestamp( args );
- break;
- default:
- res = NAME_NOT_FOUND;
- break;
- }
- return res;
-}
-
-void Surface::dispatch_setUsage(va_list args) {
- int usage = va_arg(args, int);
- setUsage( usage );
-}
-int Surface::dispatch_connect(va_list args) {
- int api = va_arg(args, int);
- return connect( api );
-}
-int Surface::dispatch_disconnect(va_list args) {
- int api = va_arg(args, int);
- return disconnect( api );
-}
-int Surface::dispatch_crop(va_list args) {
- android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
- return crop( reinterpret_cast<Rect const*>(rect) );
-}
-int Surface::dispatch_set_buffer_count(va_list args) {
- size_t bufferCount = va_arg(args, size_t);
- return setBufferCount(bufferCount);
-}
-int Surface::dispatch_set_buffers_geometry(va_list args) {
- int w = va_arg(args, int);
- int h = va_arg(args, int);
- int f = va_arg(args, int);
- return setBuffersGeometry(w, h, f);
-}
-
-int Surface::dispatch_set_buffers_transform(va_list args) {
- int transform = va_arg(args, int);
- return setBuffersTransform(transform);
-}
-
-int Surface::dispatch_set_buffers_timestamp(va_list args) {
- int64_t timestamp = va_arg(args, int64_t);
- return setBuffersTimestamp(timestamp);
-}
-
-void Surface::setUsage(uint32_t reqUsage)
-{
- Mutex::Autolock _l(mSurfaceLock);
- mBufferInfo.set(reqUsage);
-}
-
-int Surface::connect(int api)
-{
- Mutex::Autolock _l(mSurfaceLock);
- int err = NO_ERROR;
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- if (mConnected) {
- err = -EINVAL;
- } else {
- mConnected = api;
- }
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-int Surface::disconnect(int api)
-{
- Mutex::Autolock _l(mSurfaceLock);
- int err = NO_ERROR;
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- if (mConnected == api) {
- mConnected = 0;
- } else {
- err = -EINVAL;
- }
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-int Surface::crop(Rect const* rect)
-{
- Mutex::Autolock _l(mSurfaceLock);
- // TODO: validate rect size
-
- if (rect == NULL || rect->isEmpty()) {
- mNextBufferCrop = Rect(0,0);
- } else {
- mNextBufferCrop = *rect;
- }
-
- return NO_ERROR;
-}
-
-int Surface::setBufferCount(int bufferCount)
-{
- sp<ISurface> s(mSurface);
- if (s == 0) return NO_INIT;
-
- class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
- sp<ISurface> surface;
- virtual status_t operator()(int bufferCount) const {
- return surface->setBufferCount(bufferCount);
- }
- public:
- SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
- } ipc(s);
-
- status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
- LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
- bufferCount, strerror(-err));
-
- if (err == NO_ERROR) {
- // Clear out any references to the old buffers.
- mBuffers.clear();
- }
-
- return err;
-}
-
-int Surface::setBuffersGeometry(int w, int h, int format)
-{
- if (w<0 || h<0 || format<0)
- return BAD_VALUE;
-
- if ((w && !h) || (!w && h))
- return BAD_VALUE;
-
- Mutex::Autolock _l(mSurfaceLock);
- if (mConnected == NATIVE_WINDOW_API_EGL) {
- return INVALID_OPERATION;
- }
-
- mBufferInfo.set(w, h, format);
- if (format != 0) {
- // we update the format of the surface as reported by query().
- // this is to allow applications to change the format of a surface's
- // buffer, and have it reflected in EGL; which is needed for
- // EGLConfig validation.
- mFormat = format;
- }
-
- mNextBufferCrop = Rect(0,0);
-
- return NO_ERROR;
-}
-
-int Surface::setBuffersTransform(int transform)
-{
- Mutex::Autolock _l(mSurfaceLock);
- mNextBufferTransform = transform;
- return NO_ERROR;
-}
-
-int Surface::setBuffersTimestamp(int64_t timestamp)
-{
- // Surface doesn't really have anything meaningful to do with timestamps
- // so they'll just be dropped here.
- return NO_ERROR;
+int Surface::perform(int operation, va_list args) {
+ return mSurfaceTextureClient->perform(operation, args);
}
// ----------------------------------------------------------------------------
-int Surface::getConnectedApi() const
-{
- Mutex::Autolock _l(mSurfaceLock);
- return mConnected;
+int Surface::getConnectedApi() const {
+ return mSurfaceTextureClient->getConnectedApi();
}
// ----------------------------------------------------------------------------
@@ -967,16 +556,17 @@
}
// we're intending to do software rendering from this point
- setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ mSurfaceTextureClient->setUsage(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
ANativeWindowBuffer* out;
- status_t err = dequeueBuffer(&out);
+ status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = lockBuffer(backBuffer.get());
- LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
- getBufferIndex(backBuffer), strerror(-err));
+ err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+ backBuffer->handle, strerror(-err));
if (err == NO_ERROR) {
const Rect bounds(backBuffer->width, backBuffer->height);
const Region boundsRegion(bounds);
@@ -1043,110 +633,14 @@
status_t err = mLockedBuffer->unlock();
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
- err = queueBuffer(mLockedBuffer.get());
- LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
- getBufferIndex(mLockedBuffer), strerror(-err));
+ err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
}
-void Surface::setSwapRectangle(const Rect& r) {
- Mutex::Autolock _l(mSurfaceLock);
- mSwapRectangle = r;
-}
-
-int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
-{
- int idx = buffer->getIndex();
- if (idx < 0) {
- // The buffer doesn't have an index set. See if the handle the same as
- // one of the buffers for which we do know the index. This can happen
- // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
- // was dequeued from an ANativeWindow.
- for (size_t i = 0; i < mBuffers.size(); i++) {
- if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
- idx = mBuffers[i]->getIndex();
- break;
- }
- }
- }
- return idx;
-}
-
-status_t Surface::getBufferLocked(int index,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
- sp<ISurface> s(mSurface);
- if (s == 0) return NO_INIT;
-
- status_t err = NO_MEMORY;
-
- // free the current buffer
- sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
- if (currentBuffer != 0) {
- currentBuffer.clear();
- }
-
- sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
- LOGE_IF(buffer==0,
- "ISurface::getBuffer(%d, %08x) returned NULL",
- index, usage);
- if (buffer != 0) { // this should always happen by construction
- LOGE_IF(buffer->handle == NULL,
- "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
- "returned a buffer with a null handle",
- mIdentity, index, w, h, format, usage);
- err = mSharedBufferClient->getStatus();
- LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
- if (!err && buffer->handle != NULL) {
- currentBuffer = buffer;
- currentBuffer->setIndex(index);
- } else {
- err = err<0 ? err : status_t(NO_MEMORY);
- }
- }
- return err;
-}
-
-// ----------------------------------------------------------------------------
-Surface::BufferInfo::BufferInfo()
- : mWidth(0), mHeight(0), mFormat(0),
- mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
-{
-}
-
-void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
- if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
- mWidth = w;
- mHeight = h;
- mFormat = format;
- mDirty |= GEOMETRY;
- }
-}
-
-void Surface::BufferInfo::set(uint32_t usage) {
- mUsage = usage;
-}
-
-void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
- uint32_t *pFormat, uint32_t *pUsage) const {
- *pWidth = mWidth;
- *pHeight = mHeight;
- *pFormat = mFormat;
- *pUsage = mUsage;
-}
-
-bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
- // make sure we AT LEAST have the usage flags we want
- if (mDirty || buffer==0 ||
- ((buffer->usage & mUsage) != mUsage)) {
- mDirty = 0;
- return false;
- }
- return true;
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a1ff2c1..1678711 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -20,19 +20,20 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <utils/SortedVector.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
-#include <binder/IServiceManager.h>
#include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
#include <ui/DisplayInfo.h>
+#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
-#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <private/surfaceflinger/LayerState.h>
@@ -217,7 +218,7 @@
status_t SurfaceComposerClient::getDisplayInfo(
DisplayID dpy, DisplayInfo* info)
{
- if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
@@ -235,7 +236,7 @@
ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
{
- if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -244,7 +245,7 @@
ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
{
- if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -253,7 +254,7 @@
ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
{
- if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index ee97dcf..3cecdb4 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,7 @@
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
mNextCrop.makeInvalid();
+ memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
}
SurfaceTexture::~SurfaceTexture() {
@@ -270,7 +271,7 @@
if (state == BufferSlot::DEQUEUED) {
dequeuedCount++;
}
- if (state == BufferSlot::FREE || i == mCurrentTexture) {
+ if (state == BufferSlot::FREE /*|| i == mCurrentTexture*/) {
foundSync = i;
if (i != mCurrentTexture) {
found = i;
@@ -547,6 +548,7 @@
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentTimestamp = mSlots[buf].mTimestamp;
+ computeCurrentTransformMatrix();
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
@@ -596,8 +598,12 @@
}
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
- LOGV("SurfaceTexture::getTransformMatrix");
Mutex::Autolock lock(mMutex);
+ memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void SurfaceTexture::computeCurrentTransformMatrix() {
+ LOGV("SurfaceTexture::computeCurrentTransformMatrix");
float xform[16];
for (int i = 0; i < 16; i++) {
@@ -684,7 +690,7 @@
// coordinate of 0, so SurfaceTexture must behave the same way. We don't
// want to expose this to applications, however, so we must add an
// additional vertical flip to the transform after all the other transforms.
- mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+ mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
}
nsecs_t SurfaceTexture::getTimestamp() {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index c20fcf27..22b0852 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -181,6 +181,12 @@
int SurfaceTextureClient::query(int what, int* value) const {
LOGV("SurfaceTextureClient::query");
switch (what) {
+ case NATIVE_WINDOW_FORMAT:
+ if (mReqFormat) {
+ *value = mReqFormat;
+ return NO_ERROR;
+ }
+ break;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
// TODO: this is not needed anymore
*value = 0;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 2f704c8..e1a85f3 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -505,13 +505,121 @@
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ thread->run();
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
- thread->run();
- ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
- ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
+ //ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+ //ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
thread->bufferDequeued();
thread->requestExitAndWait();
}
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ st->getTransformMatrix(mtx);
+
+ EXPECT_EQ(1.f, mtx[0]);
+ EXPECT_EQ(0.f, mtx[1]);
+ EXPECT_EQ(0.f, mtx[2]);
+ EXPECT_EQ(0.f, mtx[3]);
+
+ EXPECT_EQ(0.f, mtx[4]);
+ EXPECT_EQ(-1.f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(1.f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+ st->getTransformMatrix(mtx);
+
+ EXPECT_EQ(1.f, mtx[0]);
+ EXPECT_EQ(0.f, mtx[1]);
+ EXPECT_EQ(0.f, mtx[2]);
+ EXPECT_EQ(0.f, mtx[3]);
+
+ EXPECT_EQ(0.f, mtx[4]);
+ EXPECT_EQ(-1.f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(1.f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
+}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ android_native_rect_t crop;
+ crop.left = 0;
+ crop.top = 0;
+ crop.right = 5;
+ crop.bottom = 5;
+
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 8, 8, 0));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_set_crop(anw.get(), &crop));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+ st->getTransformMatrix(mtx);
+
+ // This accounts for the 1 texel shrink for each edge that's included in the
+ // transform matrix to avoid texturing outside the crop region.
+ EXPECT_EQ(.5f, mtx[0]);
+ EXPECT_EQ(0.f, mtx[1]);
+ EXPECT_EQ(0.f, mtx[2]);
+ EXPECT_EQ(0.f, mtx[3]);
+
+ EXPECT_EQ(0.f, mtx[4]);
+ EXPECT_EQ(-.5f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(.5f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
+}
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 8747ba5..56c1702 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+
#include <gtest/gtest.h>
#include <gui/SurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
+#include <utils/threads.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/Surface.h>
@@ -270,8 +273,12 @@
*outPgm = program;
}
+ static int abs(int value) {
+ return value > 0 ? value : -value;
+ }
+
::testing::AssertionResult checkPixel(int x, int y, int r,
- int g, int b, int a) {
+ int g, int b, int a, int tolerance=2) {
GLubyte pixel[4];
String8 msg;
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
@@ -285,22 +292,22 @@
return ::testing::AssertionFailure(
::testing::Message(msg.string()));
}
- if (r >= 0 && GLubyte(r) != pixel[0]) {
+ if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
msg += String8::format("r(%d isn't %d)", pixel[0], r);
}
- if (g >= 0 && GLubyte(g) != pixel[1]) {
+ if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
if (!msg.isEmpty()) {
msg += " ";
}
msg += String8::format("g(%d isn't %d)", pixel[1], g);
}
- if (b >= 0 && GLubyte(b) != pixel[2]) {
+ if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
if (!msg.isEmpty()) {
msg += " ";
}
msg += String8::format("b(%d isn't %d)", pixel[2], b);
}
- if (a >= 0 && GLubyte(a) != pixel[3]) {
+ if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
if (!msg.isEmpty()) {
msg += " ";
}
@@ -618,4 +625,270 @@
}
}
+/*
+ * This test is for testing GL -> GL texture streaming via SurfaceTexture. It
+ * contains functionality to create a producer thread that will perform GL
+ * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
+ * Additionally it supports interlocking the producer and consumer threads so
+ * that a specific sequence of calls can be deterministically created by the
+ * test.
+ *
+ * The intended usage is as follows:
+ *
+ * TEST_F(...) {
+ * class PT : public ProducerThread {
+ * virtual void render() {
+ * ...
+ * swapBuffers();
+ * }
+ * };
+ *
+ * runProducerThread(new PT());
+ *
+ * // The order of these calls will vary from test to test and may include
+ * // multiple frames and additional operations (e.g. GL rendering from the
+ * // texture).
+ * fc->waitForFrame();
+ * mST->updateTexImage();
+ * fc->finishFrame();
+ * }
+ *
+ */
+class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+protected:
+
+ // ProducerThread is an abstract base class to simplify the creation of
+ // OpenGL ES frame producer threads.
+ class ProducerThread : public Thread {
+ public:
+ virtual ~ProducerThread() {
+ }
+
+ void setEglObjects(EGLDisplay producerEglDisplay,
+ EGLSurface producerEglSurface,
+ EGLContext producerEglContext) {
+ mProducerEglDisplay = producerEglDisplay;
+ mProducerEglSurface = producerEglSurface;
+ mProducerEglContext = producerEglContext;
+ }
+
+ virtual bool threadLoop() {
+ eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext);
+ render();
+ eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+ return false;
+ }
+
+ protected:
+ virtual void render() = 0;
+
+ void swapBuffers() {
+ eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
+ }
+
+ EGLDisplay mProducerEglDisplay;
+ EGLSurface mProducerEglSurface;
+ EGLContext mProducerEglContext;
+ };
+
+ // FrameCondition is a utility class for interlocking between the producer
+ // and consumer threads. The FrameCondition object should be created and
+ // destroyed in the consumer thread only. The consumer thread should set
+ // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
+ // and should call both waitForFrame and finishFrame once for each expected
+ // frame.
+ //
+ // This interlocking relies on the fact that onFrameAvailable gets called
+ // synchronously from SurfaceTexture::queueBuffer.
+ class FrameCondition : public SurfaceTexture::FrameAvailableListener {
+ public:
+ // waitForFrame waits for the next frame to arrive. This should be
+ // called from the consumer thread once for every frame expected by the
+ // test.
+ void waitForFrame() {
+ LOGV("+waitForFrame");
+ Mutex::Autolock lock(mMutex);
+ status_t result = mFrameAvailableCondition.wait(mMutex);
+ LOGV("-waitForFrame");
+ }
+
+ // Allow the producer to return from its swapBuffers call and continue
+ // on to produce the next frame. This should be called by the consumer
+ // thread once for every frame expected by the test.
+ void finishFrame() {
+ LOGV("+finishFrame");
+ Mutex::Autolock lock(mMutex);
+ mFrameFinishCondition.signal();
+ LOGV("-finishFrame");
+ }
+
+ // This should be called by SurfaceTexture on the producer thread.
+ virtual void onFrameAvailable() {
+ LOGV("+onFrameAvailable");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableCondition.signal();
+ mFrameFinishCondition.wait(mMutex);
+ LOGV("-onFrameAvailable");
+ }
+
+ protected:
+ Mutex mMutex;
+ Condition mFrameAvailableCondition;
+ Condition mFrameFinishCondition;
+ };
+
+ SurfaceTextureGLToGLTest():
+ mProducerEglSurface(EGL_NO_SURFACE),
+ mProducerEglContext(EGL_NO_CONTEXT) {
+ }
+
+ virtual void SetUp() {
+ SurfaceTextureGLTest::SetUp();
+
+ EGLConfig myConfig = {0};
+ EGLint numConfigs = 0;
+ EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+ 1, &numConfigs));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+ mANW.get(), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
+
+ mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
+ EGL_NO_CONTEXT, getContextAttribs());
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
+
+ mFC = new FrameCondition();
+ mST->setFrameAvailableListener(mFC);
+ }
+
+ virtual void TearDown() {
+ if (mProducerThread != NULL) {
+ mProducerThread->requestExitAndWait();
+ }
+ if (mProducerEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mProducerEglContext);
+ }
+ if (mProducerEglSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mProducerEglSurface);
+ }
+ mProducerThread.clear();
+ mFC.clear();
+ }
+
+ void runProducerThread(const sp<ProducerThread> producerThread) {
+ ASSERT_TRUE(mProducerThread == NULL);
+ mProducerThread = producerThread;
+ producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
+ mProducerEglContext);
+ producerThread->run();
+ }
+
+ EGLSurface mProducerEglSurface;
+ EGLContext mProducerEglContext;
+ sp<ProducerThread> mProducerThread;
+ sp<FrameCondition> mFC;
+};
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
+ class PT : public ProducerThread {
+ virtual void render() {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ swapBuffers();
+ }
+ };
+
+ runProducerThread(new PT());
+
+ mFC->waitForFrame();
+ mST->updateTexImage();
+ mFC->finishFrame();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) {
+ class PT : public ProducerThread {
+ virtual void render() {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ swapBuffers();
+ }
+ };
+
+ runProducerThread(new PT());
+
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ mST->updateTexImage();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+ enum { NUM_ITERATIONS = 1024 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ runProducerThread(new PT());
+
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mFC->waitForFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+ mFC->finishFrame();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+ }
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+ enum { NUM_ITERATIONS = 1024 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ runProducerThread(new PT());
+
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+ }
+}
+
+} // namespace android
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6c9c0eb..5343a05 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -476,13 +476,8 @@
snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
}
- // Clear the framebuffer where the layer will draw
- glScissor(bounds.left, mSnapshot->height - bounds.bottom,
- bounds.getWidth(), bounds.getHeight());
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- dirtyClip();
+ // Enqueue the buffer coordinates to clear the corresponding region later
+ mLayers.push(new Rect(bounds));
}
}
@@ -817,6 +812,58 @@
#endif
}
+void OpenGLRenderer::clearLayerRegions() {
+ const size_t count = mLayers.size();
+ if (count == 0) return;
+
+ if (!mSnapshot->isIgnored()) {
+ // Doing several glScissor/glClear here can negatively impact
+ // GPUs with a tiler architecture, instead we draw quads with
+ // the Clear blending mode
+
+ // The list contains bounds that have already been clipped
+ // against their initial clip rect, and the current clip
+ // is likely different so we need to disable clipping here
+ glDisable(GL_SCISSOR_TEST);
+
+ Vertex mesh[count * 6];
+ Vertex* vertex = mesh;
+
+ for (uint32_t i = 0; i < count; i++) {
+ Rect* bounds = mLayers.itemAt(i);
+
+ Vertex::set(vertex++, bounds->left, bounds->bottom);
+ Vertex::set(vertex++, bounds->left, bounds->top);
+ Vertex::set(vertex++, bounds->right, bounds->top);
+ Vertex::set(vertex++, bounds->left, bounds->bottom);
+ Vertex::set(vertex++, bounds->right, bounds->top);
+ Vertex::set(vertex++, bounds->right, bounds->bottom);
+
+ delete bounds;
+ }
+
+ setupDraw(false);
+ setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
+ setupDrawBlending(true, SkXfermode::kClear_Mode);
+ setupDrawProgram();
+ setupDrawPureColorUniforms();
+ setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
+
+ mCaches.unbindMeshBuffer();
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ gVertexStride, &mesh[0].position[0]);
+ glDrawArrays(GL_TRIANGLES, 0, count * 6);
+
+ glEnable(GL_SCISSOR_TEST);
+ } else {
+ for (uint32_t i = 0; i < count; i++) {
+ delete mLayers.itemAt(i);
+ }
+ }
+
+ mLayers.clear();
+}
+
///////////////////////////////////////////////////////////////////////////////
// Transforms
///////////////////////////////////////////////////////////////////////////////
@@ -901,7 +948,8 @@
// Drawing commands
///////////////////////////////////////////////////////////////////////////////
-void OpenGLRenderer::setupDraw() {
+void OpenGLRenderer::setupDraw(bool clear) {
+ if (clear) clearLayerRegions();
if (mDirtyClip) {
setScissorFromClip();
}
@@ -994,7 +1042,7 @@
if (mColorSet && mode == SkXfermode::kClear_Mode) {
mColorA = 1.0f;
mColorR = mColorG = mColorB = 0.0f;
- mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
+ mSetShaderColor = mDescription.modulate = true;
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 549d6e9..b9e3ddc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -249,6 +249,18 @@
*/
void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
+ /**
+ * Clears all the regions corresponding to the current list of layers.
+ * This method MUST be invoked before any drawing operation.
+ */
+ void clearLayerRegions();
+
+ /**
+ * Renders the specified layer as a textured quad.
+ *
+ * @param layer The layer to render
+ * @param rect The bounds of the layer
+ */
void drawTextureLayer(Layer* layer, const Rect& rect);
/**
@@ -280,11 +292,53 @@
void drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform = false);
+ /**
+ * Draws the shape represented by the specified path texture.
+ * This method invokes drawPathTexture() but takes into account
+ * the extra left/top offset and the texture offset to correctly
+ * position the final shape.
+ *
+ * @param left The left coordinate of the shape to render
+ * @param top The top coordinate of the shape to render
+ * @param texture The texture reprsenting the shape
+ * @param paint The paint to draw the shape with
+ */
void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
+
+ /**
+ * Renders the rect defined by the specified bounds as a shape.
+ * This will render the rect using a path texture, which is used to render
+ * rects with stroke effects.
+ *
+ * @param left The left coordinate of the rect to draw
+ * @param top The top coordinate of the rect to draw
+ * @param right The right coordinate of the rect to draw
+ * @param bottom The bottom coordinate of the rect to draw
+ * @param p The paint to draw the rect with
+ */
void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
+ /**
+ * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
+ * different compositing rules.
+ *
+ * @param texture The texture to draw with
+ * @param left The x coordinate of the bitmap
+ * @param top The y coordinate of the bitmap
+ * @param paint The paint to render with
+ */
void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);
+ /**
+ * Renders the rect defined by the specified bounds as an anti-aliased rect.
+ *
+ * @param left The left coordinate of the rect to draw
+ * @param top The top coordinate of the rect to draw
+ * @param right The right coordinate of the rect to draw
+ * @param bottom The bottom coordinate of the rect to draw
+ * @param color The color of the rect
+ * @param mode The blending mode to draw the rect
+ */
void drawAARect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode);
@@ -359,6 +413,15 @@
void drawTextDecorations(const char* text, int bytesCount, float length,
float x, float y, SkPaint* paint);
+ /**
+ * Draws a path texture. Path textures are alpha8 bitmaps that need special
+ * compositing to apply colors/filters/etc.
+ *
+ * @param texture The texture to render
+ * @param x The x coordinate where the texture will be drawn
+ * @param y The y coordinate where the texture will be drawn
+ * @param paint The paint to draw the texture with
+ */
void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint);
/**
@@ -434,7 +497,7 @@
/**
* Invoked before any drawing operation. This sets required state.
*/
- void setupDraw();
+ void setupDraw(bool clear = true);
/**
* Various methods to setup OpenGL rendering.
*/
@@ -522,6 +585,9 @@
// Various caches
Caches& mCaches;
+ // List of rectagnles to clear after saveLayer() is invoked
+ Vector<Rect*> mLayers;
+
// Indentity matrix
const mat4 mIdentity;
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index e8d40ba..093189c 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -21,6 +21,7 @@
Asset.cpp \
AssetDir.cpp \
AssetManager.cpp \
+ BlobCache.cpp \
BufferedTextOutput.cpp \
CallStack.cpp \
Debug.cpp \
diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp
new file mode 100644
index 0000000..1298fa7
--- /dev/null
+++ b/libs/utils/BlobCache.cpp
@@ -0,0 +1,232 @@
+/*
+ ** Copyright 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 LOG_TAG "BlobCache"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/BlobCache.h>
+#include <utils/Log.h>
+
+namespace android {
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+ mMaxKeySize(maxKeySize),
+ mMaxValueSize(maxValueSize),
+ mMaxTotalSize(maxTotalSize),
+ mTotalSize(0) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ mRandState[0] = (now >> 0) & 0xFFFF;
+ mRandState[1] = (now >> 16) & 0xFFFF;
+ mRandState[2] = (now >> 32) & 0xFFFF;
+ LOGV("initializing random seed using %lld", now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+ size_t valueSize) {
+ if (mMaxKeySize < keySize) {
+ LOGV("set: not caching because the key is too large: %d (limit: %d)",
+ keySize, mMaxKeySize);
+ return;
+ }
+ if (mMaxValueSize < valueSize) {
+ LOGV("set: not caching because the value is too large: %d (limit: %d)",
+ valueSize, mMaxValueSize);
+ return;
+ }
+ if (mMaxTotalSize < keySize + valueSize) {
+ LOGV("set: not caching because the combined key/value size is too "
+ "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+ return;
+ }
+ if (keySize == 0) {
+ LOGW("set: not caching because keySize is 0");
+ return;
+ }
+ if (valueSize <= 0) {
+ LOGW("set: not caching because valueSize is 0");
+ return;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ sp<Blob> dummyKey(new Blob(key, keySize, false));
+ CacheEntry dummyEntry(dummyKey, NULL);
+
+ while (true) {
+
+ ssize_t index = mCacheEntries.indexOf(dummyEntry);
+ if (index < 0) {
+ // Create a new cache entry.
+ sp<Blob> keyBlob(new Blob(key, keySize, true));
+ sp<Blob> valueBlob(new Blob(value, valueSize, true));
+ size_t newTotalSize = mTotalSize + keySize + valueSize;
+ if (mMaxTotalSize < newTotalSize) {
+ if (isCleanable()) {
+ // Clean the cache and try again.
+ clean();
+ continue;
+ } else {
+ LOGV("set: not caching new key/value pair because the "
+ "total cache size limit would be exceeded: %d "
+ "(limit: %d)",
+ keySize + valueSize, mMaxTotalSize);
+ break;
+ }
+ }
+ mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
+ mTotalSize = newTotalSize;
+ LOGV("set: created new cache entry with %d byte key and %d byte value",
+ keySize, valueSize);
+ } else {
+ // Update the existing cache entry.
+ sp<Blob> valueBlob(new Blob(value, valueSize, true));
+ sp<Blob> oldValueBlob(mCacheEntries[index].getValue());
+ size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+ if (mMaxTotalSize < newTotalSize) {
+ if (isCleanable()) {
+ // Clean the cache and try again.
+ clean();
+ continue;
+ } else {
+ LOGV("set: not caching new value because the total cache "
+ "size limit would be exceeded: %d (limit: %d)",
+ keySize + valueSize, mMaxTotalSize);
+ break;
+ }
+ }
+ mCacheEntries.editItemAt(index).setValue(valueBlob);
+ mTotalSize = newTotalSize;
+ LOGV("set: updated existing cache entry with %d byte key and %d byte "
+ "value", keySize, valueSize);
+ }
+ break;
+ }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+ size_t valueSize) {
+ if (mMaxKeySize < keySize) {
+ LOGV("get: not searching because the key is too large: %d (limit %d)",
+ keySize, mMaxKeySize);
+ return 0;
+ }
+ Mutex::Autolock lock(mMutex);
+ sp<Blob> dummyKey(new Blob(key, keySize, false));
+ CacheEntry dummyEntry(dummyKey, NULL);
+ ssize_t index = mCacheEntries.indexOf(dummyEntry);
+ if (index < 0) {
+ LOGV("get: no cache entry found for key of size %d", keySize);
+ return 0;
+ }
+
+ // The key was found. Return the value if the caller's buffer is large
+ // enough.
+ sp<Blob> valueBlob(mCacheEntries[index].getValue());
+ size_t valueBlobSize = valueBlob->getSize();
+ if (valueBlobSize <= valueSize) {
+ LOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+ memcpy(value, valueBlob->getData(), valueBlobSize);
+ } else {
+ LOGV("get: caller's buffer is too small for value: %d (needs %d)",
+ valueSize, valueBlobSize);
+ }
+ return valueBlobSize;
+}
+
+void BlobCache::clean() {
+ // Remove a random cache entry until the total cache size gets below half
+ // the maximum total cache size.
+ while (mTotalSize > mMaxTotalSize / 2) {
+ size_t i = size_t(nrand48(mRandState) % (mCacheEntries.size()));
+ const CacheEntry& entry(mCacheEntries[i]);
+ mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+ mCacheEntries.removeAt(i);
+ }
+}
+
+bool BlobCache::isCleanable() const {
+ return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData):
+ mData(copyData ? malloc(size) : data),
+ mSize(size),
+ mOwnsData(copyData) {
+ if (copyData) {
+ memcpy(const_cast<void*>(mData), data, size);
+ }
+}
+
+BlobCache::Blob::~Blob() {
+ if (mOwnsData) {
+ free(const_cast<void*>(mData));
+ }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+ if (mSize == rhs.mSize) {
+ return memcmp(mData, rhs.mData, mSize) < 0;
+ } else {
+ return mSize < rhs.mSize;
+ }
+}
+
+const void* BlobCache::Blob::getData() const {
+ return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+ return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value):
+ mKey(key),
+ mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+ mKey(ce.mKey),
+ mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+ return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+ mKey = rhs.mKey;
+ mValue = rhs.mValue;
+ return *this;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+ return mKey;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+ return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const sp<Blob>& value) {
+ mValue = value;
+}
+
+} // namespace android
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 58e0811..8db2009 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,6 +49,11 @@
// ---------------------------------------------------------------------------
+RefBase::Destroyer::~Destroyer() {
+}
+
+// ---------------------------------------------------------------------------
+
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
@@ -56,7 +61,7 @@
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
-
+ Destroyer* mDestroyer;
#if !DEBUG_REFS
@@ -65,6 +70,7 @@
, mWeak(0)
, mBase(base)
, mFlags(0)
+ , mDestroyer(0)
{
}
@@ -345,10 +351,6 @@
const_cast<RefBase*>(this)->onFirstRef();
}
-void RefBase::destroy() const {
- delete this;
-}
-
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
@@ -361,7 +363,11 @@
if (c == 1) {
const_cast<RefBase*>(this)->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- destroy();
+ if (refs->mDestroyer) {
+ refs->mDestroyer->destroy(this);
+ } else {
+ delete this;
+ }
}
}
refs->decWeak(id);
@@ -394,7 +400,9 @@
return mRefs->mStrong;
}
-
+void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
+ mRefs->mDestroyer = destroyer;
+}
RefBase* RefBase::weakref_type::refBase() const
{
@@ -420,7 +428,11 @@
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if (impl->mStrong == INITIAL_STRONG_VALUE) {
if (impl->mBase) {
- impl->mBase->destroy();
+ if (impl->mDestroyer) {
+ impl->mDestroyer->destroy(impl->mBase);
+ } else {
+ delete impl->mBase;
+ }
}
} else {
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
@@ -430,7 +442,11 @@
impl->mBase->onLastWeakRef(id);
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
if (impl->mBase) {
- impl->mBase->destroy();
+ if (impl->mDestroyer) {
+ impl->mDestroyer->destroy(impl->mBase);
+ } else {
+ delete impl->mBase;
+ }
}
}
}
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 8b5da0e..c748228 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -168,6 +168,9 @@
return 0;
}
+ // Note that *threadID is directly available to the parent only, as it is
+ // assigned after the child starts. Use memory barrier / lock if the child
+ // or other threads also need access.
if (threadId != NULL) {
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
@@ -718,7 +721,6 @@
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
- // The new thread wakes up at _threadLoop, but immediately blocks on mLock
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
@@ -742,11 +744,6 @@
{
Thread* const self = static_cast<Thread*>(user);
- // force a memory barrier before reading any fields, in particular mHoldSelf
- {
- Mutex::Autolock _l(self->mLock);
- }
-
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
@@ -816,6 +813,7 @@
status_t Thread::requestExitAndWait()
{
+ Mutex::Autolock _l(mLock);
if (mThread == getThreadId()) {
LOGW(
"Thread (this=%p): don't call waitForExit() from this "
@@ -825,9 +823,8 @@
return WOULD_BLOCK;
}
- requestExit();
+ mExitPending = true;
- Mutex::Autolock _l(mLock);
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 72d4876..87ad98e 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -6,6 +6,7 @@
# Build the unit tests.
test_src_files := \
+ BlobCache_test.cpp \
ObbFile_test.cpp \
Looper_test.cpp \
String8_test.cpp \
diff --git a/libs/utils/tests/BlobCache_test.cpp b/libs/utils/tests/BlobCache_test.cpp
new file mode 100644
index 0000000..653ea5e
--- /dev/null
+++ b/libs/utils/tests/BlobCache_test.cpp
@@ -0,0 +1,257 @@
+/*
+ ** Copyright 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/BlobCache.h>
+
+namespace android {
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+ enum {
+ MAX_KEY_SIZE = 6,
+ MAX_VALUE_SIZE = 8,
+ MAX_TOTAL_SIZE = 13,
+ };
+
+ virtual void SetUp() {
+ mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+ }
+
+ virtual void TearDown() {
+ mBC.clear();
+ }
+
+ sp<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+ char buf[2] = { 0xee, 0xee };
+ mBC->set("ab", 2, "cd", 2);
+ mBC->set("ef", 2, "gh", 2);
+ ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+ ASSERT_EQ('c', buf[0]);
+ ASSERT_EQ('d', buf[1]);
+ ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+ ASSERT_EQ('g', buf[0]);
+ ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+ char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ('e', buf[1]);
+ ASSERT_EQ('f', buf[2]);
+ ASSERT_EQ('g', buf[3]);
+ ASSERT_EQ('h', buf[4]);
+ ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+ char buf[3] = { 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ mBC->set("abcd", 4, "ijkl", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('i', buf[0]);
+ ASSERT_EQ('j', buf[1]);
+ ASSERT_EQ('k', buf[2]);
+ ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+ char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+ char key[MAX_KEY_SIZE+1];
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+ key[i] = 'a';
+ }
+ mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+ ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+ char buf[MAX_VALUE_SIZE+1];
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ buf[i] = 'b';
+ }
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ buf[i] = 0xee;
+ }
+ ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ SCOPED_TRACE(i);
+ ASSERT_EQ(0xee, buf[i]);
+ }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+ // Check a testing assumptions
+ ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+ char key[MAX_KEY_SIZE];
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+ ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+ ASSERT_EQ('w', buf[0]);
+ ASSERT_EQ('x', buf[1]);
+ ASSERT_EQ('y', buf[2]);
+ ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+ char buf[MAX_VALUE_SIZE];
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ buf[i] = 'b';
+ }
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ buf[i] = 0xee;
+ }
+ ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+ MAX_VALUE_SIZE));
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ SCOPED_TRACE(i);
+ ASSERT_EQ('b', buf[i]);
+ }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+ // Check a testing assumption
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+ ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+ char buf[1] = { 0xee };
+ mBC->set("x", 1, "y", 1);
+ ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+ ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+ for (int i = 0; i < 256; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, "x", 1);
+ }
+ int numCached = 0;
+ for (int i = 0; i < 256; i++) {
+ uint8_t k = i;
+ if (mBC->get(&k, 1, NULL, 0) == 1) {
+ numCached++;
+ }
+ }
+ ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+ // Fill up the entire cache with 1 char key/value pairs.
+ const int maxEntries = MAX_TOTAL_SIZE / 2;
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, "x", 1);
+ }
+ // Insert one more entry, causing a cache overflow.
+ {
+ uint8_t k = maxEntries;
+ mBC->set(&k, 1, "x", 1);
+ }
+ // Count the number of entries in the cache.
+ int numCached = 0;
+ for (int i = 0; i < maxEntries+1; i++) {
+ uint8_t k = i;
+ if (mBC->get(&k, 1, NULL, 0) == 1) {
+ numCached++;
+ }
+ }
+ ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+} // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 6b4391b..37fe182 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -40,7 +40,7 @@
#include <cutils/bitops.h>
#include <system/audio.h>
-#include <hardware/audio_policy.h>
+#include <system/audio_policy.h>
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a953487..b8ae79c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -128,7 +128,6 @@
size_t mNumStssTableEntries;
List<int32_t> mStssTableEntries;
- size_t mNumSttsTableEntries;
struct SttsTableEntry {
SttsTableEntry(uint32_t count, uint32_t duration)
@@ -137,8 +136,20 @@
uint32_t sampleCount;
uint32_t sampleDuration; // time scale based
};
+ size_t mNumSttsTableEntries;
List<SttsTableEntry> mSttsTableEntries;
+ struct CttsTableEntry {
+ CttsTableEntry(uint32_t count, int32_t timescaledDur)
+ : sampleCount(count), sampleDuration(timescaledDur) {}
+
+ uint32_t sampleCount;
+ int32_t sampleDuration; // time scale based
+ };
+ bool mHasNegativeCttsDeltaDuration;
+ size_t mNumCttsTableEntries;
+ List<CttsTableEntry> mCttsTableEntries;
+
// Sequence parameter set or picture parameter set
struct AVCParamSet {
AVCParamSet(uint16_t length, const uint8_t *data)
@@ -219,6 +230,7 @@
// Duration is time scale based
void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
+ void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
void sendTrackSummary(bool hasMultipleTracks);
// Write the boxes
@@ -227,6 +239,7 @@
void writeStszBox();
void writeStssBox();
void writeSttsBox();
+ void writeCttsBox();
void writeD263Box();
void writePaspBox();
void writeAvccBox();
@@ -1147,6 +1160,7 @@
mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size
mNumStssTableEntries * 4 + // stss box size
mNumSttsTableEntries * 8 + // stts box size
+ mNumCttsTableEntries * 8 + // ctts box size
stcoBoxSizeBytes + // stco box size
stszBoxSizeBytes; // stsz box size
}
@@ -1173,6 +1187,20 @@
++mNumSttsTableEntries;
}
+void MPEG4Writer::Track::addOneCttsTableEntry(
+ size_t sampleCount, int32_t duration) {
+
+ if (mIsAudio) {
+ return;
+ }
+ if (duration < 0 && !mHasNegativeCttsDeltaDuration) {
+ mHasNegativeCttsDeltaDuration = true;
+ }
+ CttsTableEntry cttsEntry(sampleCount, duration);
+ mCttsTableEntries.push_back(cttsEntry);
+ ++mNumCttsTableEntries;
+}
+
void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
++mNumStcoTableEntries;
mChunkOffsets.push_back(offset);
@@ -1483,6 +1511,7 @@
mNumStssTableEntries = 0;
mNumStscTableEntries = 0;
mNumSttsTableEntries = 0;
+ mNumCttsTableEntries = 0;
mMdatSizeBytes = 0;
mIsMediaTimeAdjustmentOn = false;
mPrevMediaTimeAdjustTimestampUs = 0;
@@ -1491,6 +1520,7 @@
mTotalDriftTimeToAdjustUs = 0;
mPrevTotalAccumDriftTimeUs = 0;
mMaxChunkDurationUs = 0;
+ mHasNegativeCttsDeltaDuration = false;
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
@@ -1932,14 +1962,19 @@
int64_t chunkTimestampUs = 0;
int32_t nChunks = 0;
int32_t nZeroLengthFrames = 0;
- int64_t lastTimestampUs = 0; // Previous sample time stamp in ms
- int64_t lastDurationUs = 0; // Between the previous two samples in ms
- int64_t currDurationTicks = 0; // Timescale based ticks
- int64_t lastDurationTicks = 0; // Timescale based ticks
- int32_t sampleCount = 1; // Sample count in the current stts table entry
- uint32_t previousSampleSize = 0; // Size of the previous sample
+ int64_t lastTimestampUs = 0; // Previous sample time stamp
+ int64_t lastCttsTimeUs = 0; // Previous sample time stamp
+ int64_t lastDurationUs = 0; // Between the previous two samples
+ int64_t currDurationTicks = 0; // Timescale based ticks
+ int64_t lastDurationTicks = 0; // Timescale based ticks
+ int32_t sampleCount = 1; // Sample count in the current stts table entry
+ int64_t currCttsDurTicks = 0; // Timescale based ticks
+ int64_t lastCttsDurTicks = 0; // Timescale based ticks
+ int32_t cttsSampleCount = 1; // Sample count in the current ctts table entry
+ uint32_t previousSampleSize = 0; // Size of the previous sample
int64_t previousPausedDurationUs = 0;
- int64_t timestampUs;
+ int64_t timestampUs = 0;
+ int64_t cttsDeltaTimeUs = 0;
if (mIsAudio) {
prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
@@ -2063,7 +2098,6 @@
*
*/
CHECK(meta_data->findInt64(kKeyTime, ×tampUs));
- LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
////////////////////////////////////////////////////////////////////////////////
if (mNumSamples == 0) {
@@ -2084,6 +2118,24 @@
timestampUs -= previousPausedDurationUs;
CHECK(timestampUs >= 0);
+ if (!mIsAudio) {
+ /*
+ * Composition time: timestampUs
+ * Decoding time: decodingTimeUs
+ * Composition time delta = composition time - decoding time
+ *
+ * We save picture decoding time stamp delta in stts table entries,
+ * and composition time delta duration in ctts table entries.
+ */
+ int64_t decodingTimeUs;
+ CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
+ decodingTimeUs -= previousPausedDurationUs;
+ int64_t timeUs = decodingTimeUs;
+ cttsDeltaTimeUs = timestampUs - decodingTimeUs;
+ timestampUs = decodingTimeUs;
+ LOGV("decoding time: %lld and ctts delta time: %lld",
+ timestampUs, cttsDeltaTimeUs);
+ }
// Media time adjustment for real-time applications
if (mIsRealTimeRecording) {
@@ -2139,6 +2191,18 @@
} else {
++sampleCount;
}
+
+ if (!mIsAudio) {
+ currCttsDurTicks =
+ ((cttsDeltaTimeUs * mTimeScale + 500000LL) / 1000000LL -
+ (lastCttsTimeUs * mTimeScale + 500000LL) / 1000000LL);
+ if (currCttsDurTicks != lastCttsDurTicks) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
+ cttsSampleCount = 1;
+ } else {
+ ++cttsSampleCount;
+ }
+ }
}
if (mSamplesHaveSameSize) {
if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
@@ -2152,6 +2216,11 @@
lastDurationTicks = currDurationTicks;
lastTimestampUs = timestampUs;
+ if (!mIsAudio) {
+ lastCttsDurTicks = currCttsDurTicks;
+ lastCttsTimeUs = cttsDeltaTimeUs;
+ }
+
if (isSync != 0) {
addOneStssTableEntry(mNumSamples);
}
@@ -2221,8 +2290,10 @@
if (mNumSamples == 1) {
lastDurationUs = 0; // A single sample's duration
lastDurationTicks = 0;
+ lastCttsDurTicks = 0;
} else {
++sampleCount; // Count for the last sample
+ ++cttsSampleCount;
}
if (mNumSamples <= 2) {
@@ -2234,6 +2305,7 @@
addOneSttsTableEntry(sampleCount, lastDurationTicks);
}
+ addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
mTrackDurationUs += lastDurationUs;
mReachedEOS = true;
@@ -2432,6 +2504,7 @@
}
mOwner->endBox(); // stsd
writeSttsBox();
+ writeCttsBox();
if (!mIsAudio) {
writeStssBox();
}
@@ -2782,13 +2855,49 @@
int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
mOwner->writeInt32(dur + it->sampleDuration);
+ int64_t totalCount = 1;
while (++it != mSttsTableEntries.end()) {
mOwner->writeInt32(it->sampleCount);
mOwner->writeInt32(it->sampleDuration);
+ totalCount += it->sampleCount;
}
+ CHECK(totalCount == mNumSamples);
mOwner->endBox(); // stts
}
+void MPEG4Writer::Track::writeCttsBox() {
+ if (mIsAudio) { // ctts is not for audio
+ return;
+ }
+
+ // Do not write ctts box when there is no need to have it.
+ if ((mNumCttsTableEntries == 1 &&
+ mCttsTableEntries.begin()->sampleDuration == 0) ||
+ mNumCttsTableEntries == 0) {
+ return;
+ }
+
+ LOGV("ctts box has %d entries", mNumCttsTableEntries);
+
+ mOwner->beginBox("ctts");
+ if (mHasNegativeCttsDeltaDuration) {
+ mOwner->writeInt32(0x00010000); // version=1, flags=0
+ } else {
+ mOwner->writeInt32(0); // version=0, flags=0
+ }
+ mOwner->writeInt32(mNumCttsTableEntries);
+
+ int64_t totalCount = 0;
+ for (List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
+ it != mCttsTableEntries.end(); ++it) {
+ mOwner->writeInt32(it->sampleCount);
+ mOwner->writeInt32(it->sampleDuration);
+ totalCount += it->sampleCount;
+ }
+ CHECK(totalCount == mNumSamples);
+ mOwner->endBox(); // ctts
+}
+
void MPEG4Writer::Track::writeStssBox() {
mOwner->beginBox("stss");
mOwner->writeInt32(0); // version=0, flags=0
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 72d0d08..c4fcc79 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1981,6 +1981,20 @@
return bufInfo;
}
+int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
+ CHECK(mIsEncoder);
+ CHECK(!mDecodingTimeList.empty());
+ List<int64_t>::iterator it = mDecodingTimeList.begin();
+ int64_t timeUs = *it;
+
+ // If the output buffer is codec specific configuration,
+ // do not remove the decoding time from the list.
+ if (!isCodecSpecific) {
+ mDecodingTimeList.erase(it);
+ }
+ return timeUs;
+}
+
void OMXCodec::on_message(const omx_message &msg) {
if (mState == ERROR) {
LOGW("Dropping OMX message - we're in ERROR state.");
@@ -2128,14 +2142,21 @@
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
}
+ bool isCodecSpecific = false;
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) {
buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
+ isCodecSpecific = true;
}
if (isGraphicBuffer || mQuirks & kOutputBuffersAreUnreadable) {
buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
}
+ if (mIsEncoder) {
+ int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
+ buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
+ }
+
buffer->meta_data()->setPointer(
kKeyPlatformPrivate,
msg.u.extended_buffer_data.platform_private);
@@ -2938,6 +2959,9 @@
int64_t lastBufferTimeUs;
CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
CHECK(lastBufferTimeUs >= 0);
+ if (mIsEncoder) {
+ mDecodingTimeList.push_back(lastBufferTimeUs);
+ }
if (offset == 0) {
timestampUs = lastBufferTimeUs;
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
index ef57228..72519fb 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
@@ -57,15 +57,15 @@
android:layout_width="match_parent"
android:layout_weight="1"
>
- <LinearLayout
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|bottom"
- android:orientation="vertical"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="afterDescendants"
+ systemui:rowHeight="@dimen/notification_height"
/>
</ScrollView>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
index 8e456b2..93085d7 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
@@ -1,6 +1,6 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="65dp"
+ android:layout_height="@dimen/notification_height"
>
<ImageButton
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 18e8273..6670eff 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,9 @@
*/
-->
-<com.android.systemui.statusbar.phone.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.phone.ExpandedView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
@@ -97,10 +99,11 @@
android:textAppearance="@style/TextAppearance.StatusBar.Title"
android:text="@string/status_bar_ongoing_events_title"
/>
- <LinearLayout android:id="@+id/ongoingItems"
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/ongoingItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ systemui:rowHeight="@dimen/notification_height"
/>
<TextView android:id="@+id/latestTitle"
@@ -111,10 +114,11 @@
android:textAppearance="@style/TextAppearance.StatusBar.Title"
android:text="@string/status_bar_latest_events_title"
/>
- <LinearLayout android:id="@+id/latestItems"
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/latestItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ systemui:rowHeight="@dimen/notification_height"
/>
</LinearLayout>
</ScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 8e456b2..93085d7 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,6 +1,6 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="65dp"
+ android:layout_height="@dimen/notification_height"
>
<ImageButton
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index fb2f7d63..5291629 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -24,5 +24,8 @@
<declare-styleable name="NotificationLinearLayout">
<attr name="insetLeft" format="dimension" />
</declare-styleable>
+ <declare-styleable name="NotificationRowLayout">
+ <attr name="rowHeight" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 657dc46..5f0fbef 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -47,5 +47,8 @@
<!-- thickness (height) of the navigation bar on phones that require it -->
<dimen name="navigation_bar_size">42dp</dimen>
+
+ <!-- thickness (height) of each notification row, including any separators or padding -->
+ <dimen name="notification_height">65dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 92b8976..51fc7c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.animation.LayoutTransition;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Display;
@@ -37,6 +38,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+
+ setLayerType(LAYER_TYPE_HARDWARE, null);
}
/** We want to shrink down to 0, and ignore the background. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 00de920..3d15a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -130,11 +130,11 @@
// ongoing
NotificationData mOngoing = new NotificationData();
TextView mOngoingTitle;
- LinearLayout mOngoingItems;
+ ViewGroup mOngoingItems;
// latest
NotificationData mLatest = new NotificationData();
TextView mLatestTitle;
- LinearLayout mLatestItems;
+ ViewGroup mLatestItems;
// position
int[] mPositionTmp = new int[2];
boolean mExpanded;
@@ -268,9 +268,9 @@
mExpandedView = expanded;
mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
- mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+ mOngoingItems = (ViewGroup)expanded.findViewById(R.id.ongoingItems);
mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
- mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+ mLatestItems = (ViewGroup)expanded.findViewById(R.id.latestItems);
mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
new file mode 100644
index 0000000..24eee27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -0,0 +1,265 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.HashSet;
+
+import com.android.systemui.R;
+
+public class NotificationRowLayout extends ViewGroup {
+ private static final String TAG = "NotificationRowLayout";
+ private static final boolean DEBUG = false;
+
+ private static final boolean ANIMATE_LAYOUT = true;
+
+ private static final int ANIM_LEN = DEBUG ? 5000 : 250;
+
+ Rect mTmpRect = new Rect();
+ int mNumRows = 0;
+ int mRowHeight = 0;
+ int mHeight = 0;
+
+ HashSet<View> mAppearingViews = new HashSet<View>();
+ HashSet<View> mDisappearingViews = new HashSet<View>();
+
+ public NotificationRowLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationRowLayout,
+ defStyle, 0);
+ mRowHeight = a.getDimensionPixelSize(R.styleable.NotificationRowLayout_rowHeight, 0);
+ a.recycle();
+
+ setLayoutTransition(null);
+
+ if (DEBUG) {
+ setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
+ @Override
+ public void onChildViewAdded(View parent, View child) {
+ Slog.d(TAG, "view added: " + child + "; new count: " + getChildCount());
+ }
+ @Override
+ public void onChildViewRemoved(View parent, View child) {
+ Slog.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
+ }
+ });
+
+ setBackgroundColor(0x80FF8000);
+ }
+
+ }
+
+ //**
+ @Override
+ public void addView(View child, int index, LayoutParams params) {
+ super.addView(child, index, params);
+
+ final View childF = child;
+
+ if (ANIMATE_LAYOUT) {
+ mAppearingViews.add(child);
+
+ child.setPivotY(0);
+ AnimatorSet a = new AnimatorSet();
+ a.playTogether(
+ ObjectAnimator.ofFloat(child, "alpha", 0f, 1f)
+// ,ObjectAnimator.ofFloat(child, "scaleY", 0f, 1f)
+ );
+ a.setDuration(ANIM_LEN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAppearingViews.remove(childF);
+ }
+ });
+ a.start();
+ requestLayout(); // start the container animation
+ }
+ }
+
+ @Override
+ public void removeView(View child) {
+ final View childF = child;
+ if (ANIMATE_LAYOUT) {
+ if (mAppearingViews.contains(child)) {
+ mAppearingViews.remove(child);
+ }
+ mDisappearingViews.add(child);
+
+ child.setPivotY(0);
+ AnimatorSet a = new AnimatorSet();
+ a.playTogether(
+ ObjectAnimator.ofFloat(child, "alpha", 0f)
+// ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
+ ,ObjectAnimator.ofFloat(child, "translationX", 300f)
+ );
+ a.setDuration(ANIM_LEN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ NotificationRowLayout.super.removeView(childF);
+ childF.setAlpha(1f);
+ mDisappearingViews.remove(childF);
+ }
+ });
+ a.start();
+ requestLayout(); // start the container animation
+ } else {
+ super.removeView(child);
+ }
+ }
+ //**
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public void onDraw(android.graphics.Canvas c) {
+ super.onDraw(c);
+ if (DEBUG) {
+ Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+ + getMeasuredHeight() + "px");
+ c.save();
+ c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
+ android.graphics.Region.Op.DIFFERENCE);
+ c.drawColor(0xFFFF8000);
+ c.restore();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int count = getChildCount();
+
+ // pass 1: count the number of non-GONE views
+ int numRows = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ if (mDisappearingViews.contains(child)) {
+ continue;
+ }
+ numRows++;
+ }
+ if (numRows != mNumRows) {
+ // uh oh, now you made us go and do work
+
+ final int computedHeight = numRows * mRowHeight;
+ if (DEBUG) {
+ Slog.d(TAG, String.format("rows went from %d to %d, resizing to %dpx",
+ mNumRows, numRows, computedHeight));
+ }
+
+ mNumRows = numRows;
+
+ if (ANIMATE_LAYOUT && isShown()) {
+ ObjectAnimator.ofInt(this, "forcedHeight", computedHeight)
+ .setDuration(ANIM_LEN)
+ .start();
+ } else {
+ setForcedHeight(computedHeight);
+ }
+ }
+
+ // pass 2: you know, do the measuring
+ final int childWidthMS = widthMeasureSpec;
+ final int childHeightMS = MeasureSpec.makeMeasureSpec(
+ mRowHeight, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ child.measure(childWidthMS, childHeightMS);
+ }
+
+ setMeasuredDimension(
+ getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
+ resolveSize(getForcedHeight(), heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int width = right - left;
+ final int height = bottom - top;
+
+ if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
+
+ final int count = getChildCount();
+ int y = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+// final int thisRowHeight = (int)(
+// ((mAppearingViews.contains(child) || mDisappearingViews.contains(child))
+// ? child.getScaleY()
+// : 1.0f)
+// * mRowHeight);
+ final int thisRowHeight = (int)(child.getAlpha() * mRowHeight);
+// child.layout(0, y, width, y + thisRowHeight);
+ child.layout(0, y, width, y + mRowHeight);
+ y += thisRowHeight;
+ }
+ }
+
+ public void setForcedHeight(int h) {
+ if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
+ if (h != mHeight) {
+ mHeight = h;
+ requestLayout();
+ }
+ }
+
+ public int getForcedHeight() {
+ return mHeight;
+ }
+}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d4a8ddb..44df5b5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -44,7 +44,7 @@
#include <private/media/AudioEffectShared.h>
#include <system/audio.h>
-#include <hardware/audio_hal.h>
+#include <hardware/audio.h>
#include "AudioMixer.h"
#include "AudioFlinger.h"
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index f3371bf..1fad987 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -39,7 +39,7 @@
#include <binder/MemoryDealer.h>
#include <system/audio.h>
-#include <hardware/audio_hal.h>
+#include <hardware/audio.h>
#include "AudioBufferProvider.h"
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index dd91788..47ca3a0 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -36,8 +36,8 @@
#include <hardware/hardware.h>
#include <system/audio.h>
+#include <system/audio_policy.h>
#include <hardware/audio_policy.h>
-#include <hardware/audio_policy_hal.h>
namespace android {
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index d9b5ada..b830120 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -23,8 +23,8 @@
#include <binder/BinderService.h>
#include <system/audio.h>
+#include <system/audio_policy.h>
#include <hardware/audio_policy.h>
-#include <hardware/audio_policy_hal.h>
namespace android {
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 29add52..6e803a4 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -192,6 +192,7 @@
outAxisInfo->maxValue = info.maximum;
outAxisInfo->flat = info.flat;
outAxisInfo->fuzz = info.fuzz;
+ outAxisInfo->resolution = info.resolution;
}
return OK;
}
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 558959b..abe1318 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -34,39 +34,6 @@
#include <linux/input.h>
-/* These constants are not defined in linux/input.h in the version of the kernel
- * headers currently provided with Bionic. */
-
-#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len)
-
-#define INPUT_PROP_POINTER 0x00
-#define INPUT_PROP_DIRECT 0x01
-#define INPUT_PROP_BUTTONPAD 0x02
-#define INPUT_PROP_SEMI_MT 0x03
-#define INPUT_PROP_MAX 0x1f
-#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
-
-#define ABS_MT_SLOT 0x2f
-#define ABS_MT_TOUCH_MAJOR 0x30
-#define ABS_MT_TOUCH_MINOR 0x31
-#define ABS_MT_WIDTH_MAJOR 0x32
-#define ABS_MT_WIDTH_MINOR 0x33
-#define ABS_MT_ORIENTATION 0x34
-#define ABS_MT_POSITION_X 0x35
-#define ABS_MT_POSITION_Y 0x36
-#define ABS_MT_TOOL_TYPE 0x37
-#define ABS_MT_BLOB_ID 0x38
-#define ABS_MT_TRACKING_ID 0x39
-#define ABS_MT_PRESSURE 0x3a
-#define ABS_MT_DISTANCE 0x3b
-
-#define MT_TOOL_FINGER 0
-#define MT_TOOL_PEN 1
-
-#define SYN_MT_REPORT 2
-#define SYN_DROPPED 3
-
-
/* Convenience constants. */
#define BTN_FIRST 0x100 // first button scancode
@@ -97,6 +64,7 @@
int32_t maxValue; // maximum value
int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
+ int32_t resolution; // resolution in units per mm or radians per mm
inline void clear() {
valid = false;
@@ -104,6 +72,7 @@
maxValue = 0;
flat = 0;
fuzz = 0;
+ resolution = 0;
}
};
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index fcc6198..15bb300 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1044,8 +1044,8 @@
void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
const RawAbsoluteAxisInfo& axis, const char* name) {
if (axis.valid) {
- dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n",
- name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
+ dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
+ name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
} else {
dump.appendFormat(INDENT4 "%s: unknown range\n", name);
}
@@ -5656,9 +5656,10 @@
dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, "
"highScale=%0.5f, highOffset=%0.5f\n",
axis.scale, axis.offset, axis.highScale, axis.highOffset);
- dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n",
+ dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, "
+ "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
- axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz);
+ axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
}
}
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index d04c9e7..acda86b 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -481,7 +481,7 @@
}
void addAbsoluteAxis(int32_t deviceId, int axis,
- int32_t minValue, int32_t maxValue, int flat, int fuzz) {
+ int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) {
Device* device = getDevice(deviceId);
RawAbsoluteAxisInfo info;
@@ -490,6 +490,7 @@
info.maxValue = maxValue;
info.flat = flat;
info.fuzz = fuzz;
+ info.resolution = resolution;
device->absoluteAxes.add(axis, info);
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 86671d6..ec59da6 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -46,6 +46,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
+import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -149,9 +150,6 @@
synchronized (mLock) {
notifyEventListenerLocked(service, eventType);
- AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
- service.mPendingEvents.remove(eventType);
- tryRecycleLocked(oldEvent);
}
}
};
@@ -319,17 +317,14 @@
public boolean sendAccessibilityEvent(AccessibilityEvent event) {
synchronized (mLock) {
- mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
- notifyAccessibilityServicesDelayedLocked(event, false);
- notifyAccessibilityServicesDelayedLocked(event, true);
+ if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
+ mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
+ notifyAccessibilityServicesDelayedLocked(event, false);
+ notifyAccessibilityServicesDelayedLocked(event, true);
+ }
}
- // event not scheduled for dispatch => recycle
- if (mHandledFeedbackTypes == 0) {
- event.recycle();
- } else {
- mHandledFeedbackTypes = 0;
- }
-
+ event.recycle();
+ mHandledFeedbackTypes = 0;
return (OWN_PROCESS_ID != Binder.getCallingPid());
}
@@ -517,46 +512,27 @@
private void notifyAccessibilityServiceDelayedLocked(Service service,
AccessibilityEvent event) {
synchronized (mLock) {
- int eventType = event.getEventType();
+ final int eventType = event.getEventType();
+ // Make a copy since during dispatch it is possible the event to
+ // be modified to remove its source if the receiving service does
+ // not have permission to access the window content.
+ AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
- service.mPendingEvents.put(eventType, event);
+ service.mPendingEvents.put(eventType, newEvent);
- int what = eventType | (service.mId << 16);
+ final int what = eventType | (service.mId << 16);
if (oldEvent != null) {
mHandler.removeMessages(what);
- tryRecycleLocked(oldEvent);
+ oldEvent.recycle();
}
Message message = mHandler.obtainMessage(what, service);
- message.arg1 = event.getEventType();
+ message.arg1 = eventType;
mHandler.sendMessageDelayed(message, service.mNotificationTimeout);
}
}
/**
- * Recycles an event if it can be safely recycled. The condition is that no
- * not notified service is interested in the event.
- *
- * @param event The event.
- */
- private void tryRecycleLocked(AccessibilityEvent event) {
- if (event == null) {
- return;
- }
- int eventType = event.getEventType();
- List<Service> services = mServices;
-
- // linear in the number of service which is not large
- for (int i = 0, count = services.size(); i < count; i++) {
- Service service = services.get(i);
- if (service.mPendingEvents.get(eventType) == event) {
- return;
- }
- }
- event.recycle();
- }
-
- /**
* Notifies a service for a scheduled event given the event type.
*
* @param service The service.
@@ -565,7 +541,7 @@
private void notifyEventListenerLocked(Service service, int eventType) {
IEventListener listener = service.mServiceInterface;
AccessibilityEvent event = service.mPendingEvents.get(eventType);
-
+ service.mPendingEvents.remove(eventType);
try {
if (mSecurityPolicy.canRetrieveWindowContent(service)) {
event.setConnection(service);
@@ -574,6 +550,7 @@
}
event.setSealed(true);
listener.onAccessibilityEvent(event);
+ event.recycle();
if (DEBUG) {
Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
}
@@ -926,7 +903,7 @@
}
}
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
@@ -961,10 +938,18 @@
return null;
}
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text) {
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
+ String text) {
+ return findAccessibilityNodeInfosByViewText(text,
+ mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID);
+ }
+
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
+ int accessibilityWindowId, int accessibilityViewId) {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
- final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
+ final boolean permissionGranted =
+ mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
if (permissionGranted) {
connection = getConnectionToRetrievalAllowingWindowLocked();
}
@@ -978,7 +963,8 @@
final long identityToken = Binder.clearCallingIdentity();
try {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- connection.findAccessibilityNodeInfosByViewText(text, interactionId, mCallback);
+ connection.findAccessibilityNodeInfosByViewText(text, accessibilityViewId,
+ interactionId, mCallback);
List<AccessibilityNodeInfo> infos =
mCallback.getFindAccessibilityNodeInfosResultAndClear(interactionId);
if (infos != null) {
@@ -1112,16 +1098,23 @@
| AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
| AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
| AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
- | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+ | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
+ | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
private int mRetrievalAlowingWindowId;
+ private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
+ // Send window changed event only for the retrieval allowing window.
+ return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+ || event.getWindowId() == mRetrievalAlowingWindowId);
+ }
+
public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) {
- final int windowId = event.getSourceAccessibilityWindowId();
+ final int windowId = event.getWindowId();
final int eventType = event.getEventType();
if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) != 0) {
mRetrievalAlowingWindowId = windowId;
- } else {
+ } else {
event.setSource(null);
}
}
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index b754dba..ab85b14 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -126,13 +126,15 @@
// Unpack the config.
// TODO: move constants into VpnBuilder.
+ int mtu = config.getInt("mtu", -1);
String session = config.getString("session");
String addresses = config.getString("addresses");
String routes = config.getString("routes");
String dnsServers = config.getString("dnsServers");
- // Create interface and configure addresses and routes.
- ParcelFileDescriptor descriptor = nativeConfigure(addresses, routes);
+ // Create and configure the interface.
+ ParcelFileDescriptor descriptor =
+ ParcelFileDescriptor.adoptFd(nativeEstablish(mtu, addresses, routes));
// Replace the interface and abort if it fails.
try {
@@ -250,7 +252,7 @@
}
}
- private native ParcelFileDescriptor nativeConfigure(String addresses, String routes);
+ 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);
diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java
index f7a7c49..4a207f7 100644
--- a/services/java/com/android/server/net/NetworkIdentity.java
+++ b/services/java/com/android/server/net/NetworkIdentity.java
@@ -26,6 +26,7 @@
import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
import static android.telephony.TelephonyManager.getNetworkClass;
import android.content.Context;
@@ -148,6 +149,7 @@
if (isNetworkTypeMobile(type)
&& Objects.equal(this.subscriberId, subscriberId)) {
switch (getNetworkClass(subType)) {
+ case NETWORK_CLASS_UNKNOWN:
case NETWORK_CLASS_2_G:
case NETWORK_CLASS_3_G:
return true;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 2766093..e7d60638 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -20,7 +20,9 @@
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
+import static android.Manifest.permission.READ_PHONE_STATE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -28,6 +30,8 @@
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.dumpPolicy;
import static android.net.NetworkPolicyManager.dumpRules;
+import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
+import static android.net.TrafficStats.isNetworkTemplateMobile;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -53,6 +57,8 @@
import android.os.IPowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.telephony.TelephonyManager;
+import android.text.format.Time;
import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.SparseArray;
@@ -96,9 +102,14 @@
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG = "NetworkPolicy";
private static final boolean LOGD = true;
+ private static final boolean LOGV = false;
private static final int VERSION_CURRENT = 1;
+ private static final long KB_IN_BYTES = 1024;
+ private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+ private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
private static final String TAG_POLICY_LIST = "policy-list";
private static final String TAG_NETWORK_POLICY = "network-policy";
private static final String TAG_UID_POLICY = "uid-policy";
@@ -126,14 +137,14 @@
private boolean mScreenOn;
- /** Current network policy for each UID. */
+ /** Current policy for network templates. */
+ private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+
+ /** Current policy for each UID. */
private SparseIntArray mUidPolicy = new SparseIntArray();
/** Current derived network rules for each UID. */
private SparseIntArray mUidRules = new SparseIntArray();
- /** Set of policies for strong network templates. */
- private HashMap<StrongTemplate, NetworkPolicy> mTemplatePolicy = Maps.newHashMap();
-
/** Foreground at both UID and PID granularity. */
private SparseBooleanArray mUidForeground = new SparseBooleanArray();
private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
@@ -150,8 +161,6 @@
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
- // TODO: dispatch callbacks through handler when locked
-
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats) {
// TODO: move to using cached NtpTrustedTime
@@ -264,8 +273,7 @@
/**
* Receiver that watches for {@link IConnectivityManager} to claim network
- * interfaces. Used to apply {@link NetworkPolicy} when networks match
- * {@link StrongTemplate}.
+ * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
*/
private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
@Override
@@ -273,6 +281,7 @@
// on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above.
synchronized (mRulesLock) {
+ ensureActiveMobilePolicyLocked();
updateIfacesLocked();
}
}
@@ -284,7 +293,7 @@
* remaining quota based on usage cycle and historical stats.
*/
private void updateIfacesLocked() {
- if (LOGD) Slog.v(TAG, "updateIfacesLocked()");
+ if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
final NetworkState[] states;
try {
@@ -307,14 +316,14 @@
}
// build list of rules and ifaces to enforce them against
- final HashMap<StrongTemplate, String[]> rules = Maps.newHashMap();
+ final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
final ArrayList<String> ifaceList = Lists.newArrayList();
- for (StrongTemplate template : mTemplatePolicy.keySet()) {
+ for (NetworkPolicy policy : mNetworkPolicy) {
// collect all active ifaces that match this template
ifaceList.clear();
for (NetworkIdentity ident : networks.keySet()) {
- if (ident.matchesTemplate(template.networkTemplate, template.subscriberId)) {
+ if (ident.matchesTemplate(policy.networkTemplate, policy.subscriberId)) {
final String iface = networks.get(ident);
ifaceList.add(iface);
}
@@ -322,7 +331,7 @@
if (ifaceList.size() > 0) {
final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
- rules.put(template, ifaces);
+ rules.put(policy, ifaces);
}
}
@@ -336,41 +345,81 @@
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
- for (StrongTemplate template : rules.keySet()) {
- final NetworkPolicy policy = mTemplatePolicy.get(template);
+ for (NetworkPolicy policy : rules.keySet()) {
final String[] ifaces = rules.get(policy);
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
final NetworkStats stats;
+ final long total;
try {
stats = mNetworkStats.getSummaryForNetwork(
- start, end, template.networkTemplate, template.subscriberId);
+ start, end, policy.networkTemplate, policy.subscriberId);
+ total = stats.rx[0] + stats.tx[0];
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading summary for template " + template.networkTemplate);
+ Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate);
continue;
}
- // remaining "quota" is based on usage in current cycle
- final long total = stats.rx[0] + stats.tx[0];
- final long quota = Math.max(0, policy.limitBytes - total);
-
if (LOGD) {
Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
- + Arrays.toString(ifaces) + " with quota " + quota);
+ + Arrays.toString(ifaces));
}
- // TODO: push rule down through NetworkManagementService.setInterfaceQuota()
+ // TODO: register for warning notification trigger through NMS
+ if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
+ // remaining "quota" is based on usage in current cycle
+ final long quota = Math.max(0, policy.limitBytes - total);
+
+ // TODO: push quota rule down through NMS
+ }
+ }
+ }
+
+ /**
+ * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
+ * have at least a default mobile policy defined.
+ */
+ private void ensureActiveMobilePolicyLocked() {
+ if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
+ final String subscriberId = getActiveSubscriberId();
+ if (subscriberId == null) {
+ if (LOGV) Slog.v(TAG, "no active mobile network, ignoring policy check");
+ return;
+ }
+
+ // examine to see if any policy is defined for active mobile
+ boolean mobileDefined = false;
+ for (NetworkPolicy policy : mNetworkPolicy) {
+ if (isNetworkTemplateMobile(policy.networkTemplate)
+ && Objects.equal(subscriberId, policy.subscriberId)) {
+ mobileDefined = true;
+ }
+ }
+
+ if (!mobileDefined) {
+ Slog.i(TAG, "no policy for active mobile network; generating default policy");
+
+ // default mobile policy has combined 4GB warning, and assume usage
+ // cycle starts today today.
+
+ // TODO: move this policy definition to overlay or secure setting
+ final Time time = new Time(Time.TIMEZONE_UTC);
+ time.setToNow();
+ final int cycleDay = time.monthDay;
+
+ mNetworkPolicy.add(new NetworkPolicy(
+ TEMPLATE_MOBILE_ALL, subscriberId, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
}
}
private void readPolicyLocked() {
- if (LOGD) Slog.v(TAG, "readPolicyLocked()");
+ if (LOGV) Slog.v(TAG, "readPolicyLocked()");
// clear any existing policy and read from disk
- mTemplatePolicy.clear();
+ mNetworkPolicy.clear();
mUidPolicy.clear();
FileInputStream fis = null;
@@ -390,13 +439,12 @@
} else if (TAG_NETWORK_POLICY.equals(tag)) {
final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
-
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
- mTemplatePolicy.put(new StrongTemplate(networkTemplate, subscriberId),
- new NetworkPolicy(cycleDay, warningBytes, limitBytes));
+ mNetworkPolicy.add(new NetworkPolicy(
+ networkTemplate, subscriberId, cycleDay, warningBytes, limitBytes));
} else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID);
@@ -419,7 +467,7 @@
}
private void writePolicyLocked() {
- if (LOGD) Slog.v(TAG, "writePolicyLocked()");
+ if (LOGV) Slog.v(TAG, "writePolicyLocked()");
FileOutputStream fos = null;
try {
@@ -433,13 +481,11 @@
writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
// write all known network policies
- for (StrongTemplate template : mTemplatePolicy.keySet()) {
- final NetworkPolicy policy = mTemplatePolicy.get(template);
-
+ for (NetworkPolicy policy : mNetworkPolicy) {
out.startTag(null, TAG_NETWORK_POLICY);
- writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.networkTemplate);
- if (template.subscriberId != null) {
- out.attribute(null, ATTR_SUBSCRIBER_ID, template.subscriberId);
+ writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, policy.networkTemplate);
+ if (policy.subscriberId != null) {
+ out.attribute(null, ATTR_SUBSCRIBER_ID, policy.subscriberId);
}
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
@@ -519,25 +565,27 @@
}
@Override
- public void setNetworkPolicy(int networkType, String subscriberId, NetworkPolicy policy) {
+ public void setNetworkPolicies(NetworkPolicy[] policies) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) {
- mTemplatePolicy.put(new StrongTemplate(networkType, subscriberId), policy);
+ mNetworkPolicy.clear();
+ for (NetworkPolicy policy : policies) {
+ mNetworkPolicy.add(policy);
+ }
- // network policy changed, recompute template rules based on active
- // interfaces and persist policy.
updateIfacesLocked();
writePolicyLocked();
}
}
@Override
- public NetworkPolicy getNetworkPolicy(int networkType, String subscriberId) {
+ public NetworkPolicy[] getNetworkPolicies() {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
synchronized (mRulesLock) {
- return mTemplatePolicy.get(new StrongTemplate(networkType, subscriberId));
+ return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
}
}
@@ -547,10 +595,8 @@
synchronized (mRulesLock) {
fout.println("Network policies:");
- for (StrongTemplate template : mTemplatePolicy.keySet()) {
- final NetworkPolicy policy = mTemplatePolicy.get(template);
- fout.print(" "); fout.println(template.toString());
- fout.print(" "); fout.println(policy.toString());
+ for (NetworkPolicy policy : mNetworkPolicy) {
+ fout.print(" "); fout.println(policy.toString());
}
fout.println("Policy status for known UIDs:");
@@ -682,6 +728,12 @@
mListeners.finishBroadcast();
}
+ private String getActiveSubscriberId() {
+ final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephony.getSubscriberId();
+ }
+
private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
@@ -734,40 +786,4 @@
out.attribute(null, name, Long.toString(value));
}
- /**
- * Network template with strong subscriber ID, used as key when defining
- * {@link NetworkPolicy}.
- */
- private static class StrongTemplate {
- public final int networkTemplate;
- public final String subscriberId;
-
- public StrongTemplate(int networkTemplate, String subscriberId) {
- this.networkTemplate = networkTemplate;
- this.subscriberId = subscriberId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(networkTemplate, subscriberId);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof StrongTemplate) {
- final StrongTemplate template = (StrongTemplate) obj;
- return template.networkTemplate == networkTemplate
- && Objects.equal(template.subscriberId, subscriberId);
- }
- return false;
- }
-
- @Override
- public String toString() {
- return "TemplateIdentity: networkTemplate=" + networkTemplate + ", subscriberId="
- + subscriberId;
- }
-
- }
-
}
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 374fd3b..b3d38dc 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -38,16 +38,10 @@
#include "jni.h"
#include "JNIHelp.h"
-#include "android_util_Binder.h"
namespace android
{
-static inline void init_sockaddr(sockaddr *sa) {
- ((sockaddr_in *)sa)->sin_family = AF_INET;
- ((sockaddr_in *)sa)->sin_port = 0;
-}
-
static inline in_addr_t *as_in_addr(sockaddr *sa) {
return &((sockaddr_in *)sa)->sin_addr.s_addr;
}
@@ -65,7 +59,7 @@
#define SYSTEM_ERROR -1
#define BAD_ARGUMENT -2
-static int create_interface(char *name, int *index)
+static int create_interface(int mtu, char *name, int *index)
{
int tun = open("/dev/tun", O_RDWR);
int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
@@ -74,7 +68,7 @@
memset(&ifr4, 0, sizeof(ifr4));
// Allocate interface.
- ifr4.ifr_flags = IFF_TUN;
+ ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
if (ioctl(tun, TUNSETIFF, &ifr4)) {
LOGE("Cannot allocate TUN: %s", strerror(errno));
goto error;
@@ -87,6 +81,13 @@
goto error;
}
+ // Set MTU if it is specified.
+ ifr4.ifr_mtu = mtu;
+ if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
+ LOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
+ goto error;
+ }
+
// Get interface index.
if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
@@ -112,7 +113,7 @@
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
strcpy(ifr4.ifr_name, name);
- init_sockaddr(&ifr4.ifr_addr);
+ ifr4.ifr_addr.sa_family = AF_INET;
in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
@@ -190,9 +191,9 @@
memset(&rt4, 0, sizeof(rt4));
rt4.rt_dev = (char *)name;
rt4.rt_flags = RTF_UP;
- init_sockaddr(&rt4.rt_dst);
- init_sockaddr(&rt4.rt_genmask);
- init_sockaddr(&rt4.rt_gateway);
+ rt4.rt_dst.sa_family = AF_INET;
+ rt4.rt_genmask.sa_family = AF_INET;
+ rt4.rt_gateway.sa_family = AF_INET;
in6_rtmsg rt6;
memset(&rt6, 0, sizeof(rt6));
@@ -223,7 +224,7 @@
if (memcmp(&rt6.rtmsg_gateway, &in6addr_any, sizeof(in6addr_any))) {
rt6.rtmsg_flags |= RTF_GATEWAY;
}
- if (ioctl(inet6, SIOCADDRT, &rt6)) {
+ if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
@@ -241,7 +242,7 @@
if (*as_in_addr(&rt4.rt_gateway)) {
rt4.rt_flags |= RTF_GATEWAY;
}
- if (ioctl(inet4, SIOCADDRT, &rt4)) {
+ if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
@@ -299,10 +300,10 @@
ifreq ifr4;
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
LOGE("Cannot check %s: %s", name, strerror(errno));
- ifr4.ifr_flags = 0;
}
close(inet4);
return ifr4.ifr_flags;
@@ -328,15 +329,15 @@
}
}
-static jobject configure(JNIEnv *env, jobject thiz,
- jstring jAddresses, jstring jRoutes)
+static jint establish(JNIEnv *env, jobject thiz,
+ jint mtu, jstring jAddresses, jstring jRoutes)
{
char name[IFNAMSIZ];
int index;
- int tun = create_interface(name, &index);
+ int tun = create_interface(mtu, name, &index);
if (tun < 0) {
throwException(env, tun, "Cannot create interface");
- return NULL;
+ return -1;
}
LOGD("%s is created", name);
@@ -370,12 +371,12 @@
LOGD("Configured %d route(s) on %s", count, name);
}
- return newParcelFileDescriptor(env, jniCreateFileDescriptor(env, tun));
+ return tun;
error:
close(tun);
LOGD("%s is destroyed", name);
- return NULL;
+ return -1;
}
static jstring getName(JNIEnv *env, jobject thiz, jint fd)
@@ -434,7 +435,7 @@
//------------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"nativeConfigure", "(Ljava/lang/String;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void *)configure},
+ {"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},
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 9daaad8..c618263 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,18 +2,18 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- clz.cpp.arm \
- DisplayHardware/DisplayHardware.cpp \
+ Layer.cpp \
+ LayerBase.cpp \
+ LayerDim.cpp \
+ DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- DisplayHardware/HWComposer.cpp \
- GLExtensions.cpp \
- Layer.cpp \
- LayerBase.cpp \
- LayerDim.cpp \
- MessageQueue.cpp \
- SurfaceFlinger.cpp \
- TextureManager.cpp \
- Transform.cpp
+ DisplayHardware/HWComposer.cpp \
+ GLExtensions.cpp \
+ MessageQueue.cpp \
+ SurfaceFlinger.cpp \
+ SurfaceTextureLayer.cpp \
+ Transform.cpp \
+
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8df2b92..2bab6a8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -18,8 +18,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/properties.h>
+#include <cutils/compiler.h>
#include <cutils/native_handle.h>
+#include <cutils/properties.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -31,12 +32,12 @@
#include <surfaceflinger/Surface.h>
#include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
#include "GLExtensions.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
-
+#include "SurfaceTextureLayer.h"
#define DEBUG_RESIZE 0
@@ -52,102 +53,83 @@
Layer::Layer(SurfaceFlinger* flinger,
DisplayID display, const sp<Client>& client)
: LayerBaseClient(flinger, display, client),
+ mTextureName(-1U),
+ mQueuedFrames(0),
+ mCurrentTransform(0),
+ mCurrentOpacity(true),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
- mNeedsBlending(true),
+ mOpaqueLayer(true),
mNeedsDithering(false),
mSecure(false),
mProtectedByApp(false),
- mTextureManager(),
- mBufferManager(mTextureManager),
- mWidth(0), mHeight(0),
- mNeedsScaling(false), mFixedSize(false)
+ mFixedSize(false)
{
+ mCurrentCrop.makeInvalid();
+ glGenTextures(1, &mTextureName);
+}
+
+void Layer::destroy(RefBase const* base) {
+ mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
+}
+
+void Layer::onFirstRef()
+{
+ LayerBaseClient::onFirstRef();
+ setDestroyer(this);
+
+ struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
+ FrameQueuedListener(Layer* layer) : mLayer(layer) { }
+ private:
+ wp<Layer> mLayer;
+ virtual void onFrameAvailable() {
+ sp<Layer> that(mLayer.promote());
+ if (that != 0) {
+ that->onFrameQueued();
+ }
+ }
+ };
+ mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
+ mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
+ mSurfaceTexture->setSynchronousMode(true);
+ mSurfaceTexture->setBufferCountServer(2);
}
Layer::~Layer()
{
- // FIXME: must be called from the main UI thread
- EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
- mBufferManager.destroy(dpy);
+ glDeleteTextures(1, &mTextureName);
+}
- // we can use getUserClientUnsafe here because we know we're
- // single-threaded at that point.
- sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe());
- if (ourClient != 0) {
- ourClient->detachLayer(this);
+void Layer::onFrameQueued() {
+ if (android_atomic_or(1, &mQueuedFrames) == 0) {
+ mFlinger->signalEvent();
}
}
-void Layer::destroy() const {
- mFlinger->destroyLayer(this);
-}
-
-status_t Layer::setToken(const sp<UserClient>& userClient,
- SharedClient* sharedClient, int32_t token)
-{
- sp<SharedBufferServer> lcblk = new SharedBufferServer(
- sharedClient, token, mBufferManager.getDefaultBufferCount(),
- getIdentity());
-
-
- sp<UserClient> ourClient(mUserClientRef.getClient());
-
- /*
- * Here it is guaranteed that userClient != ourClient
- * (see UserClient::getTokenForSurface()).
- *
- * We release the token used by this surface in ourClient below.
- * This should be safe to do so now, since this layer won't be attached
- * to this client, it should be okay to reuse that id.
- *
- * If this causes problems, an other solution would be to keep a list
- * of all the {UserClient, token} ever used and release them when the
- * Layer is destroyed.
- *
- */
-
- if (ourClient != 0) {
- ourClient->detachLayer(this);
- }
-
- status_t err = mUserClientRef.setToken(userClient, lcblk, token);
- LOGE_IF(err != NO_ERROR,
- "ClientRef::setToken(%p, %p, %u) failed",
- userClient.get(), lcblk.get(), token);
-
- if (err == NO_ERROR) {
- // we need to free the buffers associated with this surface
- }
-
- return err;
-}
-
-int32_t Layer::getToken() const
-{
- return mUserClientRef.getToken();
-}
-
-sp<UserClient> Layer::getClient() const
-{
- return mUserClientRef.getClient();
-}
-
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
// in the purgatory list
void Layer::onRemoved()
{
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (lcblk) {
- // wake up the condition
- lcblk->setStatus(NO_INIT);
- }
}
-sp<LayerBaseClient::Surface> Layer::createSurface() const
+sp<ISurface> Layer::createSurface()
{
- sp<Surface> sur(new SurfaceLayer(mFlinger, const_cast<Layer *>(this)));
+ class BSurface : public BnSurface, public LayerCleaner {
+ wp<const Layer> mOwner;
+ virtual sp<ISurfaceTexture> getSurfaceTexture() const {
+ sp<ISurfaceTexture> res;
+ sp<const Layer> that( mOwner.promote() );
+ if (that != NULL) {
+ res = that->mSurfaceTexture;
+ }
+ return res;
+ }
+ public:
+ BSurface(const sp<SurfaceFlinger>& flinger,
+ const sp<Layer>& layer)
+ : LayerCleaner(flinger, layer), mOwner(layer) { }
+ };
+ sp<ISurface> sur(new BSurface(mFlinger, this));
return sur;
}
@@ -175,17 +157,14 @@
const uint32_t hwFlags = hw.getFlags();
mFormat = format;
- mWidth = w;
- mHeight = h;
-
- mReqFormat = format;
- mReqWidth = w;
- mReqHeight = h;
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
- mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
- (flags & ISurfaceComposer::eOpaque) == 0;
+ mOpaqueLayer = (flags & ISurfaceComposer::eOpaque);
+ mCurrentOpacity = getOpacityForFormat(format);
+
+ mSurfaceTexture->setDefaultBufferSize(w, h);
+ mSurfaceTexture->setDefaultBufferFormat(format);
// we use the red index
int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
@@ -216,10 +195,12 @@
return;
}
- Transform tr(Transform(mOrientation) * Transform(mBufferTransform));
+ // FIXME: shouldn't we take the state's transform into account here?
+
+ Transform tr(Transform(mOrientation) * Transform(mCurrentTransform));
hwcl->transform = tr.getOrientation();
- if (needsBlending()) {
+ if (!isOpaque()) {
hwcl->blending = mPremultipliedAlpha ?
HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
}
@@ -236,7 +217,7 @@
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
- sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+ const sp<GraphicBuffer>& buffer(mActiveBuffer);
if (buffer == NULL) {
// this can happen if the client never drew into this layer yet,
// or if we ran out of memory. In that case, don't let
@@ -247,11 +228,11 @@
}
hwcl->handle = buffer->handle;
- if (!mBufferCrop.isEmpty()) {
- hwcl->sourceCrop.left = mBufferCrop.left;
- hwcl->sourceCrop.top = mBufferCrop.top;
- hwcl->sourceCrop.right = mBufferCrop.right;
- hwcl->sourceCrop.bottom = mBufferCrop.bottom;
+ if (isCropped()) {
+ hwcl->sourceCrop.left = mCurrentCrop.left;
+ hwcl->sourceCrop.top = mCurrentCrop.top;
+ hwcl->sourceCrop.right = mCurrentCrop.right;
+ hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
} else {
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
@@ -260,51 +241,12 @@
}
}
-void Layer::reloadTexture(const Region& dirty)
-{
- sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
- if (buffer == NULL) {
- // this situation can happen if we ran out of memory for instance.
- // not much we can do. continue to use whatever texture was bound
- // to this context.
- return;
- }
-
- if (mGLExtensions.haveDirectTexture()) {
- EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
- if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
- // not sure what we can do here...
- goto slowpath;
- }
- } else {
-slowpath:
- GGLSurface t;
- if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) {
- status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
- LOGE_IF(res, "error %d (%s) locking buffer %p",
- res, strerror(res), buffer.get());
- if (res == NO_ERROR) {
- mBufferManager.loadTexture(dirty, t);
- buffer->unlock();
- }
- } else {
- // we can't do anything
- }
- }
+static inline uint16_t pack565(int r, int g, int b) {
+ return (r<<11)|(g<<5)|b;
}
-
-void Layer::drawForSreenShot() const
-{
- const bool currentFiltering = mNeedsFiltering;
- const_cast<Layer*>(this)->mNeedsFiltering = true;
- LayerBase::drawForSreenShot();
- const_cast<Layer*>(this)->mNeedsFiltering = currentFiltering;
-}
-
void Layer::onDraw(const Region& clip) const
{
- Texture tex(mBufferManager.getActiveTexture());
- if (tex.name == -1LU) {
+ if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
@@ -330,7 +272,25 @@
}
return;
}
- drawWithOpenGL(clip, tex);
+
+ GLenum target = mSurfaceTexture->getCurrentTextureTarget();
+ glBindTexture(target, mTextureName);
+ if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
+ // TODO: we could be more subtle with isFixedSize()
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glEnable(target);
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(mTextureMatrix);
+ glMatrixMode(GL_MODELVIEW);
+
+ drawWithOpenGL(clip);
+
+ glDisable(target);
}
// As documented in libhardware header, formats in the range
@@ -340,186 +300,37 @@
// hardware.h, instead of using hard-coded values here.
#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const
+bool Layer::getOpacityForFormat(uint32_t format)
{
- // If buffers where set with eOpaque flag, all buffers are known to
- // be opaque without having to check their actual format
- if (mNeedsBlending && buffer != NULL) {
- PixelFormat format = buffer->getPixelFormat();
-
- if (HARDWARE_IS_DEVICE_FORMAT(format)) {
- return false;
- }
-
- PixelFormatInfo info;
- status_t err = getPixelFormatInfo(format, &info);
- if (!err && info.h_alpha <= info.l_alpha) {
- return false;
- }
+ if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+ return true;
}
-
- // Return opacity as determined from flags and format options
- // passed to setBuffers()
- return mNeedsBlending;
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(PixelFormat(format), &info);
+ // in case of error (unknown format), we assume no blending
+ return (err || info.h_alpha <= info.l_alpha);
}
-bool Layer::needsBlending() const
-{
- if (mBufferManager.hasActiveBuffer()) {
- return needsBlending(mBufferManager.getActiveBuffer());
- }
- return mNeedsBlending;
-}
-
-bool Layer::needsFiltering() const
+bool Layer::isOpaque() const
{
- if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
- // if our buffer is not the same size than ourselves,
- // we need filtering.
- Mutex::Autolock _l(mLock);
- if (mNeedsScaling)
- return true;
- }
- return LayerBase::needsFiltering();
+ // if we don't have a buffer yet, we're translucent regardless of the
+ // layer's opaque flag.
+ if (mActiveBuffer == 0)
+ return false;
+
+ // if the layer has the opaque flag, then we're always opaque,
+ // otherwise we use the current buffer's format.
+ return mOpaqueLayer || mCurrentOpacity;
}
bool Layer::isProtected() const
{
- sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+ const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
return (activeBuffer != 0) &&
(activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
-status_t Layer::setBufferCount(int bufferCount)
-{
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (!lcblk) {
- // oops, the client is already gone
- return DEAD_OBJECT;
- }
-
- // NOTE: lcblk->resize() is protected by an internal lock
- status_t err = lcblk->resize(bufferCount);
- if (err == NO_ERROR) {
- EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
- mBufferManager.resize(bufferCount, mFlinger, dpy);
- }
-
- return err;
-}
-
-sp<GraphicBuffer> Layer::requestBuffer(int index,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
- uint32_t usage)
-{
- sp<GraphicBuffer> buffer;
-
- if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
- return buffer;
-
- if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
- return buffer;
-
- // this ensures our client doesn't go away while we're accessing
- // the shared area.
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (!lcblk) {
- // oops, the client is already gone
- return buffer;
- }
-
- /*
- * This is called from the client's Surface::dequeue(). This can happen
- * at any time, especially while we're in the middle of using the
- * buffer 'index' as our front buffer.
- */
-
- status_t err = NO_ERROR;
- uint32_t w, h, f;
- { // scope for the lock
- Mutex::Autolock _l(mLock);
-
- // zero means default
- const bool fixedSize = reqWidth && reqHeight;
- if (!reqFormat) reqFormat = mFormat;
- if (!reqWidth) reqWidth = mWidth;
- if (!reqHeight) reqHeight = mHeight;
-
- w = reqWidth;
- h = reqHeight;
- f = reqFormat;
-
- if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) ||
- (reqFormat != mReqFormat)) {
- mReqWidth = reqWidth;
- mReqHeight = reqHeight;
- mReqFormat = reqFormat;
- mFixedSize = fixedSize;
- mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-
- lcblk->reallocateAllExcept(index);
- }
- }
-
- // here we have to reallocate a new buffer because the buffer could be
- // used as the front buffer, or by a client in our process
- // (eg: status bar), and we can't release the handle under its feet.
- const uint32_t effectiveUsage = getEffectiveUsage(usage);
- buffer = new GraphicBuffer(w, h, f, effectiveUsage);
- err = buffer->initCheck();
-
- if (err || buffer->handle == 0) {
- GraphicBuffer::dumpAllocationsToSystemLog();
- LOGE_IF(err || buffer->handle == 0,
- "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
- this, index, w, h, strerror(-err));
- } else {
- LOGD_IF(DEBUG_RESIZE,
- "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p",
- this, index, w, h, buffer->handle);
- }
-
- if (err == NO_ERROR && buffer->handle != 0) {
- Mutex::Autolock _l(mLock);
- mBufferManager.attachBuffer(index, buffer);
- }
- return buffer;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const
-{
- /*
- * buffers used for software rendering, but h/w composition
- * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
- *
- * buffers used for h/w rendering and h/w composition
- * are allocated with HW_RENDER | HW_TEXTURE
- *
- * buffers used with h/w rendering and either NPOT or no egl_image_ext
- * are allocated with SW_READ_RARELY | HW_RENDER
- *
- */
-
- if (mSecure) {
- // secure buffer, don't store it into the GPU
- usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
- GraphicBuffer::USAGE_SW_WRITE_OFTEN;
- } else {
- // it's allowed to modify the usage flags here, but generally
- // the requested flags should be honored.
- // request EGLImage for all buffers
- usage |= GraphicBuffer::USAGE_HW_TEXTURE;
- }
- if (mProtectedByApp) {
- // need a hardware-protected path to external video sink
- usage |= GraphicBuffer::USAGE_PROTECTED;
- }
- return usage;
-}
-
uint32_t Layer::doTransaction(uint32_t flags)
{
const Layer::State& front(drawingState());
@@ -531,10 +342,12 @@
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
- "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+ "resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
+ "fixedSize=%d",
this,
int(temp.requested_w), int(temp.requested_h),
- int(front.requested_w), int(front.requested_h));
+ int(front.requested_w), int(front.requested_h),
+ isFixedSize());
if (!isFixedSize()) {
// we're being resized and there is a freeze display request,
@@ -557,17 +370,7 @@
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
- setBufferSize(temp.requested_w, temp.requested_h);
-
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (lcblk) {
- // all buffers need reallocation
- lcblk->reallocateAll();
- }
- } else {
- // record the new size
- setBufferSize(temp.requested_w, temp.requested_h);
+ mSurfaceTexture->setDefaultBufferSize(temp.requested_w, temp.requested_h);
}
}
@@ -582,79 +385,69 @@
return LayerBase::doTransaction(flags);
}
-void Layer::setBufferSize(uint32_t w, uint32_t h) {
- Mutex::Autolock _l(mLock);
- mWidth = w;
- mHeight = h;
- mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-}
-
bool Layer::isFixedSize() const {
Mutex::Autolock _l(mLock);
return mFixedSize;
}
+void Layer::setFixedSize(bool fixedSize)
+{
+ Mutex::Autolock _l(mLock);
+ mFixedSize = fixedSize;
+}
+
+bool Layer::isCropped() const {
+ return !mCurrentCrop.isEmpty();
+}
+
// ----------------------------------------------------------------------------
// pageflip handling...
// ----------------------------------------------------------------------------
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- if (!lcblk) {
- // client died
- recomputeVisibleRegions = true;
- return;
- }
+ if (android_atomic_and(0, &mQueuedFrames)) {
+ if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
+ // something happened!
+ recomputeVisibleRegions = true;
+ return;
+ }
- ssize_t buf = lcblk->retireAndLock();
- if (buf == NOT_ENOUGH_DATA) {
- // NOTE: This is not an error, it simply means there is nothing to
- // retire. The buffer is locked because we will use it
- // for composition later in the loop
- return;
- }
+ // signal another event if we have more frames waiting
+ if (mSurfaceTexture->getQueuedCount()) {
+ if (android_atomic_or(1, &mQueuedFrames) == 0) {
+ mFlinger->signalEvent();
+ }
+ }
- if (buf < NO_ERROR) {
- LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
- mPostedDirtyRegion.clear();
- return;
- }
+ mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+ mSurfaceTexture->getTransformMatrix(mTextureMatrix);
- // we retired a buffer, which becomes the new front buffer
+ const Rect crop(mSurfaceTexture->getCurrentCrop());
+ const uint32_t transform(mSurfaceTexture->getCurrentTransform());
+ if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) {
+ mCurrentCrop = crop;
+ mCurrentTransform = transform;
+ mFlinger->invalidateHwcGeometry();
+ }
- const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
- const bool activeBlending =
- noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer());
-
- if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
- LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
- mPostedDirtyRegion.clear();
- return;
- }
-
- if (noActiveBuffer) {
- // we didn't have an active buffer, we need to recompute
- // our visible region
- recomputeVisibleRegions = true;
- }
-
- sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
- if (newFrontBuffer != NULL) {
- if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) {
- // new buffer has different opacity than previous active buffer, need
- // to recompute visible regions accordingly
+ const bool opacity(getOpacityForFormat(mActiveBuffer->format));
+ if (opacity != mCurrentOpacity) {
+ mCurrentOpacity = opacity;
recomputeVisibleRegions = true;
}
- // get the dirty region
- // compute the posted region
- const Region dirty(lcblk->getDirtyRegion(buf));
- mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
+ const GLenum target(mSurfaceTexture->getCurrentTextureTarget());
+ glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// update the layer size and release freeze-lock
const Layer::State& front(drawingState());
+
+ // FIXME: mPostedDirtyRegion = dirty & bounds
+ mPostedDirtyRegion.set(front.w, front.h);
+
+ sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
if ((newFrontBuffer->getWidth() == front.requested_w &&
newFrontBuffer->getHeight() == front.requested_h) ||
isFixedSize())
@@ -685,35 +478,7 @@
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
-
- // get the crop region
- setBufferCrop( lcblk->getCrop(buf) );
-
- // get the transformation
- setBufferTransform( lcblk->getTransform(buf) );
-
- } else {
- // this should not happen unless we ran out of memory while
- // allocating the buffer. we're hoping that things will get back
- // to normal the next time the app tries to draw into this buffer.
- // meanwhile, pretend the screen didn't update.
- mPostedDirtyRegion.clear();
}
-
- if (lcblk->getQueuedCount()) {
- // signal an event if we have more buffers waiting
- mFlinger->signalEvent();
- }
-
- /* a buffer was posted, so we need to call reloadTexture(), which
- * will update our internal data structures (eg: EGLImageKHR or
- * texture names). we need to do this even if mPostedDirtyRegion is
- * empty -- it's orthogonal to the fact that a new buffer was posted,
- * for instance, a degenerate case could be that the user did an empty
- * update but repainted the buffer with appropriate content (after a
- * resize for instance).
- */
- reloadTexture( mPostedDirtyRegion );
}
void Layer::unlockPageFlip(
@@ -746,329 +511,36 @@
{
LayerBaseClient::dump(result, buffer, SIZE);
- ClientRef::Access sharedClient(mUserClientRef);
- SharedBufferServer* lcblk(sharedClient.get());
- uint32_t totalTime = 0;
- if (lcblk) {
- SharedBufferStack::Statistics stats = lcblk->getStats();
- totalTime= stats.totalTime;
- result.append( lcblk->dump(" ") );
- }
-
- sp<const GraphicBuffer> buf0(getBuffer(0));
- sp<const GraphicBuffer> buf1(getBuffer(1));
- uint32_t w0=0, h0=0, s0=0;
- uint32_t w1=0, h1=0, s1=0;
+ sp<const GraphicBuffer> buf0(mActiveBuffer);
+ uint32_t w0=0, h0=0, s0=0, f0=0;
if (buf0 != 0) {
w0 = buf0->getWidth();
h0 = buf0->getHeight();
s0 = buf0->getStride();
- }
- if (buf1 != 0) {
- w1 = buf1->getWidth();
- h1 = buf1->getHeight();
- s1 = buf1->getStride();
+ f0 = buf0->format;
}
snprintf(buffer, SIZE,
" "
- "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
- " freezeLock=%p, dq-q-time=%u us\n",
- mFormat, w0, h0, s0, w1, h1, s1,
- getFreezeLock().get(), totalTime);
+ "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+ " freezeLock=%p, queued-frames=%d\n",
+ mFormat, w0, h0, s0,f0,
+ getFreezeLock().get(), mQueuedFrames);
result.append(buffer);
-}
-// ---------------------------------------------------------------------------
-
-Layer::ClientRef::ClientRef()
- : mControlBlock(0), mToken(-1) {
-}
-
-Layer::ClientRef::~ClientRef() {
-}
-
-int32_t Layer::ClientRef::getToken() const {
- Mutex::Autolock _l(mLock);
- return mToken;
-}
-
-sp<UserClient> Layer::ClientRef::getClient() const {
- Mutex::Autolock _l(mLock);
- return mUserClient.promote();
-}
-
-status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
- const sp<SharedBufferServer>& sharedClient, int32_t token) {
- Mutex::Autolock _l(mLock);
-
- { // scope for strong mUserClient reference
- sp<UserClient> userClient(mUserClient.promote());
- if (userClient != 0 && mControlBlock != 0) {
- mControlBlock->setStatus(NO_INIT);
- }
+ if (mSurfaceTexture != 0) {
+ mSurfaceTexture->dump(result, " ", buffer, SIZE);
}
-
- mUserClient = uc;
- mToken = token;
- mControlBlock = sharedClient;
- return NO_ERROR;
}
-sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
- return mUserClient.promote();
-}
-
-// this class gives us access to SharedBufferServer safely
-// it makes sure the UserClient (and its associated shared memory)
-// won't go away while we're accessing it.
-Layer::ClientRef::Access::Access(const ClientRef& ref)
- : mControlBlock(0)
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
- Mutex::Autolock _l(ref.mLock);
- mUserClientStrongRef = ref.mUserClient.promote();
- if (mUserClientStrongRef != 0)
- mControlBlock = ref.mControlBlock;
-}
-
-Layer::ClientRef::Access::~Access()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::BufferManager::BufferManager(TextureManager& tm)
- : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
- mActiveBufferIndex(-1), mFailover(false)
-{
-}
-
-Layer::BufferManager::~BufferManager()
-{
-}
-
-status_t Layer::BufferManager::resize(size_t size,
- const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
-{
- Mutex::Autolock _l(mLock);
-
- if (size < mNumBuffers) {
- // If there is an active texture, move it into slot 0 if needed
- if (mActiveBufferIndex > 0) {
- BufferData activeBufferData = mBufferData[mActiveBufferIndex];
- mBufferData[mActiveBufferIndex] = mBufferData[0];
- mBufferData[0] = activeBufferData;
- mActiveBufferIndex = 0;
- }
-
- // Free the buffers that are no longer needed.
- for (size_t i = size; i < mNumBuffers; i++) {
- mBufferData[i].buffer = 0;
-
- // Create a message to destroy the textures on SurfaceFlinger's GL
- // thread.
- class MessageDestroyTexture : public MessageBase {
- Image mTexture;
- EGLDisplay mDpy;
- public:
- MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
- : mTexture(texture), mDpy(dpy) { }
- virtual bool handler() {
- status_t err = Layer::BufferManager::destroyTexture(
- &mTexture, mDpy);
- LOGE_IF(err<0, "error destroying texture: %d (%s)",
- mTexture.name, strerror(-err));
- return true; // XXX: err == 0; ????
- }
- };
-
- MessageDestroyTexture *msg = new MessageDestroyTexture(
- mBufferData[i].texture, dpy);
-
- // Don't allow this texture to be cleaned up by
- // BufferManager::destroy.
- mBufferData[i].texture.name = -1U;
- mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
-
- // Post the message to the SurfaceFlinger object.
- flinger->postMessageAsync(msg);
- }
+ // TODO: should we do something special if mSecure is set?
+ if (mProtectedByApp) {
+ // need a hardware-protected path to external video sink
+ usage |= GraphicBuffer::USAGE_PROTECTED;
}
-
- mNumBuffers = size;
- return NO_ERROR;
-}
-
-// only for debugging
-sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
- return mBufferData[index].buffer;
-}
-
-status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
- BufferData const * const buffers = mBufferData;
- Mutex::Autolock _l(mLock);
- mActiveBuffer = buffers[index].buffer;
- mActiveBufferIndex = index;
- return NO_ERROR;
-}
-
-size_t Layer::BufferManager::getActiveBufferIndex() const {
- return mActiveBufferIndex;
-}
-
-Texture Layer::BufferManager::getActiveTexture() const {
- Texture res;
- if (mFailover || mActiveBufferIndex<0) {
- res = mFailoverTexture;
- } else {
- static_cast<Image&>(res) = mBufferData[mActiveBufferIndex].texture;
- }
- return res;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
- return mActiveBuffer;
-}
-
-bool Layer::BufferManager::hasActiveBuffer() const {
- return mActiveBufferIndex >= 0;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
-{
- BufferData* const buffers = mBufferData;
- sp<GraphicBuffer> buffer;
- Mutex::Autolock _l(mLock);
- buffer = buffers[index].buffer;
- buffers[index].buffer = 0;
- return buffer;
-}
-
-status_t Layer::BufferManager::attachBuffer(size_t index,
- const sp<GraphicBuffer>& buffer)
-{
- BufferData* const buffers = mBufferData;
- Mutex::Autolock _l(mLock);
- buffers[index].buffer = buffer;
- buffers[index].texture.dirty = true;
- return NO_ERROR;
-}
-
-status_t Layer::BufferManager::destroy(EGLDisplay dpy)
-{
- BufferData* const buffers = mBufferData;
- size_t num;
- { // scope for the lock
- Mutex::Autolock _l(mLock);
- num = mNumBuffers;
- for (size_t i=0 ; i<num ; i++) {
- buffers[i].buffer = 0;
- }
- }
- for (size_t i=0 ; i<num ; i++) {
- destroyTexture(&buffers[i].texture, dpy);
- }
- destroyTexture(&mFailoverTexture, dpy);
- return NO_ERROR;
-}
-
-status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& buffer)
-{
- status_t err = NO_INIT;
- ssize_t index = mActiveBufferIndex;
- if (index >= 0) {
- if (!mFailover) {
- {
- // Without that lock, there is a chance of race condition
- // where while composing a specific index, requestBuf
- // with the same index can be executed and touch the same data
- // that is being used in initEglImage.
- // (e.g. dirty flag in texture)
- Mutex::Autolock _l(mLock);
- Image& texture(mBufferData[index].texture);
- err = mTextureManager.initEglImage(&texture, dpy, buffer);
- }
- // if EGLImage fails, we switch to regular texture mode, and we
- // free all resources associated with using EGLImages.
- if (err == NO_ERROR) {
- mFailover = false;
- destroyTexture(&mFailoverTexture, dpy);
- } else {
- mFailover = true;
- const size_t num = mNumBuffers;
- for (size_t i=0 ; i<num ; i++) {
- destroyTexture(&mBufferData[i].texture, dpy);
- }
- }
- } else {
- // we failed once, don't try again
- err = BAD_VALUE;
- }
- }
- return err;
-}
-
-status_t Layer::BufferManager::loadTexture(
- const Region& dirty, const GGLSurface& t)
-{
- return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
-}
-
-status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
-{
- if (tex->name != -1U) {
- glDeleteTextures(1, &tex->name);
- tex->name = -1U;
- }
- if (tex->image != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(dpy, tex->image);
- tex->image = EGL_NO_IMAGE_KHR;
- }
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
- const sp<Layer>& owner)
- : Surface(flinger, owner->getIdentity(), owner)
-{
-}
-
-Layer::SurfaceLayer::~SurfaceLayer()
-{
-}
-
-sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
- sp<GraphicBuffer> buffer;
- sp<Layer> owner(getOwner());
- if (owner != 0) {
- /*
- * requestBuffer() cannot be called from the main thread
- * as it could cause a dead-lock, since it may have to wait
- * on conditions updated my the main thread.
- */
- buffer = owner->requestBuffer(index, w, h, format, usage);
- }
- return buffer;
-}
-
-status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
-{
- status_t err = DEAD_OBJECT;
- sp<Layer> owner(getOwner());
- if (owner != 0) {
- /*
- * setBufferCount() cannot be called from the main thread
- * as it could cause a dead-lock, since it may have to wait
- * on conditions updated my the main thread.
- */
- err = owner->setBufferCount(bufferCount);
- }
- return err;
+ return usage;
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 278d64e..e3fc13d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,9 +20,11 @@
#include <stdint.h>
#include <sys/types.h>
+#include <gui/SurfaceTexture.h>
+
+#include <pixelflinger/pixelflinger.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
-#include <pixelflinger/pixelflinger.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -30,8 +32,8 @@
#include <GLES/glext.h>
#include "LayerBase.h"
+#include "SurfaceTextureLayer.h"
#include "Transform.h"
-#include "TextureManager.h"
namespace android {
@@ -40,11 +42,10 @@
class FreezeLock;
class Client;
class GLExtensions;
-class UserClient;
// ---------------------------------------------------------------------------
-class Layer : public LayerBaseClient
+class Layer : public LayerBaseClient, private RefBase::Destroyer
{
public:
Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -58,164 +59,59 @@
status_t setBuffers(uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
- // associate a UserClient to this Layer
- status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
- int32_t getToken() const;
- sp<UserClient> getClient() const;
-
// Set this Layer's buffers size
- void setBufferSize(uint32_t w, uint32_t h);
bool isFixedSize() const;
// LayerBase interface
virtual void setGeometry(hwc_layer_t* hwcl);
virtual void setPerFrameData(hwc_layer_t* hwcl);
- virtual void drawForSreenShot() const;
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
- virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
- virtual bool needsBlending() const;
+ virtual bool isOpaque() const;
virtual bool needsDithering() const { return mNeedsDithering; }
- virtual bool needsFiltering() const;
virtual bool isSecure() const { return mSecure; }
virtual bool isProtected() const;
- virtual sp<Surface> createSurface() const;
virtual void onRemoved();
// only for debugging
- inline sp<GraphicBuffer> getBuffer(int i) const {
- return mBufferManager.getBuffer(i); }
- // only for debugging
- inline const sp<FreezeLock>& getFreezeLock() const {
- return mFreezeLock; }
+ inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
protected:
- virtual void destroy() const;
+ virtual void destroy(RefBase const* base);
+ virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
private:
- void reloadTexture(const Region& dirty);
+ friend class SurfaceTextureLayer;
+ void onFrameQueued();
+ virtual sp<ISurface> createSurface();
uint32_t getEffectiveUsage(uint32_t usage) const;
- sp<GraphicBuffer> requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
- status_t setBufferCount(int bufferCount);
+ void setFixedSize(bool fixedSize);
+ bool isCropped() const;
+ static bool getOpacityForFormat(uint32_t format);
// -----------------------------------------------------------------------
- class SurfaceLayer : public LayerBaseClient::Surface {
- public:
- SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
- ~SurfaceLayer();
- private:
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
- virtual status_t setBufferCount(int bufferCount);
- sp<Layer> getOwner() const {
- return static_cast<Layer*>(Surface::getOwner().get());
- }
- };
- friend class SurfaceLayer;
-
- // -----------------------------------------------------------------------
-
- class ClientRef {
- ClientRef(const ClientRef& rhs);
- ClientRef& operator = (const ClientRef& rhs);
- mutable Mutex mLock;
- // binder thread, page-flip thread
- sp<SharedBufferServer> mControlBlock;
- wp<UserClient> mUserClient;
- int32_t mToken;
- public:
- ClientRef();
- ~ClientRef();
- int32_t getToken() const;
- sp<UserClient> getClient() const;
- status_t setToken(const sp<UserClient>& uc,
- const sp<SharedBufferServer>& sharedClient, int32_t token);
- sp<UserClient> getUserClientUnsafe() const;
- class Access {
- Access(const Access& rhs);
- Access& operator = (const Access& rhs);
- sp<UserClient> mUserClientStrongRef;
- sp<SharedBufferServer> mControlBlock;
- public:
- Access(const ClientRef& ref);
- ~Access();
- inline SharedBufferServer* get() const { return mControlBlock.get(); }
- };
- friend class Access;
- };
-
- // -----------------------------------------------------------------------
-
- class BufferManager {
- static const size_t NUM_BUFFERS = 2;
- struct BufferData {
- sp<GraphicBuffer> buffer;
- Image texture;
- };
- // this lock protect mBufferData[].buffer but since there
- // is very little contention, we have only one like for
- // the whole array, we also use it to protect mNumBuffers.
- mutable Mutex mLock;
- BufferData mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
- size_t mNumBuffers;
- Texture mFailoverTexture;
- TextureManager& mTextureManager;
- ssize_t mActiveBufferIndex;
- sp<GraphicBuffer> mActiveBuffer;
- bool mFailover;
- static status_t destroyTexture(Image* tex, EGLDisplay dpy);
-
- public:
- static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
- BufferManager(TextureManager& tm);
- ~BufferManager();
-
- // detach/attach buffer from/to given index
- sp<GraphicBuffer> detachBuffer(size_t index);
- status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
- // resize the number of active buffers
- status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
- EGLDisplay dpy);
-
- // ----------------------------------------------
- // must be called from GL thread
-
- // set/get active buffer index
- status_t setActiveBufferIndex(size_t index);
- size_t getActiveBufferIndex() const;
- // return the active buffer
- sp<GraphicBuffer> getActiveBuffer() const;
- // return wether we have an active buffer
- bool hasActiveBuffer() const;
- // return the active texture (or fail-over)
- Texture getActiveTexture() const;
- // frees resources associated with all buffers
- status_t destroy(EGLDisplay dpy);
- // load bitmap data into the active buffer
- status_t loadTexture(const Region& dirty, const GGLSurface& t);
- // make active buffer an EGLImage if needed
- status_t initEglImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& buffer);
-
- // ----------------------------------------------
- // only for debugging
- sp<GraphicBuffer> getBuffer(size_t index) const;
- };
-
- // -----------------------------------------------------------------------
+ // constants
+ sp<SurfaceTextureLayer> mSurfaceTexture;
+ GLuint mTextureName;
// thread-safe
- ClientRef mUserClientRef;
+ volatile int32_t mQueuedFrames;
+
+ // main thread
+ sp<GraphicBuffer> mActiveBuffer;
+ GLfloat mTextureMatrix[16];
+ Rect mCurrentCrop;
+ uint32_t mCurrentTransform;
+ bool mCurrentOpacity;
// constants
PixelFormat mFormat;
const GLExtensions& mGLExtensions;
- bool mNeedsBlending;
+ bool mOpaqueLayer;
bool mNeedsDithering;
// page-flip thread (currently main thread)
@@ -226,18 +122,8 @@
// page-flip thread and transaction thread (currently main thread)
sp<FreezeLock> mFreezeLock;
- // see threading usage in declaration
- TextureManager mTextureManager;
- BufferManager mBufferManager;
-
// binder thread, transaction thread
mutable Mutex mLock;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mReqWidth;
- uint32_t mReqHeight;
- uint32_t mReqFormat;
- bool mNeedsScaling;
bool mFixedSize;
};
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 022f251..bcd8c83 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -32,8 +32,6 @@
#include "LayerBase.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
-#include "TextureManager.h"
-
namespace android {
@@ -44,7 +42,7 @@
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
- mFlinger(flinger),
+ mFlinger(flinger), mFiltering(false),
mNeedsFiltering(false),
mOrientation(0),
mLeft(0), mTop(0),
@@ -54,8 +52,6 @@
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
- mBufferCrop.makeInvalid();
- mBufferTransform = 0;
}
LayerBase::~LayerBase()
@@ -310,6 +306,16 @@
hwcl->handle = NULL;
}
+void LayerBase::setFiltering(bool filtering)
+{
+ mFiltering = filtering;
+}
+
+bool LayerBase::getFiltering() const
+{
+ return mFiltering;
+}
+
void LayerBase::draw(const Region& clip) const
{
// reset GL state
@@ -318,10 +324,12 @@
onDraw(clip);
}
-void LayerBase::drawForSreenShot() const
+void LayerBase::drawForSreenShot()
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ setFiltering(true);
onDraw( Region(hw.bounds()) );
+ setFiltering(false);
}
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@@ -332,8 +340,12 @@
const uint32_t fbHeight = hw.getHeight();
glColor4f(red,green,blue,alpha);
- TextureManager::deactivateTextures();
-
+#if defined(GL_OES_EGL_image_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+#endif
+ glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
@@ -354,24 +366,11 @@
clearWithOpenGL(clip,0,0,0,0);
}
-template <typename T>
-static inline
-void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
+void LayerBase::drawWithOpenGL(const Region& clip) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
-
- // bind our texture
- TextureManager::activateTexture(texture, needsFiltering());
- uint32_t width = texture.width;
- uint32_t height = texture.height;
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
if (UNLIKELY(s.alpha < 0xFF)) {
@@ -387,7 +386,7 @@
} else {
glColor4f(1, 1, 1, 1);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- if (needsBlending()) {
+ if (!isOpaque()) {
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
} else {
@@ -395,86 +394,20 @@
}
}
- /*
- * compute texture coordinates
- * here, we handle NPOT, cropping and buffer transformations
- */
-
- GLfloat cl, ct, cr, cb;
- if (!mBufferCrop.isEmpty()) {
- // source is cropped
- const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
- const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
- cl = mBufferCrop.left * us;
- ct = mBufferCrop.top * vs;
- cr = mBufferCrop.right * us;
- cb = mBufferCrop.bottom * vs;
- } else {
- cl = 0;
- ct = 0;
- cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
- cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
- }
-
- /*
- * For the buffer transformation, we apply the rotation last.
- * Since we're transforming the texture-coordinates, we need
- * to apply the inverse of the buffer transformation:
- * inverse( FLIP_V -> FLIP_H -> ROT_90 )
- * <=> inverse( ROT_90 * FLIP_H * FLIP_V )
- * = inverse(FLIP_V) * inverse(FLIP_H) * inverse(ROT_90)
- * = FLIP_V * FLIP_H * ROT_270
- * <=> ROT_270 -> FLIP_H -> FLIP_V
- *
- * The rotation is performed first, in the texture coordinate space.
- *
- */
-
struct TexCoords {
GLfloat u;
GLfloat v;
};
- enum {
- // name of the corners in the texture map
- LB = 0, // left-bottom
- LT = 1, // left-top
- RT = 2, // right-top
- RB = 3 // right-bottom
- };
-
- // vertices in screen space
- int vLT = LB;
- int vLB = LT;
- int vRB = RT;
- int vRT = RB;
-
- // the texture's source is rotated
- uint32_t transform = mBufferTransform;
- if (transform & HAL_TRANSFORM_ROT_90) {
- vLT = RB;
- vLB = LB;
- vRB = LT;
- vRT = RT;
- }
- if (transform & HAL_TRANSFORM_FLIP_V) {
- swap(vLT, vLB);
- swap(vRT, vRB);
- }
- if (transform & HAL_TRANSFORM_FLIP_H) {
- swap(vLT, vRT);
- swap(vLB, vRB);
- }
-
TexCoords texCoords[4];
- texCoords[vLT].u = cl;
- texCoords[vLT].v = ct;
- texCoords[vLB].u = cl;
- texCoords[vLB].v = cb;
- texCoords[vRB].u = cr;
- texCoords[vRB].v = cb;
- texCoords[vRT].u = cr;
- texCoords[vRT].v = ct;
+ texCoords[0].u = 0;
+ texCoords[0].v = 1;
+ texCoords[1].u = 0;
+ texCoords[1].v = 0;
+ texCoords[2].u = 1;
+ texCoords[2].v = 0;
+ texCoords[3].u = 1;
+ texCoords[3].v = 1;
if (needsDithering()) {
glEnable(GL_DITHER);
@@ -497,20 +430,6 @@
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
-void LayerBase::setBufferCrop(const Rect& crop) {
- if (mBufferCrop != crop) {
- mBufferCrop = crop;
- mFlinger->invalidateHwcGeometry();
- }
-}
-
-void LayerBase::setBufferTransform(uint32_t transform) {
- if (mBufferTransform != transform) {
- mBufferTransform = transform;
- mFlinger->invalidateHwcGeometry();
- }
-}
-
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
@@ -518,10 +437,10 @@
"+ %s %p\n"
" "
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
- "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
+ "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
- needsBlending(), needsDithering(), contentDirty,
+ isOpaque(), needsDithering(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
s.transform[1][0], s.transform[1][1]);
@@ -555,9 +474,22 @@
}
}
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+sp<ISurface> LayerBaseClient::createSurface()
{
- sp<Surface> s;
+ class BSurface : public BnSurface, public LayerCleaner {
+ virtual sp<ISurfaceTexture> getSurfaceTexture() const { return 0; }
+ public:
+ BSurface(const sp<SurfaceFlinger>& flinger,
+ const sp<LayerBaseClient>& layer)
+ : LayerCleaner(flinger, layer) { }
+ };
+ sp<ISurface> sur(new BSurface(mFlinger, this));
+ return sur;
+}
+
+sp<ISurface> LayerBaseClient::getSurface()
+{
+ sp<ISurface> s;
Mutex::Autolock _l(mLock);
LOG_ALWAYS_FATAL_IF(mHasSurface,
@@ -573,12 +505,6 @@
return mClientSurfaceBinder;
}
-sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
-{
- return new Surface(mFlinger, mIdentity,
- const_cast<LayerBaseClient *>(this));
-}
-
void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
{
LayerBase::dump(result, buffer, SIZE);
@@ -601,44 +527,14 @@
// ---------------------------------------------------------------------------
-LayerBaseClient::Surface::Surface(
- const sp<SurfaceFlinger>& flinger,
- int identity,
- const sp<LayerBaseClient>& owner)
- : mFlinger(flinger), mIdentity(identity), mOwner(owner)
-{
+LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
+ const sp<LayerBaseClient>& layer)
+ : mFlinger(flinger), mLayer(layer) {
}
-LayerBaseClient::Surface::~Surface()
-{
- /*
- * This is a good place to clean-up all client resources
- */
-
+LayerBaseClient::LayerCleaner::~LayerCleaner() {
// destroy client resources
- mFlinger->destroySurface(mOwner);
-}
-
-sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
- sp<LayerBaseClient> owner(mOwner.promote());
- return owner;
-}
-
-status_t LayerBaseClient::Surface::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- return BnSurface::onTransact(code, data, reply, flags);
-}
-
-sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
- return NULL;
-}
-
-status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
-{
- return INVALID_OPERATION;
+ mFlinger->destroySurface(mLayer);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 6c49a19..faf71dd 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -29,7 +29,6 @@
#include <ui/Region.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
-#include <private/surfaceflinger/SharedBufferStack.h>
#include <private/surfaceflinger/LayerState.h>
#include <pixelflinger/pixelflinger.h>
@@ -43,13 +42,12 @@
// ---------------------------------------------------------------------------
-class DisplayHardware;
class Client;
+class DisplayHardware;
class GraphicBuffer;
class GraphicPlane;
class LayerBaseClient;
class SurfaceFlinger;
-class Texture;
// ---------------------------------------------------------------------------
@@ -121,7 +119,7 @@
* to perform the actual drawing.
*/
virtual void draw(const Region& clip) const;
- virtual void drawForSreenShot() const;
+ virtual void drawForSreenShot();
/**
* onDraw - draws the surface.
@@ -174,9 +172,9 @@
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
/**
- * needsBlending - true if this surface needs blending
+ * isOpaque - true if this surface is opaque
*/
- virtual bool needsBlending() const { return false; }
+ virtual bool isOpaque() const { return true; }
/**
* needsDithering - true if this surface needs dithering
@@ -184,11 +182,9 @@
virtual bool needsDithering() const { return false; }
/**
- * needsLinearFiltering - true if this surface needs filtering
+ * needsLinearFiltering - true if this surface's state requires filtering
*/
- virtual bool needsFiltering() const {
- return (!(mFlags & DisplayHardware::SLOW_CONFIG)) && mNeedsFiltering;
- }
+ virtual bool needsFiltering() const { return mNeedsFiltering; }
/**
* isSecure - true if this surface is secure, that is if it prevents
@@ -231,21 +227,25 @@
void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
GLclampf b, GLclampf alpha) const;
void clearWithOpenGL(const Region& clip) const;
- void drawWithOpenGL(const Region& clip, const Texture& texture) const;
-
- // these must be called from the post/drawing thread
- void setBufferCrop(const Rect& crop);
- void setBufferTransform(uint32_t transform);
+ void drawWithOpenGL(const Region& clip) const;
+
+ void setFiltering(bool filtering);
+ bool getFiltering() const;
sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
- // post/drawing thread
- Rect mBufferCrop;
- uint32_t mBufferTransform;
+private:
+ // accessed only in the main thread
+ // Whether filtering is forced on or not
+ bool mFiltering;
// cached during validateVisibility()
+ // Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
+
+protected:
+ // cached during validateVisibility()
int32_t mOrientation;
GLfloat mVertices[4][2];
Rect mTransformedBounds;
@@ -281,52 +281,38 @@
class LayerBaseClient : public LayerBase
{
public:
- class Surface;
-
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client);
- virtual ~LayerBaseClient();
- sp<Surface> getSurface();
+ virtual ~LayerBaseClient();
+
+ sp<ISurface> getSurface();
wp<IBinder> getSurfaceBinder() const;
- virtual sp<Surface> createSurface() const;
+
virtual sp<LayerBaseClient> getLayerBaseClient() const {
return const_cast<LayerBaseClient*>(this); }
+
virtual const char* getTypeId() const { return "LayerBaseClient"; }
uint32_t getIdentity() const { return mIdentity; }
- class Surface : public BnSurface {
- public:
- int32_t getIdentity() const { return mIdentity; }
-
- protected:
- Surface(const sp<SurfaceFlinger>& flinger, int identity,
- const sp<LayerBaseClient>& owner);
- virtual ~Surface();
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- sp<LayerBaseClient> getOwner() const;
-
- private:
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
- uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
- virtual status_t setBufferCount(int bufferCount);
-
- protected:
- friend class LayerBaseClient;
- sp<SurfaceFlinger> mFlinger;
- int32_t mIdentity;
- wp<LayerBaseClient> mOwner;
- };
-
- friend class Surface;
-
protected:
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void shortDump(String8& result, char* scratch, size_t size) const;
+ class LayerCleaner {
+ sp<SurfaceFlinger> mFlinger;
+ wp<LayerBaseClient> mLayer;
+ protected:
+ ~LayerCleaner();
+ public:
+ LayerCleaner(const sp<SurfaceFlinger>& flinger,
+ const sp<LayerBaseClient>& layer);
+ };
+
private:
+ virtual sp<ISurface> createSurface();
+
mutable Mutex mLock;
mutable bool mHasSurface;
wp<IBinder> mClientSurfaceBinder;
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index f79166d..654817d 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -65,8 +65,6 @@
glDisable(GL_TEXTURE_EXTERNAL_OES);
}
#endif
- glDisable(GL_TEXTURE_2D);
-
glVertexPointer(2, GL_FLOAT, 0, mVertices);
while (it != end) {
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 75f9a89..8770e6d 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -37,7 +37,7 @@
virtual ~LayerDim();
virtual void onDraw(const Region& clip) const;
- virtual bool needsBlending() const { return true; }
+ virtual bool isOpaque() const { return false; }
virtual bool isSecure() const { return false; }
virtual bool isProtectedByApp() const { return false; }
virtual bool isProtectedByDRM() const { return false; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b7a51a4..97edfee 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -53,6 +53,8 @@
#include "DisplayHardware/DisplayHardware.h"
#include "DisplayHardware/HWComposer.h"
+#include <private/surfaceflinger/SharedBufferStack.h>
+
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
*/
@@ -133,17 +135,6 @@
return bclient;
}
-sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
-{
- sp<ISurfaceComposerClient> bclient;
- sp<UserClient> client(new UserClient(this));
- status_t err = client->initCheck();
- if (err == NO_ERROR) {
- bclient = client;
- }
- return bclient;
-}
-
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
@@ -322,11 +313,6 @@
mEventQueue.invalidate();
}
-void SurfaceFlinger::signal() const {
- // this is the IPC call
- const_cast<SurfaceFlinger*>(this)->signalEvent();
-}
-
bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
Mutex::Autolock _l(mStateLock);
sp<IBinder> surfBinder(surface->asBinder());
@@ -658,7 +644,7 @@
// handle hidden surfaces by setting the visible region to empty
if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
- const bool translucent = layer->needsBlending();
+ const bool translucent = !layer->isOpaque();
const Rect bounds(layer->visibleBounds());
visibleRegion.set(bounds);
visibleRegion.andSelf(screenRegion);
@@ -921,7 +907,7 @@
for (size_t i=0 ; i<count ; i++) {
if (cur[i].hints & HWC_HINT_CLEAR_FB) {
const sp<LayerBase>& layer(layers[i]);
- if (!(layer->needsBlending())) {
+ if (layer->isOpaque()) {
transparent.orSelf(layer->visibleRegionScreen);
}
}
@@ -979,8 +965,6 @@
composeSurfaces(repaint);
}
- TextureManager::deactivateTextures();
-
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
@@ -1070,6 +1054,7 @@
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
@@ -1269,7 +1254,7 @@
uint32_t flags)
{
sp<LayerBaseClient> layer;
- sp<LayerBaseClient::Surface> surfaceHandle;
+ sp<ISurface> surfaceHandle;
if (int32_t(w|h) < 0) {
LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
@@ -1300,13 +1285,13 @@
surfaceHandle = layer->getSurface();
if (surfaceHandle != 0) {
params->token = token;
- params->identity = surfaceHandle->getIdentity();
+ params->identity = layer->getIdentity();
params->width = w;
params->height = h;
params->format = format;
if (normalLayer != 0) {
Mutex::Autolock _l(mStateLock);
- mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
+ mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
}
}
@@ -1782,7 +1767,6 @@
GLfloat vtx[8];
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
- glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tname);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1900,6 +1884,7 @@
glEnable(GL_SCISSOR_TEST);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(1, &tname);
+ glDisable(GL_TEXTURE_2D);
return NO_ERROR;
}
@@ -1930,7 +1915,6 @@
GLfloat vtx[8];
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
- glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tname);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -2044,6 +2028,7 @@
glEnable(GL_SCISSOR_TEST);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(1, &tname);
+ glDisable(GL_TEXTURE_2D);
return NO_ERROR;
}
@@ -2408,20 +2393,72 @@
return lbc;
}
-sp<IMemoryHeap> Client::getControlBlock() const {
- return 0;
+
+status_t Client::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // these must be checked
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ LOGE("Permission Denial: "
+ "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
}
-ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
- return -1;
-}
+
+
sp<ISurface> Client::createSurface(
ISurfaceComposerClient::surface_data_t* params,
const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
- return mFlinger->createSurface(params, name, this,
- display, w, h, format, flags);
+ /*
+ * createSurface must be called from the GL thread so that it can
+ * have access to the GL context.
+ */
+
+ class MessageCreateSurface : public MessageBase {
+ sp<ISurface> result;
+ SurfaceFlinger* flinger;
+ ISurfaceComposerClient::surface_data_t* params;
+ Client* client;
+ const String8& name;
+ DisplayID display;
+ uint32_t w, h;
+ PixelFormat format;
+ uint32_t flags;
+ public:
+ MessageCreateSurface(SurfaceFlinger* flinger,
+ ISurfaceComposerClient::surface_data_t* params,
+ const String8& name, Client* client,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+ : flinger(flinger), params(params), client(client), name(name),
+ display(display), w(w), h(h), format(format), flags(flags)
+ {
+ }
+ sp<ISurface> getResult() const { return result; }
+ virtual bool handler() {
+ result = flinger->createSurface(params, name, client,
+ display, w, h, format, flags);
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
+ params, name, this, display, w, h, format, flags);
+ mFlinger->postMessageSync(msg);
+ return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
}
status_t Client::destroySurface(SurfaceID sid) {
return mFlinger->removeSurface(this, sid);
@@ -2432,113 +2469,6 @@
// ---------------------------------------------------------------------------
-UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
- : ctrlblk(0), mBitmap(0), mFlinger(flinger)
-{
- const int pgsize = getpagesize();
- const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
-
- mCblkHeap = new MemoryHeapBase(cblksize, 0,
- "SurfaceFlinger Client control-block");
-
- ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
- if (ctrlblk) { // construct the shared structure in-place.
- new(ctrlblk) SharedClient;
- }
-}
-
-UserClient::~UserClient()
-{
- if (ctrlblk) {
- ctrlblk->~SharedClient(); // destroy our shared-structure.
- }
-
- /*
- * When a UserClient dies, it's unclear what to do exactly.
- * We could go ahead and destroy all surfaces linked to that client
- * however, it wouldn't be fair to the main Client
- * (usually the the window-manager), which might want to re-target
- * the layer to another UserClient.
- * I think the best is to do nothing, or not much; in most cases the
- * WM itself will go ahead and clean things up when it detects a client of
- * his has died.
- * The remaining question is what to display? currently we keep
- * just keep the current buffer.
- */
-}
-
-status_t UserClient::initCheck() const {
- return ctrlblk == 0 ? NO_INIT : NO_ERROR;
-}
-
-void UserClient::detachLayer(const Layer* layer)
-{
- int32_t name = layer->getToken();
- if (name >= 0) {
- int32_t mask = 1LU<<name;
- if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
- LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
- }
- }
-}
-
-sp<IMemoryHeap> UserClient::getControlBlock() const {
- return mCblkHeap;
-}
-
-ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
-{
- int32_t name = NAME_NOT_FOUND;
- sp<Layer> layer(mFlinger->getLayer(sur));
- if (layer == 0) {
- return name;
- }
-
- // if this layer already has a token, just return it
- name = layer->getToken();
- if ((name >= 0) && (layer->getClient() == this)) {
- return name;
- }
-
- name = 0;
- do {
- int32_t mask = 1LU<<name;
- if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
- // we found and locked that name
- status_t err = layer->setToken(
- const_cast<UserClient*>(this), ctrlblk, name);
- if (err != NO_ERROR) {
- // free the name
- android_atomic_and(~mask, &mBitmap);
- name = err;
- }
- break;
- }
- if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
- name = NO_MEMORY;
- } while(name >= 0);
-
- //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
- // sur->asBinder().get(), name, this, mBitmap);
- return name;
-}
-
-sp<ISurface> UserClient::createSurface(
- ISurfaceComposerClient::surface_data_t* params,
- const String8& name,
- DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags) {
- return 0;
-}
-status_t UserClient::destroySurface(SurfaceID sid) {
- return INVALID_OPERATION;
-}
-status_t UserClient::setState(int32_t count, const layer_state_t* states) {
- return INVALID_OPERATION;
-}
-
-// ---------------------------------------------------------------------------
-
GraphicBufferAlloc::GraphicBufferAlloc() {}
GraphicBufferAlloc::~GraphicBufferAlloc() {}
@@ -2547,11 +2477,11 @@
PixelFormat format, uint32_t usage) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
status_t err = graphicBuffer->initCheck();
- if (err != 0) {
- LOGE("createGraphicBuffer: init check failed: %d", err);
- return 0;
- } else if (graphicBuffer->handle == 0) {
- LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+ if (err != 0 || graphicBuffer->handle == 0) {
+ GraphicBuffer::dumpAllocationsToSystemLog();
+ LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+ "failed (%s), handle=%p",
+ w, h, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 992861a..af1ef04 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -50,6 +50,7 @@
class FreezeLock;
class Layer;
class LayerDim;
+struct surface_flinger_cblk_t;
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
@@ -72,14 +73,14 @@
private:
// ISurfaceComposerClient interface
- virtual sp<IMemoryHeap> getControlBlock() const;
- virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
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);
// constant
sp<SurfaceFlinger> mFlinger;
@@ -92,40 +93,6 @@
mutable Mutex mLock;
};
-class UserClient : public BnSurfaceComposerClient
-{
-public:
- // pointer to this client's control block
- SharedClient* ctrlblk;
-
-public:
- UserClient(const sp<SurfaceFlinger>& flinger);
- ~UserClient();
-
- status_t initCheck() const;
-
- // protected by SurfaceFlinger::mStateLock
- void detachLayer(const Layer* layer);
-
-private:
-
- // ISurfaceComposerClient interface
- virtual sp<IMemoryHeap> getControlBlock() const;
- virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
- 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);
-
- // atomic-ops
- mutable volatile int32_t mBitmap;
-
- sp<IMemoryHeap> mCblkHeap;
- sp<SurfaceFlinger> mFlinger;
-};
-
class GraphicBufferAlloc : public BnGraphicBufferAlloc
{
public:
@@ -199,7 +166,6 @@
// ISurfaceComposer interface
virtual sp<ISurfaceComposerClient> createConnection();
- virtual sp<ISurfaceComposerClient> createClientConnection();
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
@@ -208,7 +174,6 @@
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);
- virtual void signal() const;
virtual bool authenticateSurface(const sp<ISurface>& surface) const;
virtual status_t captureScreen(DisplayID dpy,
@@ -235,7 +200,6 @@
friend class Client;
friend class LayerBase;
friend class LayerBaseClient;
- friend class LayerBaseClient::Surface;
friend class Layer;
friend class LayerDim;
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
new file mode 100644
index 0000000..60fa965
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include "Layer.h"
+#include "SurfaceTextureLayer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+
+SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
+ : SurfaceTexture(tex), mLayer(layer) {
+}
+
+SurfaceTextureLayer::~SurfaceTextureLayer() {
+}
+
+
+status_t SurfaceTextureLayer::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+ //LOGD("%s, w=%u, h=%u", __PRETTY_FUNCTION__, w, h);
+ return SurfaceTexture::setDefaultBufferSize(w, h);
+}
+
+status_t SurfaceTextureLayer::setDefaultBufferFormat(uint32_t format)
+{
+ mDefaultFormat = format;
+ return NO_ERROR;
+}
+
+status_t SurfaceTextureLayer::setBufferCount(int bufferCount) {
+ status_t res = SurfaceTexture::setBufferCount(bufferCount);
+ return res;
+}
+
+status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+
+ status_t res(NO_INIT);
+ sp<Layer> layer(mLayer.promote());
+ if (layer != NULL) {
+ if (format == 0)
+ format = mDefaultFormat;
+ uint32_t effectiveUsage = layer->getEffectiveUsage(usage);
+ //LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
+ // __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
+ res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
+ if (res == NO_ERROR) {
+ layer->setFixedSize(w && h);
+ }
+ }
+ return res;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
new file mode 100644
index 0000000..7faff54
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 ANDROID_SURFACE_TEXTURE_LAYER_H
+#define ANDROID_SURFACE_TEXTURE_LAYER_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Layer;
+
+class SurfaceTextureLayer : public SurfaceTexture
+{
+ wp<Layer> mLayer;
+ uint32_t mDefaultFormat;
+
+public:
+ SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer);
+ ~SurfaceTextureLayer();
+
+ status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+ status_t setDefaultBufferFormat(uint32_t format);
+
+public:
+ virtual status_t setBufferCount(int bufferCount);
+
+protected:
+ virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+ uint32_t format, uint32_t usage);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_TEXTURE_LAYER_H
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index 0ddf986..ca445553 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -20,18 +20,10 @@
namespace android {
-int clz_impl(int32_t x);
-
-int inline clz(int32_t x)
-{
-#if defined(__arm__) && !defined(__thumb__)
+int inline clz(int32_t x) {
return __builtin_clz(x);
-#else
- return clz_impl(x);
-#endif
}
-
}; // namespace android
#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f831ca3..476aded 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -297,7 +297,7 @@
final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(5, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 5, 1024L, 1024L);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -307,7 +307,7 @@
final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(20, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 20, 1024L, 1024L);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -317,7 +317,7 @@
final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(30, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -327,7 +327,7 @@
final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
- final NetworkPolicy policy = new NetworkPolicy(30, 1024L, 1024L);
+ final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertEquals(expectedCycle, actualCycle);
}
@@ -366,7 +366,7 @@
// TODO: write up NetworkManagementService mock
replay();
- mService.setNetworkPolicy(TEMPLATE_WIFI, null, new NetworkPolicy(CYCLE_DAY, 1024L, 2048L));
+ setNetworkPolicies(new NetworkPolicy(TEMPLATE_WIFI, null, CYCLE_DAY, 1024L, 2048L));
verifyAndReset();
}
@@ -376,6 +376,10 @@
return result.toMillis(true);
}
+ private void setNetworkPolicies(NetworkPolicy... policies) {
+ mService.setNetworkPolicies(policies);
+ }
+
private static NetworkState buildWifi() {
final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 7abae09..171b371 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1803,33 +1803,33 @@
Call call;
StringBuilder b = new StringBuilder();
- b.append("########### Dump CallManager ############");
- b.append("\nCallManager state = " + getState());
+ b.append("CallManager {");
+ b.append("\nstate = " + getState());
call = getActiveFgCall();
- b.append("\n - Foreground: " + getActiveFgCallState());
+ b.append("\n- Foreground: " + getActiveFgCallState());
b.append(" from " + call.getPhone());
- b.append("\n Conn: ").append(getFgCallConnections());
+ b.append("\n Conn: ").append(getFgCallConnections());
call = getFirstActiveBgCall();
- b.append("\n - Background: " + call.getState());
+ b.append("\n- Background: " + call.getState());
b.append(" from " + call.getPhone());
- b.append("\n Conn: ").append(getBgCallConnections());
+ b.append("\n Conn: ").append(getBgCallConnections());
call = getFirstActiveRingingCall();
- b.append("\n - Ringing: " +call.getState());
+ b.append("\n- Ringing: " +call.getState());
b.append(" from " + call.getPhone());
for (Phone phone : getAllPhones()) {
if (phone != null) {
- b.append("\n Phone: " + phone + ", name = " + phone.getPhoneName()
+ b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
+ ", state = " + phone.getState());
call = phone.getForegroundCall();
- b.append("\n - Foreground: ").append(call);
+ b.append("\n- Foreground: ").append(call);
call = phone.getBackgroundCall();
b.append(" Background: ").append(call);
call = phone.getRingingCall();
b.append(" Ringing: ").append(call);
}
}
- b.append("\n########## End Dump CallManager ##########");
+ b.append("\n}");
return b.toString();
}
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 014901d..457fa7a 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.location.CountryDetector;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
@@ -29,6 +30,13 @@
import android.text.TextUtils;
import android.util.Log;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberOfflineGeocoder;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+import java.util.Locale;
+
/**
* Looks up caller information for the given phone number.
@@ -72,7 +80,8 @@
*/
public String name;
public String phoneNumber;
- public String nomalizedNumber;
+ public String normalizedNumber;
+ public String geoDescription;
public String cnapName;
public int numberPresentation;
@@ -131,7 +140,7 @@
info.isCachedPhotoCurrent = false;
info.contactExists = false;
- if (VDBG) Log.v(TAG, "construct callerInfo from cursor");
+ if (VDBG) Log.v(TAG, "getCallerInfo() based on cursor...");
if (cursor != null) {
if (cursor.moveToFirst()) {
@@ -156,7 +165,7 @@
// Look for the normalized number
columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER);
if (columnIndex != -1) {
- info.nomalizedNumber = cursor.getString(columnIndex);
+ info.normalizedNumber = cursor.getString(columnIndex);
}
// Look for the label/type combo
@@ -236,6 +245,8 @@
* with all relevant fields empty or null.
*/
public static CallerInfo getCallerInfo(Context context, String number) {
+ if (VDBG) Log.v(TAG, "getCallerInfo() based on number...");
+
if (TextUtils.isEmpty(number)) {
return null;
}
@@ -473,6 +484,66 @@
}
/**
+ * Updates this CallerInfo's geoDescription field, based on the raw
+ * phone number in the phoneNumber field.
+ *
+ * (Note that the various getCallerInfo() methods do *not* set the
+ * geoDescription automatically; you need to call this method
+ * explicitly to get it.)
+ *
+ * @param context the context used to look up the current locale / country
+ * @param fallbackNumber if this CallerInfo's phoneNumber field is empty,
+ * this specifies a fallback number to use instead.
+ */
+ public void updateGeoDescription(Context context, String fallbackNumber) {
+ String number = TextUtils.isEmpty(phoneNumber) ? fallbackNumber : phoneNumber;
+ geoDescription = getGeoDescription(context, number);
+ }
+
+ /**
+ * @return a geographical description string for the specified number.
+ * @see com.google.i18n.phonenumbers.PhoneNumberOfflineGeocoder
+ */
+ private static String getGeoDescription(Context context, String number) {
+ if (VDBG) Log.v(TAG, "getGeoDescription('" + number + "')...");
+
+ if (TextUtils.isEmpty(number)) {
+ return null;
+ }
+
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
+
+ String countryIso;
+ Locale locale = context.getResources().getConfiguration().locale;
+ CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ countryIso = detector.detectCountry().getCountryIso();
+ } else {
+ countryIso = locale.getCountry();
+ Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ + countryIso);
+ }
+
+ PhoneNumber pn = null;
+ try {
+ pn = util.parse(number, countryIso);
+ if (VDBG) Log.v(TAG, "- parsed number: " + pn);
+ } catch (NumberParseException e) {
+ Log.w(TAG, "getGeoDescription: NumberParseException for incoming number '" + number + "'");
+ }
+
+ if (pn != null) {
+ String description = geocoder.getDescriptionForNumber(pn, locale);
+ if (VDBG) Log.v(TAG, "- got description: '" + description + "'");
+ return description;
+ } else {
+ return null;
+ }
+ }
+
+ /**
* @return a string debug representation of this instance.
*/
public String toString() {
@@ -482,8 +553,11 @@
if (VERBOSE_DEBUG) {
return new StringBuilder(384)
+ .append(super.toString() + " { ")
.append("\nname: " + name)
.append("\nphoneNumber: " + phoneNumber)
+ .append("\nnormalizedNumber: " + normalizedNumber)
+ .append("\ngeoDescription: " + geoDescription)
.append("\ncnapName: " + cnapName)
.append("\nnumberPresentation: " + numberPresentation)
.append("\nnamePresentation: " + namePresentation)
@@ -502,10 +576,11 @@
.append("\nemergency: " + mIsEmergency)
.append("\nvoicemail " + mIsVoiceMail)
.append("\ncontactExists " + contactExists)
+ .append(" }")
.toString();
} else {
return new StringBuilder(128)
- .append("CallerInfo { ")
+ .append(super.toString() + " { ")
.append("name " + ((name == null) ? "null" : "non-null"))
.append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
.append(" }")
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index c47e076..bbd4232 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -34,9 +34,11 @@
import android.util.Log;
/**
- * ASYNCHRONOUS QUERY API
+ * Helper class to make it easier to run asynchronous caller-id lookup queries.
+ * @see CallerInfo
+ *
+ * {@hide}
*/
-
public class CallerInfoAsyncQuery {
private static final boolean DBG = false;
private static final String LOG_TAG = "CallerInfoAsyncQuery";
@@ -239,12 +241,31 @@
+ mCallerInfo);
}
+ // Final step: look up the geocoded description.
+ //
+ // For now, do this only if we *don't* have a valid name (i.e. if
+ // no contacts matched the phone number of the incoming call),
+ // since that's the only case where the incoming-call UI cares
+ // about this field.
+ // (TODO: But if we ever want the UI to show the geoDescription
+ // even when we *do* match a contact, we'll need to either call
+ // updateGeoDescription() unconditionally here, or possibly add a
+ // new parameter to CallerInfoAsyncQuery.startQuery() to force
+ // the geoDescription field to be populated.)
+ if (TextUtils.isEmpty(mCallerInfo.name)) {
+ // Actually when no contacts match the incoming phone number,
+ // the CallerInfo object is totally blank here (i.e. no name
+ // *or* phoneNumber). So we need to pass in cw.number as
+ // a fallback number.
+ mCallerInfo.updateGeoDescription(mQueryContext, cw.number);
+ }
+
// Use the number entered by the user for display.
if (!TextUtils.isEmpty(cw.number)) {
CountryDetector detector = (CountryDetector) mQueryContext.getSystemService(
Context.COUNTRY_DETECTOR);
mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number,
- mCallerInfo.nomalizedNumber,
+ mCallerInfo.normalizedNumber,
detector.detectCountry().getCountryIso());
}
}
@@ -412,7 +433,7 @@
* Method to create a new CallerInfoAsyncQueryHandler object, ensuring correct
* state of context and uri.
*/
- private void allocate (Context context, Uri contactRef) {
+ private void allocate(Context context, Uri contactRef) {
if ((context == null) || (contactRef == null)){
throw new QueryPoolException("Bad context or query uri.");
}
@@ -424,7 +445,7 @@
/**
* Releases the relevant data.
*/
- private void release () {
+ private void release() {
mHandler.mQueryContext = null;
mHandler.mQueryUri = null;
mHandler.mCallerInfo = null;
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index 31dc75a..5cdacf7 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -19,14 +19,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
+
android:useDefaultMargins="true"
android:marginsIncludedInAlignment="false"
+
android:columnCount="4"
>
<TextView
android:text="Email account"
android:textSize="48dip"
+
android:layout_columnSpan="4"
android:layout_gravity="center_horizontal"
/>
@@ -34,12 +37,14 @@
<TextView
android:text="You can configure email in just a few steps:"
android:textSize="20dip"
+
android:layout_columnSpan="4"
android:layout_gravity="left"
/>
<TextView
android:text="Email address:"
+
android:layout_gravity="right"
/>
@@ -49,6 +54,7 @@
<TextView
android:text="Password:"
+
android:layout_column="0"
android:layout_gravity="right"
/>
@@ -58,14 +64,15 @@
/>
<Space
- android:layout_rowWeight="1"
- android:layout_columnWeight="1"
android:layout_row="4"
android:layout_column="2"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
/>
<Button
android:text="Manual setup"
+
android:layout_row="5"
android:layout_column="3"
android:layout_gravity="fill_horizontal"
@@ -73,6 +80,7 @@
<Button
android:text="Next"
+
android:layout_column="3"
android:layout_gravity="fill_horizontal"
/>
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index 5e29cf1..32365d7 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -20,11 +20,15 @@
import android.content.Context;
import android.os.Bundle;
import android.view.View;
-
-import android.widget.*;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.GridLayout;
+import android.widget.Space;
+import android.widget.TextView;
import static android.text.InputType.TYPE_CLASS_TEXT;
-import static android.view.inputmethod.EditorInfo.*;
+import static android.view.inputmethod.EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+import static android.view.inputmethod.EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
import static android.widget.GridLayout.*;
public class Activity2 extends Activity {
@@ -42,12 +46,12 @@
Group row6 = new Group(6, CENTER);
Group row7 = new Group(7, CENTER);
- Group col1a = new Group(1, 5, CENTER);
- Group col1b = new Group(1, 5, LEFT);
+ Group col1a = new Group(1, 4, CENTER);
+ Group col1b = new Group(1, 4, LEFT);
Group col1c = new Group(1, RIGHT);
- Group col2 = new Group(2, LEFT);
- Group col3 = new Group(3, FILL);
- Group col4 = new Group(4, FILL);
+ Group col2 = new Group(2, LEFT);
+ Group col3 = new Group(3, FILL);
+ Group col4 = new Group(4, FILL);
{
TextView v = new TextView(context);
@@ -55,20 +59,17 @@
v.setText("Email setup");
vg.addView(v, new LayoutParams(row1, col1a));
}
-
{
TextView v = new TextView(context);
v.setTextSize(20);
v.setText("You can configure email in just a few steps:");
vg.addView(v, new LayoutParams(row2, col1b));
}
-
{
TextView v = new TextView(context);
v.setText("Email address:");
vg.addView(v, new LayoutParams(row3, col1c));
}
-
{
EditText v = new EditText(context);
v.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
@@ -78,13 +79,11 @@
vg.addView(v, lp);
}
}
-
{
TextView v = new TextView(context);
v.setText("Password:");
vg.addView(v, new LayoutParams(row4, col1c));
}
-
{
TextView v = new EditText(context);
v.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
@@ -94,7 +93,6 @@
vg.addView(v, lp);
}
}
-
{
Space v = new Space(context);
{
@@ -104,13 +102,11 @@
vg.addView(v, lp);
}
}
-
{
Button v = new Button(context);
v.setText("Manual setup");
vg.addView(v, new LayoutParams(row6, col4));
}
-
{
Button v = new Button(context);
v.setText("Next");
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
index b49db7c5..1c82e9b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
@@ -79,6 +78,9 @@
}
canvas.restore();
canvas.drawText("OpenGLRenderer", 50.0f, 50.0f, mClearPaint);
+ mClearPaint.setColor(0xff000000);
+ canvas.drawRect(800.0f, 100.0f, 900.0f, 200.0f, mClearPaint);
+ mClearPaint.setColor(0x0000ff00);
}
canvas.restore();
}
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index b5f1a17..4837eb9 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -528,12 +528,8 @@
public void answerCall(String sessionDescription, int timeout) {
synchronized (SipSessionGroup.this) {
if (mPeerProfile == null) return;
- try {
- processCommand(new MakeCallCommand(mPeerProfile,
- sessionDescription, timeout));
- } catch (SipException e) {
- onError(e);
- }
+ doCommandAsync(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
}
}
diff --git a/wifi/java/android/net/wifi/SupplicantState.java b/wifi/java/android/net/wifi/SupplicantState.java
index 91e685f..509b02c 100644
--- a/wifi/java/android/net/wifi/SupplicantState.java
+++ b/wifi/java/android/net/wifi/SupplicantState.java
@@ -216,6 +216,28 @@
}
}
+ static boolean isDriverActive(SupplicantState state) {
+ switch(state) {
+ case DISCONNECTED:
+ case DORMANT:
+ case INACTIVE:
+ case AUTHENTICATING:
+ case ASSOCIATING:
+ case ASSOCIATED:
+ case SCANNING:
+ case FOUR_WAY_HANDSHAKE:
+ case GROUP_HANDSHAKE:
+ case COMPLETED:
+ return true;
+ case INTERFACE_DISABLED:
+ case UNINITIALIZED:
+ case INVALID:
+ return false;
+ default:
+ throw new IllegalArgumentException("Unknown supplicant state");
+ }
+ }
+
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 4a45825..4ec4cfc 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -107,7 +107,7 @@
* <pre>
* CTRL-EVENT-DRIVER-STATE state
* </pre>
- * <code>state</code> is either STARTED or STOPPED
+ * <code>state</code> can be HANGED
*/
private static final String driverStateEvent = "DRIVER-STATE";
/**
@@ -304,11 +304,7 @@
if (state == null) {
return;
}
- if (state.equals("STOPPED")) {
- mWifiStateMachine.notifyDriverStopped();
- } else if (state.equals("STARTED")) {
- mWifiStateMachine.notifyDriverStarted();
- } else if (state.equals("HANGED")) {
+ if (state.equals("HANGED")) {
mWifiStateMachine.notifyDriverHung();
}
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 6df37bb..3df3736 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -212,22 +212,18 @@
static final int SUP_CONNECTION_EVENT = BASE + 31;
/* Connection to supplicant lost */
static final int SUP_DISCONNECTION_EVENT = BASE + 32;
- /* Driver start completed */
- static final int DRIVER_START_EVENT = BASE + 33;
- /* Driver stop completed */
- static final int DRIVER_STOP_EVENT = BASE + 34;
- /* Network connection completed */
- static final int NETWORK_CONNECTION_EVENT = BASE + 36;
+ /* Network connection completed */
+ static final int NETWORK_CONNECTION_EVENT = BASE + 33;
/* Network disconnection completed */
- static final int NETWORK_DISCONNECTION_EVENT = BASE + 37;
+ static final int NETWORK_DISCONNECTION_EVENT = BASE + 34;
/* Scan results are available */
- static final int SCAN_RESULTS_EVENT = BASE + 38;
+ static final int SCAN_RESULTS_EVENT = BASE + 35;
/* Supplicate state changed */
- static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 39;
+ static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 36;
/* Password failure and EAP authentication failure */
- static final int AUTHENTICATION_FAILURE_EVENT = BASE + 40;
+ static final int AUTHENTICATION_FAILURE_EVENT = BASE + 37;
/* WPS overlap detected */
- static final int WPS_OVERLAP_EVENT = BASE + 41;
+ static final int WPS_OVERLAP_EVENT = BASE + 38;
/* Supplicant commands */
@@ -1421,6 +1417,35 @@
return mNetworkInfo.getDetailedState();
}
+
+ private SupplicantState handleSupplicantStateChange(Message message) {
+ StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+ SupplicantState state = stateChangeResult.state;
+ // Supplicant state change
+ // [31-13] Reserved for future use
+ // [8 - 0] Supplicant state (as defined in SupplicantState.java)
+ // 50023 supplicant_state_changed (custom|1|5)
+ EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
+ mWifiInfo.setSupplicantState(state);
+ // Network id is only valid when we start connecting
+ if (SupplicantState.isConnecting(state)) {
+ mWifiInfo.setNetworkId(stateChangeResult.networkId);
+ } else {
+ mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
+ }
+
+ if (state == SupplicantState.ASSOCIATING) {
+ /* BSSID is valid only in ASSOCIATING state */
+ mWifiInfo.setBSSID(stateChangeResult.BSSID);
+ }
+ setNetworkDetailedState(WifiInfo.getDetailedStateOf(state));
+
+ mSupplicantStateTracker.sendMessage(Message.obtain(message));
+ mWpsStateMachine.sendMessage(Message.obtain(message));
+
+ return state;
+ }
+
/**
* Resets the Wi-Fi Connections by clearing any state, resetting any sockets
* using the interface, stopping DHCP & disabling interface
@@ -1674,14 +1699,6 @@
sendMessage(SCAN_RESULTS_EVENT);
}
- void notifyDriverStarted() {
- sendMessage(DRIVER_START_EVENT);
- }
-
- void notifyDriverStopped() {
- sendMessage(DRIVER_STOP_EVENT);
- }
-
void notifyDriverHung() {
setWifiEnabled(false);
setWifiEnabled(true);
@@ -1737,8 +1754,6 @@
case CMD_REASSOCIATE:
case SUP_CONNECTION_EVENT:
case SUP_DISCONNECTION_EVENT:
- case DRIVER_START_EVENT:
- case DRIVER_STOP_EVENT:
case NETWORK_CONNECTION_EVENT:
case NETWORK_DISCONNECTION_EVENT:
case SCAN_RESULTS_EVENT:
@@ -2284,13 +2299,19 @@
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch(message.what) {
- case DRIVER_START_EVENT:
- transitionTo(mDriverStartedState);
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ SupplicantState state = handleSupplicantStateChange(message);
+ /* If suplicant is exiting out of INTERFACE_DISABLED state into
+ * a state that indicates driver has started, it is ready to
+ * receive driver commands
+ */
+ if (SupplicantState.isDriverActive(state)) {
+ transitionTo(mDriverStartedState);
+ }
break;
/* Queue driver commands & connection events */
case CMD_START_DRIVER:
case CMD_STOP_DRIVER:
- case SUPPLICANT_STATE_CHANGE_EVENT:
case NETWORK_CONNECTION_EVENT:
case NETWORK_DISCONNECTION_EVENT:
case AUTHENTICATION_FAILURE_EVENT:
@@ -2429,8 +2450,11 @@
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch(message.what) {
- case DRIVER_STOP_EVENT:
- transitionTo(mDriverStoppedState);
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ SupplicantState state = handleSupplicantStateChange(message);
+ if (state == SupplicantState.INTERFACE_DISABLED) {
+ transitionTo(mDriverStoppedState);
+ }
break;
/* Queue driver commands */
case CMD_START_DRIVER:
@@ -2465,11 +2489,23 @@
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch (message.what) {
- case CMD_START_DRIVER:
- mWakeLock.acquire();
- WifiNative.startDriverCommand();
- transitionTo(mDriverStartingState);
- mWakeLock.release();
+ case CMD_START_DRIVER:
+ mWakeLock.acquire();
+ WifiNative.startDriverCommand();
+ mWakeLock.release();
+ break;
+ case SUPPLICANT_STATE_CHANGE_EVENT:
+ SupplicantState state = handleSupplicantStateChange(message);
+ /* A driver start causes supplicant to first report an INTERFACE_DISABLED
+ * state before transitioning out of it for connection. Stay in
+ * DriverStoppedState until we get an INTERFACE_DISABLED state and transition
+ * to DriverStarting upon getting that
+ * TODO: Fix this when the supplicant can be made to just transition out of
+ * INTERFACE_DISABLED state when driver gets started
+ */
+ if (state == SupplicantState.INTERFACE_DISABLED) {
+ transitionTo(mDriverStartingState);
+ }
break;
default:
return NOT_HANDLED;
@@ -2535,29 +2571,8 @@
sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
break;
case SUPPLICANT_STATE_CHANGE_EVENT:
- stateChangeResult = (StateChangeResult) message.obj;
- SupplicantState state = stateChangeResult.state;
- // Supplicant state change
- // [31-13] Reserved for future use
- // [8 - 0] Supplicant state (as defined in SupplicantState.java)
- // 50023 supplicant_state_changed (custom|1|5)
- EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
- mWifiInfo.setSupplicantState(state);
- // Network id is only valid when we start connecting
- if (SupplicantState.isConnecting(state)) {
- mWifiInfo.setNetworkId(stateChangeResult.networkId);
- } else {
- mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
- }
-
- if (state == SupplicantState.ASSOCIATING) {
- /* BSSID is valid only in ASSOCIATING state */
- mWifiInfo.setBSSID(stateChangeResult.BSSID);
- }
-
- mSupplicantStateTracker.sendMessage(Message.obtain(message));
- mWpsStateMachine.sendMessage(Message.obtain(message));
- break;
+ handleSupplicantStateChange(message);
+ break;
/* Do a redundant disconnect without transition */
case CMD_DISCONNECT:
WifiNative.disconnectCommand();
@@ -2964,12 +2979,7 @@
/* Ignore network disconnect */
case NETWORK_DISCONNECTION_EVENT:
break;
- case SUPPLICANT_STATE_CHANGE_EVENT:
- StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
- setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
- /* DriverStartedState does the rest of the handling */
- return NOT_HANDLED;
- case CMD_START_SCAN:
+ case CMD_START_SCAN:
/* Disable background scan temporarily during a regular scan */
if (mEnableBackgroundScan) {
WifiNative.enableBackgroundScanCommand(false);